Resources · Knowledge Base

Knowledge Base

This is everything there is to know about Incisor®, gathered into one place as plain text: the full API documentation, tutorial scripts, example projects, questions and answers, inspector tool tips, release notes, and deprecation schedule.

Search it for answers, or give it to an AI assistant such as Claude or ChatGPT. With the knowledge base as reference, an assistant can answer questions about Incisor and help write code that uses the Incisor API correctly. Download the zip below to add the documents to your assistant's project files, or read them in full further down this page.

You can also connect your assistant to Incisor directly. Incisor has a public MCP server at https://mcp.incisordev.com/mcp, and VS Code plugins for Claude and ChatGPT.

Any use of this content is subject to the INCISOR® End User License and Terms of Use.

INCISOR SOFTWARE DEVELOPMENT PLATFORM

IncisorOverview.txt

INCISOR SOFTWARE DEVELOPMENT PLATFORM

THE OMNICHANNEL SOLUTION FOR YOUR WHOLE TEAM

Incisor is a comprehensive platform that enables developers and designers to build high-quality interactive software and gaming products. The platform consists of JavaScript or TypeScript APIs, a customizable GUI, and other tools bundled together into a single application. Incisor can be used to create extremely lightweight apps that operate on any target device or EGM - all from a single codebase. With Incisor, your team can Build It Once.

WHAT MAKES INCISOR BETTER

The primary driving force behind Incisor is making the development of commercial-grade software more collaborative, efficient, flexible, and generally straightforward. Whether your focus is on highly optimized products downloadable at a fraction of the size without sacrificing quality, or creating 4k resolution products for the casino floor, Incisor is the only solution. The platform incorporates countless efficiencies into both the production process and the published result, enabling not only better products, but better development.

INCLUDED FEATURES

Developers using this platform benefit from a truly comprehensive set of production features, but perhaps the greatest benefit is the simplicity of this functionality bundled into a single application. Incisor ties together each of the elements of the software development process, and the result is an unparalleled boost to project organization, scalability, as well as collaboration and creativity. Incisor boasts the following features:

JavaScript or TypeScript APIs
- Manipulate graphics, sounds, and other assets easily and efficiently
- Includes complete API reference documentation and examples
- JSDoc-enabled
- Comprehensive autocomplete library
- Dynamic autocomplete reflects project assets and customization

GUI
- Incisor's inspection GUI, built using Incisor:
  - Object Inspector
  - Hierarchy Inspector
  - Tool Tips Panel
  - Layer Inspector
  - Construct Editor
  - Timeline Editor
  - Particle System Inspector
  - Asset Browser and Settings Inspector
  - Publishing Analysis Panel
  - Project Settings Popup
  - Flow Controller Inspector

GUI Content Creation
- User-defined object and asset assembly: "Constructs"
- Inspect and edit visual effects
- GUI timeline animation:
  - Easily animate all object components, even user-defined visual effects
  - Multi-timeline constructs with influence-crossfading for smooth transitions
  - Constructs with timelines are a download-saving frame-based animation alternative
- Highly optimized GPU particle system editor

Built-In Optimizations
- LoadingTier (lazy loading)
- Color Palette Compression
- Automatic Overdraw Reduction
- Sprite Sheet Generation
- Dynamic Runtime Animation
- Shapify (Signed Distance Field)
- Graphicexpander (9 Slice)
- GPU Particle Systems
- Textbox (Pre-Rendered Text)
- Effectnode (GPU Visual Effects)
- Optional Code Modules
- Asset Package Configurations
- Code Minification
- Precomp (Pre-Rendered Scenes)
- Target-Specific File Inclusion
- Language-Driven Font Reduction

Development Pipeline
- Fully configurable and customizable GUI layout
- Comprehensive tool for technical artists and animators to contribute directly to projects without needing to code
- CustomAddOns are modular and reusable scripts that can be added by designers within the GUI to give SceneObjects custom behaviors
- Editor Extensions are a means to tailor the functionality of the GUI by incorporating custom tools, menus, GUI panels, and more
- Includes FileIO capabilities for scripted project manipulation
- Non-destructive pipeline gives developers a broad range of iteration and optimization options without any asset re-work
- Ability to expose Effectnode variables in GUI for manipulation by non-coding team members

Publishing
- Supports multi-configuration publishing allowing for truly omnichannel development
- Pre-publish and post-publish scripting extends publishing configurability
- Built-in code optimization includes minification, whitespace-removal, and conditional code
- Publishing analysis tools provide package-size efficiency overview
- PDF documentation generation capabilities
- Localization management tools enabling a single project to support multiple languages and markets
- Honing the final product is made easy with built-in publishing analysis tools

Website: www.incisordev.com
Call to action: Free trial - click or scan

Incisor® Questions and Answers

IncisorQuestionsAndAnswers.txt

Incisor® Questions and Answers
This document is part of the compiled knowledge base for the Incisor® Software Development Platform.
Any use of this content is subject to the INCISOR® end user license and terms of use agreement.
https://www.incisordev.com/eultua
2026.11.05.12.18.07






----------------------------------------------------------
TABLE OF CONTENTS:
----------------------------------------------------------
Section 1: Remote Hosting On Windows
Section 2: Font Characters Disappearing in Published Project
Section 3: Tagging Code that only Runs when in Editor Mode
Section 4: Particles Disappearing when the Object is out of the Camera View
Section 5: SpriteAnimation
Section 6: 9 Slice
Section 7: Reel Timing and Sequencing in the Slot Template
Section 8: Sounds not Not Showing Up
Section 9: Generating Sprite Sheets
Section 10: Graphic Fonts
Section 11: Adding Constructs
Section 12: Inline TextBox Graphics and Rich Text
Section 13: Containing Directory
Section 14: Dragging Buttons
Section 15: Changing the Order that FlowStateElements Happen In
Section 16: Button Clickable Area
Section 17: Changing the Browser
Section 18: Time ramping gameplay
Section 19: Pausing Everything when game has 'TILT'










----------------------------------------------------------
Section 1: Remote Hosting On Windows
----------------------------------------------------------


PERSON1--------------------
Does anyone know if remote hosting works on Windows with the latest release?
I want to publish and test on my phone without having to post the project online.


PERSON2--------------------
Testing on your mobile devices is very simple with Incisor.  
Go to Application Setting which can be found by clicking on the Incisor logo on the top right corner.  
Check "allowRemoteHosting."  
When you publish the project, check "enable remote hosting."  
This will create a QR code which will work with your mobile devices. 
Just make sure that you are on the same network.  
I just tested this with the latest version of Incisor with the poker project and it worked.
Also on Windows you may have to disable your firewall in order for it to work.











----------------------------------------------------------
Section 2: Font Characters Disappearing in Published Project
----------------------------------------------------------


PERSON1--------------------
Quick follow up on this, we're also seeing a very strange issue in the published version of the poker game. 
It looks like there are a bunch of font issues. 
If we just use the default "sample font", every character appears as vertical bars. 
We tried a different font, which only worked for numbers and capital letters, all lowercase letters are shown as bars. 
Any ideas on that one?


PERSON2--------------------
There are “font reduction” settings in the project settings that are likely removing all of the characters during publishing if you’re not using the project transcript for your phrases. 
You can turn it all off in the project settings.










----------------------------------------------------------
Section 3: Tagging Code that only Runs when in Editor Mode
----------------------------------------------------------


PERSON1--------------------
I have a question, I just thought of today. 
In [another popular engine] code it's possible do do something like #if EDITOR and have code only run if in the editor or #if !EDITOR for code that only runs when not in the editor. 
Is there something like this in Incisor?


PERSON2--------------------
Yeah, Incisor has this:

CODE.includeIf___published;
   // this only runs in the published version
CODE.includeEnd___published;
CODE.includeIf___unpublished;
   // this only runs in the un-published version (in the editor)
CODE.includeEnd___unpublished;
The “CODE” has all of the ‘pre-processor-style’ code manipulation tags on it .










----------------------------------------------------------
Section 4: Particles Disappearing when the Object is out of the Camera View
----------------------------------------------------------


PERSON1--------------------
We have a coin fountain in our game but it won't appear because its point of origin is outside the view of the camera, so the particles never start rendering. 
Is there a way to make a particle system work even if it's outside the camera view?


PERSON2--------------------
Yes, you can set the 'frustumCulling' property to false, either in code or in the GUI. If you select the ParticleSystem you'll see the frustumCulling property in the Object panel
You can turn it off there and if the ParticleSystem is in a Construct, the change will be saved.










----------------------------------------------------------
Section 5: SpriteAnimation
----------------------------------------------------------


PERSON1--------------------
Can I play a png sequence in Incisor?


PERSON2--------------------
Yes, just ensure that the png sequence is included somewhere in the project's Assets directory, and that the image names end in a numeric sequence that makes the ordering clear.
Next, within your project, add a GraphicObject and configure it with a SpriteSetter (either in the GUI within a Construct, or by calling 'configureSpriteSetter' on the GraphicObject).
To configure the SpriteSetter, you'll need to provide a 'keyGraphicAsset' which can be any GraphicAsset within your enumerated png sequence - Incisor will automatically find the whole png sequence.
Once the SpriteSetter is configured, the "spriteSetter" member of the GraphicObject will no longer be undefined, and instead it will be a PlaybackController object that has all of the animation playback controls needed to play the sequence as an animation.










----------------------------------------------------------
Section 6: 9 Slice
----------------------------------------------------------


PERSON1--------------------
Does Incisor have a system for doing a 9 slice?

PERSON2--------------------
Yes. In Incisor it's called "GraphicExpander" and it's an add-on that can be activated on GraphicObjects (or anything that inherits from GraphicObject).
Other names people use for this type of feature are:
"9 Slice"
"9-Slice"
"9 Slice Patch"
"Nine Slice"
"Nine Patch"










----------------------------------------------------------
Section 7: Reel Timing and Sequencing in the Slot Template
----------------------------------------------------------


PERSON1--------------------
Can you help us customize our reel spins in [our game]? 
I looked at the api for SlotReel, but didn't see a simple way to accomplish what we're trying to do: 

1. How can we change the amount of time between each individual reel stop? 
Right now the reels all stop with a very short delay between each one, about 0.1s. 
Would we do this via the windupMotionFunctionName and make a windup function that sets different values for each reel? 
If so, could you provide an example of this?
    
2. How do we modify the behavior of the wheel bounce? 
I saw there's a "bounceMotionFunctionName" so it looks like we can make our own bounce function, but without knowing anything about the internals of the current bounce function, 
I'm not really sure what variables we do or don't have access to to control this. Could you provide an example?


PERSON2--------------------
The timing of the reel starts and stops in the Incisor Slot Template is mostly managed in the SpinReels FlowState...
you’ll see in the constructor that there are two loops that set up the timing for all of the starts and stops, 
and there is an increasing stagger set up within the loops. You can change all of the timing there.

As for the reel bounce, if you build your own bounce function using bounceMotionFunctionOwner and bounceMotionFunctionName, that takes 2 parameters: progress, and magnitude. 
Progress will just be an input number from 0 to 1 over the bounce duration property attached to the reel, and the magnitude is just the bounce magnitude property of the SlotReel itself, you can use it or not… the function takes those properties and should return a number that determines the bounce position at any point during the bounce duration (as represented by the progress parameter). 
The bounce position that function returns should be on a scale where 1 means 1 whole symbol position, so if you want it to bounce up a half a symbol’s height that function should return .5 at its peak.

The windup motion can be replaced similarly.










----------------------------------------------------------
Section 8: Sounds not Not Showing Up
----------------------------------------------------------


PERSON1--------------------
Good day everyone,
I have a question regarding how to properly implement the sound in my game.
So currently on tutorial it has these steps:
- We add the sound assets
- We use the nc.sounds.NameOfTheSoundFile.play()
I am trying to do it the same way it's done in the tutorial, but when I call the name of my sound file even though it's in the Assets folder it doesn't show on the list of auto-complete names. 😅


PERSON2--------------------
Did you add the sounds to the Assets directory in your project?


PERSON1--------------------
Yep. I have my 38 '.ogg' sound files in a GameSounds folder within my project Assets directory.


PERSON2--------------------
Incisor only recognizes ".wav" files for sounds. So your sounds being OGG files is causing this issue.
The reason for the WAV file requirement is that Incisor wants only completely lossless formats (wavs, pngs, etc...) so that it can handle the compression dynamically based on your desired configurations.
You can make different configurations in the ProjectSettings that have different bit rates for the sounds and you can also determine if the sounds are Mono or Stereo.
Since Incisor uses lossless formats, you can export all of these versions/configurations of the project without having to change any of the source files or code.
I hope this clears things up. Be sure to let me know if you have any other questions - thanks!











----------------------------------------------------------
Section 9: Generating Sprite Sheets
----------------------------------------------------------


PERSON1--------------------
Does Incisor have the ability to make sprite sheets from png sequences?


PERSON2--------------------
Yes. 
First, put all of the pngs in your sequence into a directory within the project's "Assets" directory. 
Then, in the Incisor GUI, open an 'Assets' panel, find that folder, uncheck the 'inherit' button (otherwise the directories settings will just inherit the values of the containing directory), and enter a name in the 'spriteSheet' field. 
This will automatically ensure that all of the pngs in the directory are automatically included into a single sprite sheet, without any changes to any of the code that uses those image assets.
You can see the configuration of image assets within the project from within the PublishingAnalysis panel; just select 'Current Configuration', and click on the 'Graphic Summary' button to see all of the Graphics in your project - their inclusion in sprite sheets will be evident from within this menu.











----------------------------------------------------------
Section 10: Graphic Fonts
----------------------------------------------------------


PERSON1--------------------
I've tried to make a font in my project using a folder of pngs it but I feel like I'm missing one step to define it as a font. 
When I select a font, for example, on a TextBox object, I don't have the new font as an option.


PERSON2--------------------
To ensure that a 'graphic font' is discoverable by Incisor, the individual images must all end with "_CharX", where X is the unicode decimal value of the character (this is the same thing as the ascii value for standard english characters). 
You must also ensure that you include the "_Char0" character, as that is the key character graphic that Incisor uses to detect each font. 
In other words, for every "SomeFontName_Char0.png" file that Incisor finds in your assets, it will recognize a new font by the name of "SomeFontName". 

An important note here is that the null character you supply (the _Char0 character) can just be png with a rectangle in it, and Incisor will look at that character for some basic information about the associated font such as the line height and generic character width. 
These values can be adjusted after the fact in the ProjectSettings menu too.










----------------------------------------------------------
Section 11: Adding Constructs
----------------------------------------------------------


PERSON1--------------------
Would you mind giving me a piece of example code to make a scene containing an instance of a Construct?


PERSON2--------------------
This adds a construct to the main scene:
nc.constructDefs.[your construct name].add(nc.mainScene);










----------------------------------------------------------
Section 12: Inline TextBox Graphics and Rich Text
----------------------------------------------------------


PERSON1--------------------
Is there any way to show inline sprites with a text box? In [another tool we use] we could have rich text mode and indicate a sprite graphic like <sprite = "someSprite"> or something like that. And with rich text mode we could also do dynamic character sizing, bold, italic, etc.


PERSON2--------------------
Yeah to include GraphicAssets within a TextBox or TextAssembly you can look at TextBox.setSubstitutionCharacter and TextAssembly.setSubstitutionCharacter.

Also, for rich text, look at TextFormat and TextBox.setTextFormat and TextAssembly.setTextFormat. These enable you to change the font, character size, kerning, and even the material properties (including changing EffectNodes and EffectControllers) for specific portions of the text within a given TextBox or TextAssembly. 

Check out these examples for inline images in TextBoxes:
// This is the main entry point for this Incisor® project. 
// Throughout the project, this object can be referenced as 'pr'.
class ProjectMain
{
    text:TextAssembly;
    init()
    {
    // SUBSTITUTION CHARACTER APPROACH
        let alternateTextFormat = new TextFormat();
        alternateTextFormat.fontName = nc.fontNames["NotoSansMono_Condensed-Black"];
        alternateTextFormat.characterMaterial.colorMultiply.red = 0;

        let placedImageFormat = new TextFormat();
        placedImageFormat.characterMaterial.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.ColorMultiply]);
        placedImageFormat.verticalShift = .25;

        let text = new TextBox();
        text.string = "Left*Right";
        text.setSubstitutionCharacter("*",nc.graphicAssets.SampleParticle,placedImageFormat);
         

    // LAYOUT STACK APPROACH
        
        let textBox0 = new TextBox();
        textBox0.string = "Left";
        
        let graphic = new GraphicObject(nc.graphicAssets.SampleParticle);

        let textBox1 = new TextBox();
        textBox1.string = "Right";

        let layoutStack = new LayoutStack();
        layoutStack.isVertical = false;
        layoutStack.addElements(textBox0);
        layoutStack.addElements(graphic);
        layoutStack.addElements(textBox1);
        layoutStack.position.y = -200;
        layoutStack.pivotPoint = new Vector2(0,0);

        textBox0.layoutObject.justification = "center";
        graphic.layoutObject.justification = "center";
        textBox1.layoutObject.justification = "center";
    }
}










----------------------------------------------------------
Section 13: Containing Directory
----------------------------------------------------------


PERSON1--------------------
I'm working in a pre-publish callback in an extension that I'm writing and I'm wondering if there's a way for me to get the current project working directory before I hit publish. 
I know the publish result returns me the publish directory, but I'd like to know the base directory prior to that so that I can check something with that.


PERSON2--------------------
Check out nce.paths.projectPath or nce.paths.splitPath().










----------------------------------------------------------
Section 14: Dragging Buttons
----------------------------------------------------------


PERSON1--------------------
Any ideas on how to get a continuous particle system to stop gracefully?


PERSON2--------------------
There’s a “stopEmitting” function on the ParticleSystem object that would do that.










----------------------------------------------------------
Section 15: Changing the Order that FlowStateElements Happen In
----------------------------------------------------------


PERSON1--------------------
How can I change the order that my FlowStateElements happen dynamically after they have already been instantiated?


PERSON2--------------------
FlowStateElements are not reordered by manipulating an internal list, and there is no API such as FlowState.getElements() that lets you retrieve and sort them after creation. 
The sequence in which FlowStateElements run is determined solely by each element’s netTime value, which is calculated from its time value plus any variable offset values. 
To change the happening order dynamically, you modify the time values or the offset values that contribute to netTime.

Method 1: Modify the element time values directly.
To do this, you must save references to each FlowStateElement when you call addElement. Later, you can change their time property, which will automatically change their order of execution.

Example:
class MyFlowState extends FlowState {
    constructor(controller) {
        super(controller);
        this.elemA = this.addElement(0.0, "stepA");
        this.elemB = this.addElement(1.0, "stepB");
        this.elemC = this.addElement(2.0, "stepC");
    }

    stepA() {}
    stepB() {}
    stepC() {}
}

//After instantiation elsewhere:
let state = nc.flows.GameFlowController.MyFlowState;
state.elemA.time = 3.0;
state.elemB.time = 0.5;
state.elemC.time = 1.5;



This changes the order because netTime recalculates automatically.

Method 2: Use variableOffsets for more organized control.
When calling addElement, you can pass one or more variable offset names. 
These become numeric properties on the FlowState and can be changed later without touching the elements directly.

Example in constructor:
this.addElement(0.0, "stepA", [], "aOffset");
this.addElement(1.0, "stepB", [], "bOffset");
this.addElement(2.0, "stepC", [], "cOffset");

//Later:
state.aOffset = 0.5;
state.bOffset = 2.0;
state.cOffset = -1.0;

Since netTime is time plus offsets, operations like these dynamically reorder execution.

Summary:
FlowStateElement order cannot be changed by rearranging a list or calling something like getElements, because no such method exists. 
To dynamically reorder events, store references when creating them and modify their time values, or define variableOffsets and adjust them later. 
Changing netTime changes the order that FlowStateElements occur.










----------------------------------------------------------
Section 16: Button Clickable Area
----------------------------------------------------------


PERSON1--------------------
When I make a button from a graphic in my project, the clickable area is restricted to the opaque portions of the image - can I change that?


PERSON2--------------------
Yes. By default, images that are included in an Incisor project have a 'trimMode' setting of 'hugged'.
This is a really cool feature that automatically decreases the download size of your project and improves the runtime performance by reducing the amount of 'overdraw' of images.
The 'hugged' setting is telling Incisor to automatically change the geometry associated with images in their associated GraphicAssets to 'hug' the outline of the non-transparent areas of the image.
This hugging is what is causing your button to be only clickable within the opaque area. 
To change this, open the 'Assets' panel and find the image file in question (the one that you used for your Button), then change the 'trimMode' setting to be 'none' or 'rectangular'.
... Save the project and reload to see the results.
Now the associated GraphicAsset will have rectangular geometry and the clickable area of that Button will be anywhere within that rectangle.











----------------------------------------------------------
Section 17: Changing the Browser
----------------------------------------------------------


PERSON1--------------------
When I open Incisor, the GUI opens in Edge. Is there a way to get it to work with Firefox?

PERSON2--------------------
You can change which browser Incisor uses by changing the "browserClient" value in your Incisor Application Settings. 
There is an Application Settings menu in the GUI accessible for the Incisor menu in the upper lefthand corner of the GUI.
You can also manually change the settings file directly by going the Incisor Application Support directory (users/[username]/Incisor/Red/Application Settings/ApplicationSettings.json).
You can change the 'browserClient' property to "Chrome", "msedge", or "firefox" in Windows. In OSX you can use "Google Chrome", "Safari", or "Firefox".










----------------------------------------------------------
Section 18: Time ramping gameplay
----------------------------------------------------------


PERSON1--------------------
[Another popular engine] has Time.timescale which defaults to 1. Set it to 100 and the game runs 100 times faster.  
Set to .01 and, you get the idea. I see Incisor has TimePlaybackController.time() but does Incisor have a way to control the global time scale?


PERSON2--------------------
Speed controls should be able to accomplish that.


PERSON3--------------------
Looks like nc.softwareSpeed might do the trick.


PERSON4--------------------
Both are good options for certain circumstances but they work a little differently.
TimePlaybackController is not what you want - it's an API for things that play pause etc. 
It does have playbackRate, but that would just be for that thing.










----------------------------------------------------------
Section 19: Pausing Everything when game has 'TILT'
----------------------------------------------------------


PERSON1--------------------
On an EGM, the game must pause everything if a door is opened or any tilt condition and resume after the tilt has cleared.
I know all our playable items have the ability to pause but is there a way to do that for the whole game without having to write pause code for each object?
I see the DefinePauseEvent example but it looks like each item will need custom code.


PERSON2--------------------
Yes there is a way, and you don’t need custom code for each object. 
As a default all sequenced items in Incisor are susceptible to all PauseEvents, so you could define a new 'Tilt' PauseEvent, and that would automatically affect everything in code that doesn't call out specific pause immunity.\
You can set nc.defaultPauseImmunity at any point in the code and everything declared after that will automatically get the new PauseImmunity as a default.

Incisor® Tutorial Scripts

IncisorTutorialScripts.txt

Incisor® Tutorial Scripts
This document is part of the compiled knowledge base for the Incisor® Software Development Platform.
Any use of this content is subject to the INCISOR® end user license and terms of use agreement.
https://www.incisordev.com/eultua
2026.11.05.12.18.08






----------------------------------------------------------
TABLE OF CONTENTS:
----------------------------------------------------------
Section 1: GUI
Section 2: AppEvents
Section 3: Getting Started with JavaScript
Section 4: GraphicObjects
Section 5: Animation
Section 6: UnitsPerPixel
Section 7: Showcase - ExampleGallery.sb-fae7be28-8wSMBa
Section 8: Trimming
Section 9: SpriteSetter
Section 10: IntroToButtons
Section 11: Curved Reels and EffectNodes
Section 12: GraphicExpander
Section 13: IntroToPrecomps
Section 14: CustomAddOnsAndCustomObjects
Section 15: ParticleSystems
Section 16: WaitThens
Section 17: Showcase - Poker
Section 18: ObjectPanel
Section 19: Swoopers
Section 20: Showcase - ForkYourFood
Section 21: PivotPoints
Section 22: Sounds
Section 23: CreatingConstructs
Section 24: LiveView
Section 25: Getting Started with TypeScript
Section 26: Extensions
Section 27: Timelines
Section 28: Showcase - ExampleGallery
Section 29: PublishingWithElectron
Section 30: ParticleSystemOverview
Section 31: ResolutionScaling
Section 32: FlowStates
Section 33: TextAssemblies
Section 34: Shapify










----------------------------------------------------------
Section 1: GUI
----------------------------------------------------------


00:00:07:06 - 00:00:30:24
Unknown
In this tutorial we'll be going over the Incisor user interface. We'll cover the top bar, the bottom bar panels, and a brief overview of panel functionality. Here we have the top bar. As you can see, it contains the project name, project directory and a menu bar. If you make changes to the project, an asterisk will appear next to the project name, indicating that the project has been modified and you need to save to make the changes permanent.

00:00:30:27 - 00:00:51:08
Unknown
The Project Updated button will appear below the project directory if changes have been made, and the live view is of date. This button will reload the project to reflect any updates. Lastly, we have the menu bar. Stay tuned for an upcoming tutorial on how to add custom menu items to Incisor. Next we have the bottom bar. It contains a short version of Incisors, logs, and tooltip information.

00:00:51:10 - 00:01:10:12
Unknown
Incisor will occasionally log pertinent information like warnings if your project is configured incorrectly. Errors in your project code, and other useful readouts. These entries are written to a more detailed log that can be found in the Application Support directory. You can access this directory by clicking the Incisor icon in the menu bar and selecting Open Application Support Directory.

00:01:10:15 - 00:01:31:08
Unknown
You can also view the most recent log by clicking the eye icon in the lower right corner. You can copy the log entry by clicking the copy icon, then paste the log into your preferred text editor. Alternatively, you can use the developer tools in your browser to view the logs in the console as well. Incisor also has built in tooltips that display information about what your cursor is hovering over.

00:01:31:10 - 00:01:51:28
Unknown
This info is displayed below the logs in the bottom bar. You can also view tooltip information using the tooltips panel. Now let's talk a little bit about panels. The default view for Incisor consists of four panels. The tooltips panel. The object panel hierarchy panel, and Live you panel. You can change the size of the panels by dragging the divider to the desired size.

00:01:52:00 - 00:02:08:28
Unknown
Panels can be added by clicking the plus icon in the upper right of any panel, and reposition by clicking and dragging the top area of the panel to a new location. You can change an existing panel by clicking the name of the panel in the upper left, and selecting from the list of panels. To close the panel, click the X in the upper right.

00:02:09:00 - 00:02:27:01
Unknown
Let's briefly go over the functionality of some of these panels. Tooltips, as we mentioned earlier, simply displays the tooltip text. It's a good idea to keep this panel open until you are familiar with Incisors UI. The Live View panel displays a current live view of the project that's running. It has several controls at the top, starting from left to right.

00:02:27:03 - 00:02:47:18
Unknown
We see maximize, refresh, pause, and inspect. It can be helpful to pause your project and inspect so that you're able to select objects and view information about them in the Object and Hierarchy panels. If the desired object is obscured by another object, you can use the scroll wheel on your mouse to highlight the objects underneath and left click select the desired object.

00:02:47:21 - 00:03:10:20
Unknown
As we mentioned in the Live View panel when you were in selection mode, the object panel will display information about the selected object. It will also display information about objects selected in the Construct and Hierarchy panels. In general, to select multiple objects, hold the shift button down while clicking on the desired objects. If multiple objects are selected, the object panel will only display attributes that are shared across all the selected objects.

00:03:10:23 - 00:03:34:18
Unknown
The hierarchy panel will display the hierarchy of the selected objects. The controls at the top of the panel allow you to change the selected scene. Search for objects within the hierarchy. Expanding. Collapse all descendants and highlight and scroll to the selected object. You can also show disabled objects by clicking the Show Disabled checkbox. You can rearrange objects in the hierarchy by clicking and dragging the drag handle next to the object.

00:03:34:21 - 00:03:55:11
Unknown
Other panels include the layers panel where you can add, remove, and reorder layers in your project. The construct panel allows you to add and edit constructs, and also allows you to create new timelines that can be edited in the timeline panel. Use the Particle System panel to create and modify existing particle systems. The transcript panel can be used to add, edit, and remove translations in your project.

00:03:55:14 - 00:04:14:02
Unknown
The assets panel will show the folder structure of your assets and allows you to modify attributes associated with those assets. And finally, the Publishing Analysis Panel allows you to view a summary of the results from publishing a specific configuration Incisor also allows you to add your own custom panels. Stay tuned for an upcoming tutorial on that feature.

00:04:14:04 - 00:04:28:17
Unknown
That does it for this video, but if you'd like to learn more about these panels individually, go to our YouTube channel or visit the tutorials page on Incisor Devcon. Also, feel free to ask questions about Incisor via Stack Overflow or on the Incisor subreddit. Have fun creating with Incisor.












----------------------------------------------------------
Section 2: AppEvents
----------------------------------------------------------


Hello, and welcome to this AppEvents tutorial for Incisor. In this tutorial, we will cover:
- What an AppEvent is, and the main functionality of AppEvents
- How to create an AppEvent
- Some creative applications of AppEvents
- A brief look at Incisor’s built-in AppEvents

An AppEvent is a type of object that can execute a callback function when triggered by a
given type of event. There are two main types of AppEvents in Incisor— AppEvents for
automatically recurring events that essentially act as “listeners”, and AppEvents that are
triggered by specific user-input. In this tutorial we’ll start with the “keyDown” AppEvent,
that responds to user input from the keyboard, and then play with the “fixedUpdate”
AppEvent that recurs every frame the application is running.
To get started, let’s open a blank Incisor project. We can leave the sample text in for
now, just set the string to blank. The first thing I’ll do is define a new appEvent. Let’s set
the variable “myAppEvent” equal to nc.appEvents.keyDown. Keydown will trigger a
callback whenever a key on the keyboard is pressed down. Now that we’ve defined our
AppEvent, we’ll use the addCallback function to specify what we want to execute when
the AppEvent is triggered. Simply pass the callback owner object, and the name of the
callback as a string. Now let’s write our callback function. The Keydown AppEvent takes
the key as an argument, so we’ll need to pass an arguments parameter into the function.
I’ll set the string of the sample text to whatever key is being pressed down at the time,
and save our code. Now we can see the text changing accordingly in real time. Let’s
have our function look at a specific key now. I’ll make it so that if “w” is pressed, the text
box position moves up.
You can see that holding down the “w” key causes the text to move constantly, but the
movement is choppy. This is because the callback is only being triggered whenever it
receives a message that the key is down.
To achieve a smooth movement, we’ll need to use an AppEvent that is triggered much
more frequently. The “fixedUpdate” AppEvent is triggered every frame the application is
running, which in Incisor is a default of 60 frames per second. Let’s create another
AppEvent using fixedUpdate, and add a callback to it. We’ll have our callback function
look at the “keyDownStates” parameter that is built into Incisor. This is a parameter that
is set to “true” whenever the given key is in a “down” state. I’ll put the same position
change as before into this function instead. Now we can see that holding the “w” key
down results in a much smother movement across the canvas. Let’s take this one step
further and have our callback respond to the “a”, “s”, and “d” keys as well. Let’s also
replace our textAssembly with a graphicObject. For more information on graphicObjects,
check out our graphicObjects tutorial. By setting our position changes accordingly, we
now have a character that can move in four directions across the canvas.
Now, click the Incisor Icon in the top left corner and choose “Incisor Documentation.” If
we click on AppEvents, we can see a list of built-in events and their functionality. We
won’t be going over all of these AppEvents in this overview, but feel free to ask any
Questions you have via stackoverflow and our subreddit. 











----------------------------------------------------------
Section 3: Getting Started with JavaScript
----------------------------------------------------------



Incisor is a software development platform that is finely tuned for creating extremely light apps and games that will run on any browser. 

In this tutorial, we will cover getting started with Incisor using the Javascript coding language. 

If you'd like to use TypeScript, follow the link in the description to the Getting Started with Typescript video tutorial.

Before you get started, you'll need to choose a code editor. In this tutorial, we'll be using Visual Studio Code, which is a great free editor and can be downloaded from the VS code download page.

Next, we'll need to download the latest version of Incisor, which can be found in the Incisor download page. 

Once downloaded, open the zip file and click the app to open Incisor.

Next, you'll need to enter some information and an email address to create an Incisor account. 

You'll need to confirm your email account before you can get started. Now you'll be prompted to open a project, but we will choose to make a new project instead.  

When opening a brand new project, it will take a few seconds for Incisor to process the included sample assets.

Once loaded, you'll see the sample project up and running in the live view in the Incisor GUI. Now let's look at the new project directory that was created. You can see a few items in the directory, including a project code folder, which is where the code for the project lives, and an assets folder, which is where assets for the project can be placed.

Let’s open this project in our code editor.

Within our code editor we want to navigate to project Main.js. That's where we can see the basic sample code running our new project. As you can see, the existing code is very simple. It adds a text assembly object which uses the sample font included in the assets directory. Let's make a change to the text that appears on the main screen.

Notice that when we save the file, the live view is automatically reloaded.

Now let's make the text bounce up and down. As you can see, autocomplete options are built into Incisor. Dotting your way around the API is one of the easiest ways to familiarize yourself with Incisor’s broad functionality.

You can also access documentation for the entire API in the Incisor menu in the left corner.

Now let's add an asset of our own. To include a new image in our project, all we'll need to do is drag the PNG file into the assets folder. Now we can use that new asset in our project. For example, we can add a graphic object to our scene using this new asset.

Notice our graphic is now accessible from within VS code when we start typing.

To view the final product, we'll need to publish it, which can be done through the project menu. New projects come included with a dev mode configuration for publishing, but more configurations can be added in the project settings.

Let's publish. Click the new URL in the pop up window and we can now see the final published product in action.

Looking back in our project directory, we can see that Incisor has added a publishing folder and put the newly published and timestamped website under its own directory.

This concludes our Getting Started with Incisor JavaScript tutorial.

Check the link in the description for more tutorials, and feel free to leave questions and feedback on StackOverflow and our subreddit.

Enjoy creating with Incisor.

  











----------------------------------------------------------
Section 4: GraphicObjects
----------------------------------------------------------


Graphic Objects
 2024.10.03- Hello and welcome to this Graphic Objects tutorial.- In this tutorial we will cover- Importing Graphic Assets into a new project- Creating Graphic Objects with a Graphic Asset- Positioning Graphic Objects within a scene, using the GUI 
to design the scene and to obtain our object’s position values- Setting a Graphic Objects parent in the hierarchy to 
demonstrate inherited values- Making a Graphic Object visible or not visible- And enabling and disabling a graphic object- This video also assumes that you have watched either the 
"Getting started with Javascript" or "Getting started with 
Typescript"- All code examples shown in this tutorial will be in 
Javascript.- Let’s create and open a new project in Incisor®.- After creating a new project, We need to put our assets into 
the project.- To do this, you will navigate to the assets folder in your new 
project. You can then drag and drop your assets into the folder. - Incisor will automatically recognize the assets and make them 
available for use.- Now that the assets are in the project, we will navigate to 
ProjectMain.js in the Project Code folder of your new project.- Go ahead and remove the code inside of the init() function, 
which is the entry point to your project, so that we can start 
with a blank slate.- To start, in the init() function of ProjectMain.js, we will 
create a new graphic object.- This Class accepts three parameters a Graphic Asset, a Parent, 
and a Name.- the graphic asset may be any graphic asset in your project, we 
will be using the “Farm” graphic. If a graphic asset is not 
provided, the built in “White Box” asset will be used. - The parent can be any scene object in your project. If left 
undefined, the default parent is the main scene.- The name is a string that will be viewable in the Hierarchy 
inspector. If no name is provided, the name will default to 
“Graphic Object” in the Hierarchy.
- The name is a string that will be viewable in the Hierarchy 
inspector. If no name is provided, the name will default to 
“Graphic Object” in the Hierarchy.- Now we will add in two more Graphic Objects, each using one of 
the graphic assets that we previously imported.- We have intentionally left the parent as undefined.- You can see in the Hierarchy Inspector that all three are 
children of the main scene.- Now we will set the parent of the “chicken graphic” to the 
“farm graphic”.- If I grab the “farm graphic” in the live view, you will see 
that the “chicken graphic” inherits the movement from its 
parent, while the “scarecrow graphic” does not.- Now we will set the parent of the “scarecrow graphic” to the 
“farm” as well.- The “chicken” and “scarecrow” graphic objects are now 
descendants of the “farm” object.- Currently, all of our graphics are stacked on top of each 
other.- Let’s use the “Live View” to arrange the elements where we 
want them in the scene.- Clicking the magnifying glass in the upper left corner of the 
“live view” will allow you to select individual elements in your 
scene.- Now that the elements are where we want them, when we select 
an element, we can see the X, Y, and Z position values for that 
element in the object inspector.- With these numbers, we can go into our code and set these 
position values for each element.- Now, when we save our code, the scene will remain in this 
configuration.- Each graphic object contains a property called “Visible”.- Setting this property to false stops it from being rendered 
without disabling it in the hierarchy, therefore descendants 
will remain visible.- We will set the “farm” graphic visible property to false.- Note that the graphic object remains in the scene but is not 
visible, while its children will remain visible.- Now we will set the “farm” visible property back to true.- Each graphic object also contains a property called enabled.- Setting this property to false disables the graphic object in 
the hierarchy, along with all of its descendants.- We will set the “farm” objects enabled property to false,- Now we can see that all of our graphic objects are no longer 
rendered in the scene.
- This concludes the Graphic Objects tutorial.- Don’t forget to check www.incisordevdocumentation.com for more 
tutorial videos, and feel free to leave questions and feedback 
on StackOverflow and our SubReddit.- Enjoy creating with Incisor!










----------------------------------------------------------
Section 5: Animation
----------------------------------------------------------



Animation

In this tutorial, we’ll be looking at some of the basics of animating with Incisor.

We’ll be working with the Incisorsaurus character, which you can find in the Example Gallery on incisordev.com.

Head over to incisordev.com, go to the Downloads section, and scroll down to the Example Gallery. Download the Incisor Red Example Gallery. Since we won’t be covering any code in this tutorial, either version will work.

Open Incisor, select Open Project, and navigate to the IncisorExampleGallery folder you just downloaded.

For this tutorial, we’ll focus on the Incisorsaurus animations in Example 6: Construct with Timelines.

As you can see, there are four animations: Walk, Run, Growl, and Idle.

We’ll be covering how to set up your art for animation, and how to create some basic animations in the timeline.

When animating, we will be using the Hierarchy, Object, Construct, and Timeline panels. Feel free to arrange your workspace however you prefer.

Go to the Construct panel and select the Incisorsaurus construct.

Constructs are collection of different types of SceneObjects that can be built, arranged, and animated from within the Incisor GUI. For more details, check out our tutorial on Constructs (link below).

When you open the Construct, you’ll see Incisorsaurus in the Neutral State. The Neutral State is where you set up your SceneObjects for animation, such as parenting, adding effect nodes, and changing pivot points, and more. If you ever need to make changes to the basic structure of your Construct, you need to be in the Neutral State. 

The Timeline pulldown menu is where you set up new Timelines, navigate between timelines and the Neutral State, and also access the Mange Timelines popup menu. 

If you hold the space bar you can drag or scroll in the Contruct panel to move or zoom the view. 

When you select an object in the Construct panel, that selection appears in the Hierarchy panel, and more detailed information shows up in the Object panel. For example, here I’ve selected the tip of Incisorsaurus’ tail (Incisorsaurus_0031_Tail3). In the Hierarchy panel, you can see it’s a child of Tail2, which is a child of Tail1, which is a child of Body.

In the Object panel, you can see its position, scale, and rotation values—and notice that the pivot point has been adjusted so the tail rotates from the correct spot.

Let’s build this from scratch so you can see how everything is set up.

In the Construct panel, select New Construct and name it IncisorsaurusNEW. Press Command+S (or Ctrl+S) to save.

If you open the Assets folder in the Incisor project, you’ll see a folder called IncisorsaurusAnim, which contains PNGs for all of the pieces of Incisorsaurus. Incisor automatically generates .ncdata files for each PNG.  You’ll also see your new IncisorsaurusNEW construct file. You can move these files around for organizational purposes, but make sure they stay within the Assets folder. 

Now let’s go back to Incisor.

In the Hierarchy panel, we’ll bring in the PNGs as a graphic stack. The artwork was created in Photoshop, and the layers were exported as numbered PNGs, so Incisor knows the order in which to stack them.

Right-click on IncisorsaurusNEW in the Hierarchy and select Add Graphic Stack.

Navigate to the folder with your PNG files. You can see there are settings to control the Z range, the sublayer range, and whether to add graphics to a new SceneObject. There’s also a checkbox to flip front and back layers. 

The Z range is the distance between your layers on the Z axis. This is useful for creating parallax in your animations. 

The SubLayer range is the distribution between -1 and 1 of the layers render order

Adding graphics to a new SceneObject creates a SceneObject parent for your graphic stack. This allows you to animate the entire stack inside of a single SceneObject. 

Since the PNGs were numbered in the desired order from Photoshop, we don’t need to flip the front and back. All the other default values here are also fine for this example. 

Click Add Graphic Stack, and now you’ll see Incisorsaurus in the Construct panel, with the PNGs listed as GraphicObjects in the Hierarchy. Since we added them to a SceneObject, they’re grouped under Added Graphic Stack. You can rename any of the SceneObjects or GraphicObjects however you like in the Object panel. 

Next, we’ll adjust pivot points so each object rotates correctly. For example, right now if we rotate Tail1, it spins from the center instead of where it connects to the body. To fix this, select the object in the Construct panel, hold Option/Alt, and drag the gizmo to the correct pivot location. The gizmo will turn blue, and in the Object panel you’ll see new pivot point parameters you can fine-tune numerically.  Note that changing the pivot point in this manner only changes it for this instance in the project. If you want to change the pivot point for all instances of the asset in the project, you can change it in the Assets panel. 

Now let’s create parent/child relationships. For example, fingers should be children of forearms, which are children of upper arms, which are children of the body, and so on. To do this, drag one GraphicObject on top of another to make it a child. Since we already adjusted pivot points, it is important that you hold Alt while dragging to create children “in place.”  If you don’t do this, you will see objects shift out of place like this. If this happens, just hit undo and try again. 

We don’t need the background PNG in our animation, so we can delete it from the Hierarchy. You can always re-import it later.

You’ll also notice there’s only one set of eyelids in our stack. We can duplicate these in the Hierarchy, then position and scale them over the other eye. In the Object panel, move the eyelid sublayers so they appear in front of the pupils. Since we don’t want them always visible, uncheck Visible in the Object panel. (Alternatively, you can hide them by scaling to zero, setting opacity to zero, or unchecking Enabled, which is more performance-friendly.)

Now that our setup is ready, let’s start animating!

In the Construct panel, go to Timeline → New Timeline and name it Walk.

In the Timeline panel (top left), you’ll see playback controls: Play, Stop, and Loop. You can also use the spacebar to play/pause. Stop resets the playhead to the beginning of the timeline, while Pause holds it in place. By default, playback is looped, but you can disable that by clicking the Loop button. The playback rate is set to 1, meaning real-time playback. You can use this to speed up or slow down your playback, but we will leave it at 1. Let’s set the walk animation to 4 seconds. As you can see, the timeline length updates accordingly.

You can move around the timeline by clicking and dragging at in the header bar And just like in the Construct panel, when you hold down the spacebar, you can move and zoom into the timeline. 

Let’s start animating the legs. In the list of your objects in the timeline, hold Shift and select the shorts, lower legs, and sneakers. Right-click and choose Animate SceneObjects → Rotation → Z. Set the initial keyframes by clicking the Set Keyframe button. Now, when you move the playhead and change rotation, new keyframes will be created automatically.

I’ve gone ahead and added rotation keyframes for the legs, making sure to copy the first keyframes to the end so the animation loops smoothly.

Continue to add keyframes for all the objects that you want animated until you have a complete looping walk cycle. 

As you can see, our character is walking—but it looks a little stiff. This is where the Graph Editor comes in. Right now, all the keyframes are linear, which makes the motion robotic. If you right-click a keyframe, you can apply easing to smooth out the movement. Adjust the handles until the walk feels more natural.

If you’ve applied effect nodes to your SceneObjects, you can also animate those in your timeline. We will dive deeper into effect nodes in a future tutorial. 

You can create more timelines and manage them in the Construct panel. 

And that’s it! 
Be sure to check out incisordev.com for more tutorials, and feel free to leave questions and feedback on Stack Overflow or our subreddit.

Have fun creating with Incisor!
















----------------------------------------------------------
Section 6: UnitsPerPixel
----------------------------------------------------------



As an enterprise-level development platform, Incisor offers a variety of ways to optimize your application and boost development team efficiency.


One powerful feature is Units per Pixel Geometry Scaling, which allows for easy image scaling without the need for code changes.


While images are often scaled dynamically using the Incisor API, especially with a variety of swooping or motion effects, there are times in large projects where a particular image needs to be scaled without requiring a full code overhaul. 


In this case, we’ll use Units per Pixel scaling.


To demonstrate, I’ll be using 2 instances of the Incisorsaurus. Both instances reference the exact same leg asset. 


I’ve opened the Asset Browser and Asset Settings panel, and selected the leg asset. Here, I’ll locate the Units per Pixel X and Units per Pixel Y properties, which are set to 1 by default.


Now, I’ll change both values to 2. After saving the project and refreshing Live View, you’ll see that the leg has been scaled on both dinosaurs, all without making any changes to the code.










----------------------------------------------------------
Section 7: Showcase - ExampleGallery.sb-fae7be28-8wSMBa
----------------------------------------------------------



The Incisor Example Gallery is a free project that you can use to try out many of Incisor’s exciting and unique features. Each example is separated into its own class and is available as a typescript and javascript file. In the inspector you can use the arrow buttons to cycle through all of the current examples, or use the searchable drop-down menu to find something specific. The example gallery is regularly updated, so be sure to check out incisordev.com for new versions of this project and tu torials based on it. 
 











----------------------------------------------------------
Section 8: Trimming
----------------------------------------------------------



Trimming is a technique used to reduce both the download size of a graphic and the number of pixels rendered for the graphic.

With trimming, we eliminate unnecessary portions of an image or geometry that won’t be visible in the final render. 

This process helps improve rendering efficiency by cutting out parts of the asset that won’t contribute to the final image.

This, in turn, reduces overdraw. By removing these invisible areas, we eliminate calculations for pixels that won’t ultimately be displayed, saving valuable resources.

In Incisor, there are three distinct trimming modes: None, Rectangular, and Hugged.

To showcase this, I’ll be using a red circle with a white border.

I’ve already opened the Asset Browser and the Asset Settings panel, where I’ve selected the red circle asset.

Now, let’s locate the Trim Mode property in the Asset Settings panel. By default, this is set to Hugged. 

You’ll notice that the blue border wraps closely around the visible parts of the circle, trimming away many of the extra transparent pixels from the original rectangular image.

We can also fine-tune how tightly the border hugs the image using the Trim Buffer property. If I increase this value to 50,  SAVE and REFRESH LIVE VIEW,  you’ll see a larger buffer zone between the image and the border.

Notice how in this example, the increased buffer has NOT gone beyond the bounds of the original image, so it has created a sharp line at the image edge.  If this is undesired, we can enable the "allowAdditiveTrimBuffer" setting.  

This allows the trim buffer calculations to add extra pixels to the image so that enough buffer pixels will exist. I can also make this a negative value, allowing us to cut into the image if necessary.

The Rectangular option keeps the original image’s rectangle intact, but it still trims away many of the extra transparent pixels. Meanwhile, the None option disables trimming entirely, leaving the original asset unchanged.












----------------------------------------------------------
Section 9: SpriteSetter
----------------------------------------------------------


Sprite setters

Sprite Setters are Incisor's main way of controlling frame based animations

First, make sure the frames of your animation are named with sequential numbers at the end of each asset.

Then select the graphic object and in the object panel, choose Configure Add-On and select Sprite Setter.

Incisor will automatically associate all the numerically sequential assets with your animation.

Now you can play and adjust your animation in real time.












----------------------------------------------------------
Section 10: IntroToButtons
----------------------------------------------------------


Buttons Tutorial

Hello and welcome to this Incisor Button tutorial. 

Creating and using buttons and incisor is easier than ever. 

In this tutorial we're going to cover creating buttons, adding button callbacks, removing button callbacks, and expected behavior when layering multiple buttons. 

To create a button, simply call new button. 

The constructor does not require any parameters, but to make life easier, the constructor accepts a graphic asset, a parent, and a name.

The graphic asset can be any graphic in your project. 

If a graphic asset is not provided, it will default to the built-in white box asset. 

The parent can be any scene object in your project. 

If a parent is not provided, it will default to the main scene. 

The name is simply a string. It will help identify the button object in the hierarchy viewer, and for this reason, we highly recommend providing unique names for all objects you create. 

If a name is not provided, it will default to "button."

Once the button is created, we can add a callback function that will be triggered on specific cursor events.

To add a callback for the press event, just call the add press callback method.

It requires a callback owner and a callback name.

The callback owner can be any object in your project.

The callback name is a string specifying the name of the function that you would like to call. 

Optional callback arguments can be added and will be passed to the callback function when called. 

It's important to note that when creating a button callback function, the first two parameters will always be the browser event and the camera.

If optional callback arguments are provided, they will be added after the camera. 

Removing callbacks is just as easy as adding them. 

To remove a press callback. Simply call removePressCallback with the same callback owner and function name that were provided when adding the press callback. 

Incisor buttons support a variety of cursor event callbacks.

For a full list of callbacks that can be added or removed, please refer to the Incisor documentation. 

When interacting with multiple buttons that overlap, it is important to remember the button that is visually in front will execute the callback, while buttons behind will not.

And this concludes the button tutorial.

Don't forget to check out incisordevdocumentation.com for more tutorial videos and feel free to leave questions and feedback on StackOverflow and our subreddit.

Enjoy creating with incisor.













----------------------------------------------------------
Section 11: Curved Reels and EffectNodes
----------------------------------------------------------


Hello, and welcome to this Incisor tutorial.

In this tutorial, we'll be walking through a step-by-step example in which we modify the Incisor Slot Template project to give the reels a curved "stepper reel" appearance. By the end, you'll have two different techniques for creating curved reels, and then we'll take a deeper look at how the shader-based version is built under the hood.

It should be noted that some of the features in this tutorial require an Incisor Pro subscription or higher.

Section 1: Curved reels without EffectNodes

We'll start by downloading a copy of the Incisor Slot Template.

For this example, we'll be using TypeScript.

Let's rename the project to reflect that it's a version of the slot template with curved reels.

We're going to be exploring two quick ways of giving slot reels a curved appearance, and both of them make use of Incisor's PerspectiveCamera, which provides an easy way to create the bulged look that best represents 3D curvature.

To do this, we can change the mainCamera from orthographic to perspective in the ProjectSettings popup.

Now we can save and reload.

You'll notice that the defaults for this perspective camera make it so that the main content of the slot template is a bit too zoomed.

To fix this, we can play with the core view angles in the Object panel to get an idea of what the values should be, and then we can change those values permanently by adding a line to the project main in code.

Now let's recompile the TypeScript to see the permanent change in the LiveView.

Section 1.1: Quick curved look using symbol rotation and z offset

Now, we'll show a very quick and easy way to give these slot reels a curved look, and it will only take a few lines of code.

Since we want to give the appearance that the symbols on this reel are arcing toward the viewer as they travel from top to bottom, we will open the SlotReelSymbol TypeScript file and edit the updateSymbolPosition function.

When implemented in the SlotReelSymbol class, the updateSymbolPosition function is automatically called by the owning SlotReel class every time it updates the symbolPosition value of each SlotReelSymbol. This function can then be used to interpret the new symbolPosition value, which operates in a range where the first visible symbol's value is 0, the second is 1, the third is 2, etc.

So, to change the path of the symbol, we can simply add two lines to the function.

The first line gives each symbol a rotation that gradually changes as the symbolPosition increases.

And the second line gives each symbol an adjusted z position value that also steadily arcs toward the camera and then away from the camera as the symbolPosition increases.

Here we're using a sine function to approximate the curve of the reel as a quick example, but it should be noted that it's only a rough approximation. Any mathematical expressions can be used here to dictate the rotation and location of the symbols according to their symbolPosition value.

Now we can recompile the TypeScript and see the effect.

You can see how the PerspectiveCamera appropriately interprets the curved z path of the symbols by bulging them as they get nearer to the camera and shrinking them as they move away. Because we're actually changing the z position of each symbol in 3D space, the perspective camera naturally turns that into a convincing bulged effect without us needing to write any shader code yet.

With this new symbol path, our reel masks are cutting off at the sides.

We can fix this by scaling up the reel mask GraphicObjects in the GameLayoutConstruct.

We just go to each ReelMask graphic and increase the x scale value.

While this way of giving the reels a curved appearance is really quick and easy, if we look closely, we can see that this method leaves each symbol looking like a flat panel instead of a completely curved surface. This method also doesn't mimic any of the effects of how light interacts with a curved surface.

So next, we'll upgrade to a EffectNode-based approach that actually deforms the geometry and adds curved shading.

Section 2: Curved reels with a custom EffectNode

In this section, we'll use a custom EffectNode to get a more realistic curved reel with shading, without worrying yet about how the shader itself is written. We'll treat the EffectNode as a higher-level tool, and then do a deeper shader dive in the next section.

First, we'll comment out the symbol-path altering lines that we added to the updateSymbolPosition function, and when we recompile the TypeScript we can see the reels are flat again.

Next, we'll use the TemplateLibrary to create a new EffectNode to achieve the exact look we want.

Let's base our new EffectNode on the Arch EffectNode in the Incisor TemplateLibrary menu. We can rename it to CurvedReel.

We see now that this has added a new codeAsset file to our project's Assets directory. Let's open it and have a look.

This particular codeAsset defines an EffectNode and the associated EffectController.

EffectNodes are modular visual effects that can be applied to any GraphicObject in any combination and order. When an object has more than one EffectNode, Incisor automatically builds a bespoke shader for that object based on the combination of EffectNodes that a given object has.

Each EffectNode can have EffectControllers, which are just the properties that enable us to manipulate the given effect. You can think of EffectControllers as the knobs and sliders for that effect.

Fundamentally, EffectNodes are applied directly to the Materials of GraphicObjects, and the Materials will be given the companion EffectControllers. One of the nice things about the way that this works in Incisor is that EffectControllers can be adjusted on any SceneObject, and those adjustments will automatically apply to all of that SceneObject's descendants.

This makes adjusting the visual effects of groups of objects really easy. For example, you'll see that as a default, all of the Materials in Incisor projects have the ColorMultiply EffectNode and the associated EffectController. We can adjust the EffectController on every Material individually, but we can also go to any point further up in the hierarchy and adjust the values for groups of objects with a single slider. This can be done either in code or in the Graphical User Interface.

For now, we'll quickly modify these definitions from their original Arch functionality, and change them to produce the curved reel effect we're after. We'll do a deeper dive on how to do this later in the tutorial.

Section 2.1: Applying the ReelCurve EffectNode to the SlotReel

Now that we have our ReelCurve EffectNode asset in the project, we can wire it into the slot template without worrying about its inner workings just yet.

In the Incisor Slot Template, the EffectNodes for the symbol objects are explicitly set in the start callback of the SlotReelSymbol class. If we add the ReelCurve EffectNode here, we'll see the change when we recompile the TypeScript and re-run our project.

Once we do that, you'll notice that each symbol is positioned and shaded as if it were in the topmost reel position. This is because the progress component of our reelCurve EffectController needs to be updated according to the symbolPosition value of each symbol.

To do that we can simply add a line to the updateSymbolPosition callback. Notice that our custom new EffectController automatically appears in autocomplete when we dot our way into the SlotReelSymbol object. This is because Incisor's dynamic autocomplete detects definitions and adds them to the IncisorAPI reference file in the project utilities.

Once we have the progress component being updated, we should be able to see our reels curving nicely according to our new EffectNode.

Notice that the EffectNode is now evenly deforming the symbols on the desired curve and they now have shading to help reinforce the curved reel effect. We now also see our EffectController supervisors on the SlotReelSymbol Materials as well as all of their ancestors. Because of Incisor's inheritance scheme, all of the EffectController values for all of the symbols can be adjusted from a single hierarchy owner.

Since the ReelCurve EffectNode adjusts the actual positions of the vertices in our symbols, the mainCamera - which is now a perspective camera - will display this vertex deformation in full perspective 3D.

Section 2.2: Improving the reel background with more geometry

To push the "curved stepper reel" look even further, we can add a SymbolBackground image to the project and tell the SlotReelSymbol to add it as a child. We'll make a new layer between the Reels and the ReelBackground and add a line to put the new GraphicObject on that layer.

We'll also need to be sure that we add a line to update the progress component of the reelCurve EffectController on the new symbolBackground object within the updateSymbolPosition function, just like we did for the symbol itself.

Recompile the TypeScript and see the result.

This new background image is a nice touch when it comes to recreating the look of the reels in a physical stepper, but when we look more closely, we can still see evidence that the symbol background image is made of rectangular panels. This is because our SymbolBackground image is a simple rectangle and therefore its geometry only has 4 vertices - one in each corner.

Remember that our ReelCurve EffectNode is literally moving each vertex along a curved path in 3D. With only 4 vertices, we're essentially bending just a single flat quad, so it still looks like a panel. To make the curve look smooth, we need more vertices for the effect to "grab" and bend along the reel.

So while our EffectNode is working as designed by putting all of the vertices on a perfectly curved path, we will need to increase the number of vertices in the SymbolBackground to avoid the appearance that the reel is made of flat panels. Incisor can do that too!

To modify the geometry of the SymbolBackground image, we can use the nc.editGeometry function. Since this function requires the provided geometry to be loaded, we can either asynchronously await its execution using the await keyword, or we can provide a callback that will be called when the geometry loads.

The call to nc.editGeometry returns a GeometryEditor object that allows us to make changes to the geometry in question. We'll use the newGrid function, which makes a grid geometry in which we can pick the width, height and number of horizontal and vertical segments. For width and height we can just enter the dimensions of the source image, and since the curvature affects the symbol's positioning along the vertical axis, we'll be sure to include plenty of extra vertical segments in the new geometry. The more segments we add along that axis, the smoother the visible curve will be once the ReelCurve EffectNode deforms it.

Now we just need to call commitChanges on our GeometryEditor and then we can recompile the TypeScript.

We can see that our symbol backgrounds are now smoothly curved by the ReelCurve EffectNode, and it no longer looks like the symbol backgrounds are made of flat panels.

To show off our new reel curvature in full perspective 3D, we can also add some motion to the rotation property on the ReelsContainer to keep our reels moving.

At this point, we've used the ReelCurve EffectNode as a tool: we created it from the TemplateLibrary, wired it into our symbols and backgrounds, and adjusted geometry to make the curve look smooth. In the final section, we'll look under the hood at how an EffectNode like this actually works and how the shader code is structured.

Section 3: Deep dive on EffectNodes, shaders, and the ReelCurve implementation

In this last section, we'll step back and look more closely at how EffectNodes work in the context of GLSL shaders, and how this particular ReelCurve EffectNode was built.

If terms like "uniform" and "varying" are new to you, you can think of them like this:

A vertex shader moves the corners, or vertices, of your geometry in 3D.

A fragment shader decides the color of the pixels on the surface.

Uniforms are the adjustable inputs to those shaders - in Incisor, these are exposed as EffectControllers.

Varyings are values passed from the vertex stage to the fragment stage for each pixel.

You don't have to be a GLSL expert to follow along, but this should help the structure make sense.

Section 3.1: Defining the EffectController

Let's look more closely at the definition of our EffectController, which takes place in the nc.defineEffectController function call.

First, we supply the name of the EffectController. When an EffectNode has a single EffectController, the Incisor convention is that the EffectController is camel case and the EffectNode is title case.

Next, we have to pick a type for the EffectController. In this case we're going to use a Vector4 for this EffectController, where the individual components each control a different aspect of the associated EffectNode.

Next, we give the components descriptive names. For this particular "reel curve" exam ple our EffectController will allow control of the progress along the curve,the depth of the curve, a location along the curve for a bright shiny reflection, and the brightness of that shiny reflection.

Next, we supply the default values for each of the components.

This parameter here determines how the EffectController values mix together as they are passed from parent to child in the inheritance discussed earlier.

This parameter lists the likely ranges of the component values and helps inform the slider sensitivity of the supervisors in Incisor's Graphical User Interface; larger ranges here make the sliders more reactive.

This parameter is a description of the EffectController in general - this description will appear in tool tips in the Graphical User Interface as well as autocomplete whenever you dot into this property within an owning SceneObject.

This parameter is for descriptions of the individual components.

Section 3.2: Defining the EffectNode and its shader code

So now that we have our EffectController defined, we can have a closer look at the definition of our EffectNode, which takes place in this call to nc.defineEffectNode.

The first parameter of this function is the name of the EffectNode.

The next four parameters are where we include the actual GLSL shader code for this EffectNode.

This tutorial will not go into great depth on the subject of writing the actual content of the shader code, but in general, shaders are a means to enable the graphics card to calculate or modify the positions of vertices within geometry, and the color of fragments, which is another name for the pixels drawn on the surfaces of geometry. As such, shaders are broken into two parts: vertex and fragment.

So, this second parameter is where you put the shader code that supports the vertex portion of this particular EffectNode. In other words, this is where you put declarations of the varying and uniform variables that will be used within the vertex portion of the shader code. You can also use this portion to define functions that can be called from within the main vertex body.

Notice that the supplied vertexSupport parameter can be either a string or an array of strings. Supplying the vertex support as an array of strings, as we've done here, allows you to break statements up, and in the event that multiple EffectNodes make use of the same supporting statements, Incisor will cull the duplicate statements to avoid shader errors. For example, if you were to write multiple EffectNodes that made use of the same special rotation function, you could include the definition of that function as a separate statement in the vertex support for both EffectNodes. Then, if the two EffectNodes are ever used together on the same Material, Incisor would only include the function definition once when compiling the shader for that Material. While this detail may not be important for any one EffectNode example, it can be important when writing production EffectNodes for use within a larger group.

The third parameter is where we put the portion of the vertex shader body code for this EffectNode. You'll notice that this example, and many of the other examples included in the Incisor Template Library, usually end with a statement involving the vertex vec3 variable. This is because the primary job of the vertexNode is to calculate or alter the positions of vertices.

One important thing to remember when building your own EffectNodes is that each of these code blocks will be compiled together with the code blocks from other EffectNodes, so you'll want to be sure you are specific with the names of your variables, and avoid using the same variable name within two EffectNodes that may be used together, as this will cause shader errors.

The next two parameters are similar to the last two, only these two define the fragment portion of the shader code in this EffectNode.

So the fourth parameter is for the shader code that supports the fragment portion of the EffectNode, and the fifth is for the shader code for the main body of the fragment portion of the EffectNode.

It should be noted that many EffectNodes include only vertex code or only fragment code, and to do so you simply supply empty quotes for the appropriate parameters.

Finally, we look at this sixth parameter, which is where we list the EffectControllers that are going to be associated with this EffectNode. In this case we supply a list containing the EffectController we've defined above.

While there are more optional parameters in the defineEffectNode function, they are generally for more advanced uses and these six are all we'll need at the moment.

Section 3.3: A Line-by-line overview of the ReelCurve shader

Now that we've seen where the code lives, here is a quick line-by-line description of how the shader code in this EffectNode works.

This line declares the reelCurve uniform for the vertex shader, which is just the same thing as our EffectController.

This line creates a new reelCurve_progression variable which can be used across the vertex and fragment shader.

These lines give us handles to some of the components of our EffectController.

These lines transform the progression input value from our EffectController into a nearly unit value that ranges from 0.1 to 0.9.

This uses the progression value to arc the z value along the top portion of a sine curve to simulate the curvature of a round reel. You can see that it is also where the depth value from our EffectController is factored in.

This line declares the reelCurve uniform for the fragment shader.

This line declares the reelCurve_progression variable for the fragment shader.

These lines give us handles to more of the components of our EffectController.

This line defines the portion of the progression curve where the brighter "shine" area will be in effect.

These lines create a shading effect to simulate the larger curved contour, making the bulged areas brighter and the other areas darker.

And finally this line applies the shine area defined above, adding to the fragment brightness within the affected area.

You can see more examples of how EffectNodes and EffectControllers are built from within the Incisor Template Library. Adding these examples to a project, checking out the code, and playing with modifications is one of the best ways to familiarize yourself with making new shader-based EffectNodes.

If you are using AI to help you, remember that Incisor publishes its entire knowledge base in an AI-friendly format at incisorDev.com.

And that concludes this curved slot reels tutorial.

A link to the project in this tutorial is in the description below. Downloading this project is a great way to explore the concepts we've reviewed.

You can find more tutorials at incisorDev.com, and if you have any questions feel free to ask them on Stack Overflow or on the Incisor subreddit.

Have fun creating with Incisor.







Code discussed in this tutorial:
--------------------------------


// START - SlotReelSymbolClass
    class SlotReelSymbol extends GraphicObject
    {
        // property value is set by SlotReel as the symbol moves along the symbol path...
        symbolPosition:number;
        symbolBackground:GraphicObject;


        constructor(graphicAsset:GraphicAsset,parent:SceneObject,name:string)
        {
            // call the super constructor
            super(graphicAsset,parent,name);
            // make the symbol 'masked' by the ReelMask masking group
            this.masking.makeMasked(nc.maskGroups.ReelMask,false);
            this.layer = nc.layers.Reels;
            nc.appEvents.start.addCallback(this,"start");
            this.symbolBackground = new GraphicObject(nc.graphicAssets.SymbolBackground,this);
            this.symbolBackground.masking.makeMasked(nc.maskGroups.ReelMask);
            this.symbolBackground.layer = nc.layers.SymbolBackground;
        }


        start()
        {   
            // set the EffectNodes of the symbol to have BrightnessContrast for easy 'dimming'
            this.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.BrightnessContrast,nc.effectNodes.ColorMultiply,nc.effectNodes.ReelCurve]);
        }


        // function called by SlotReel (if implemented) whenever the symbol is changed to a new symbol
        setSymbol(symbol:string)
        {
            this.setGraphicAsset(nc.graphicAssets[symbol],true,false);
        }


        // function called by SlotReel (if implemented) whenever the symbolPosition is updated
        updateSymbolPosition()
        {
            // ensures that the symbols have 'reverse shingled' layering
            this.subLayer = this.symbolPosition*.05;

            // simple method of curving reels...
            // this.rotation.x = -25 + 50*this.symbolPosition/3;
            // this.position.z = 100*Math.sin(this.symbolPosition*Math.PI/3);

            // inform the 'reelCurve' EffectController of the 'symbolPosition' value
            this.reelCurve.progress = this.symbolPosition;
        }
    }

    CODE.runBeforeInit___begin;
        // register the CustomAddOn with the Incisor inspector, so that it can be added within the GUI.
        nc.registerCustomObject(SlotReelSymbol);
    CODE.runBeforeInit___end;
// END




// START - (in ProjectMain.init) edit the Geometry of the SymbolBackground GraphicAsset
    let geometryEditor = await nc.editGeometry(nc.geometries.SymbolBackground);
    geometryEditor.newGrid(350,300,2,10);
    geometryEditor.commitChanges();
// END




// START - (In ProjectMain.init) add motions to the rotation components to show off curved reels
    let reelsContainer = this.gameLayout.descendantsByName.ReelsContainer;
    reelsContainer.rotation.addMotion.x(-15,15,.1,nc.motionTypes.Pendulum);
    reelsContainer.rotation.addMotion.y(-15,15,.16124,nc.motionTypes.Pendulum);
    reelsContainer.rotation.addMotion.z(-15,15,.09211,nc.motionTypes.Pendulum);
// END



// START - CurvedReel.codeAsset.js
    CODE.runBeforeInit___begin;
        let curvedReel_def = nc.defineEffectController(
            "reelCurve", 
            constants.effectControllerBaseTypes.Vector4, 
            ["progress", "depth", "shineOffset","shineBrightness"], 
            [0, 150, 0, .35], 
            nc.constants.effectControllerMixModes.addition, 
            [[0, 1], [0, 150], [0, 1], [0, 1]],
            "EffectController for the ReelCurve EffectNode, which deforms geometry by pushing the vertices into an arch.", 
            ["progress", "height", "shineOffset","shineBrightness"]
        );
        nc.defineEffectNode(
            "ReelCurve",
            [
                "uniform vec4 reelCurve;",
                "varying float reelCurve_progression;"
            ],
            "float reelCurve_progress = reelCurve.x;\n\
            float reelCurve_depth = reelCurve.y;\n\
            reelCurve_progression = (reelCurve_progress-vertex.y/300.0)/3.0;\n\
            float reelCurve_progression = 0.1 + 0.8*reelCurve_progression;\n\
            vertex.z=reelCurve_depth*sin( 3.14159*reelCurve_progression );",
            [
                "uniform vec4 reelCurve;",
                "varying float reelCurve_progression;"
            ],
            "float reelCurve_shineOffset = reelCurve.z;\n\
            float reelCurve_shineBrightness = reelCurve.w;\n\
            float shine = smoothstep(0.15, 0.2, reelCurve_progression+reelCurve_shineOffset) *(1.0 - smoothstep(0.25, 0.3, reelCurve_progression+reelCurve_shineOffset));\n\
            float generalContour = smoothstep(-.15, 0.25, reelCurve_progression) *(1.0 - smoothstep(0.75, 1.15, reelCurve_progression));\n\
            fragment.rgb*= vec3(0.4+0.7*generalContour);\n\
            fragment.rgb+= fragment.a*vec3(reelCurve_shineBrightness*shine);",
            [curvedReel_def]
        );
    CODE.runBeforeInit___end;
// END














----------------------------------------------------------
Section 12: GraphicExpander
----------------------------------------------------------


Graphic Expander

If you have a graphic object that you want to resize without distorting the edges, you can use the graphic expander add on in the object panel.

You can increase the expanded area width and height while preserving the original sizes of the corners.

This is great for buttons and panels, enabling multiple sizes in your project without having multiple assets, which will decrease the download size of your project.












----------------------------------------------------------
Section 13: IntroToPrecomps
----------------------------------------------------------


Hello, and welcome to this introduction to precomps in Incisor. In this tutorial, we’ll cover:

What a precomp is
How to set up a basic precomp

Precomp is short for precomposition, and is an object with its own scene, camera, render target, and resulting graphic asset. We can think of a precomp as a separate composition running independent of our main scene. By making graphic objects using the precomp, we can instantiate multiple “windows” to this independent precomposed scene without duplicating the scene itself. This is very useful for optimization because it allows us to visualize something many times over without actually duplicating all of the elements associated with it. This can greatly reduce the object count of our project. 

To demonstrate this, let’s step through the precomp example in the Incisor example gallery project, which you can download for free at incisordev.com. First, we create a new precomp using the precomp class. We simply have to supply a name, and the dimensions of the camera that will be pointing at our precomposed scene. The last parameter is autorender and it tells our precomp to either render every frame, or render only once when instantiated. Since we have some moving elements in our precomp, we’ll set autorender to true. Let’s also change the background color of the precomp camera, so it’s a little easier to see its boundaries. Next, we add a simple graphic object. We’ll use our beach ball graphic, called “Ball”. The important thing here is to set the parent of our graphic object to the scene of the precomp we made. Now we’ll set some basic scale and position values, and add some motion to the ball. You can learn more about that by checking out our Swoopers and Motions tutorial. 

When we made our precomp, a graphic asset with the name we gave the precomp was generated. We can use this graphic asset to create any number of new graphic objects. If we just make one, we’ll have a window into our precomposed scene. We can simply duplicate this code, rename the objects, and position them accordingly. As you can see, they’re all displaying identical representations of the precomp we made earlier. If you inspect these objects using the object panel, you can see that despite adding multiple visual elements, each reference to the precomp has only added one new object to our main scene. These are single graphic objects without children of their own, and we can manipulate them accordingly. That concludes this introduction to precomps tutorial. Feel free to check out our other tutorials on incisordev.com, and leave questions and feedback on stack overflow and our subreddit. Have fun creating with Incisor!











----------------------------------------------------------
Section 14: CustomAddOnsAndCustomObjects
----------------------------------------------------------


CUSTOM ADDONS CUSTOM OBJECTS TUTORIAL
- Welcome to this Incisor CustomAddOns and CustomObjects tutorial.
- CustomAddOns and CustomObjects are ways to create custom functionality that can be used in the Incisor Graphical User Interface.
- For example, a developer can create a CustomAddOn to define special properties and behaviors that can then be added to objects in the GUI within the Construct panel, and those properties can be manipulated and even animated from with the Timeline panel.
- We'll begin this Tutorial in a blank new project.
- The best way to get started with CustomAddOns and CustomObjects in Incisor is by looking at the examples provided in the Incisor Template Library.
- You'll see there are options for both CustomAddOns, and CustomObjects. These are two different ways to make custom functionality for objects available within the GUI; CustomAddOns are more modular bits of functionality that can be dropped or 'added-on' to existing objects, and CustomObjects serve as a way to define entirely custom objects.
- In this tutorial we'll look closely at CustomAddOns, but as we'll see, working with CustomObjects is very similar.
- Let's start by adding a CustomAddOn from the Template Library.
- CustomAddOns can be created to add custom functionality to specific types of existing objects and you can see all of the associated options from within the TemplateLibrary menu.
- To make a CustomAddOn that can be added to any kind of object, we can choose a CustomAddOn_SceneObject since all hierarchy objects inherit from SceneObject.
- For now we'll create a "Chase Cursor" CustomAddOn.
- By selecting this option, Incisor will automatically generate the new code asset file where the functionality for this CustomAddOn is defined, so we'll need to choose a name for the CustomAddOn and the associated file - let's call it 'CursorChaser'.
- Now we can see that our new codeAsset file as been added and the "Project Updated" button has appeared in the upper right corner of the Incisor GUI.
- It's important to note that if you are using typescript, you'll need to recompile the typescript at this time to ensure that the new code asset is compiled and registered with the GUI.
- Now that our Cursor Chaser CustomAddOn is included in our project, we'll see a CustomAddOns menu in the Object panel whenever a SceneObject is selected - this menu will enable us to add the CursorChaser functionality to any object we want to have chase the cursor.
- Watch as we add the ChaseCursor CustomAddOn to the sample text included in a the new project.
- We have to toggle the inspector mode off within the LiveView panel to ensure that the target project is getting normal cursor input. 
- You can see that the CursorChaser functionality makes the object it's added to follow the Cursor.
- Since we've added the CustomAddOn in the LiveView, its effect is only temporary and will be lost when the project is reloaded.
- To add the ChaseCursor functionality permanently we can either add in code, or add it within a Cunstruct in the Incisor GUI.
- To add a customAddOn in code, we can simply declare a new instance, providing the target object as the parameter.
- Next we'll cover how to use CustomAddOns within a Construct.
- To make this example a little more fun we can add some Assets to our project and create a SpaceGame Construct.
- We'll add image assets to our project including a StarryBackground, a PlayerShip and an AlienShip.
- Next we'll create a new SpaceGame Construct and add those images, being sure to set the sublayer values of each GraphicObject so that everything is visible.
- Next we'll change the code in the ProjectMain.js file to remove the sample text assembly from the project and instead we'll have the code add our new Construct to the MainScene using the nc.constructDefs.SpaceGame.add function.
- We'll also add a line to put the main Camera into the 'maximizeSafeZone' mode, which will ensure that our construct will always be visible within the window.
- Upon saving and refreshing the project now we can see our new SpaceGame construct in the LiveView.
- Now we can make the PlayerShip follow the cursor by adding the 'CursorChaser' CustomAddOn.
- Save and reload the project to see our work in action.
- You can see that our ship follows the cursor, but appears to be moving backwards.
- Notice that when we add CursorChaser to this GraphicObject a new section appears in the Object panel and that our CursorChaser add-on comes with a couple of properties we can manipulate.
- One of the ChaseCursor properties allows us to change the rotationOffset for the item chasing the cursor, so we can use that to adjust the ship's angle accordingly.
- If we want to make the PlayerShip keep up closely with the cursor, we can crank up the 'chaseSpeed' property to achieve that goal.
- If we make this adjustment within the SpaceGame Construct, the newly adjusted property values will also be saved in the construct file.
- Now let's give our alien ships the ability to chase the player ship - but to ensure that our new game isn't too difficult we can make the aliens a bit slower.
- To do so, we can add the CursorChaser CustomAddOn to the AlienShip GraphicObjects and adjust the 'chaseSpeed' and 'rotationOffset' property accordningly.
- Now let's save and refresh the project to play our new game!
- To make our game a little more interesting, we might want to make one alien ship slower than the other.
- Now let's look at the code behind the CursorChaser CustomAddOn, and see how we might be able to modify it.
- The code for creating CustomAddOns is basically done in two parts; the definition of the class, and the 'runBeforeInit' section of the code, in which the new CustomAddOn class is registered with the Incisor GUI.
- Since the CursorChaser example is meant to be functionality that can be added to any SceneObject, our class extends the CustomAddOn_SceneObject class.
- By extending the CustomAddOn_SceneObject class this entire class will automatically have access to an 'owner' property, which represents the given SceneObject that owns the instance of this particular CustomAddOn.
- In the class constructor, the chaseSpeed and rotationOffset properties are defined, and a callback for the fixedUpdate appEvent is added that will happen during every frame of gameplay - this is where all of the math is done to point and move the owning object towards the Cursor.
- There is also an 'enableStateChange' callback added, which ensures that the 'fixedUpdate' callback is removed if the owning object is disabled.
- The fixedUpdate function first ensures that a local reference to the pertinent camera is connected, and then does the calculation for the change to the rotation and position of the owning object.
- You can see that after the calculation is made, the fixedUpdate sets the rotation of the owning object, as well as the position, which is done using a 'swoopGlobalPosition' call, since this calculation is done according to global coordinates.
- Once the class for the CustomAddOn is defined, it is registered with the Incisor GUI. This is done within the 'runBeforeInit' section below using the nc.registerCustomAddOn function, which takes the class definition as its parameter.
- Below that the 'registerCustomAddOnProperty' function is used to expose the 'chaseSpeed' and 'rotationOffset' properties within the GUI and to make their values savable within a construct and animatable within Timelines.
- As you can see the 'registerCustomAddOnProperty' function returns a RegisteredProperty object that can be further manipulated to adjust things like value validation and the sensitivity of dragging the associated supervisor within the Incisor GUI.
- Now let's customize this functionality further by creating bounds for our Alien enemies.
-  We can start by adding a new "horizontalBound" property in the CursorChaser constructor.
-  Now we can use that property in the fixedUpdate function to limit the x position of any cursor-chasing item with a couple of simple if statements.
- We will also register the horizontalBound property the same way the other properties are registered below.
- Now, if we save go back to our SpaceGame Construct, we can adjust the horizontalBound values on the AlienShips to enable our PlayerShip to have safe zones on either side of the game area.
- We can also add a transparent box to help mark these bounds with a visual aid.
- We'll do more with this in a moment.
- Now to demonstrate how we can animate registered properties of CustomAddOns, we'll add a new timeline to our SpaceGame Construct, and call it 'ChangingSafeZones'.
- In this new timeline, we can animate the horizontalBound values for the CustomAddOns on our alien ships. 
- When we right click on the AlienShip objects in the Timeline panel, we can see that the additional options for the CursorChaser CustomAddOn are available.
- Adding keyframes to expand and contract the horizontalBound value will effectively allow us to change the size of the safe zones from within a the Timeline.
- While we're at it, we can animate the scale of the transparent box to match our new changing bounds.
- We can ensure that this timeline automatically plays by checking the 'autoplayWhenInConstruct' box, and by changing it to be the default Timeline for the SpaceGame Construct.
- Now let's investigate what we've built.
- Enabling this kind of custom functionality to be editable in from within the Incisor GUI be a powerful tool when it comes to tightening the iterative design loop and creating better ways for designers, artists, and animators to work together with coders.
- This SpaceGame is a great example of how we can use and modify the CustomAddOn examples provided in Incisor's Template Library.
- As you can see there are many examples and even blank templates for building CustomAddOns from scratch.
- Comprehensive templates are also provided with lots of blank functionality if you want to take the approach of starting with everything and then removing unneeded functionality. 
- You can access lots of examples of CustomObjects from within the Template Library.
- The primary differences between CustomAddOns and CustomObjects are that with CustomAddOns, you define custom functionality to add on to objects, and with CustomObjects you are defining entirely custom objects.
- So for CustomObjects, this means that instead of extending CustomAddOn classes, you're just extending normal hierarchy objects such as SceneObjects, GraphicObjects.
- Other than those differences CustomObjects are built in a similar fashion to CustomAddOns; by defining classes and registering those classes and their properties with the GUI.
- To quickly show an example use of a CustomObject, let's add the ClockExample CustomObject from the TemplateLibrary - we can call it "Clock".
- Once the new code asset file has been included in the project, we can right-click on objects in the Hierarchy panel or LiveView panel, and we'll see the option for adding our new Clock CustomObject.
- The clock example is straight-forward, defining a customized TextBox that automatically shows the time, with boolean option for whether or not to show seconds.
- Just like with CustomAddOns, CustomObjects and their registered property values are savable when added to within Constructs.
- Let's save and reload to try our final product.
- We now have a game where the player controls their ship with alien ships in pursuit. And now that we've added a clock, we know our players will never lose track of time.
- That's all for this Incisor CustomAddOns and CustomObjects tutorial. 
- You can also see a practical example of CustomObjects in use in the Incisor Slot Template, which defines a "Symbol" CustomObject used by reels in the slot game. 
- To download the Incisor slot template incisordev.com/downloads.
- You can stay tuned for an upcoming tutorial covering the Incisor Slot Template by subscribing to the Incisor YouTube channel.
- And if you have any questions feel free to ask them on stack overflow or on the Incisor sub-reddit.
- Have fun creating with Incisor.










----------------------------------------------------------
Section 15: ParticleSystems
----------------------------------------------------------


 0
Hello, and welcome to this tutorial on creating and using Incisor ParticleSystems.  In this tutorial, we will cover the following topics: What a ParticleSystem is, how to create a ParticleSystem, and how to use a ParticleSystem in your project.
A ParticleSystem is a special type of GraphicObject that allows us to control the behavior of many separate graphics called particles.  Suppose we want to create a snow effect in our application.  One approach would be to create a unique GraphicObject for each snow flake and control the motion of each GraphicObject manually.  While this can work, the computation required does not scale well to hundreds or thousands of snow flake particles.  To solve this, a ParticleSystem merges all the particles into a single GraphicObject, and uses the GPU to make each particle obey a randomized variation of the same basic particle behavior.

1
To define this particle behavior, we use a ParticleSystemDefinition.  To get started, click the "create new" button in the Particle System panel.  In the popup, we'll choose Fountain as the template for our new definition, and give it whatever name we like.  To see the results of changing this definition, we first need to add a ParticleSystem instance that uses this definition.  Right click in the live view, and add ParticleSystem.  In the ParticleSystem panel, we'll switch the definition this ParticleSystem uses to the new definition that we created.

2
Now that we've got a ParticleSystem up and running, let's look at the ParticleSystem Panel to see how we can control the particle behavior.

3
In the Particles section, we have a list of Particle types that this system will use.  This system currently uses the SampleParticle2 graphic asset for all the particles.  Let's add another particle type, and select SampleParticle.  Now we see two different particle graphics in our system.  We can control the emission rate of each type of particle independently, using the particlesPerSecond value, to control how many of each graphic we want to see, as we see here when we change the particles per second of the second particle.
Because two graphics in the same particle system might have mismatched scales, we can also control the scale of each particle using the scale value.  For example, if we decide that the circular particles here are too large relative to the star particle, we can lower the scale of just SampleParticle.

4
Next we have the Emission section.  Particle Lifetime controls the amount of time a particle lives after it is emitted.  Here we have our first example of randomness.  If we set the particle lifetime value to 1 and randomness to 0, each particle will live for exactly 1 second.  If we increase the randomness value, we increase the amount each particle's lifetime is allowed to deviate from the base value.  Note that this random deviation is plus or minus the randomness amount.  In other words, the lowest lifetime allowed with this setup is 1 minus .9, or .1 seconds.  The largest possible lifetime would be 1 plus .9, or 1.9 seconds.  Each emitted particle will then pick a random number in this range for its unique lifetime.

5
Next we have emission time randomness.  To move easily observe the effect of this value, let's lower the particles per second of this system.  With an emission time randomness of 0, we can see that the particle system will emit particles at equally spaced intervals.  By increasing the emission time randomness, we cause each particle's emission time to be delayed by a random amount of time between zero and this amount.  Let's set this back to zero and bring the particles per second back up.

6
The emission duration controls that amount of time over which particles are emitted.  Let's look at the ParticleSystem section in the Object Inspector for a clear picture of what's happening here.  Here we see the interface for the Particle System's playback controller.  An emissionDuration of 0 indicates that the particle system will emit particles endlessly.  But if we change the emission duration to 1 second, we see that that after 1 second, no more particles are emitted, and the existing particles are allowed to complete their lifetime.  Note that the playback controller automatically adjusts the end time of the particle system to be the last possible time at which a particle might die.

7
Next we have emission velocity.  This is our first example of a parameter that can be one of three types.  Currently, the type of the emission velocity is set to Constant.  This means that the path each particle takes will be calculated using an unchangeable initial velocity that, in this case, shoots it straight up at a velocity of 1000 units per second.  If we want to shoot the particles up and to the right, we can simply edit the X component of the velocity to shoot them 1000 units per second to the right as well.

8
Now Suppose we want this emission velsocity to change over time.  This brings us to an important concept regarding particle system definitions.  While it is technically possible to modify the x component of the definition's emission velocity every frame, this is not recommended for several reasons.  First, as we can see here if we slide the x component around in the interface, the path of every particle is recomputed as if that new value had been the emission velocity for the entirety of the particle system's existence, which is typically not the desired effect.  More importantly, changing this value causes a costly rebuild of the entire definition, including rebuilding geometry and rebuilding the effect node definition.  This is why the changing of the definition in this way is only recommended at initialization.

9
The much better way of modifying the emission velocity's value is to use one of the other two parameter types.  If we click the type button, we can see that this can be changed to a an Expression or a Ramp.  First, we'll look at the Ramp type.  This is a built in type that allows us to specify parameter values that change over time.  If we want each particle to evaluate this Ramp using the time at which it was emitted, we can choose an inputType of emissionTime.  All ramp inputs are done in a normalized range from 0-1.  By specifying an input maximum of 4, we indicate that we want the ramp to be evaluated over 4 seconds of emission time.  Note that is common to set this inputMaximum to match the emission duration of the particle system.  But with an emission duration of 0, meaning emitting forever, there is no length of time to match, so one must be chosen here.

10
The Ramp initializes with a single keyframe, seen here at time 0.  Let's add another keyframe by pressing the plus button on the top right.  Now we have another keyframe that has been added at time 1.  Because we have selected an inputType of Emission Time, the second keyframe corresponds to the value that will be calculated at our inputMaximum of 4 seconds.  Now we can change the emission velocity over 4 seconds by modifying the values at these keyframes.  Let's select the first keyframe and set its value in the X graph to negative one thousand, and set its value in the Y graph to one thousand.  This will emit particles up and to the left.  Then we can select the second keyframe and set its value in the X graph to positive one thousand, and set its Y value to positive 1000.  Then we can observe in the particle system that the emission direction has interpolated between these two values over 4 seconds.

11
We can also modify the Ramp's interpolation type to change the shape of the curve between the keyframes.  To better demonstrate the different types, let's add a few more keyframes.  We'll hit the plus button two time to get a total of 4 keyframes.  Then we'll set the second keyframe to time 0.25, and a value of 1000.  Let's set the third keyframe to a time of .5, and a value of 1000, and the last keyframe we'll set to a time of 0.75, and a value of negative one thousand.  Notice how with linear interpolation selected, the curve is made of straight lines between each keyframe.  With smoothstep mode, we get S shaped curves that ease into and out of each keyframe value.  With Catmull Rom mode, the curve becomes rounded between the middle two keyframes.

12
The other option to change the emission velocity over time is to use an expression.  When we change the type to expression, we see the value is populated with a default expression specifying a vector with no velocity.  We can easily restore our original velocity by giving the particles an upward velocity here.  We can then modify this expression using some built in functionality.  Using the built in rotate2D function, we can change the vector's direction based on the time at which the particle was emitted, similar to the way we did with a Ramp.  In this case, we can make the emisison rotate indefinitely with this simple expression.

13
To best observe emission velocity randomness, let's put the emission velocity back to a constant upward emission.  Let's also set the particle lifetime randomness to 0.  This definition currently has a constant randomness of .3.  If we reduce this to 0, we see that the particles all reach around the same height, because their velocities all have the same magnitude.  As we increase the randomness, we observe an important property of the randomness system.  For parameters that are vectors, meaning they have more than one component, the randomness value causes deviation of the magnitude or length of that vector.  Importantly, the direction of that vector is unaffected.  We can see this as we increase the emission velocity randomness.  Notice how the emission directions did not change, but the magnitude of their emission vector is allowed to deviate.  To achieve this, the base vector is multiplied by a number randomly chosen from within a range.  The lower end of this range is one minus the randomness value.  The upper end of this range is 1 plus the randomness value.  In this example, this works out to scaling the vector by a number randomly chosen in the range of 0.75 to 1.25.

14
The emission cone angle controls how much the emission velocity vector is allowed to be randomly rotated away from the base value.  Notice how a value of 0 emits particles in a straight line, while raising this all way to 360 emits particles equally in every direction.

15
Emitter position allows us to animate the position from which particles are emitted.  Notice how grabbing the particle system in the GUI (gooey) and moving it also moves any previously emitted particles, which is often undesireable.  Using the emitterPosition parameter, we can animate this position without affecting the behavior of particles that have already been emitted.  Let's reduce the emission velocity to make this more visible.  If we then use this expression , we get a moving emitter position that does not affect the previously emitted particles.

16
The emitter shape lets us choose from a few predefined shapes where particles may be emitted.  To make this more apparent, let's lower the particle lifetime to something very short, and increase the particles per second to something very high.  We can now see that by choosing the Rectangle emitter shape, and giving it some larger dimensions, we get particles emitted from a rectangle.  If we switch to circle uniform, we see that we get particle emitted uniformly across a circle.  If we choose circle center, we get a similar circle, but with particles more likely to be emitted near the center.  Choosing custom lets us populate the custom emitter shape code, where the expression is responsible for choosing a new position for every particle.  For example, we can emit particles only along the edge of a circle using this expression.
A few random number variables are already available to use in expressions.  These are named rand0 through rand5, and each have an x, y, z, and w component.  Here we have used rand1.w.  Each of the provided random numbers is in the range -1 to 1, and is unique to each particle.

17
The system automatically recycles old particles after their lifetime is over, so that it can create fewer particles and use less memory and set up time.  The particlePoolCount number reflects how many particles were actually needed to support the requested emission parameters.  It is often far fewer than number of particles that appear.

18 is a shot of resetting that jason can use if he wants, nothing to say really.

19
In the Physics section, we have the force parameter.  This is often used to simulate gravity.  Notice how the particle move down more quickly as we increase the strength.  Extra velocity x and extra velocity y are an additional factor that is added the motion of each particle, and are often used to simulate things like wind.  Notice how all particles are pushed to the right as we increase extra velocity x.

20
Motion stretch will scale each particle along the direction it is moving.  combined with the motion stretch alpha influence, this is often used as a quick approximation of motion blur.  To see this, let's lower the sizes of the particles and increase both of these values to .2.

21
The age ramp expression lets us modify a particle's age value.  For example, we can make a particle move through the beginning of its lifetime more slowly, then speed up, by squaring the age.  Let's reset these parameters.

22
In the rotation section, we can control the rotation speed of the particles.  This system currently has a rotation speed base value of 0, with a randomness of 180.  This gives us a system where some particles will arrive at a rotation number near the middle of the range, resulting in very little rotation.  Suppose we instead want each particle to spin quickly in either the positive or negative direction.  To achieve this, we can remove the randomization and use an expression for the base value.  We'll use the x component of rand2 to get a random number that is unique to each particle.  Because these numbers are in the range -1 to 1, we check if the number is negative or positive to choose which direction this particle should rotate.  Let's now put this back to 0 rotation speed.

23
The initial rotation sets the rotation of the particle before any rotation speed or any of the additional rotation parameters are applied.  If we remove the randomization of the initial rotation, we see that all particles have the same rotation.  The rotation sway strength, rotation sway speed, and rotation sway phase all work together to sway the rotation back and forth.  If we set the speed to 1, and the strength to 100, we see that each particle rotates back and forth over its lifetime.  Because the rotation sway can cause particle rotations to sync up, which may be undesirable0, the rotation sway phase is available to offset the rotation sway of each particle.

24
The Wiggle section lets us control an extra movement factor on each particle.  Let's remove the other motion on these particles to make this more obvious, and set the emission shape to a rectangle.  Now we see that each particle remains in its initial position.  If we modify the wiggle parameters, we can see that the wiggle strength and wiggle speed work together to move each particle in a back and forth motion.  If we make the x and y speeds mismatched, we can get a more chaotic feeling wiggle motion.

25
The last wiggle parameter is best demonstrated if we set the emission shape to a point, lower the sizes, and increase the particles per second.  By doing this, we can see that the sine wave nature of the movement means the particles will naturally fill out a rectangle, since the x and y are wiggling independently.  We can alter this by using the wiggle circular strength.  Setting it to 1 forces this movement to fill out a circle instead.  Moving this value outside the zero to one range can also create some interesting effects, as we see here.  Let's spread these particle out by increasing the wiggle strengths and lowering the speeds.  (500 and .1, .08)

26
The particle scale lets us control the scale of each particle.  Let's set this to an expression that makes each particle scale up, then scale down over the course of its life.  First, lets use the smoothStep function to scale the particle up:
The age ratio variable represents how far through its lifetime this particle is, expressed in the range zero to one.  We can then modify this further to scale the particle down again using another smoothStep function:

27 (Matt, I say this as "color alpha section" in my head, but maybe "color slash alpha section" is better?  I don't know)
In the color/alpha section, we can control the color and transparency of the particles.  First, let's change the color of all of these particles by lowering the blue channel of the color.  Then lets hue shift each particle using the particle hue shift parameter.  Changing the base value will change all particles together.  But note how the randomness parameter can give us a useful variation in the hue of each particle.

28
We can also change the alpha value to change the transparency of each particle.  Here, let's use a Ramp and tell it to use the ageRatio as input.  This means the lifetime of the particle will be mapped to the Ramp values, with 0 being the moment the particle is emitted, and 1 being the time it dies.  Let's add another keyframe to this Ramp, then set the first keyframe's alpha value to 1.  We see that the particle's alpha starts at 1 and fades to 0 over the course of its lifetime.
In the randomness section, we can control whether the default behavior for any particle system using this definition will be to change the random seed of the particle system every time playback is started.  This can be very useful for making the random variations of each particle be different every time the particle system playback is started, so that it appears less repetitive.  The seed can also be specified manually in the randomSeed field.  The particle seed draw order can be used to randomly shuffle the interleaving of particles.  This is only meaningful when a system contains multiple graphics.  because changing this value causes a costly rebuild of the particle system's geometry, it is recommended to only set this value at initialization.
The randomness distribution is an advanced setting that can bias all random numbers toward 0, which can alleviate certain visual artifacts, but it is not typically needed.

29
Now that we've gone through the entire panel, let's see how we use a particle system in code.

30
Earlier, we added a particle system to our scene by right clicking in the Live View.  To do this in code, we'll call nc.addaParticleSystem.  We'll pass it the definition we created earlier, which can be found in nc.particleSystemDefs, and tell the particles to play using its playback controller.  Now that we've got our infinitely emitting particles created, we might decide dynamically in code that it's time for these particles to stop emitting.  to gracefully accomplish this, the particle system has a stopEmitting function that stops the creation of new particles after the function call is performed, but allows existing particles to complete their lifetime.  To see this, let's add a keystroke callback where we call this function.  If we do nothing, these particles will never stop emitting.  but once we press a key, we see that the particles have stopped emitting, but the existing particles are unaffected.

31
A noteworthy property of Incisor's Particle Systems is that we can set the playback controller to arbitrary time with no performance cost.  Jumping to a different time does not require stepping through the intermediate particle states.  Because of this, we can even tell the playback controller to play the system backwards with exactly the same performace.
This concludes this Incisor Particle System tutorial.  Check the link in the description for more tutorials, and feel free to leave questions and feedback on our Stack Overflow and subreddit.  Enjoy creating with Incisor.










Because the ParticleSystemDefinition is separate from the ParticleSystem, multiple ParticleSystems can use the same definition.  This allows much of the work to inialize a particlesystem to be done only once, regardless of how many ParticleSystems use the definition.






merge publishing analytics
merge the geometry editor/asset browser changes











----------------------------------------------------------
Section 16: WaitThens
----------------------------------------------------------



Hello and welcome to this waitThens tutorial in Incisor.

waitThens are a very simple yet powerful tool included in the Incisor API. 

In this tutorial we are going to cover: Creating waitThens, activating created waitThens, stopping created waitThens, non-pooled waitThens, and stopping non-pooled waitThens.

In Incisor, a waitThen is used to schedule a delayed callback, which is similar to JavaScript's Set timeout function. 

The only difference between the two is that Incisor waitThens are compatible with Incisor's pausing and speed control systems. 

Now that we have the basic idea of waitThens, let's check out some examples. 

I've opened up a new JavaScript project. 

If you're unsure on how to set that up, be sure to check out our Getting Started video.

Before we start using waitThens, I'm going to first remove the out of the box code that each project starts with, and set up our scene with some boxes to visualize what's going on. 

Okay, you can see here I created two boxes, one white and one green, and offset their y coordinate positions to give a better view of each.

Usually when you want to call a waitThen, you use nc.waitThen.

In this function call takes the following parameters: duration, which is in seconds, callback owner, callback name, any callback arguments, name, pause immunity, and speed controls, which I mentioned earlier.

So we don't have any functions yet to call, so we can't use this waitThen function just yet.

Let's make a function to add some motion to the white box. 

Okay, now here we have a function called add motion to white box, which takes two arguments: motionSpeed0 and motionSpeed1. 

The function itself simply adds two motions, one for the white box's X position and one for the white box's Z rotation. 

If you're unfamiliar with motions, please be sure to check out our tutorial on motions and swoopers.

Okay, back to the waitThen.

We are going to call our function we just created using nc.waitThen.

I'm going to pass in 1 for the duration and seconds to wait. This as the callback owner, our function name as the callback name, and then an array with .2 and .05, which are motionSpeed0 and motionSpeed1, respectively.

Now saving and going back to Incisor, we see that after one second, the white box on top will start moving and rotating. 

In general, you will usually want to use nc.waitThen to schedule delayed callbacks in your Incisor projects, as this method makes use of an internally pooled group of waitThens. 

However, there's also another way to call a waitThen in Incisor, which I will show you now.

First, I'm going to create a new function to add some motion to our green box. 

This function is similar to the first one we made, and now we are adding motion to the green box's x and y positions. 

Now the other way to use waitThens in Incisor is very similar as you will see here. 

First we make a new waitThen object using new.waitThen and then pass the name of our waitThens into the constructor. 

Now similar to using nc.waitThen, we can call the activate function on our waitThen object, and it takes the exact same arguments as nc.waitThen. 

So let's call activate using a three second delay. 

Again, using this as the callback owner, add motion to green box as the function name, and an array with .25 and .5 as the parameters.

After saving and going back to Incisor, we'll see the green box start moving after a three second delay. 

And there it is. 

Now what is the difference between the first and second way we use the waitThens in this tutorial? 

The second way we made a waitThen does not make use of the internally pooled waitThens and instead adds a bit more overhead to the project.

Because of this, it is usually best to make use of the nc.waitThen function we used first.

Now that we've seen the two ways to use waitThens in Incisor, let's see how we can cancel these scheduled callbacks, as sometimes this is necessary. 

To stop a pooled waitThen, we can use nc.stopAllWaitThensByCallback back or nc.stopAllWaitThensByName.

If we stop the waitThen using stopAllWaitThensByCallback, we simply need to pass the callback owner and callback name, and then specify if we want the callback function to perform or not. 

Now if we call stopAllWaitThensByCallback on the function we created for the white box and choose not to perform the callback, you can see the box never starts moving.

Now, for the stopAllWaitThensByName function. 

In order for this call to work, our wait then must have a name. 

I notice now that I did not give our first waitThen a name, so I'm going to add that now. 

Now for calling stopAllWaitThensByName, I'm going to also have the waitThen callback execute.

Saving and going back to Live View, we can see the white box now starts moving immediately because we called that method immediately. 

Both of these methods can also be used on non pooled waitThens.

There's one last way to stop a waitThen, and it is only available in non-pooled waitThens

Going to our waitThen for the green box motion, we can call the stop function on our created waitThen object. 

This method simply asks if we want to perform the callback or not.

Saving and going back to Incisor, you can see since we called stop on the waitThen the green box will not start moving. 

And this concludes the waitThens tutorial.

Don't forget to check out Incisor dev.com/tutorials for more tutorial videos, and feel free to leave questions and feedback on StackOverflow and our subreddit. 

Have fun creating with Incisor.












----------------------------------------------------------
Section 17: Showcase - Poker
----------------------------------------------------------


Audio timing: (Play the Clark_Poker_1.wav and the Poker UI video at the same time.)
0 to 1:13 - Intro
1:14 - Playing games
1:36 - turn off game audio and autoplay
1:46 - Guarantee hand
2:16 - Customize interface
2:30 - panels can be opened and type of panel
2:42 - Tool Tips
2:55 - Card0 selected
3:18 - GameLogo Event Animation
3:28 - Particle Pannel
3:50 - Hierarchy Pannel
4:20 -  Graphic expander
4:40 - Paytable background box
5:00 - Gamelogo Timeline
5:31 - Idle state - Scrub timeline - Play - Curve mode
5:43 - Paytable - Royal Flush - change position, rotation and scale

Code (Start playing the Poker Code video here.)
6:41 - Init function in Project Main
7:10 - Adaptive Camera
7:24 - Project settings
7:29 - Remove Adaptive Camera
7:35 - NC and PR
7:50 - Game Construct
8:00 - ContructGetter
8:09 - Game Audio
8:20 - Poker Logic and Client
8:40 - Poker. run()
8:46 - Logic Events - defineAppEvent- 
9:18 - Client events - Callback - requestDeal
9:45 - gaffHand
9:56 - AddMotion
10:31 - Swoop

The full script can be found here.  https://docs.google.com/document/d/1vPgAuV61Xv47FdaI1r6yxxvZXRW_trCSlVNLrx1EMmM/edit?usp=sharing






Greetings and welcome to the Incisor Draw Poker demonstration. This complimentary project is here to help you dive into creating games and experiences using Incisor's powerful development tools and APIs. The game made its debut at the 2025 ICE Conference in Barcelona, where we showed it off running on both slot machines and mobile devices. 

In this demo, I’ll play through a few hands of the game so you can get a feel for the rules and features. After that, we'll take a brief look at some of the key concepts behind building the game. And finally, we’ll go over how you can get your hands on it and start experimenting yourself.

Before we get started, if you haven’t already, be sure to visit incisordev.com to download the latest version of Incisor and explore the instructional tutorials. They’ll guide you through the basics, help you get started, and further examine some of the more detailed topics we’ll cover in this video.






Incisor Draw Poker was modelled after the traditional draw poker games many of us are familiar with. The rules involve placing a bet, receiving five cards, and deciding which to hold or discard. You aim to create the highest-ranking poker hand possible and winnings are paid out according to the pay table. 

I’ll start by playing a few hands and walk you through some of the key components. To get going, click "Deal", "Play 5 Credits," or just hit the Spacebar. You can adjust your bet size using the Bet Up or Down buttons. There’s an automatic hold feature, but you can always deselect any held cards. When you're ready, press the Draw button to replace any cards you didn’t hold. Winning hands will be highlighted on the Paytable and above the cards. If you want to turn off the game audio, just click the speaker button, and you can enable autoplay by hitting the play button.

  
If at any point you want to guarantee a winning hand in the next game, just click on the name of the hand you want from the Paytable. The selected hand will be highlighted to confirm your choice, and you’ll win that hand on your next deal.






Now that we've seen the game, let's explore how it was built. We’ll take a brief look at some of the core principles behind it. This tutorial won't go into great detail, but future tutorials will dive deeper into each of these topics.

First up, let’s explore the Incisor User Interface. 

As you can see, the Incisor interface is fully customizable. It features a variety of panels, each offering different views, tools, and properties to suit your development needs. You can even design your own custom panels to provide the specific functionality you require throughout the development process. Panels can be selected HERE, and you have the flexibility to place and move them wherever you like. Let’s take a look at a few examples.


The Tooltips panel offers detailed information when you hover over an item. You can see the tooltips in action as we navigate through different elements in the Object panel. For example, we currently have CardLocation0 selected, which is also visible in the Hierarchy panel.

The Live View is an invaluable feature, allowing you to instantly preview changes without the need to publish the game, streamlining your workflow.

In the Construct panel, you’ll find a collection of objects that can be animated within the Timeline panel. To view an animation, simply select a state. By default, it's set to NeutralState, but let's switch it to Event. Now, you'll see the animation in the Timeline.

The Particle panel lets you create dynamic, real-time particle effects. For instance, if I select CoinFountain, you can observe the effect change as I remove and then re-add Particle 1.

These are just a few examples of the many panels available. Feel free to experiment with different panels and layouts to create a personalized Incisor development environment that works best for you.






Now, let’s use the UI to explore the game’s hierarchy. At the root level, we have the MainScene, which contains a single orthographic camera. The Game Construct serves as the master construct, housing other constructs and graphical elements. Notice that each card is treated as a separate Construct, while the paytable is added directly to the Game Construct.

We can also dive deeper into other Incisor components used in the creation of this game to understand how everything fits together.






We’ll start by focusing on the Incisor Graphic Expander. Graphic Expanders are a great tool for creating dynamically sized graphics without stretched edges, and they do so with significantly reduced download size and load times. They also lower the graphics card memory footprint and boost overall performance. This game makes extensive use of Graphic Expanders.

Let’s take a look at one of the background boxes on the paytable. I’ll open the Object Inspector and adjust the properties of the background’s Graphic Expander so you can see the asset change in real-time. If we set all properties back to zero, you’ll see the original image. As you can see, using Graphic Expander results in a pretty significant reduction in size.





Next, let’s check out some of the game logo animations. The animations are created using Incisor’s Timeline editor, along with the Swoop and AddMotion APIs. All the particle effects are generated in real-time, which means there are no sprite animations or pre-recorded videos used in this game.

I’ll open the Construct and Timeline editor, along with the Live View, to give you a closer look.

In the Construct window, I’ll select the game logo. By default, the neutral state won’t automatically load in the Timeline, so we’ll change it to the Idle state. Scrubbing through the Timeline lets you view the full animation, and hitting play will loop the animation so you can see it in action. If you switch to curve mode, you’ll also see a graph of the values controlling the animation.

The paytable is created using Incisor TextBoxes, which makes it data-driven and allows for real-time swapping. This approach also helps reduce both download size and memory footprint. I've selected the Royal Flush TextBox, and its data will appear in the Object window. You can adjust properties like position, scale, and rotation, along with other data. These changes are temporary and can be cleared by refreshing the screen.

There’s still much more to explore within the Incisor UI and Inspector. You can even add your own custom elements using Incisor Extensions, which we'll cover in another video.







Alright, let’s jump into some code. I’ll be using VS Code—it’s my preferred editor, but it’s definitely not a requirement.

We’ll start with a high-level overview of the key elements of the code, beginning with the entry point for every Incisor application: the init() function in ProjectMain.js. Draw Poker is written in JavaScript, but Incisor also supports TypeScript, so if you're interested, check out the tutorial videos for a walkthrough on setting up an Incisor TypeScript project.

Following best practices, the game’s logic is separated from the interface. It’s built using object-oriented principles, with all the code organized into different class files and packaged logically.






Starting with the very first line of code, we set the main camera’s adaptive camera to "maximize safe zone." This ensures the game resizes to fit the browser window and uses the Core Canvas Resolution X and Core Canvas Resolution Y settings. You can adjust these values by going to Project > Project Settings. I’ll go ahead and remove this line to show you what happens when it’s not there.

You’ll also notice the frequent use of "nc dot" throughout the code. "NC" stands for Incisor, and it’s the key to accessing all of Incisor’s internal functions. You’ll also see "PR" used often — this provides a way to access globally scoped variables that were initialized inside the ProjectMain init() function


The next line retrieves an instance of the Game Construct. This is the main construct for the entire game, and it includes other nested constructs within it.

We use constructGetter as a helper to simplify the function call for descendantsByName.


As for the game’s audio, it’s synchronized by starting all of the looping sounds at the same time, and then the volumes are gradually ramped up and down. The sounds index helps with keeping everything in sync.


As previously stated, the game’s logic is kept separate from the user interface, which is crucial for a production game. This separation allows for the use of a mock client or a logic simulation module to test the game, or to let a client engineer work independently from the backend developer.

The two parts communicate by sending custom Incisor AppEvents.

When you call the PokerLogic run functions, it kicks off the entire game cycle.

The game logic handles just two events. 

The init game event is used only at startup to provide the client with all the initial values for the meters. 

The game outcome event is sent every time the Deal or Draw button is pressed. 

It sends all the necessary data for that part of the game, like the evaluation results, the cards to be displayed, and the bank. These events are built into the game logic, and they can be sent out as needed. To define custom events, we use nc.defineAppEvent("InitGame").

The game logic also listens for three client events by using a callback. This is done by calling nc.appEvents, followed by the name of the event you want to register or listen to. The client triggers the "requestDeal" and "requestDraw" events. It’s important to note that the game logic always maintains control, as the client can’t be trusted. So, when the request deal event is triggered, the logic’s process deal function is called.

As we discussed earlier, you can manipulate the cards for upcoming games. By pressing the winning hand, the request gaff event is triggered, and the pay category for the chosen hand is passed.

For more info on AppEvents, check out the Incisor tutorials page.




Now let's look at motion.

AddMotion creates continuous movement, but you can adjust or stop it by modifying its influence. This function returns a motion object. To make it more dynamic, we add a new variable called scaleMotion to the handNameText and assign it the motion object. Now that we have access to the motion instance, we can tweak its influence to create smooth fade-in and fade-out transitions. In this case, the value is set to 1 for full motion, and it’ll be set to 0 when we want to stop the motion.




Lastly, let’s take a look at swooping.

Similar to AddMotion, swooping interpolates a numeric property over time. The key difference is that, unlike AddMotion, swooping is finite—it doesn’t run continuously. In this example, we’re swooping the alpha value of the text box, gradually fading it down to zero. This creates a much smoother, more visually pleasing effect than instantly turning the visibility on and off.




And that’s a wrap! You’ve just seen a complete game built with Incisor, showcasing many of its capabilities. This game can serve as a great starting point to boost your knowledge and help you start building your own Incisor applications.

To download... 

Thank you for watching. Enjoy creating with Incisor!












----------------------------------------------------------
Section 18: ObjectPanel
----------------------------------------------------------


Object Panels

Today we’ll be talking about the Object panel in Incisor. The main use of the object panel is to inspect and manipulate an individual object within a scene, or SceneObject. With our project open, we’ll access the object panel by adding a new panel, clicking the panel drop down menu, and selecting “Object.” At first the panel will be mostly blank because we don’t have any object selected. To populate the panel with an object, we can select something from the live view, or click on something using a hierarchy panel. Look for our separate tutorial on Hierarchy for a deeper dive there. Now that we have an object selected, we can see a lot more information in our object panel. 

The first thing we’ll see in the panel header is the type of object we’ve selected, and any inheriting classes in parentheses. Next we’ll see some methods of monitoring and manipulating object properties, which we call supervisors. We’ll see common supervisors like the object’s name, whether or not it’s enabled, and its position, scale and rotation. We can alter these by entering numbers or clicking and dragging the label. Holding shift while dragging will increase the sensitivity, and holding command on Mac or control on Windows will decrease it. Next we can see something called the Scene path. This shows where the object lives in the hierarchy, what it’s currently being parented to, and its children if there are any. We can also use this section to select other objects. You might have noticed that when I clicked this “container” object, a lot of information left the object panel. That’s because our previous object was a GraphicObject, which has more configurable parameters like visibility, the asset being used with the object, the layer it’s on, and other class specific variables. 

If I select a different type of object, like a TextAssembly for example, you’ll see some text specific elements appear. Selecting a sprite animation or particle system will populate a playback controller in our object panel. All of these elements correspond to parameters that can be set on the object through code. This is important because unless we’re working within a construct, changes that we make in the panel won’t be permanent unless we enter them in the project’s code. So the object panel is a very useful way to preview specific changes before hard coding them. Another useful thing for engineers is the “print object to console” button which is common to any object being inspected. If we inspect the page and click this button, we’ll see our object appear in the console, and can view all of its associated variables and parameters. If you select multiple objects by holding shift, you’ll see any shared elements they have on the Object panel. But note that even if you have multiple object panels open, they will all reflect the current selection. And that’s all for Object Panel basics. Check out our other tutorials on YouTube or IncisorDev.com, and be sure to leave questions or comments on StackOverflow or the Incisor SubReddit. Have fun creating with Incisor!











----------------------------------------------------------
Section 19: Swoopers
----------------------------------------------------------



Hello and welcome to the Swooping in Motions tutorial for Incisor. 

In this tutorial, we'll cover:

What swooping and adding motion mean in Incisor. 

Basic examples of how to swoop and add motion. 

How to use motion types to control the nature of the motion. 

How to use tween types to control the Swoopers interpolation method, 

and finally, how to add custom tween type code assets to your project.

In Incisor,  motion and swooping are both ways to interpolate numeric values over time.

The difference between the two is that motion is unending, while swooping is finite. 

This could apply to properties like an object's position, color, scale, or any other numeric property. 

Let's go ahead and look at a few examples. 

I've opened up a new Incisor JavaScript project. 

If you're unsure how to set that up, be sure to check out our Getting Started video.

For our first example, we'll create a simple motion that continuously updates the color of a box. 

I will remove the out of the box code that every new project starts with. 

Now let's start by creating a simple graphic object and using the white box asset. 

Now we'll add motion to the color multiply property of the box. 

Specifically, we'll update the red, green, and blue color channels.

Notice that the lower and upper bounds for each of the color channels are set to cover the full range from 0 to 1. 

The key difference here is the motion speed parameter.

By varying the speeds of each color, we create a sense of random color changes. 

Let's save it and check out Live View. 

As we can see, the box continuously changes color; and because motion is unending, this will not stop.

Now let's make the box move. 

We'll use the same graphic object, but this time we'll add motion to its position property. 

The Each function allows us to define lower and upper bounds for the x, y, and z coordinates as arrays. 

Let's save the project and check out Live View again. 

Great. Our box is now moving back and forth continuously within the bounds we set.

But what if I want the box to move in a circular motion instead? 

This is where motion types come in. 

Motion types in Incisor are fully customizable, but we also provide a few built in types that can save you time. 

Let's look at the library tab. 

Here you'll find a variety of tools you can import directly into your project.

I'll select motion types and then import move in circle. 

Now that we've imported the moving circle motion type, we can apply it to our existing motion. 

Earlier, when we added motion to the position. we got back a motion instance. 

We can now update this instance with our newly imported motion type. 

And that's it. Let's save the project and check out Live View to see it in action.

Now we have our box spinning in a continuous circle, but let's take it a step further. 

We'll dynamically increase the speed of the box as it moves. 

So far we've been using specific motion functions like the each function on the position property of our graphic object, but with Incisor, we can apply swooping to any numeric property on any object using nc.swoopValue.

To make the box speed up as it moves, we'll use nc.swoopValue on the motion speed property of our motion instance. 

Now save your changes and watch as the box accelerates to a speed of ten over 10 seconds.

Okay, now that we've covered motion, let's move on to an example of swooping. 

We'll create another graphic object.

Next, let's swoop its position by providing an array of its ending values and the duration. 

In this example, we'll swoop the box to the position 300,300,0 over a period of five seconds. 

Let's save it and check out Live View. We now have a second box that moves from the center up to the right over five seconds, and then stops.

The swoop is complete, but just like with motion, we can change the way the box moves using a tween type. 

Let's go back to the library. 

Select tween types and choose Import WindupOvershoot. 

Now let's go back to the code and make the swoop more interesting by adding the WindupOvershoot tween type to the each function. 

Let's save the project and check out Live View again.


Notice how the white box first moves down and to the left, which is the wind up. 

Then it overshoots its intended destination before returning, creating the overshoot effect. 

Now let's wrap up with one last concept. 

The swoop completion callback. In many cases, you'll want to be notified when an event or action has completed. 

The completion callback allows you to do just that.
  
Let's add two more parameters to the each function. 

The callback owner, in this case this and the name of the callback function. 

Next, we'll implement the callback and display a textbox when the swoop is finished. 

Save your changes, then check out Live View to see it in action.

And there you have it. 

We've covered how to add motion, swooping, and how to use custom code assets like motion types and tween types to create dynamic animations. 

Check the link in the description for more tutorials, and feel free to leave questions and feedback on StackOverflow and our subreddit. 

Thanks for watching! Enjoy creating with Incisor.












----------------------------------------------------------
Section 20: Showcase - ForkYourFood
----------------------------------------------------------


Fork Your Food 

Hi everyone, and welcome to this showcase of making a new game using Incisor. My name’s Veronica, and I had the opportinuty to intern at Incisor this summer. While I was there, I was given an exciting challenge: to create an entirely new game using the Incisor platform. As someone studying art and visual effects, with no prior development experience, I saw this as the perfect chance to dive in, learn something new, and document the journey along the way. 

I’ll be making this “falling objects” game, where the player moves a character back and forth to either catch or avoid objects falling from the top of the screen. 

When I was working on the game concept, I went through a bunch of different thematic ideas, and ended up choosing the one I was most excited about, “Fork Your Food". You play as an angry chef who’s just been laid off, and you have to build gross recipes by catching bad things like saw blades and poison, while avoiding real food like tomatoes and sauce. 

The first step is to start making assets for the game. This is my comfort zone! I use Photoshop as my tool of choice, but feel free to use whatever software you're comfortable with, as long as you can export your images as semi-transparent PNGs. I sketched out the main character and scene to help visualize the concept. These early drawings were rough and just meant to prove the idea. More refined versions will come later. The setting I chose was a kitchen, and our star is the not-so-happy chef.

With some visuals ready, it was time to jump into the fun part: working in Incisor. Incisor’s documentation includes a lot of great tutorials covering various features, so if you're looking for in-depth guidance on setting up a project or using the graphical interface, I highly recommend checking out incisordev.com.

So let’s go ahead and create a new project! The first thing you see when you open up Incisor is called the control center. You can see your files and projects, or create a new one. So just click on “New Project”, choose the project location and give it a name. Now open it up. The first thing I’m going to do is move my panels around to where I want them. I want a timeline panel going across the bottom, and a construct view up top. I’m also leaving tool tips up, which will give me information in Incisor about things I hover my cursor over. The object panel will let me manipulate idems, and the heirarchy window will help me order and parent things. 

Now I’m going to go to where the project lives on my computer, and open the Assets folder. I’ll make a new folder for the chef assets, and an ncData file will pop up— that’s normal, don’t worry about it right now. I’ll also make a folder for the kitchen scene assets. Since we’re going to import all the images at once, we should name them with ascending numbers at the end. This will tell Incisor what order to import them. Now that that’s done, let’s go back to Incisor. We’re going to use the assets we just added to create a new construct. Constructs are a major Incisor feature. They're collections of different types of SceneObjects that can be built, arranged, and animated directly within Incisor. I created one construct for the kitchen and another for the chef. Here’s how I approached it.  In the construct panel, click “Select”, “New Construct” and name it. You can always change this name later if you need to. Now right click somewhere in the panel and choose “new graphic stack.” Find the folder with your assets and add it in. Now all your numbered graphics will be imported, and we can hold the space bar and scroll to zoom in and out. Immediately we can see that something is in the wrong order. Just select the item you want to move, and in the Object panel we had open before, find the sublayer value and change it closer to -1 to push the item back. Now that they’re in the right order, I’ll rename the items and clean things up a little bit. I’ll also click and drag some things in the heirarchy window to parent different items. I went through a similar process to get all the assets for the kitchen in there. Ok, now that I have a scene and a character, it's time to bring the game to life. If the chef is going to catch falling objects, he needs to move! This was my first dive into Incisor’s timelines and animations. Let me show you how I set it up. 
Back in the construct panel, click the Timeline drop-down, which will say NeutralState by default. Then click on “Add Timeline” and give it a name. You’ll see all the objects in your construct appear in the timeline panel. First, I’ll set my animation duration to 5 seconds. To start animating, right click on an object and click “Animate Graphic Object,” then choose the parameter you want to animate. The keyframe button, the curve graph toggle, and the value will appear. I’ll mostly use position and rotate to animate, using x and y for position and z for rotation. Press the keyframe button to add a keyframe, and set the value. Now I’ll click the curve button and then right click on a keyframe. Depending on what you select, you’ll get some handles to change the curves. 

Now I’ll jump forward a bit and show you some completed animations. Here’s my running animation for the chef. Let’s look at the torso. You can see how manipulating keyframes changes the value on the left, and you can use the curve handles to mess with the interpolation between keyframes. Since the neck and head are parented to the Torso, they’ll move along with any changes I make. But I’m also animating some of these things independently to make things feel more organic. 

Now It’s time to start working with something that was a little scary to me at first: code. But don’t worry— I’ll go through everything step by step! The first thing you’ll need is a code editor. I’ll be using Visual Studio code— that’s not a requirement, any code editor will work. But I do recommend using VS code if you’re following along, because it’s free and widely used. I’ll drop a download link in the video description. We’ll also be using some very basic Javascript that should be easy to follow along with. Alright, with our editor ready, let’s open up the project code. All Incisor projects have the same entry point. You can think of it as “the place where the project starts.” Locate the file called ProjectMain.js. Inside, you’ll find a function named “init.” The most important element of the game is controlling the chef, so that will be our first goal. But before I can do anything, I need to get my kitchen construct into the scene. You can see everything in our construct view, but our live view, where the game is actually running, is completely blank. That’s because we haven’t added anything to the scene yet. We'll have to do that in code. So the first thing I’ll do is set up variables for my two main gameplay elements-- the kitchen and the chef. I’ll set my first variable to the kitchen construct, by using nc.constructDefs. Incisor’s autocomplete will show you all of the constructs available in the project. So we’ll click the one we want, and type  "dot add," adding it to the main scene. The chef is a little different-- his construct is inside of the kitchen construct. So instead of using nc.constructDefs, I’ll type the kitchen variable I just made, and use "dot descendantsByName” with another dot afterward to see everything that’s parented to it. Then I’ll select the chef. Now I can use these variables to get to my kitchen and chef from anywhere else in the code. If I save the code, Incisor will refresh and we can see our elements in the live view!

So I want to make the left and right arrow keys move the chef around. To get this going, we’ll use something called an appEvent. An appEvent listens for something else to happen in the environment, and then executes any function that’s been added to it. So we need to use an appEvent that can always be looking for whether a keyboard key is pressed down. For that, we’ll use fixedUpdate— this is a built-in appEvent that’s updating every frame the game is running, so 60 times per second. Now we add a callback to the appEvent. This is the function that will run every time the appEvent is triggered. We can name this whatever we want-- I’ll just call it “fixedUpdateCallback”. And now we just need to make a callback function with the same name. Inside the callback, I’ll start with changing the chef’s position. If I type my chef variable with a dot next to it, I can see a lot of options come up in the autocomplete menu. Remember all of the stuff we were animating back in the timeline panel? Most of those are parameters we can also access through code. I want the chef moving on the x axis, so I’m going to find position and type "dot x.” Negative values will move him left and positive values will move him right. I’m going to start by using “minus equals.” This will subtract a number every time the function it’s inside of is run. If I save, we can see that the chef immediately moves off the screen. So we need to wrap this in something so it only happens if a certain key is pressed. All we need is an “if” statement that looks at the right condition. Incisor has some built in functionality that registers keyboard presses, called “nc.keyDownStates”. This is a variable that will be true if the key is down and false if it’s not. So if we put our position change inside this statement that checks for “ArrowLeft” to be down, and save, we can see the chef is no longer moving automatically, and only moves when we press the key! Now we can copy all of this, change Arrow Left to arrow right, and change minus equals to plus equals. The only difference here is that I’m going to put an else in front of our second if statement. I’ll get back to that a little later. Tada! We can now control how the chef moves. But even though he’s changing direction, it doesn’t look like he’s turning. So I’m just going to simply flip the chef when he changes direction. All we have to do is set the chef’s x scale to either positive or negative depending on the direction. 

Ok, we’re controlling the chef, but he’s still just gliding across the floor. So now it’s time to hook up some of the animations we made earlier. I’m going to quickly go back to my “init" function. I’ll type my chef variable again, and I can see all the animations available by using “ dot timelines. Now I'll call play on a few animations. This will kick them off in the background, but they won’t be showing up just yet. In order to actually see the animation playing, we need to turn up its influence. So back in my fixed update callback, I’ll get my run animation, and turn its influence to 1 whenever I’m pressing a key. Now we can see the run, but the chef doesn’t stop running when the key is released! To fix this, I’m going to make an else statement. This basically says, if there’s any situation other than what I put in my if statements, then do something else. So in here I’ll set the influence of the Idle to 1. That will have Incisor automatically turn the Run influence back to 0. Now the chef will stop when we stop moving him. It’s working, but the change is still pretty abrupt. What we really want is a smooth transition between the timelines. Instead of just setting the influence of our run timeline, let’s try incrementing it by a small amount. Then when the chef stops, we can bring the Idle back in. 

Something’s still not quite right. It looks like the Idle timeline is being played when we’re not moving, but since we’re constatly adding to it, the influence is going above 1, causing some weird things to happen. And when we run for too long, the influence of the run goes above one, which also gets us some wacky results.
So I’m going to use another if/else statement to make sure the influence of either timeline never goes above 1. If the influence is greater than or equal to 1, I’ll just set it to one. Otherwise I’ll increment it. I’ll also do this for the Run timeline for the key presses. Copy that around real quick and … now we have a smooth transition between the different timelines! But it looks like he’s still runnning for a little too long when we actually release the arrow key. So I’m just going to increase how much we increment the Idle timeline and speed up that transition. I think .05 looks good. Ok, that got a little technical but it wasn’t too bad! We’re controlling the chef and it could use a little polish, but it’s looking pretty good. However we still don’t quite have a game yet. So let’s get some objects in there for him to catch. 

I ended up creating around 12 different falling objects. Some are food-related and some, not so much. In addition, I created shadow versions of each object. These will appear as silhouettes when objects pass behind the kitchen cabinets, which helps create a nice sense of depth in the scene. I’ve also added some updates to the chef construct and added an impact animation that will play when objects make contact. With our new assets and timelines created, let’s head back to the code. Let’s start with making the items fall from the shelves. Since our falling objects will look different from each other but share a lot of the same properties, our goal is to make a chunk of code that can be any of the falling objects, instead of having to keep track of 12 seperate ones all the time. So things are gonna get slightly more abstract for a second, but stick with me. 

We're going to go back to the projectCode folder of our project in VSCode and create a new file. I’m going to call it FallingObject.js. At the top of this new file, we’re going to declare our FallingObject as a class that extends the GraphicObject class that’s built into Incisor already. This basically means that our FallingObject will automatically have everything that a default GraphicObject in Incisor has. Now there’s a couple things we need to set up in order to get our new class doing stuff. First we’ll make a function called constructor, and we need to give it a few variables to look at so it knows what it’s doing. This is sort of like the “init” function in our main project, but specific to our FallingObject. It will come in handy when we start using our class a bit later. Then inside of our constructor we need to call the “super” function which basically does the same thing for the outer class-- in this case GraphicObject. Ok, now that that's out of the way let’s start doing some more custom stuff. I want to start by setting up a few things that I know every object will share-- a main graphic, shadow, and impact animation. Since our FallingObject is a type of GraphicObject, we’ve got the main graphic covered already through the “graphicAsset” in our constructor. I’ll show you how to mess with that in a little bit. But before we do, I want to at least set up the shadow and the impact animation. For the shadow, I’m going to make a new variable and set it equal to “nc.addGraphicObject” with an open parentheses. Whenever you open a function you’ll see a popup that shows if the function needs to be given any variables. So it wants a graphic asset, which will just be generic for now, a parent, which is this object, and a name. This name is what shows up if we want to look at this object in the inspector, so call it something that makes sense. I’ll just name it “shadow.” I also want to push the shadow sublayer way back so that it’s always behind this main graphic. I’ll set up the impact construct the same way I set up the chef and the kitchen. Now, to get some falling objects into our game, let’s head back to ProjectMain. 

Ok, back in our Init function, the first thing we need to do is create some falling objects using our custom class. What I want to end up with is a pool of a bunch of objects that I can pull from as needed. So first I’m going to make an empty array by making a new variable and setting it equal to some empty square brackets. Then I’ll using something called a “for loop” to put a bunch of objects into the array. This is a snippet of code that will do whatever is inside of it a given number of times. I have 12 total objects I want to use, but let’s just start with one for now— we can always add more later. Now inside our loop I’ll make a local variable using “let” and set it equal to a new FallingObject with open parentheses. Again, I'll see a popup that shows me the variables I need to give it. Remember all the parameters we put into the constructor of our class? This will be where those things come from. So, I’ll keep the main graphic generic for now, parent all of these to the kitchen construct, and name them all “fallingObject." Then on a new line, I’ll get the empty array we made earlier and use a function called “dot push” with my local variable in the parentheses. This will put the falling object I just added into the empty array. Since we parented our fallingObject to the kitchen, it should be in the scene now. Going back to the inspector, we see a new white box in the middle of the scene. When we inspect it we see it’s named “fallingObject." Now we just have to tell it what to look like, and what to do. 

So back in our FallingObject codeAsset, let’s make a function that does just that. We’ll start off by positioning it and moving it down. I’ll make a function here called “setFallingObject”. And I need to start it off at a certain height. I’ll use the inspector to drag my box to where I want the starting point to be, and check the y position in the Object panel. 930 looks pretty good! So back in my function, I’ll set the y position equal to that, save, and update. Looks like it’s still in the center. That’s because we haven’t called this function yet. So back in projectMain, let’s make a function called “dropObject.” Inside this function we need to get our fallingObject from our array and call setFallingObject on it. To do that, we need its index in the array. So in my init function I’ll make a variable called this.fallingObjectIndex and set it to 0. Then in drop objects I’ll get my array and in closed brackets put in the variable for the index. This tells the code to look at whatever is at that index of the array. I can call my function on this and save again. Now we see the box is where we want it to start. So let’s make it fall.

To move it, we’ll use an Incisor function called a swooper. A swooper is a function that tweens between two values. In my FallingObject code, I’ll make a new function called “fall” where I’ll put my swooper. I want to swoop the y position down. So first I’m going to see where I want the box to end up, which I’ll do the same way I found the starting height. -1030 looks good. Now in my code I’ll type “this.position.swoop.y", and provide my destination value, and how long I want the swoop to last in seconds. Then I’ll call this function inside of setFallingObject, save, and update. Yay, our little square is falling down. Now let’s make it look like something. 

I can set what graphic I want my box to be according to the name of any graphic in my project assets. I want to use all the falling object graphics that I made, so I’m going to make an array of names. This will eventually have all the names in it, but let’s just stick with one for now. I’ll start with “Bottle Poison.” I want to pass an index of this array into my setFallingObject function, and then use the name to tell the box what to look like. So down in dropObject I’ll get the name in the same way I got the object itself, just using the array of names instead, and put that in these parentheses. Now let’s go back to setFallingObject. In these parentheses I’ll put in a variable that represents what I passed into the function. I’ll just call it “name." Now all I have to do is type this.graphicAsset and set it equal to nc.graphicAssets with my name variable in brackets. Now when I save and update, my box has transformed into a bottle of poison! But that’s a really big bottle. I could go into my assets and scale everything down manually, but it’s really easy to do with a simple Incisor function. I’ll go back to my constructor and just write “this.scaleByFactor" and put a multiplier in these parentheses. I think it needs to be a little more than half the size so I’ll put in .4. That’s looking a lot better. Ok, now let’s get all of our objects in there. Back in projectMain, I’ll go to the loop where I made the FallingObject, and change 1 to 12. Which will add 12 blank FallingObjects to my array. Then I’ll add the rest of my names to the names array, in quotes separated by commas. Now back in my "dropObjects" function, I need to increment the array so it actually changes the name getting passed to setFallingObject. Remember plus equals? I’ll use that to increment the fallingObjectIndex by 1 every time the function is called. I’ll save and … we still only have one bottle. Well that’s because we’re only calling this function once at the beginning of the game. We want to be calling it over and over again. To do that I’ll use an Incisor function called a waitThen, which waits a certain amount of time and then executes a callback function. I’ll type nc.waitThen, give it the wait time in seconds, the function owner, and the name of the function I want to call. So now our wait then will call dropObject once every second. Let’s save and see what that looks like. Alright, multiple different objects are falling now! But after a while the game stops. Eventually our fallingObjects index number gets bigger than the amount of elements in the array, which causes an error. So we need to cap this index at the max number of objects. We’ll do that the exact same way we capped the influence of our animations earlier. 

So until our whitebox becomes something, it’s just sitting on the screen. We probably want to do some enabling and disabling. In the constructor of my FallingObject, I’ll set it to disabled. Then in setFallingObject, I’ll enable it and save. Much better! But we don’t want them just piling up on the floor, so let’s do something with them when they reach the ground. Swoopers can be given a callback function that will be executed whenever the swoop is complete. So I’m going to go to my swooper and set the tweentype to undefined— don’t worry about that for now— then give the function owner and name. Let’s call it splat. Now I’ll make a new function called splat, and put what we want to happen in here. We want the object to go away, so let’s disable it. But having them just disappear is a little rough looking. Thankfully, we already have an animation we can use to spruce it up. Earlier, we added our impact construct to FallingObject. It has a timeline called “splat." So now I’ll enable it, set the splat timeline influence to 1, and use a function called playOnce. This will play the designated function only one time. Save and … nothing happens. Since we're immediately disabling the entire object and the splat is parented to it, that gets disabled too. So instead of calling disable, we’ll set the visibility equal to false. This parameter doesn’t affect children, so our object will disappear, but the splat will still be seen. Now it’s looking like how we wanted. For good housekeeping, we should disable everything once the whole sequence is over. We can do this in the playOnce function, which takes a callback once it’s complete, just like a swooper. And we also need to make sure we set the visibility back to true or else we’ll end up with permanently invisible objects. 

Now we’re getting somewhere. But this game won’t be any fun if all the objects fall from the same place in the same order. Let’s start by randomizing thier starting position a bit. I’m going to pause the live view and grab one of our objects. I want to drag it around to see what the boundaries of its x position should be. Looks like somewhere around -350 for left boundary and 920 for the right boundary. So we should try to randomize the x position within that range. To make things simple, I figured out some more or less evenly spaced positions for the objects to fall from, and made an array of them in the constructor. Now I just want to get a random index of that array to use each time an object is brought in. I got a little bit of help figuring out the math— these math functions are some javascript stuff that I won’t get into, but it basically gives me a random whole number between 0 and the max number of items in the array. In this case, that’s 8. So I’m going to set a local variable called “index" equal to that, and set the x position of my object to the value of that index in my array. We can use pretty much this exact same method to randomize the index of the objects that fall. I’ll just copy this line, and back in my projectMain, paste it into the drop objects function. I need to be looking at my names array here, and then replace my old index with my new variable. Alright, now we have random objects falling from random places, and it’s really starting to look like an actual game now. But there’s one more big step to take, and that’s having the chef actually be able to catch the objects. 

So there’s a few things we need to know in order for this to work. We need to know the position of the chef’s hand at any given time, the position of the object, and whether or not they intersect. In the chef construct, his hand is seperate, so I'm going to access that using "descendants by name." But instead of doing “dot position” like we have been, we need to something a little different. The normal position paramater is relative to how an object parented, not the overall screen space it’s a part of. So we need to use the “GetGlobalPosition” function instead. This will tell us the object's absolute position wherever it’s moved to, regardless of its parenting. Since the chef could potentially catch any object at any time, we need to always be looking at all of the objects. Thankfully we already have a function that’s constantly updating. In the same way we are “listening” to what key is being pressed, we can have it constantly looking at where any object is. We just need to give it the right things to look at. We'll use another "for loop" which will run constantly. We’ll loop through the array of falling objects. Then we can use the “i” in this loop to get a specific one in the array. So to reference our objects in here, we’ll use “this.fallingObjects" with “i" in square brackets. The first thing we'll do is write an “i"f statement to only do something if the given object is enabled. Then we’ll get the global position of the object. Now we can decide where we want them to collide. Let’s just say if the hand and the falling object’s y position and x position are both equal, disable the falling object.” 

Hmm, that’s not working. Since we’re only looking at a single coordinate, we have to be way too accurate in order for that collision to happen. What we need to do instead is look at a range of coordinates. Rather than doing exactly equals, I’ll look at whether the falling object is with in a 100 unit range in either direction. Alright, now the objects disappear if they hit the platter, and if they don’t they drop to the floor like normal. Might as well hook up our splat here too! We just need to add it to the “init" function and play it like before, except this time just be a little more specific with the positioning. 

So the last part of this step is to show the items piling up on the platter. I’ve already made side versions of each item and put them in the chef construct. They’re  parented to the right hand and disabled by default. I’ve also numbered them 1 - 30, which will help us know which one to turn on. At the same place where we disable the falling object, we can enable the side object. We just need to keep track of how many we’ve caught so the right one gets turned on. So in my init function I’m going to make a "number of items caught” variable and set it to 0. Then when I catch something, I’ll increment that number. 

Now we can see them appearing, but they’re just the default ones I put in the construct. We need to make sure they correspond to the actual item that’s being caught. I need a way to get the name of the graphic being used on the caught item, so I’ll go back to "fallingObject" and in my “setFallingObject” function I'll define a new variable and set it equal to the name. Now back where we were in project main, I can reference that. All of my side view graphics have the same name as the falling objects, but with "underscore side” at the end. So I’ll make a local variable here called “sideName” and set it equal to the variable I just referenced from falling object and write “plus underscore side” in quotes. Now right below that I’ll copy the side item object we enabled, and set its graphic equal to nc.graphicAssets with my sideName variable in brackets. Now the side graphic appears according to the item we caught, but the item still has to pass through the whole stack in order to be collected. We want it to collect when it hits the top of the stack. To fix this, all we have to do is get the position of the top item of the stack, instead of the hand which is always at the bottom. Let’s just change our hand position variable to reference that instead. 

Ok, we’ve got a chef you can move, and catchable items that randomly fall. We can really see our vision for this game coming together. To bring it home, I want to add a basic level system and a goal for each level, and then we’ll start polishing some of the movement, and add in some music and sound effects. We’ll get into all that in the next part. 

I ran some ideas by the Incisor team, and we decided that each level should be a recipe order that the chef is trying to get ingredints for. If you catch all the right items on the receipt, then you move on to the next level. So I made a reciept that can live on the left side of the kitchen, and an “OrderLine” construct, that contains elements like the item number, which ingredient, and whether it’s been collected or not. Since all the order lines are duplicates of each other, the first thing I have to do is use code to change their numbers so they don’t all just say 1. I’ll just loop through the number of OrderLines on my reciept and set the string of each text box equal to that number in the loop. Ok, next I want to populate my list with some random bad food objects. I’m going to make a new array with just the names of the bad objects in it. Now back in my loop I’m going to get a random number using the same math we’ve used before, but give it my bad objects array. Now I’ll just set the graphic asset equal to the index of that random number. With that all set up, we need to create a system that keeps track of whether I’ve caught the right object. So I’ll make an empty array to hold my current list of ingredients, then push all the badObject names into it. I’m also gonna add one more variable called "current order line." This will come in handy in a second. 

Back where we set up the code for catching an object, we can also check if we’ve caught the right one. I just need an “if" statement that looks at whether the name of the object we caught matches the name of the object we’re aiming for. I’ll use my current order line variable as the index of the ingredients array I made before. To show the player that they got it right, I’ll enable this “Check" graphic that’s a part of the orderline construct. I also need to increment the current order line so next time we’re looking at the right object. Now I’ll make an else, and play an “Xflash” timeline that’s also a part of the order line construct. Lastly, I have a box around the current item needed that moves down as you complete the order.  

After getting some feedback, it seemed like I needed to make things a little more obvious. So I added a new construct with a timeline that would bring up a “good job” or “wrong” message. The timeline is called “toss” and I just enable the right message according to the situation. 

I also decided to implement a scoring system, where you get points for catching the correct item, and lose points if you don’t. I used a loop to add scores that increase by 100 points to each line item. Now I just need a variable for the current score, and an array of scores. When I catch the right item, I’ll just add the index of whatever line I’m on to my score tally, and set the string of my score equal to that. If I catch wrong, I’ll subtract half that amount of points from my score. 

My next step was to enable a success or failure screen for the end of each level, and I went ahead and made a construct for each of them, making sure to add the restart and continue graphics as buttons. I’ll get into that in a little bit. I decided that if you catch 20 items and you still haven’t completed the order, then you fail the level and you have to try again. I’m already tracking the number of items caught, so I’ll just use an "if" statement to check that number— this will be for if you fail. Otherwise, you made it to the last line item and that’ll be what I check if you succeed. Now I’ll make a function called “roundComplete" that I’ll give “false" if you fail and "true" if you succeed. Inside this function, I’ll reset elements of the game. I’ll start with stuff I know needs to happen no matter what. I’ll remove the fixedUpdate callback we made a while ago so you can’t control the chef until you proceed. I’ll also use a function called “stopAllWaitThensByCallback" to stop new items from falling. I’m going to reset a bunch of indexes back to 0, and reset the position of the highlight box. I’ll loop through all of the items on the chef’s platter and disable them, and do the same for all the check marks on the recipe list and any objects that might have still been falling. I’ll set the chef’s animation back to idle as well. If this function received “true," I’m going to enable the success screen I made, and get a new list of ingredients for the next round. I’ll do that in the exact same way as when you first start the game. If we get “false," I’m going to enable the fail screen, but keep everything else the same so you can try the level again. 

Back in our init function where the constructs were added, I’m going to take advantage of the buttons I mentioned earlier. I’ll use an “addReleaseCallback" function on the buttons inside my fail and success constructs. This will execute a function when the left mouse button is clicked and released on this graphic. I’ll call my function “start.” In my start function I’m going to re-add my fixedUpdateCallback so we can control the chef, and use a waitThen to kick off the dropObject function to get objects falling again. Now we’ll be set up for the next round.

This is all looking good, but I think the whole game needs a start screen so the player isn’t launched right into everything right away. I made a title screen construct with a play button, and added it to my init function. Now I’m also going to make sure the kitchen is disabled upon loading, so we have a clean background behind our title screen. I’ll add the “start" function to the play button, and enable the kitchen in there. I’ll also disable all the screens you’re not supposed to see while playing the game. 

Okay! I think we’ve finally gotten everything we need into this game. Now there’s a few things I want to do to really polish it up. We have a system set up for changing levels, but right now levels don’t really mean anything— I want the game to get harder the more levels you play. So I’m going to add a level and difficulty variables to my “init" function. In "roundcomplete", I’ll increment the level when we’re successful, and set the level number on the receipt to the level we’re on. I think the best way to make the game harder would be to have the objects start falling faster. I’m going to try out having them get 10 percent faster each level, so I’ll decrement this by .1. Now back in my FallingObject class, I’m going to multiply the duration of my swoop by my difficulty variable, which I can get to with the prefix “pr.” Now every new level we reach, the time it takes for the items to reach the bottom will increase by 10 percent. 

I’m also gonna do a couple visual things. I want to make the chef’s movement a little less jerky so that it matches what what we did with the animations better. So I’ll put a speed variable on the chef and multiply his position by it. While he’s running, I’ll increment the speed by .01 and limit it to 1. Now we can see that the chef ramps up into his run. We just need to make sure to set this back to 0 when we’re not pressing a key. I also want to give the falling objects a little more motion, so let’s make them spin as they’re falling. I’ll just go back to FallingObject and swoop the z rotation of the object over the same amount of time it takes to them to fall. I’ll need to set the rotation back to zero in setFallingObject as well. I think this is a good time to hook up the shadow graphics I made back in Part II. My goal is to make the falling objects look like they’re passing behind the cabinets, and show the shadow versions when that’s happening. I can set this up using Incisor’s masking system. Inside my kitchen construct, I added some rectangles that cover the cabinet areas. Using the object panel, I’ll go to the “GraphicObject” section, and open the “masking” menu. Check the “enabled” box, and set the type to “mask.” Under mask groups, make sure “MainMaskGroup” is checked. Then I’ll save the project within the Inspector. Now I can use these graphics to mask the objects and reveal the shadows as they fall behind the cabinets. Back in my FallingObject code, I need to make any falling object obey this mask. I'll type “this.masking.MakeMasked” with open parentheses. I need to give it the mask group I checked earlier, and say whether I want Incisor to invert the masking. I’m going to say true, so that when the object crosses the mask, it disappears. Then I need to do this same thing for my shadow, except set the inverting to false, so it only shows up when it’s inside the mask. Ok, it looks like the masking is working, but my shadows are still just white boxes. So in my “setFallingObject” function, I just need to set thier graphic asset with “underscore Shadow” at the end of the name. I’ll save the code and make sure that it’s all working as intended. 

Ok, we’ve got some more polish on the movement, and life to the objects, but this isn’t a silent film! The last thing we need to do is get some sounds in here. I worked with a composer to come up with some music and sounds that fit the theme of the game. Implementing sounds is a lot like playing timelines— we’ll mostly be using play and playOnce functions. We also have a swooper specific to sounds called swoopVolume. After adding all the sounds to the assets of my game files, I’m going to set the volume of the title music and play it— that’ll be the first thing we hear. Now in my “start" function I’ll play this bell sound for when the play button is pressed, stop the TitleMusic, and play the BaseGame music. I’ve got some footstep sounds for the Chef, so inside the chef controls I’ll play those when we’re running, and swoop them down when we stop. For catching the objects we want, I’ll play the bell sound, and for the wrong object I’ll play this buzzer sound. I want to have specific sounds for objects falling to the floor, so I set up a “play sound" function with a bunch of if statements. This gets called in my “splat” function. I’m getting a random number that’s either 0 or 1, and using that to call one of two sounds for each type of object. 

With all that done, we now have a complete game! Thanks for going on this journey with me— I learned a lot about using Incisor and game development during this process. Make sure to check out incisordev.com, where you’ll be able to play and download the code for this game! There’s also a bunch of tutorials there, that go even deeper into some of the things we talked about in this video. I had a great time making Fork Your Food, and I hope you enjoyed following along with the showcase too. See you later! 












----------------------------------------------------------
Section 21: PivotPoints
----------------------------------------------------------


Pivot Points

When animating objects, we may want to adjust the pivot point of a GraphicObject.

Incisor makes this easy.

Here I have two images: A dinosaur and a leg stacked on top.

When I select the leg, notice the pivot point is centered by default.

We can reposition the pivot point in two ways.

By adjusting it in the Assets panel, it will be updated for all instances of this GraphicAsset.

This is the most performance efficient way.

However, we can also change the pivot for a single instance to reposition the pivot.

Click the pivot icon and hold option on a mac or Alt on Windows and drag.

This automatically configures a "PivotPointAdjuster" object on the given GraphicObject, which changes the pivot point for this instance of the GraphicObject.

PivotPointAdjusters can also be activated from within code by calling GraphicObject.configurePivotPointAdjuster.













----------------------------------------------------------
Section 22: Sounds
----------------------------------------------------------


Sounds - Javascript - Hello, and welcome to this tutorial for the sounds API in Incisor. - Implementing sounds in Incisor is intuitive and flexible. - This tutorial will cover: - Adding a sound asset to your project - Using playback functions to control individual sounds - Defining a volume control - Creating dynamic volume char nges - And syncing multiple sounds together. - Let’s open the directory of the project we want to add sounds to. - To add sounds to our project, simply drag and drop files into the project’s assets folder. - Sounds must be encoded in the .wav filetype. - For the purposes of this tutorial, I’ve set up a few buttons that will control our sounds. Check out our tutorial on buttons for more information. - To access a sound, type nc.sounds and select the intended asset from the list of auto-complete suggestions. - Now we’ll take a look at basic playback functions. - .play() will play the sound and loop it continuously. I’ve assigned this to our control 1 button. - Now I’ll assign pause() to our control 2 button. Calling .pause() immediately pauses the sound, and allows us to resume playing the sound from the point at which it was paused. Now I’ll change pause to stop. .stop() immediately stops the sound and starts it from its beginning when played again. - Now I’ll change play to playOnce. The sound will play one time through and then stop. PlayOnce also accepts a callback function as an argument, which will be triggered once the sound reaches its end. Here I’ve set it to call a function that changes the color of the button. - The mainVolume parameter sets the volume of an individual sound, with 0 being silent and 1 being the original volume of the sound. - Any sound can be assigned to a volume control. This allows us to change the volume of multiple sounds at once. - To create a volume control, call nc.defineVolumeControl, using a string as the name. This will return the new volume control. It can now be found using nc.volumeControls. To make this volume control modify the sound's volume, push it on to to the sound's soundControl array. - One useful way to manipulate sounds is by using Incisor’s “swoopValue” function on a volume parameter. This way we can create dynamic fades and volume changes with specific timing. I’ll assign the volume control we just made to another sound. Now I’ll use swoopValue on the volume parameter of the volume control, setting the volume control as the object, volume as the parameter, 0 as the end value, and 2 as the duration. Now when I click on control 2, the sounds will fade to 0 over 2 seconds. - we can also set the playback rate of a sound. This will change the speed and the pitch of the sound. The default playback rate is 1. - HTML5 can introduce small delays between the instructions to play sounds, and when the sounds actually play. This can cause looped sounds of different lengths to get out of sync over time. - The “defineSyncedLoopingTrackGroup” function can be used to sync multiple sounds together and eliminate these delays. This is useful for mixing dynamically between different layers of a soundscape that are meant to loop constantly over long periods of time. - To sync our sounds, we simply call nc.defineSyncedLoopingTrackGroup(), name the group using a string, and list the sounds we want to sync in an array. - I’ll put a playback rate change on control 2. When played simultaneously, the sounds will synced with each other, even if the playback rate or other parameters are changed. - This concludes the tutorial for the sounds API in Incisor. - Don’t forget to check www.incisordevdocumentation.com for more tutorial videos, and feel free to leave questions and feedback on StackOverflow and our SubReddit. - Have fun creating with Incisor!











----------------------------------------------------------
Section 23: CreatingConstructs
----------------------------------------------------------



Hello and welcome to this tutorial on creating and using Incisor Constructs. 

In this tutorial we will cover the following topics:

What a Construct is, how to create a Construct, and how to use a Construct in your project. 

Before diving in, make sure you've watched either the Getting Started with JavaScript or Getting Started with TypeScript tutorials.

All the code examples in this session will be written in JavaScript

At its core, an Incisor Construct is simply a collection of objects that you can instantiate and manipulate in your project.

Think of it as a reusable component made up of various elements. 

Constructs can be created either through the GUI or directly in code. 

In this tutorial, we will walk through creating a Construct using the GUI. 

First, make sure you've set up your project and imported the necessary assets.

Next, we'll begin by adding a Construct panel to the GUI.

This panel will allow us to view and edit our Construct. 

We will also be working with the Hierarchy and Object panels to organize everything.

To create a new Construct, click the select dropdown in the Construct panel and choose New Construct. 

For this example, let's name our new Construct "Card." 

Now you'll see the card Construct is selected across all three panels. The Construct panel, Hierarchy panel and Object panel.

To start building the card, we will need to add objects to it. 

There are two ways to do this. 

Click the plus icon in the upper left corner of the hierarchy panel, or right click on the object you want to add to. 

Let's go with the second option. 

Right click on the card in the Hierarchy panel and select Add Graphic Object.

Next, let's rename the object to "Background" and assign the background graphic asset. 

Now, we'll add another graphic object to represent the suit of our card. 

Right click again, choose Add Graphic Object, rename this one to "Suit", and assign the heart's graphic asset. 

Finally, we need a text box to display the card's rank. 

Right click once more, choose Add Text box.

We'll rename it to "Rank." Position it properly. 

Change its color to match the suit, and set the text to A for ace. 

Once you're happy with the layout, go ahead and click save in the project menu.

Now you'll have a card Construct file saved in your asset folder.

This file can easily be moved or added to other projects.

Just remember, if you're importing this Construct into another project, all the assets used in it must also exist in the new project, like graphics and fonts. 

To use the card Construct in your code, call nc.constructDefs.Card.add

Don't forget to specify the parent object and the name for your new instance. 

Save the code and you'll see your new card appear in the live view.

Let's take things a step further and deal an entire hand of cards. 

This is how we'll do it. 

First, create three arrays, one for the cards, one for the suits, and one for the ranks.

Use a loop to instantiate and position the cards on screen. 

Next, randomly assign a rank and suit to each card. 

Change the color of the card based on the suit.

Red for hearts and diamonds. Black for clubs and spades. 

Once you've written the code, save the project and watch as your cards are dealt. 

You might even get a winning hand.

And that's it for this introduction to Incisor Constructs. 

You've learned how to create and use Constructs in your project, and even how to deal a hand of cards programmatically. 

Remember, Constructs are a powerful way to organize and reuse objects in your project, making development faster and more efficient. 

Check the link in the description for more tutorials, and feel free to leave questions and feedback on StackOverflow and our subreddit.

Have fun creating with Incisor 











----------------------------------------------------------
Section 24: LiveView
----------------------------------------------------------



In this tutorial we'll be discussing the Live View panel. The Live View panel displays the current live view of your project while it is running, and has several controls at the top. First, we have maximize, which will maximize the Live View panel to fill the browser window. Clicking this button again will revert the Live View panel back to its previous size and restore your previous panel configuration.

00:00:28:04 - 00:00:45:29
Unknown
Refresh will reload your project and update the live view. The pause button will pause the live view, and a skip forward button will populate next to the play button. Clicking the Skip forward button will advance the live view by one frame at a time. Clicking the play button will unpause the Live View. And lastly, we have the inspect button.

00:00:46:01 - 00:01:10:15
Unknown
Clicking it will allow you to select objects in the live view. In this mode, you can also select and edit objects in the object panel and hierarchy panel if the desired object is obscured by another object. You can use the scroll wheel on your mouse to highlight the objects underneath, and left click to select that object. It should be noted that live View is a runtime view of your project, and any changes made to selections will not take effect even if you save the project.

00:01:10:17 - 00:01:33:06
Unknown
Also, while in selection mode, any buttons in your project will not be interactive. If an object is selected in your live view, you can press the escape key to clear the selection. To exit selection mode, click the pointer icon. This will re-enable any interactivity built into your project. Next we have view controls. This button allows you to select a fill mode and or pixel ratio, or a pixel dimension of the Live View.

00:01:33:09 - 00:01:51:16
Unknown
Maximize will maximize the view and match the dimensions of the browser window that Incisor is currently running in pixel ratio with underscore. Maximize or constrain the view to the ratio while trying to maximize it in the Live View panel. Choosing a hard dimension will force the view to be those dimensions, regardless of the live view panel size.

00:01:51:18 - 00:02:11:07
Unknown
In this case, you may have to resize or maximize the panel in order to see the entire project in the Live View panel. To add a custom view to the list, click project in the menu bar and select Project Settings. In the project settings, you will see additional Live View modes under the Development Settings section. Add your custom view to this comma separated list.

00:02:11:10 - 00:02:28:23
Unknown
Save and refresh and you'll see the new option in the list of dimensions. If you do not include underscore maximized to a pixel ratio Incisor will consider the entry to be a pixel dimension. That's all for this video, but if you'd like to learn more about Incisor, go to our YouTube channel or visit the tutorials page on incisordev.com.

00:02:28:25 - 00:02:35:01
Unknown
Also, feel free to ask questions about Incisor via Stack Overflow or on the Incisor subreddit. Have fun creating with Incisor.












----------------------------------------------------------
Section 25: Getting Started with TypeScript
----------------------------------------------------------


Incisor is a software development platform that is finely tuned for creating extremely light apps and games that will run on any browser.

In this tutorial, we will be going over some basics for getting started with Incisor using the Typescript coding language. 

If you'd like to use JavaScript, follow the link in the description to the Getting Started with JavaScript video tutorial.

Before you get started, you'll need to choose a code editor. In this tutorial, we'll be using Visual Studio Code, which is a great free editor and can be downloaded from the VS code download page.

Next, we'll need to download the latest version of Incisor, which can be found in the Incisor download page. 

Once downloaded, open the zip file and click the app to open Incisor.

Next, you'll need to enter some information and an email address to create an Incisor account. 

You'll need to confirm your email account before you can get started. Now you'll be prompted to open a project, but we will choose to make a new project instead.  

Since we are developing the TypeScript, be sure to check the use TypeScript checkbox.

When opening a brand new project. It will take a few seconds for Incisor to process the included sample assets.

Once loaded, you'll see the sample project up and running in the live view in the Incisor GUI. Now let's have a look at the new project directory that was created. You can see a few items in the directory, including a TypeScript project code folder, which is where the TypeScript code for the project lives, a project code folder, which is where the generated JavaScript code is distributed to, and an assets folder, which is where the assets for the project can be placed.

Let's open this project in our code editor.

Within our code editor, we want to navigate to the TypeScript project code directory and open the project main.ts file. That's where we can see the basic sample code running in our new project. As you can see, the existing code is very simple. It adds a text assembly object which uses the sample font included in the assets directory.

Let's make a change to the text that appears in the main screen. Working in TypeScript is just like working in JavaScript. When you save your TypeScript code, Incisor compiles it into JavaScript for you and Live View updates automatically. Incisor includes its own TypeScript compiler, so there is nothing to install and no build step to run.

If you'd like to see TypeScript errors in your code editor, Incisor adds a task to your project when you open it. In Visual Studio Code, allow the automatic task when you are prompted, or run it from the Terminal menu with Run Task. Your errors will then appear in the Problems panel. Incisor also shows the errors in its own console.

Now let's add a few exclamation points. Save the file and watch Live View update automatically.

Now let's make the text bounce up and down. As you can see, autocomplete options are built into Incisor. Dotting your way around the API is one of the easiest ways to familiarize yourself with Incisor's broad functionality.

I'll add some motion along the y axis. Save again. You can also access documentation for the entire API and the Incisor menu in the corner.

Now let's add an asset of our own. To include a new image in our project, all we need to do is drag the PNG file into the assets folder. Now we can use that new asset in our project. For example, we can add a graphic object to our scene using this new asset.

Notice our graphic is now accessible from within VS code when we start typing.

To view the final product, we'll need to publish it, which can be done through the project menu. New projects come included with the dev mode configuration for publishing, but more configurations can be added in the project settings. 

Let's publish. Click the new URL in the pop up window and we can now see the final published product in action.

Looking back in our project directory, we can see that Incisor has added a publishing folder and put the newly published and timestamped website under its own directory. 

This concludes the Getting Started with Incisor TypeScript tutorial.

Check the link in the description for more tutorials, and feel free to leave questions and feedback on StackOverflow and our subreddit.

Enjoy creating with Incisor.

    











----------------------------------------------------------
Section 26: Extensions
----------------------------------------------------------


INCISOR EXTENSIONS TUTORIAL

In this tutorial we'll cover What Incisor Extensions are, How to Build Extensions, and Basic examples of Extensions use cases.Along with it's rich library for creating  interactive user experiences, Incisor also offers a powerful set of tools for streamlining and optimizing the production process. (incisor intro screen)

Incisor Extensions let you write scripts for the Incisor Inspector and environment, making it easy to integrate custom workflow tools directly into Incisor. Since the Inspector is built using the same core Incisor API, creating custom tools, works seamlessly with the same reliable API you use for standard projects.(video 1)

To get started with Extensions, click on the Template Library Tab and select Project Extensions from the dropdown menu. From here you can see our list of available Extension Examples. They are designed to walk you through various implementations of Incisor Extensions including, CustomMenus, CustomPanels, FileIO, PopUps, ProgressBars, Project Connection Actions, Publishing Actions and Various UiComponents. It's recommended to check these out after the video.(video 2)

Two easy methods of adding custom workflow tools to your project is by adding custom Menus and adding custom Panels. Menus are our purely functional option with all visuals being preset for you by Incisor. The other option is Panels, which can be customized both functionally and visually including the ability to add buttons, search bars, dropdowns, collapsible menus and much more.(video 3)

You can quickly get started with your custom menu by going to the project Extensions in the template library and choosing add custom menu. This will immediately set you up with a working menu with a popup alert. You would then just add your functionality to this.You can also add a custom panel quickly with the template add custom panel. You can then add whatever additional functionality and visuals you may want to this panel.It’s important to note that while Incisor extensions are compatible with both TypeScript and JavaScript projects, extensions are exclusively written with/in/using JavaScript. (video 4)

To take a more in depth look at Incisor extensions, in this tutorial we will be building extensions from scratch. Given this, we're going to select the ‘Add Blank Template’ option. Incisor will then prompt you to name your new Extension in the Popup's TextField. After selecting OK you will notice a new js file appear under ProjectExtensions in your project's Utilities directory.
Opening this file you can see Incisor has already laid out for you, our standard 2 part systems to Extensions. There's the Main Definition section where you will put your class definitions at the top of the file, and at the bottom of the file will be your Run Before Init section. This section is marked by the CODE tags runBeforeInit_begin and runBeforeInit_end. This is where you will put your runtime commands.(video 5)

We'll Start with Menus. Creating a new Menu with Incisor requires a new class to hold our Menu Item's functionality. In this example I want my new Menu Item to take screenshots of my project so I'm going to name it SaveScreenshots. Then moving to our runBeforeInit section, we're going to create an instance of our new class and create our two Menu Items one a standard Menu Item, the other a Sub-Menu Item. This is done with the addInspectorMenuItem function. This function takes the parameters, Location, object owning our callback function, and of course the name of our actual callback we want to call when the Menu Item is selected. You'll notice our location parameter is an array. This allows you to put your Menu Item at whatever depth (in the Incisor menu) you choose. Each string is the Menu and proceeding Sub-Menus you want your Menu Item to be in, with the last string being the one actually calling your callback. If the Menu or Sub-Menu you listed doesn't exist Incisor will automatically add them for you.(video 6)

Going back to our class lets actually implement the 2 function callbacks for our Items. The first is going to be our standard Menu Item that will take a screenshot of our Inspector. We'll set our destination for the screenshot and create the corresponding directory if it doesn't already exist. We'll take our screenshot using saveInspectorScreenshot and then use an alert to inform our user that the action has been completed. Next for our Sub-Menu callback we'll do a similar thing, however for capturing our screenshot I'll actually show you two methods we could use. If you've noticed we've been using nce throughout this script instead of the usual nc. This is because, while nc is our primary accessor for Incisor, Incisors Extensions instead uses the accessor nce. Nce stands for incisor extensions and while it does share a lot of the functionality as NC Keep in mind nce runs in its own context within the inspector so it doesn't behave exactly the same as NC. If there is something you need to access from the Incisor project itself you have to use nce.projectNC. You can see us using nce's method for screenshot capture here with nce.saveProjectScreenShot and just below that the same thing is done but with with what would've been nc.saveScreenshot now as nce.projectNC.saveScreenshot.In this example you can also see that we’ve used the async and await keywords. Because Incisor extensions incorporate functionality that interacts with external processes, using the ‘await’ tag can be necessary to help ensure that the given commands have completed before the subsequent javascript actions. If you use an Incisor extensions function that is itself marked as asynchronous, it is generally a good idea to mark the function you are using it in as ‘async’ and to use the ‘await’ keyword when calling it. (video 7)

Now lets check out our new Menu Items! you can see how Incisor treats Menus and Sub-Menus and when we select one you'll see how alerts appear to the user. Thanks to the alert we know our screenshots are in the screenshots directory.(video 8)

Next we'll create our own custom Incisor Inspector Panel. Our first step will be creating a new class that extends the InspectorPanel class. Be sure to include a constructor that calls the superclass constructor, which in this case takes the name of the new custom Panel. InspectorPanel is a class that extends SceneObject and provides the basic elements for an Inspector Panel. Inspector Panels include all the members needed to define Borders, Menu Bar features, and standard Panel functionality.Panels have 2 main customizable sections, the headerScrollingPanel section and bodyScrollingPanel. These contain LayoutStacks that will define where the content for the custom panel is placed.(Video 9)

In our sample you can see we kept our headerScrollingPanel simple with only a UiText being added to its body Stack. Meanwhile there are several built in GUI items placed within the bodyScrollingPanel. Some of the items placed in the body of the example Inspector Panel include UiText, UiCollapsibleStack, UiDropDown menu, UiButtons, including LinkButtons and GraphicButtons and finally Popups including the preset YesNoQueryPopup and the TextQueryPopup. Each item in the bodyScrollingPanel is connected to functionality defined within the Inspector Panel class.(video 10 most likely to need redone cause of the end)

Before going more in depth with our functionality lets add our custom Panel to the Incisor GUI by going back to our runBeforeInit Section and using registerInspectorPanelDefinition. This makes it available for users to select from the Panel type dropdown.(video 11)

Now let’s take a closer look at how our Panel functions, focusing first on the UiCollapsibleStack and how it uses runtime project analysis to dynamically populate its contents.
We’ve added a triggerCallback to the stack so that whenever a user expands it, our function grabObjects is executed. Inside this function, we begin by clearing the stack to ensure a clean slate before adding new scene objects. Next, we retrieve all scene objects from the main scene by calling nce.projectNC.mainScene.getDescendants(). You'll notice we're using the projectNC reference again. By referencing projectNC, we ensure we’re accessing the project’s descendants rather than those of the Inspector. Once we’ve gathered the scene objects, we iterate through them, creating a new UiText element for each object using its name. Each new UiText is then added to the bodyStack of our UiCollapsibleStack. Now that we’re done coding our collapsible stack’s functionality, let's check it out in real time. You’ll see that I can close and open our collapsible stack, and every time I open it I can see the objects in my hierarchy reflected in the bodystack of the collapsible stack. Next, let’s examine the Dropdown Menu, which also interacts directly with the scene. The dropdown's callback makeNewObject allows users to create new SceneObjects based on their selection, and automatically updates the collapsible stack to reflect these changes.User input is captured through the UiMenuItem parameter, and a switch statement handles each menuItem option, enabling specialized functionality for our menu options. “Show here the menu opening and making the new object” This example allows us to create different kinds of sceneObjects based on user input. “If we test our dropdown menu you can see the new object of our choice pop up both in our hierarchy and the live view.” When creating a new SceneObject, we again use nce.projectNC to access the proper GraphicAsset and the proper parent for the object, the mainScene. After creating the new SceneObject, we generate a corresponding UiText element with the same name and add it to the collapsible stack.(Video 12 also a little off at the end)

Now, let’s look at our first button, objectsToFileButton, and the functionality it provides with FileIO extensions. In this example, we’re exporting all scene objects to a text file.
We begin by defining a destination path for the output file, then use nce.fileIO.createDirectory() to create the directory if it doesn’t already exist.We again retrieve the scene’s descendants, but this time, instead of adding elements to a UI component, we concatenate each object’s name into a single text string with a newline. Once complete, we create the file, if it doesn’t already exist, and write the concatenated text to the file using nce.fileIO.writeTextFile(). Now let's test out our FileIO button. When we click on the button we can see a file generated in the top left corner, and if we open it we’ll see a list of objects that matches what's in our hierarchy. (video 13)

Custom inspector visuals, fileIO, and project access enable you to build many time-saving tools for specific project needs, but extensions provide other avenues for creating productivity tools as well. Commands can be invoked when the Inspector connects to or disconnects from a project. Using nce.addProjectConnectionCallback and nce.addProjectDisconnectionCallback. Functions can also be triggered right before or after a project is published, making publishing procedures fully automatable. Simply use nce.addPrePublishCallback and postPublishCallback. In our example, we implemented a postPublishCallback that compresses the screenshots and text files generated earlier. The functionality for this callback also resides in our Panel class. The function first sets the location of both of our files and checks if the directories to be zipped do indeed exist along with checking if the zip files already exist. If the files exist and we haven't already zipped them, it will compress our files using nce.fileIO.compress(); Incisor extensions can also be used to run external commands via the nce.runBash, and nce.runCmd functions. If we take a look at our zipfiles function again, at the very end we have a runCmd(dir) response being printed to an alert so the user can see that the files have been zipped. Project Extensions create functionality specific to a given project. If you want to apply the same functionality to all Incisor projects, simply place the Extension scripts in the globalExtensionsDirectory inside the Incisor application support folder. This folder can be found either in the user directory, or it can be accessed from within the incisor menu by clicking on the little Incisor Logo in the top left corner and selecting open application support directory.(video 14)


This concludes our tutorial on Extensions within Incisor. If you’d like to explore this example more you can find it in the projectExtensions folder in the incisor example gallery. Check the link in the description to download this example and for more tutorials, and feel free to leave questions and feedback on stack overflow and our subreddit. Enjoy creating with Incisor!(incisor outro)











----------------------------------------------------------
Section 27: Timelines
----------------------------------------------------------



001
Hello, and welcome to this Incisor tutorial about Timelines. 

This tutorial is a great follow up to our video covering Constructs.

Incisor’s graphic user interface allows artists and animators to contribute directly to the apps and games developed with Incisor without code.

One of the most useful ways in which Incisor empowers designers is by adding timelines to a construct. 

Using the Incisor GUI panels, let’s get set up for this tutorial….


002
Next, we are setting up a Construct - called Sample Construct - with two graphic objects.

In Neutral State of my Sample Construct, we will manipulate the two instances of White Box so that they appear as a red square and a blue rectangle.

We can do this easily by Using X scale and manipulating the Color Multiply Effect Node of each of our objects.

Using the hierarchy panel, we will also place the blue rectangle inside a SceneObject which acts as a container. 

Once we have an Incisor construct set up, one or multiple timelines can be added to it, allowing for dynamic, key frame based animation. 


003
Now let’s add a timeline to this construct. 

By clicking on Manage Timelines, the timeline manager appears and we can see the option to add a timeline….. and now name it. Let’s call this timeline, Idle. 

Now when we click on Neutral State in the Construct Panel, we can select our new timeline.

This changes the construct view from Neutral State to the our new Idle Timeline. 

By clicking inside the construct panel, the hierarchy panel now changes form reflecting the neutral state to reflecting the timeline view, which is indicated by the header. The hierarchy is no longer editable - as changes to the construct’s setup need to be done in Neutral state - but this list can be used to select scene objects. 

With a timeline panel open, notice it is also populated with our new timeline called “Idle”.


004
Everything in our construct appears in the timeline list, ready to be animated with keyframes.

The timeline panel header is where we can setup the parameters of our current timeline - the basics of which are length and playback rate - as well as use playback controls to preview your animation.

Let’s set our timeline to be 2 seconds long and keep the playback rate at 1.

There are also tools to control how our timeline list of scene objects can be viewed. Collapsing, filtering, and sorting all help navigate the timeline list - especially when our constructs have a lot of content and your animations become more robust.

A basic example is the sorting toggle. The list of scene objects can match the hierarchy of the construct, or be listed alphabetically.

There are three main categories of keyframes: numeric, boolean, and invocation keyframes.

We’ll cover invocation keyframes in a later video about advanced timeline techniques.

Numeric keyframes are keyframes that require values, such as scale, position, or even color. Boolean keyframes appear as checkboxes for enabling or disabling scene objects or for toggling visibility on and off. 

The timeline panel functions as we would expect, with time markings, an indication of our animation’s beginning and end, and a playhead. Like all other panels within Incisor, spacebar allows us to pan and zoom.


005
Let’s first add some common keyframes and get to know animating with the Timeline panel.

By right-clicking on a scene object in the timeline list, we can see what is available to keyframe. Let’s add a position Y keyframe to our red square scene object. 

By adding the position Y parameter, we can now keyframe that parameter by clicking the add keyframe button.

Let’s add some keyframes to animate the scene object on the Y axis. 

Once a keyframe is placed, you can right click on the keyframe to add preset easing. Let’s make this scene object’s Y position ease in to the second keyframe. 

For more specific motion design, we can toggle the view between keyframe view and curve view. This allows us to tailor the motion between keyframes with familiar handles.


006
Scene objects being used as a container can also be keyframed, as well as effect nodes that have been added in neutral state. 

Let’s add some scale keyframes to our container scene object. 

And now some X position keyframes to the blue rectangle scene object within the container.

Incisor Effect Nodes and add-ons are also able to be keyframed. 

Let’s animate the color multiply effect node on our objects and keyframe them to change the color of our objects during this animation.

As mentioned before, we can preview our animation with the playback controls. Let’s preview it now and also change the playback rate.

We can see the timeline list filtering more effectively now that we have some animated parameters. 


007
Incisor constructs and timelines combine to create a powerful dynamic animation tool and allow artists, animators, and engineers to collaborate seamlessly.

Once a construct has one or more timelines, auto-complete will reflect their existence in project code, thanks to Incisor’s dynamic documentation feature.

Enjoy animating with Incisor!












----------------------------------------------------------
Section 28: Showcase - ExampleGallery
----------------------------------------------------------



The Incisor Example Gallery is a free project that you can use to try out many of Incisor’s exciting and unique features. Each example is separated into its own class and is available as a typescript and javascript file. In the inspector you can use the arrow buttons to cycle through all of the current examples, or use the searchable drop-down menu to find something specific. The example gallery is regularly updated, so be sure to check out incisordev.com for new versions of this project and tu
torials based on it. 
 











----------------------------------------------------------
Section 29: PublishingWithElectron
----------------------------------------------------------


Hello, and welcome to this Incisor tutorial.

In this tutorial, we'll be walking through a step-by-step example of how to build native apps with Incisor's built-in Electron support.

Note that some of the features in this tutorial require an Incisor Enterprise subscription.

Electron is an open-source framework that lets developers build cross-platform desktop applications using web technologies like HTML, CSS, and JavaScript. It bundles a Chromium browser engine and a Node.js runtime, allowing web apps to run as native desktop apps with access to system resources.

Incisor can be configured to create Electron apps when projects are published.

To demonstrate this, we'll start by making a new project and then make a few changes to make the project our own.

When we publish this project, the files created are standard web content files, which you can see in the associated Publishing directory.

We want to turn these web files into a native app using Electron.

To do this, we need to add an auxiliary publishing package to the configuration we are using to publish the project.

Auxiliary publishing packages are defined in the ProjectSettings.

As you can see, we can create different Electron publishing packages where we specify things about the published Electron app, such as the target OS and attributes about the app's appearance and behavior.

Once you have defined your Electron publishing package, you can enable it within the configuration you'll be using to publish the project.

Then we can save the ProjectSettings, and now whenever we publish the project using this configuration, Incisor will create a built Electron app that includes our published project.

When publishing Electron apps with Incisor, it's important to watch for alerts and messages in the console, as some setup may be required. The Electron publishing process requires that npm, npx, and node are installed globally on your system. If you attempt to publish with Electron without those dependencies, you will see messages in the console letting you know that they need to be installed. You may also need to grant Incisor permission to run npm commands.

Publishing an Electron app can take a few minutes.

When the publishing process is complete, we'll see that a folder with the name of our Electron publishing package has been populated in the Publishing directory, and this is where we find our new native app.

Opening this, we can see that we now have a native app running free of browser or web dependencies.

Now let's take a closer look at the publishing process.

When Incisor publishes with an Electron publishing package, a new directory by that name is created in the project's Utilities folder.

This directory houses the files that inform the creation of the Electron app.

Electron apps host an internal Node runtime, and the JavaScript “main” for that environment is stored here in ElectronMain. All files placed here will be concatenated and included in the app, comprising its internal Node runtime.

JavaScript files can be placed within the ElectronPreload directory, and these scripts will run before the core web content of the app starts running. Functionality allowing for communication between the Electron app's internal Node environment and the environment of the core web content can be set up here.

To build the Electron app, Incisor deploys a Node library called electron-builder, and the package.json that configures this library is stored here in ElectronPackage.
The contents of these directories are compiled and used when creating the new Electron app, so customization beyond Incisor's built-in interface can be achieved by editing these files or including additional files.

To illustrate an example of customizing Electron further, we can look at the Incisor Slot Template. The Slot Template incorporates extra Electron functionality to enable its published Electron app to communicate with an external process using a GRPC connection to get its game outcome data.

So let's open the Incisor Slot Template, and remember, this project can be downloaded at incisordev.com

We can see in the EgmPublish Electron package directory that there have been some modifications to existing files as well as some added files.

For example, in the ElectronMain directory, this GRPC.js file sets up the functions within the published Electron app's Node runtime that handle the communications to and from the external process.

Also, the ElectronPreload in this package has been altered to expose the GRPC functionality to the core content's JavaScript runtime. These preload scripts make the GRPC features available to the web content in a controlled way.

In addition, the ElectronPackage.json file has been edited to ensure that the required GRPC dependencies are included in the published Electron app.

Now, when the Electron app for this project is published, it can create a connection with any other GRPC-enabled process over port 50051.

The Incisor Slot Template includes two examples of companion GRPC-enabled servers in the EgmPublish package, and if you run either of them before opening the newly published Electron app, the connection is made and communication between the two processes is enabled.

You can see that when we spin the reels in the published electron app, a request is made of the external GRPC server to acquire the data for the game outcome. And you can even spin the game from within the external server by hitting the spacebar.

So in this tutorial, we’ve walked through the full workflow of using Electron support in Incisor: starting from a standard web project, publishing it as normal web content, enabling an Electron auxiliary publishing package, and then looking under the hood at the directories that support the publishing of the Electron app. We also saw how the Slot Template takes things a step further by wiring up GRPC so your Electron app can talk to external processes in real time.

The built-in support for Electron publishing in Incisor can be very useful in that it enables you ship your published projects as a native desktop apps, and it's built right into the standard Incisor publishing workflow. 

And this concludes the Electron publishing tutorial.

Don't forget to check out incisordev.com for more tutorials, and leave questions and feedback on StackOverflow and our subreddit.

Enjoy creating with Incisor.












----------------------------------------------------------
Section 30: ParticleSystemOverview
----------------------------------------------------------


Particle System Overview

A particle system is a technique for efficiently controlling and rendering a collection of graphics called particles.

These particles are merged into a single graphic object and controlled by the GPU, which can significantly improve performance.

We can specify different graphics for particles, each with their own emission rate and scale. 

We can control where the particles are emitted, their velocity when emitted, and how long they live.

We can apply physics concepts to simulate things like gravity, wind, and motion stretching. 

We can control the rotation of each particle, wiggle the position randomly, and control their scale and color properties. 

These parameters can be specified as constant values or changed over time, with ramps or expressions

Combined with the built in randomization of each parameter, these tools let us create a wide variety of effects.












----------------------------------------------------------
Section 31: ResolutionScaling
----------------------------------------------------------




Resolution downscaling helps improve image download times and reduce the rendering workload.


Incisor makes resolution scaling easy.


To demonstrate this, I’ll be using Incisorsaurus.


First, I've opened an Asset Browser and an Asset Settings panel and have selected the leg of the dinosaur. 


I'll find the Resolution Scale X and Resolution Scale Y properties. By default, these are set to 1, which means the image is downloaded at its original size.


Now, I’ll adjust both values to zero point one. After saving the project and refreshing Live View, you’ll notice that while the image appears the same size, it’s much blurrier. 


This is because the image is now significantly smaller than its original size.










----------------------------------------------------------
Section 32: FlowStates
----------------------------------------------------------


Hello and welcome! In this tutorial, we're exploring high-level project architecture in Incisor. We'll be using a sample game to demonstrate how FlowControllers and FlowStates handle your project's flow. This system not only keeps your code modular and timed, but also gives you a clear way to monitor the status and progress of your states during execution.


Think of the FlowController as a manager of your project's current phase that tracks which state you're currently in. You can create one to define the major sections of your app such as game introduction screen, main menu, gameplay, pause menu and a game over screen.


These states are globally accessible in your code and appear directly in the Flow Panel. This makes it easy to monitor timings and debug your project's sequencing in real-time.


Let's create a new empty Incisor project. I'm gonna call it Flow States Example.


To keep track of our states, I'll need to open the Flows panel. It's empty for now, but once we start defining our states, they'll all show up right here. 


In Incisor, flow states are defined through the project code. I'm gonna open my code editor and navigate to the ProjectMain javascript file.


Let's keep the default text for now. To start working with flow states, first I need to define a flow controller with nc.defineFlowController. As an argument you can provide any flow controller unique name you want. I'll call it my default flow controller.


Then we can start defining our individual flow states that will be a part of this flow controller. Each flow state should be defined as a class that extends a FlowState class. You can define those classes in your ProjectMain file, however a good practice is to store them separately.


In the ProjectCode directory let's create a new folder called "FlowStates" and in it I'm gonna create a new JavaScript file for my Introduction state.


In the constructor we can now add new Flow State Elements to this FlowState. Such elements are essentially timed callbacks to functions within this FlowState, which are used to create the sequencing for this FlowState.


I will add an element for displaying the introduction screen at time 0 and then I want the introduction screen to hide after 2 seconds.

And we have to write the corresponding functions with a logic for displaying and hiding introductions. I will modify the text assembly that I kept in the ProjectMain

Let's go back to the ProjectMain and add the Introduction flow state to our Default Flow Controller.


We can see the flow states are now visible in the flow panel however they are not playing.


To start them, we need to set our Introduction state as a currentState in the code.


Now as you can see the Introduction state is active and automatically moves to its next element after 2 seconds.


I am gonna quickly create a simple construct for a game screen.


And add another flow state for gameplay



In Incisor, flow states are defined through the project code. Let's jump into the code editor and open up ProjectMain javascript file

First, I'll clear out the default template code that every new project starts with. To begin working with flow states, we need to define a flow controller using nc dot define flow controller. This takes a unique name as an argument—I'll just call mine 'default flow controller'.

If we check the Flows panel, you'll see that the controller has been successfully registered.

Now we can start defining the individual states for this controller. Each one should be a class that extends the base FlowState class. While you could define them all in ProjectMain, it's better practice to keep them in separate files to keep things organized.

That's why I'm creating a folder called 'FlowStates', and inside it, a dedicated JavaScript file for my Introduction state.

Our Introduction class extends FlowState, which gives us access to all the built-in state management tools in Incisor. For example, we can use the addElement method to define 'elements'. These elements act as timed callbacks, allowing us to easily sequence the events within our flow state.

This method takes a timestamp as its first argument and the callback name as its second. I'll add an element to display the introduction screen at the zero-second mark, and then I'll add another element to hide it at the two-second mark.

Then let's define those functions, I'll leave them empty for now.

Next, we need to register this new state with the Flow State Controller so it knows to include it in the logic.

Now, if we look at the Flows Panel, you'll see the Introduction flow state along with our two elements for showing and hiding the screen.

However, the state isn't playing yet. To activate it, we need to call the setToCurrentState method to set this as our active flow.

As you can see, the Flow Controller now automatically starts with the Introduction state. It triggers our 'display' element, waits for two seconds, and then seamlessly transitions to the 'hide' element.

Since we haven't defined any logic for our display and hide elements yet, you won't see any changes in the live view.


Let's go ahead and quickly build a construct for the Introduction screen so we can see it in action.

If you're unfamiliar with Incisor constructs, there's a separate video tutorial that breaks that concept down in detail. You can find the link for that in the description below.

I'm also creating a second construct for a gameplay screen.

Let's set up a simple coin flip example. First, I'll create a text box to display the game status. Then, I'll import a coin texture and an .obj file to add them as a GraphicalObject to our construct.

And let's add those constructs to the main scene via the code. Since they're both active at once, they'll show up together in the live view. To clean things up, let's hide them for now by setting their alpha to zero.

Tweaking the color alpha of our screen instances allows us to easily show and hide them.

Let's use that in our Introduction class. In the displayIntroductionScreen method we can set the alpha color to 1.

We can also take advantage of Incisor's built in colorMultiply swoop method to smoothly change the color to desired value in a defined time, for example 1 second.

Now we need to define a FlowState for our gameplay screen. I'll create a new file in the FlowStates directory and copy over the contents from our Introduction state.

Then, I'll register this new state with the flow controller, following the same process we used for the Introduction state earlier.

In the Flow States window, we can see that the Gameplay state is registered. However, once the Introduction ends, it doesn't automatically move on. That's because we haven't defined the transition yet.

Inside the hideIntroductionScreen method, we simply need to tell the Flow Controller to set Gameplay as the active state.

And there we go. The transition is now working correctly.

I'm going to quickly fill in these text boxes so they actually show the game title and status.

Since the Introduction screen is static, I've updated its text directly in the construct. However, we'll update the Gameplay status dynamically in the code, depending on which flow state the player is currently in.

Once the game screen is displayed, I don't want to automatically trigger the 'hide' method. Instead, I want to wait for the player to press the spacebar to proceed and start the game.

To achieve this, we can use another built-in FlowState function called addPause. This method keeps the state paused until the callback provided in the second argument returns true.

For this callback I'm writing a waitForUserInput function that returns the boolean value of isWaitingForInput to determine if the flow should stay paused.

In the displayGameScreen method, I'm setting this flag to true. This ensures the pause condition is met immediately, and the state remains locked until we're ready to proceed.

We'll flip this flag inside the onKeyDown callback, specifically checking for a spacebar input to move the game forward.

We want this onKeyDown method to start listening after the Introduction screen is displayed..

To do that, let's hook into the built-in Incisor app events by adding a callback to nc.appEvents.keyDown

Then, it's important to unhook it as soon as the spacebar is pressed to prevent any accidental double-inputs

Let's see it in action. As you can see, the flow is paused, but I'll hit the spacebar now and... there we go, it moves to the next state.

Let's also wipe the status text when the spacebar is pressed to keep the UI clean for the next state.

Great, that's working well, but we're still missing the actual game. The coin flip logic can be defined as another element within our Gameplay state

Next, I'll set up some basic randomization and use a rotation.swoop to give us a nice and smooth, flipping animation for the coin.

Let's also update the status text during the flipping state to give the player better feedback.

And finally, we can hook this method up as an element in our FlowState to tie everything together.

I'm going to give the flip a half-second delay to start after the user input pause is cleared. We also need to adjust the timing for our hideGameScreen element. Since the flipping animation takes two seconds, it finishes at the 2.0-second mark. I'll add another 1.5 seconds of hang time so the player can actually see the result, meaning we'll set the hide element to trigger at 3.5 seconds.

And there we have it—our state machine is officially up and running! To make this feel like a complete experience, it'd be great to add one more state after the flip to display the result and then loop it back to the introduction.

...and to loop it back, simply go into the last element of our gameplay flow and tell the flow controller to set 'Introduction' as the current state.


If you want to use an external server or a backend script to handle your result calculations, Flow States make that easy to set up. 


We can simply utilize another addPause() element, just like we did for the keyboard input


I'm using the same approach here: a boolean flag that keeps the flow paused. But instead of waiting for a keyboard input to flip that flag, I'll write a getResult() method to fetch the data from the server.


Now, when I press Space, the flow moves to the getResult element. This triggers the call to our external server to fetch the coin flip result.



As you can see, the integration is seamless. In the event of network lag or a server timeout, the Flow Controller allows you to monitor exactly where the sequence is hanging, making it much simpler to debug and handle those edge cases.



That's it for this tutorial. Thanks for watching and happy coding. Enjoy creating with Incisor.





This is the code discussed in this tutorial:

------------ ProjectMain.js
// This is the main entry point for this Incisor® project. 
// Throughout the project, this object can be referenced as 'pr'.
class ProjectMain
{
    init()
    {
        // introduction screen
        this.introductionScreen = nc.constructDefs.IntroductionScreen.add();
        this.introductionScreen.descendantsByName.Container.colorMultiply.alpha = 0;
        
        // game screen
        this.gameScreen = nc.constructDefs.GameScreen.add();
        this.gameScreen.descendantsByName.Container.colorMultiply.alpha = 0;
        
        nc.defineFlowController("DefaultFlowController");
        nc.flows.DefaultFlowController.addFlowState(Introduction);
        nc.flows.DefaultFlowController.addFlowState(Gameplay);

        nc.flows.DefaultFlowController.Introduction.setToCurrentState(true);
    }
}


------------ FlowStates/Introduction.js
class Introduction extends FlowState {
    constructor() {
        super();

        this.addElement(0.0, "displayIntroductionScreen");
        this.addElement(2.0, "hideIntroductionScreen");
    }

    displayIntroductionScreen() {
        pr.introductionScreen.descendantsByName.Container.colorMultiply.swoop.alpha(1.0, 1);
    }

    hideIntroductionScreen() {
        pr.introductionScreen.descendantsByName.Container.colorMultiply.swoop.alpha(0.0, 1);

        nc.flows.DefaultFlowController.Gameplay.setToCurrentState(true);
    }
}


------------ FlowStates/Gameplay.js
class Gameplay extends FlowState {
    constructor() {
        super();
        this.isWaitingForInput = false;
        this.isWaitingForResult = false;

        this.addElement(0.0, "displayGameScreen");
        this.addPause(0.01, "waitForUserInput");
        this.addPause(0.02, "waitForResult");
        this.addElement(0.5, "flipCoin");
        this.addElement(2.5, "displayResult");
        this.addElement(5.5, "hideGameScreen");
    }

    displayGameScreen() {
        pr.gameScreen.descendantsByName.Container.colorMultiply.swoop.alpha(1.0, 1);
        pr.gameScreen.descendantsByName.StatusText.string = "Press SPACE to flip";
        pr.gameScreen.descendantsByName.Coin.rotation.y = 0;

        this.isWaitingForInput = true;

        nc.appEvents.keyDown.addCallback(this, "onKeyDown");
    }

    onKeyDown(args) {
        if (args.key === " ") {
            this.isWaitingForInput = false;
            this.isWaitingForResult = true;
            this.getResult();

            pr.gameScreen.descendantsByName.StatusText.string = "";
            nc.appEvents.keyDown.removeCallback(this, "onKeyDown");
        }
    }

    waitForResult() {
        return (!this.isWaitingForResult);
    }

    getResult() {
        fetch('https://www.random.org/integers/?num=1&min=0&max=1&col=1&base=10&format=plain&rnd=new')
        .then(response => response.json()) // Converts response body to JSON
        .then(data => {
            console.log("Result: " + data);
            this.coinResult = parseInt(data);
            this.isWaitingForResult = false;
        })    // Handles the actual data
        .catch(error => console.error('Error:', error)); // Catches network failures

    }
    
    flipCoin() {
        pr.gameScreen.descendantsByName.Coin.rotation.swoop.y(pr.gameScreen.descendantsByName.Coin.rotation.y + 180 * (12 + this.coinResult), 2.0);
        pr.gameScreen.descendantsByName.StatusText.string = "Flipping...";
    }

    displayResult() {
        pr.gameScreen.descendantsByName.StatusText.string = "Winner: " + (this.coinResult == 1 ? "STAR" : "INCISOR");
    }

    waitForUserInput() {
        return (!this.isWaitingForInput);
    }

    hideGameScreen() {
        pr.gameScreen.descendantsByName.Container.colorMultiply.swoop.alpha(0.0, 1);

        nc.flows.DefaultFlowController.Introduction.setToCurrentState(true);
    }
}










----------------------------------------------------------
Section 33: TextAssemblies
----------------------------------------------------------


Text Box and Text Assembly
2024.10.01

- Hello and welcome to this Text Box and Text Assembly tutorial.
- In this tutorial we will cover
	- Creating a Text Assembly and a Text Box
	- Adjusting the size of the Text Assembly and Text Boxes
	- Explaining some of the justifications and customizations available
	- How to change the displayed string
	- And a fundamental difference between a Text Assembly vs a Text Box
- This video also assumes you have watched either the "Getting started with Javascript" or "Getting started with Typescript"
- All code examples shown will be in Javascript.
- Create and open a new project in Incisor®.  Once open navigate to ProjectMain.js in the Project Code folder of your project.
- To start a Text Assembly and Text Box have many similarities.
- They both have the ability to have their font, scale, alignment, wrap mode, and many other parameters set.
- They also have a fairly fundamental difference, which we will discuss soon.
- We are going to start with a completely blank project so please delete anything in the init function of the ProjectMain.js file.
- In the init function create a new Text Assembly. 
- You can set the string of the Text Assembly directly, in this example we will set the string to "Text Assembly String".
- We are going to set the colorMultiply of the created text assembly to 1,0,0,1.  This will change the text to red.
- We will also move the Text Assembly up by 200 units, we will now save to update the live view.
- Similarly we will create a new Text Box, set its string to "Text Box String" and set its color Multiply to 0,1,0,1 making it green and then moving it down 200 units.
- The different colors and strings are for demonstrative purposes only.
- In both a Text Assembly and Text Box we can set the Box Width or Box Height of both types of objects.  This can be set in the "Text" section of the object inspector when you select your Text Assembly or Text Box.
- If either box width or box height are set to 0, then the text assembly and text box will be 'unbound' in that direction.  This means that the Text Assembly and Text Box will expand in those directions so that the full string is shown.
- You can set the all parameters either through code or through the Object Inspector.  Please note, any changes made through the object inspector will be lost upon refresh.
- We will set the Box Width to 500 and the box height to 250. 
- By changing either the horizontal or vertical justifications we can ensure that our string is shown exactly how we want it to be. 
- By changing the box width to 250 we can begin to explore we get our text to always show up in a given size.  
- When setting a box width or box height you can also set if you want the string to wrap or scale to fit into the described areas.
- When we turn off wrap to fit, and leave scale to fit enabled it will shrink the text to be visible within the bounds you set. 
- When we turn off scale to fit and turn on wrap to fit you can see the text wrap to the next line.
- Now let's undo these changes. 
- Using the Object Inspector in Incisor we can see one inherent difference between a Text Assembly and a Text Box.
- In a Text Assembly, each character is a separate object, in the hierarchy.
- This means, each character in the string can have its position, scale, rotation, effect controllers, and many other aspects edited independently from the other characters. Lets move and scale up the A
- This provides the ability to customize each character individually at the cost of more objects in the hierarchy.
- In a Text Box, all characters in a string are treated as a single hierarchy object. 
- In general, the fewer objects in your project the more performant your project will be.
- This allows a lightweight way to show long strings that does not add unnecessary objects to your project.
- However you will not be able to edit the position, scale, rotation, etc of individual characters in a Text Box.

- A further difference is how you edit the strings through the Object Inspector.
- Both a Text Assembly and a Text Box can have their strings edited from the string field in the Text section in the Object Inspector.
- Let's edit the string of the Text Box first.
- Now we can edit the string of the Text Assembly.
- Please note, that when you edit a string in this way, any scale and position changed you have made to individual characters will be reverted.
- With a Text Box, you can also edit the string through a cursor or mouse by changing the Text Box's edit mode.
- Now when selecting the text box you can type directly into the text box to update its string. 
- This concludes the Text Assembly and Text Box tutorial.
- Don’t forget to check www.incisordevdocumentation.com/videotutorials for more tutorial videos, and feel free to leave questions and feedback on StackOverflow and our SubReddit.
- Enjoy creating with Incisor!













----------------------------------------------------------
Section 34: Shapify
----------------------------------------------------------


Incisor's shapify system lets us create graphic objects with sharp edges at a wide range of scales, without needing to download a large image.  To demonstrate this, we've added a two graphic objects to our scene.

[select graphic asset and show the unchecked box]
The top graphic object uses a typical graphic asset, without the shapify option enabled.

The bottom use a copy of the same graphic, but with the shapify setting enabled.
[show the effect nodes containing Shapify]
Enabling this setting automatically applies the shapify effect node to the graphic object, which causes it to turn white, with the alpha channel forming the reconstructed edge.

The effect of the shapify setting becomes more obvious if we increase the scale of both of these graphic objects.  Notice how the edge of the top graphic becomes blurry, while the bottom graphic's edge remains sharp.

[showing effect controllers edgeOffset]
The position of this edge can be changed dynamically using the edgeOffset effect controller.  This allow the shape to be made thicker or thinner than the shape in the original graphic.

[showing the level going up to .94]
In the asset settings, the shapify optimization level controls how much data is used to encode the edge information.  Increasing this value reduces the size of the asset, but as you can see here after we save and refresh the live view, it also makes the edge less accurate.

The edge range is used to control how thick or thin the shape can be made using the edgeOffset effect controller.  If we increase the edge range, save, and refresh the live view, we see that adjusting the edgeOffset effect controller now has a bigger effect on the edge position.

Incisor® Inspector Tool Tips

IncisorToolTips.txt

Incisor® Inspector Tool Tips

"Top Bar→project name": "This is the public name for this project. Projects also have a 'code name' which is the name used within Javascript API."

"Top Bar→save star": "When this star is visible, the project differs from what is on disk and is in need of saving."

"Top Bar→disconnection icon": "This icon means that this instance of the Incisor® front-end has lost its connection with the Incisor® application. Open a new project from the 'Control Center' tab, or re-open the Incisor® application."

"Top Bar→Incisor® menu": "The menu containing options related to the Incisor® application."

"Top Bar→Project menu": "The menu containing options related to the current project."

"Project menu→Import": "Options to import data from third party applications, and to add stock components from the Template Library."

"Top Bar→Manage menu": "Menu with options to manage project definitions including Constructs, Timelines, Masks, and Layers."

"Top Bar→View menu": "Menu containing visuals options related to the Incisor inspector."

"Drag Handle": "This button indicates that the associated item can be 'rearranged'. Drag this button to move it up or down within the list that contains it."

"Keyframe": "One value at a specific time in a KeyframedValue.\n\nSELECT\n- Click selects\n- Shift+click adds, Cmd/Ctrl+click toggles\n- Double-click snaps the playhead to this keyframe\n- Right-click for options\n\nMOVE (drag)\n- Graph mode: time + value; dope sheet: time only\n- Shift locks to the dominant axis\n- Cmd/Ctrl stretches the selected keyframes in time, anchored at the far end\n- Option duplicates the selection and drags the copies\n- Boolean: up = true, down = false\n\nSTEPS ('left' / 'right' keyframes)\n- Hold a second value (dimmer dot + connector) for the far side of the time\n- Drag either dot; 'split' makes a step, 'type' sets standard/left/right\n\nHANDLES (graph mode, floatingPoint)\n- Drag a handle dot to shape the curve\n- Default: opposite handle stays rotation-locked (its angle follows)\n- Option: move only the dragged handle\n- Cmd/Ctrl: also match the opposite handle's length\n- Shift: flatten the dragged handle level\n\nRIGHT-CLICK also has ease presets: linear, ease in, ease out, ease in & out, smooth."

"SceneObject": "Click to select; Shift+click to add to selection; Cmd/Ctrl+click to toggle; right-click for more options."

"Animate→search all properties...": "Every animatable property of the selection in one searchable list, named by its full path. Hold Alt while opening this menu to go straight here."

"Animate Timelines→advanced": "Timeline invocations - play, pause, stop and the rest - are best avoided. They ignore Timeline weight, and they leave the target Timeline running in a state that is hard to anticipate once other Timelines and blending are in play. Keyframe 'time' instead: it pins the target Timeline's time to this Timeline's time, so it plays the same way every pass and blends like any other animated property."

"Panel Type": "Use this menu to select a panel type."

"Rearrange Inspector": "Drag the panel menu bar to a new location to rearrange the panels within the inspector."

"Add Panel": "Use this button to add a panel to the inspector."

"Close Panel": "Use this button to close the panel."

"Application Settings→logs": "Settings for how Incisor log files are written... Incisor log files are written to the 'Application Support' directory, which can be accessed from the Incisor menu."

"Application Settings→verbosity": "The amount of information included in the logs. Incisor log files are written to the 'Application Support' directory, which can be accessed from the Incisor menu."

"Application Settings→entryCharLimit": "When logging verbosity is set to anything but 'full' each log entry is limited to this number of characters. Incisor log files are written to the 'Application Support' directory, which can be accessed from the Incisor menu."

"Application Settings→window": "Settings for the Incisor application window and its tabs, and the ports used to host projects locally."

"Application Settings→runHiddenTabsUnthrottled": "Setting determining if projects in tabs that are not showing keep running at full speed. When unchecked, hidden tabs are throttled to save resources."

"Application Settings→connectionPorts:": "This is a list of ports that Incisor can use when hosting projects locally. Incisor does its best to determine when ports are in use by other processes, but in some cases different ports must be used."

"Application Settings→security": "Settings that affect Incisor security and options associated with risk."

"Application Settings→allowUniversalFileIO": "Setting to determine if Incisor is allowed universal FileIO from within projects. Be advised that by checking this box, project and extension code can affect any file on your computer. Please be aware of the risk you are assuming and take great care! Note: this governs FileIO while developing in Incisor; published Electron builds have their own separate 'allowUniversalFileIO' option on the Electron auxiliaryPublishingPackage."

"Application Settings→allowRemoteHosting": "Setting to determine if Incisor is allowed to host files remotely. This is primarily used to host published projects for testing on external devices. Be advised that remote hosting may expose your system to significant risk of unauthorized access. Please be aware of the risk you are assuming and take great care!"

"Application Settings→allowExternalExecutableProcesses": "Setting to determine if Incisor is allowed to run external executable processes on behalf of extensions code. Be advised that by checking this box, extension code can be used to run virtually any command on your system. Please be aware of the risk you are assuming and take great care!"

"Application Settings→allowEditorDebugging": "Setting to determine if Incisor opens a debugging port that code editors such as Visual Studio Code can attach to, to debug your projects. The port is only open to this computer, and the setting takes effect the next time Incisor starts. Be advised that any program on this computer, including those run by other user accounts, could connect to the port and run code inside your projects. Please be aware of the risk you are assuming and take great care!"

"Application Settings→editorDebuggingPort": "The port Incisor opens for code editors to attach to when allowEditorDebugging is on. Change it if another program on this computer already uses the default, 9222. The setting takes effect the next time Incisor starts."

"Application Settings→enableCLI": "Setting to determine if Incisor accepts commands from the command line, such as publishing a project, taking a screenshot of a project tab, or running a script inside an open project. Be advised that any program on this computer, including those run by other user accounts, can issue these commands, and a script can do anything the open project can do. Every command is recorded in the log. Please be aware of the risk you are assuming and take great care!"

"Application Settings→applicationSetup": "Settings to configure how Incisor works."

"Application Settings→maxUndoStates": "The maximum number of Undo/Redo steps stored in Incisor memory during runtime."

"Application Settings→maxThreads": "The maximum number of threads Incisor can use in its operations."

"Application Settings→refreshOnCodeChange": "Setting determining if changing code on disk causes the given project to automatically refresh."

"Application Settings→clearConsoleOnProjectRefresh": "Setting determining if refreshing the project clears the browser console."

"Application Settings→runProjectOnOpen": "Setting determining if a project's code runs as soon as the project opens. When unchecked, the project opens stopped, with its code switched off, until the Run button in the Live View is pressed."

"Application Settings→stopProjectOnException": "Setting determining if an exception thrown by project code stops the project, reloading it with its code switched off so that the inspector stays usable. When unchecked, the project keeps running after an exception."

"Application Settings→showToolTips": "Setting determining if tool tips are shown when hovering over controls."

"Application Settings→toolTipDisplayDelay": "The number of seconds the cursor must hover over a control before a tool tip appears."

"Application Settings→colorTheme": "Choose from built-in or custom color themes."

"Color Picker→2D area": "Represents the two color components that are not active in the selected color space.  For example, if 'saturation' is active, the X axis of this gradient represents 'hue', and the Y axis represents 'value'."

"Color Picker→selection gradient": "Represents the color component that is active."

"Color Picker→alpha": "Represents the alpha, or opacity, of the current color."

"Color Picker→hue active": "Selects the hue/saturation/value color space and makes 'hue' the active component."

"Color Picker→hue": "The 'hue' of the current color as expressed in the hue/saturation/value color space."

"Color Picker→saturation active": "Selects the hue/saturation/value color space and makes 'saturation' the active component."

"Color Picker→saturation": "The 'saturation' of the current color as expressed in the hue/saturation/value color space."

"Color Picker→value active": "Selects the hue/saturation/value color space and makes 'value' the active component."

"Color Picker→value": "The 'value' of the current color as expressed in the hue/saturation/value color space."

"Color Picker→red active": "Selects the red/green/blue color space and makes 'red' the active component."

"Color Picker→red": "The 'red' of the current color as expressed in the red/green/blue color space."

"Color Picker→green active": "Selects the red/green/blue color space and makes 'green' the active component."

"Color Picker→green": "The 'green' of the current color as expressed in the red/green/blue color space."

"Color Picker→blue active": "Selects the red/green/blue color space and makes 'blue' the active component."

"Color Picker→blue": "The 'blue' of the current color as expressed in the red/green/blue color space."

"Color Picker→hexadecimal": "The hexadecimal representation of the current color.  The red, green, and blue values are each represented as a hexadecimal value ranging from 00-FF."

"Color Picker→alpha": "The alpha, or opacity, of the current color."

"Color Picker→new color": "The current value of the color.  The color is show with and without the alpha, or opacity, applied."

"Color Picker→original color": "The original value of the color before any changes were made.  The color is show with and without the alpha, or opacity, applied."

"Color Picker→sample": "Allows selection of a color from within the Incisor® window."

"Lock Selection": "Toggles the selection lock. When locked, the panel's selection will not change as you click different objects in the scene."

"Loading Tier Testing Panel→auto-block tiers": "When on, loading tiers are automatically blocked as the project asks for them, so you can see how the project behaves while their assets are withheld. Turn it off to let every tier load normally."

"Loading Tier Testing Panel→un-block all": "Releases every blocked tier at once, sending out any request that was being held. With auto-block tiers on, the tiers are locked again on the next refresh."

"Loading Tier Testing Panel→added delay per tier": "Seconds of artificial delay added to each tier before its assets are processed, for testing how the project handles slow loading. A value of 0 leaves loading at its normal speed - anything that is not a non-negative number reverts to the previous value."

"Loading Tier→block": "Blocks this loading tier, holding its assets back so you can see how the project behaves without them. The closed padlock means the tier is blocked, the open padlock means it is free to load."

"": ""

"Loading Tier→auto loaded": "This tier is marked isAutoLoaded in ProjectSettings, so the project asks for it at startup rather than waiting on a call to nc.loadTier."

"Loading Tier→loadTier": "Asks the project for this tier, as a call to nc.loadTier would. It goes inactive once the tier has been asked for, since a tier can only be requested once."

"Loading Tier→edit": "Opens Project Settings and scrolls to this tier's entry under loadingTierDefinitions, where its isAutoLoaded, duplicate removal and asset data file size settings live."

"": ""

"": ""

"Sounds Panel→sound search": "Use this field to search for a particular Sound by name. Multiple space-separated keywords are each scored independently, and only Sounds matching them are listed."

"Sounds Panel→playing only": "Lists only the Sounds that are playing right now. Sounds that are paused or stopped are left out."

"Sounds Panel→sort": "Orders the list below - alphabetically by name, or by when each Sound last started playing, most or least recent first. Sounds that have never played are listed last either way."

"": ""

"Sounds Panel→play": "Plays this Sound from the inspector without the project asking for it, so it can be auditioned in place. The scrubber alongside moves its playhead."

"Sounds Panel→mainVolume": "This Sound's own volume, before any VolumeControl it answers to is applied. The level actually heard is its netVolume, which combines this with those VolumeControls."

"Transcript Panel→filter": "Filters the phrase list by phrase ID and phrase content across all languages. Multiple space-separated keywords are each scored independently - results are ranked by total match strength."

"Transcript Panel→Font Reduction...": "Opens the Font Reduction overview popup, showing how the current phrase and language settings map to the project's font assets."

"Transcript Panel→open/close all": "Expands or collapses all phrase entries in the list at once. The caret rotates to indicate the current state."

"Transcript Panel→set all to:": "Sets the displayed language for all currently visible phrase entries at once."

"Transcript Panel→Detect Pairings...": "Scans all project constructs for TextBox and TextAssembly objects using a phrase ID and surfaces any phrase-font pairs not yet registered in font definitions."

"Transcript Panel→phrase ID": "The unique identifier for this phrase entry. Edit to rename the phrase ID - the new name must not be empty or already in use."

"Transcript Panel→language": "Selects which language variant is displayed in the phrase field. The selection is stored per phrase and persists in panel state."

"Transcript Panel→phrase": "The phrase text for the currently selected language. Editing and committing updates the transcript data for this phrase ID and language. Switch languages using the dropdown above."

"Transcript Panel→include in fonts:": "Controls which font assets include this phrase in their character set. Font reduction uses this to trim each font to only the characters it actually needs, reducing per-language download size."

"include in fonts→" + _fontDef.fontName: "Toggles whether this phrase is included in the '" + _fontDef.fontName + "' font's character set for font reduction."

"Lock Timeline": "Toggles the timeline lock. When locked, this panel will not follow automatic timeline changes (selecting a timeline in the Construct Panel, or the Object Panel's viewTimeline button). Manual selection here still works."

"Timeline Panel→current:": "Selects which timeline this panel is editing. Lists every timeline across all constructs as [Construct]"+this._entrySeparator+"[Timeline]; type to search by construct or timeline name."

"Timeline Panel→play": "Plays or pauses the current timeline's playhead, advancing it at the timeline's playbackRate."

"Timeline Panel→play once": "Plays the current timeline through once and then stops, instead of looping."

"Timeline Panel→stop": "Stops the current timeline and resets its playhead to initialTime."

"Timeline Panel→time:": "Scrubs the current timeline's playhead between its startTime and endTime."

"Timeline Panel→startTime:": "The start of the current timeline's playback window, in time units. Playback and the scrub slider run from startTime to endTime. Must be less than endTime - a larger entry is rejected."

"Timeline Panel→endTime:": "The end of the current timeline's playback window, in time units. Playback and the scrub slider run from startTime to endTime. Must be greater than startTime - a smaller entry is rejected."

"Timeline Panel→playbackRate:": "The playback speed of the current timeline: 1 is normal speed, 2 is double, 0.5 is half; a negative value plays in reverse. The actions menu's 'normalize playbackRate' rebases the timeline so this becomes 1."

"Timeline Panel→autoplayMode:": "How the current timeline behaves when its Construct is instantiated: 'none' does not auto-play (manual control), 'loop' auto-plays and repeats continuously, and 'once' auto-plays through once and then stops."

"Timeline Panel→initialTime:": "The playhead time the current timeline starts at, and resets to when stopped, in time units."

"Timeline Panel→isDefaultTimeline:": "Whether the current timeline is the one that controls its Construct - a new instance gives it full weight and influence. Only one timeline can hold this, so checking it takes it from whichever timeline had it, and unchecking hands it back to NeutralState."

"Timeline Panel→actions→normalize playbackRate": "Rebases the current timeline to play at playbackRate 1 by scaling its start/end times and every keyframe time around 0 - the animation plays the same, just at rate 1. Destructive: keyframe time values shift slightly onto the grid. Inactive when the rate is already 1."

"Timeline Panel→actions→change timeStep": "Sets the current timeline's timeStep (the keyframe-time grid) and remaps every keyframe onto it, nudging as needed so none are lost. Destructive: keyframe time values shift slightly onto the new grid."

"Timeline Panel→time ruler": "Drag here to scrub the playhead (snapped to the timeStep); double-click to frame the view to the whole timeline. Hold Space and drag to pan the visible time span, or scroll to zoom it."

"Timeline Panel→expand/collapse all": "Expands or collapses the properties of every object at once. A convenience toggle - individual rows are still remembered on their own."

"Timeline Panel→reveal selected": "Scrolls to and flashes the next currently-selected object in the timeline. Click repeatedly to cycle through all selected objects that are in view."

"Timeline Panel→object search": "Filter the timeline's objects by name: matching objects are sorted to the top and non-matching ones are hidden. Clear the field to show everything again."

"Timeline Panel→Timeline Object Filter Presets": "Filter the object list to a saved group of objects (a Timeline Object Filter Preset). Create presets from the current selection; they are saved per construct and shared across all timeline panels."

"Timeline Panel→sort": "Choose how objects are ordered in the list: 'hierarchy' follows the construct's object order; 'alpha.' sorts them by name."

"Timeline Panel→property filter": "Toggles AnimatedProperty filtering on/off. When on, only the property types checked in the dropdown to the right are shown."

"Timeline Panel→visible properties": "Choose which AnimatedProperty types are shown (multi-select; the menu stays open). '(all)' shows every property, '(none)' hides them all. Only applies while the 'filter:' toggle is on."

"Timeline Panel→frame view": "Frames the visible time span to the whole timeline (same as double-clicking the time ruler)."

"Timeline Panel→previous keyframe (all properties)": "Snaps the playhead to the next keyframe to the left across every property currently shown in the list (loops to the last when already past the first)."

"Timeline Panel→next keyframe (all properties)": "Snaps the playhead to the next keyframe to the right across every property currently shown in the list (loops to the first when already past the last)."

"Timeline Panel→drop keyframe (selected properties)": "Adds a keyframe at the current time on every currently-selected AnimatedProperty, capturing each one's current value. Active only while one or more properties are selected."

"AnimatedProperty": "Click to select; Shift+click to add to selection; Cmd/Ctrl+click to toggle."

"Timeline Panel→drop keyframe": "Adds a keyframe for this property at the current time, capturing its current value."

"Timeline Panel→graph mode": "Toggles this property's keyframe track between the value graph and the standard keyframe view."

"Timeline Panel→previous keyframe": "Snaps the playhead to this property's next keyframe to the left (loops to the last keyframe when already past the first)."

"Timeline Panel→next keyframe": "Snaps the playhead to this property's next keyframe to the right (loops to the first keyframe when already past the last)."

"Publishing Analysis→Published Project": "The published project to analyze."

"Publishing Analysis→Asset Configuration": "Which asset configuration to analyze from the published project."

"Publishing Analysis→Asset Summary": "Show a summary of the number of assets that will be loaded by the published project."

"Publishing Analysis→Graphic Summary": "Show all graphics the published project will load, organized by loading tier."

"Lock Construct": "Toggles the construct lock. When locked, this panel will not follow automatic timeline changes made in the Timeline panel. This panel's own Construct/Timeline selectors still work."

"Assets Panel→asset search": "Use this field to search for a particular asset by name. Multiple space-separated keywords are each scored independently, and only the assets matching them are listed."

"Assets Panel→"+_settingName: _tip

"Assets Panel→"+_settingName+" inheritance": "Whether this setting takes its value from the directory above rather than holding one of its own. Turning inheritance off starts from the inherited value."

"Live View Panel→run": "Runs the project's code, or resumes the project when it is paused. Set runProjectOnOpen in Application Settings to run projects as soon as they open."

"Live View Panel→stop": "Stops the project's code."

"Live View Panel→camera": "Choose which Camera to view through. 'Target' shows the live project, and any other Camera shows that Camera's view for inspection."

"Live View Panel→checkerboard": "Toggles a checkerboard behind the Camera's view, so its transparent areas are easy to see. Only available while viewing a Camera other than 'Target'."

"project stopped→run": "Runs the project's code. Set runProjectOnOpen in Application Settings to run projects as soon as they open."

"Project stopped→see the console...": "Opens the developer tools to the console, where the error that stopped the project is shown."

"Particle System Panel→Definition": "The ParticleSystemDefinition being edited.  If a ParticleSystem is currently selected, changing this will also change the ParticleSystemDefinition used by the ParticleSystem."

"Particle System Panel→create new": "Creates a new ParticleSystemDefinition based off of an existing or one of Incisor's embedded templates."

"Particle System Panel→Emission": "The collection of parameters to control way particles are emitted."

"Particle System Panel→Emission→particleLifetime": "The amount after of time after being emitted that each particle will last."

"Particle System Panel→Emission→particleLifetime→value": "The base value for particleLifetime."

"Particle System Panel→Emission→particleLifetime→randomness": "The lifetime for each particle will be the base value +/- a random number between 0 and this amount."

"Particle System Panel→Emission→emissionTimeRandomness": "A per particle perturbation of that particle's emission time. By default, particles are emitted at evenly spaced intervals. A random number between 0 and this value will added to the default emission time of each particle."

"Particle System Panel→Emission→emissionDuration": "The length of time over which to emit particles. Set to 0 to emit particles forever."

"Particle System Panel→Emission→emitterShape": "The shape of the area in which a particle may be created."

"Particle System Panel→Emission→emitterShape→emitterShape": "The shape of the area in which a particle may be created. 'point' emits particles from a point with no dimensions.  'rectangle' emits particles from points within a rectangle with dimensions determined by emitterShapeDimensions.  'circleUniform' emits particles from points uniformly distributed within a circle.  This circle can be made oblong using emitterShapeDimensions.  'circleCenter' emits particles from points distributed within a circle.  This distribution is biased to be more dense toward the center, which is more efficent that uniform distrubition. This circle can be made oblong using emitterShapeDimensions. 'custom' uses the contents to of customEmitterShapeExpression to determine the emission points."

"Particle System Panel→Emission→emitterShape→customEmitterShapeExpression": "This expression will be used to choose an initial position for each emitted particle. Note that precomputed random numbers are available as vec4s named rand0 through rand5, though typically rand2.x and rand2.y are used in this context. The value of emitterShapeDimensions is available in a vec2 by the same name."

"Particle System Panel→Emission→emitterShape→customEmitterShapeExpression": "This expression will be used to choose an initial position for each emitted particle. Note that precomputed random numbers are available as vec4s named rand0 through rand5, though typically rand2.x and rand2.y are used in this context."

"Particle System Panel→Emission→particlePoolCount": "The total number of particles that are required by this ParticleSystemDefinition. Because particles that have 'died' can often be reused as later particles, this number will often be less than the total number seen throughout the ParticleSystem's playback."

"Particle System Panel→Physics": "The collection of parameters to control the way particles are affected by physics."

"Particle System Panel→ageRemap": "An expression used to remap particle age values to a new value."

"Particle System Panel→ageRemap": "An expression used to remap particle age values to a new value."

"Particle System Panel→Rotation": "The collection of parameters to control the way particles rotate."

"Particle System Panel→Wiggle": "The collection of parameters to control the way particles randomly oscillate around the position determined by their physics parameters."

"Particle System Panel→Scale": "The collection of parameters to control the scale of each particle."

"Particle System Panel→Color/Alpha": "The collection of parameters to control the color and transparency of each particle."

"Particle System Panel→Randomness": "The collection of parameters to control the generation of per-particle randomness."

"Particle System Panel→randomizeOnPlay": "When enabled, a new randomSeed will be chosen each time the ParticleSystem instance is played from the beginning."

"Particle System Panel→randomSeed": "Changing this generates new values for all per particle randomness. This is the default value of the material's particleSystemRandomSeed EffectController for all ParticleSystem instances using this ParticleSystemDefinition."

"Particle System Panel→particleDrawOrderSeed": "When multiple GraphicAssets are used as particles, the draw order of all the particles is shuffled to randomly interleave the particles. This seed will deterministically alter the outcome of this shuffle, creating a different draw order of the particles. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization. To randomize the behavior of a ParticleSystem without this costly rebuild, see randomSeed."

"Particle System Panel→" + _parent.titleTextBox.string + "→" + _labelText: _toolTip

"Particle System Panel→" + _parent.titleTextBox.string + "→" + _labelText + "→type": "The data type for this parameter may be set to Constant, Expression, or Ramp.  Constant values do not change.  Expressions are used to write GLSL code defining the value.  Ramps define multiple values that to be mixed according to particle age or particle emission time."

"Particle System Panel→" + _parent.titleTextBox.string + "→" + _labelText + "→" + _randomnessLabel: _randomnessTip

"Particle System Panel→" + _parent.titleTextBox.string + "→" + _labelText + "→" + _randomnessLabel + "→type": "The data type for this parameter may be set to Constant, Expression, or Ramp.  Constant values do not change.  Expressions are used to write GLSL code defining the value.  Ramps define multiple values that to be mixed according to particle age or particle emission time."

"Hierarchy Panel→select Scene": "Select a Scene to inspect its hierarchy."

"Hierarchy Panel→object search": "Use this field to search for a particular object in this Scene by name."

"Hierarchy Panel→expand/collapse all": "Use this button to expand or collapse all objects in the Scene."

"Hierarchy Panel→reveal selected": "Click this button to reveal currently selected items within the Hierarchy panel."

"Inspected Object Quantity": "The Hierarchy panel is actively inspecting more than 1000 objects, which can affect performance of the inspector. Collapse objects to reduce the number of inspected objects."

"Hierarchy Panel→show disabled button": "Button that toggles whether or not disabled objects are displayed within the Hierarchy panel."

"Hierarchy Panel→show disabled": "Choose whether to show disabled objects."

"Lock Selection": "Toggles the selection lock. When locked, the panel's selection will not change as you click different objects in the scene."

"Template Library→search": "Filters the library down to matching items. While a search is underway the folder structure is set aside and only items are listed, so a name is enough to find something without knowing where it lives. Clear the field to return to the folders."

"Example Code→copy": "Copies the example code above to the clipboard, ready to paste into a code asset. The example is written against the item's default name, so a copy added to the project under a different name needs the name changed to match."

"Manage Timelines→default:": "Makes this the Timeline that controls the Construct - a new instance gives it full weight and influence."

"Select GraphicAsset→maintain current EffectNodes": "Every GraphicAsset carries EffectNode presets, and taking a new GraphicAsset normally replaces the GraphicObject's EffectNodes with that asset's presets. Check this to keep the EffectNodes already on the object instead, which is what you want when the object has been given effects of its own that the new asset's presets know nothing about. Leave it unchecked to adopt the new asset's presets wholesale. This resets to unchecked each time the window opens, since adopting the presets is the ordinary case."

"Select GraphicAsset→rename GraphicObject": "Renames the GraphicObject to match the GraphicAsset it is being given, so an object that shows a particular graphic is named for it. Checked by default, and applied to every object when several are selected at once - which does leave those objects sharing a name, so uncheck it when the names already mean something. This option is unavailable where the graphic does not stand for the object's identity: a SpriteSetter's keyGraphicAsset is one of many graphics it cycles through, and a ParticleSystem's graphic belongs to a ParticleInfo rather than to any one object."

"SpineImportNotes->DontShowAgain": "Hidden for this construct until a future import reports a new note."

"": ""

"": ""

"": ""

"": ""

"": ""

"": ""

"Object Panel→EffectControllers": "Effect Controllers drive shader parameters on the EffectNodes applied to this object's materials. EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. The EffectController settings on each SceneObject apply to its own Material effects as well as those of its descendants additively or multiplicatively."

"Object Panel→type": "The type of the currently selected SceneObject(s). For a single selection, the type icon and name are shown, followed by the full inherited type chain in parentheses - from most specific to most general. For a multi-selection, each distinct type is listed with the number of selected objects of that type in parentheses."

"Object Panel→SymbolReel Info": "The SymbolReel Info section exposes the properties of SymbolReel scene objects. A SymbolReel owns a set of symbol objects and moves them along a reel path to create a spinning reel. The class used to build those symbol objects is supplied in code through 'symbolClassDefinition' and is deliberately not settable here - until project code supplies one, a built-in placeholder symbol is used so the reel is visible while you lay it out. This section only appears when one or more selected objects are of type SymbolReel."

"SymbolReel Info→spin reel": "Spins the selected SymbolReel here in the editor, so the symbol path, windup and bounce can be watched in motion rather than read off their curves. Press once to start the spin - it brings itself gracefully to rest after a second and a half, or press again to slam it onto its target immediately. The reel is targeted at the initialReelData below, so it lands back on the symbols it started from and the preview reads as a round trip. The reel is granted immunity to the editor's pause while it is being previewed."

"SymbolReel Info→state": "Which point of the spin the selected reel is at, read straight off its 'reelState'. A reel at rest reads 'stopped', and a spin passes through 'windup', 'spinFree', 'stopping', 'stopImminent' and 'bounce' before returning to it. This is a readout rather than a setting - reelState is driven by the reel itself, through 'beginSpin', 'beginStop' and 'slam'. Several properties here are only accepted while the reel is 'stopped', so this is what to check when one of them refuses a change. With more than one reel selected it shows their shared state, or a dash while they differ."

"SymbolReel Info→defaultSymbolType": "Which built-in stand-in symbol this reel builds while project code has not supplied a symbolClassDefinition. 'TextBox' draws a grey card showing the symbol string itself, which reads clearly while laying a reel out. 'GraphicObject' draws the GraphicAsset whose name matches the symbol, falling back to the WhiteBox for a symbol naming no asset in this project - use it once the symbol names line up with real assets. This has no effect once project code supplies its own symbol class, which is the normal arrangement for a finished game. Changing it disposes the existing symbol objects and rebuilds them."

"SymbolReel Info→numTopBufferSymbols": "The number of symbol objects populated above the main visible symbols, giving the reel somewhere to bring new symbols in from. Since the symbol path is fully customizable these buffer symbols are not necessarily above the main symbols. Changing this disposes the existing symbol objects and rebuilds them, and is only permitted while the reelState is 'stopped'."

"SymbolReel Info→numMainSymbols": "The number of symbol objects meant to be the main, visible symbols on this SymbolReel. Changing this disposes the existing symbol objects and rebuilds them, so any symbol state is lost. The rebuild is deferred, so several count changes in a row cost only one rebuild. This can only be changed while the reel's reelState is 'stopped' - a change attempted mid-spin is refused and reported rather than applied."

"SymbolReel Info→numBottomBufferSymbols": "The number of symbol objects populated below the main visible symbols, giving the reel somewhere to carry symbols out to. Since the symbol path is fully customizable these buffer symbols are not necessarily below the main symbols. Changing this disposes the existing symbol objects and rebuilds them, and is only permitted while the reelState is 'stopped'."

"SymbolReel Info→spinSpeed": "The rate of motion for each symbol object during the spin, measured in symbol slots per sixtieth of a second - so a value of 1 moves each symbol one full symbol position every sixtieth of a second. Negative values travel toward increasing pathPosition, which for the default symbol path reads as spinning downward. The reel advances on real time rather than per tick, so this rate holds at any fixedUpdate rate."

"SymbolReel Info→pathPositionSnap": "The grid that Keyframe positions snap onto across every KeyframedValue this SymbolReel owns - the symbol path values as well as the windup and bounce curves. The reel holds this single value for all of them, in the same way that a Timeline holds one timeSnap for its AnimatedProperties, so it does not need setting per curve. Lower it when a curve needs finer detail than the default of 0.01. Setting it to zero or leaving it empty returns it to that default."

"SymbolReel Info→initialReelData": "The authored starting symbols for this reel, written as a comma-separated list. These are the symbols the reel displays when it builds, which is what makes a reel readable while you lay it out here - without them the placeholder symbols come up blank. The first 'numSymbols' entries are the ones actually shown, and any position without an entry has undefined handed to its symbol object's 'setSymbol' function. This list also seeds the working reel data that each spin adds to, unless project code has taken over supplying the reel strip itself. This list travels with the Construct - the full working reel strip never does."

"SymbolReel Info→windup": "The motion the reel makes just before the main portion of the spin, as it winds up. The curve below is sampled over a progress range of 0 to 1, where 1 is the full windupDuration, and its value is a pathPosition offset applied to every symbol at once - so a curve peaking at 0.5 pulls the whole reel back half a symbol position before it releases."

"windup→windupDuration": "How long, in seconds, the reel spends in the 'windup' state before it moves on to spinning freely. This is the time that the windup curve's 0 to 1 progress range is stretched across. Staggering this slightly across a row of reels is a common way to make them feel less mechanical."

"windup→windupMagnitude": "A plain multiplier applied to whatever the windup curve returns. The shape of the motion lives in the curve, so this exists to scale that shape without editing it - which is what makes it useful to drive from code at runtime, for instance to exaggerate the windup on a teaser spin."

"SymbolReel Info→bounce": "The recoil the reel makes as it settles, simulating a physical reel coming to rest. The curve below is sampled over a progress range of 0 to 1, where 1 is the full bounceDuration, and its value is a pathPosition offset applied to every symbol at once. The reel's symbols are already on their exact resting positions when the bounce begins, so this motion is purely visual and always returns to zero."

"bounce→bounceDuration": "How long, in seconds, the reel spends in the 'bounce' state before its reelState becomes 'stopped'. This is the time that the bounce curve's 0 to 1 progress range is stretched across. The reel is not considered stopped until this has elapsed, so game logic waiting on the 'stopped' state waits out this duration."

"bounce→bounceMagnitude": "A plain multiplier applied to whatever the bounce curve returns. The shape of the recoil lives in the curve, so this exists to scale that shape without editing it - which is what makes it useful to drive from code at runtime, for instance to land a big win harder than an ordinary stop."

"SymbolReel Info→symbol path": "How each symbol object is arranged as it travels along the reel. Every entry here keyframes one property of a symbol against that symbol's pathPosition, which is measured in symbol slots - so a Keyframe at 0 describes the first main visible position, 1 the next, and -1 the top buffer position. A new reel starts with a 'position.y' entry describing a straight vertical drop and a 'colorMultiply.alpha' entry fading the symbols out at the wrap points, and further entries can be added for anything a plain property path can reach, such as scale.x or rotation.z. These entries are ignored entirely while project code has set a symbol path override callback on the reel."

"symbol path→property path": "The property of each symbol object that this entry drives, written relative to a symbol object in dot notation. The KeyframedValue below is sampled at every symbol's pathPosition and written straight to this property, so only paths a plain property walk can reach are supported - where more is needed, expose a property with a getter and setter on the symbol class and drive that instead. Renaming moves the curve onto a different property with its Keyframes intact, and a name already driven by this reel is refused and reverted."

"symbol path→unresolved path": "This property path does not currently reach a settable property on the symbol objects, so the reel is leaving it alone rather than writing to it. Its Keyframes are kept exactly as they are, and it begins driving the symbols the moment the path names a property the symbol class actually has - so a curve can be authored here ahead of the property being implemented in code. This also shows for a path naming a whole object, such as 'position' in place of 'position.y', since writing a number over one of those would break the symbol."

"symbol path→reset keyframes": "Redraws this property's curve from scratch, discarding whatever Keyframes it currently holds. The fields here are inputs to that redraw rather than a reading of the curve, so they keep whatever was last typed into them and never report back what the curve holds now."

"symbol path→linear": "Lays down one handleless Keyframe per resting symbol position, each holding 'start' plus its own pathPosition times 'delta', extrapolating beyond both ends. This is the shape the reel gives 'position.y' when it first builds, where 'delta' is the vertical distance between neighbouring symbols."

"symbol path→fade in/out": "Lays down four Keyframes holding 1 across the resting range and 0 at each wrap point, so a symbol is invisible at the moment it takes on a new symbol. 'fadeTime' is how many symbol positions the ramp at each end covers. This is the shape the reel gives 'colorMultiply.alpha' when it first builds."

"Material Info→EffectNodes": "The EffectNodes applied to this Material. EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. EffectNodes can be added, removed, and rearranged by dragging. The order determines the sequence in which visual effects are applied to the Material."

"Material Info→EffectNodes→set EffectNodes": "Replaces all EffectNodes on this material with a chosen set."

"Material Info→EffectNodes→add EffectNodes": "Adds a chosen set of EffectNodes to this material without removing their existing ones."

"": ""

"Add EffectNode": "Adds a new EffectNode to this Material, inserted directly below this one."

"Material Info→EffectNodes→"+_key: _en.description || "An EffectNode applied to this Material."

"Material Info→EffectNodes→"+_key: _addEn.description || "An EffectNode applied to this Material."

"Object Panel→GraphicObject Info": "Properties common to all GraphicObjects: visibility, graphic asset, layer, sub-layer, frustum culling, masking, geometry modifiers, and sprite animation."

"GraphicObject Info→visible": "Whether the object is rendered. Unlike 'enabled', visibility does not affect descendants."

"GraphicObject Info→graphicAsset": "The graphic asset (texture or sprite sheet) assigned to this GraphicObject. Changing this value updates the Geometry, Textures, and other settings to reflect those of the new asset. Click to open the asset browser."

"GraphicObject Info→subLayer": "Fine-grained draw order within the same layer. Range: -1 to 1. Lower values render behind higher values."

"GraphicObject Info→layer": "The rendering layer that determines draw order relative to other objects. Objects on higher layers render in front."

"GraphicObject Info→frustumCulling": "When enabled, the object is skipped during rendering if it falls outside the camera's view (its frustum). This defaults to true, but should be disabled when an EffectNode is deforming the object's geometry on the GPU - in that case the object's scene position may indicate it should be culled while its actual deformed geometry is still in view and should still be rendered."

"GraphicObject Info→masking": "Settings that control whether this GraphicObject acts as a mask or is clipped by another object's mask."

"masking→enabled": "Activates masking for this GraphicObject. When false, the object renders normally regardless of any mask settings."

"masking→type": "'mask' means this object defines the masking shape. 'masked' means this object is clipped by a mask object."

"masking→invert": "Reverses the mask effect: the object renders outside the mask shape rather than inside it."

"masking→maskGroups": "In overlapping masking mode, mask groups link specific masks to specific masked objects. Check a group to include this object in it."

"maskGroups→manage MaskGroups": "Opens the Manage MaskGroups popup to add, remove, or rename MaskGroups in the project."

"GraphicObject Info→geometryMods": "Geometry modifiers that alter the rendered shape of the GraphicObject without affecting its scene transform."

"geometryMods→add geometry mod": "Adds a geometry modifier to the selected GraphicObject. PivotPointAdjuster offsets the visual pivot; GraphicExpander enables nine-slice stretching."

"add geometry mod→PivotPointAdjuster": "Adds a PivotPointAdjuster, which lets you offset the object's visual pivot independently of its transform origin."

"add geometry mod→GraphicExpander": "Adds a GraphicExpander, which stretches the nine-slice regions of the graphic asset to fill a specified expanded area."

"geometryMods→PivotPointAdjuster": "Offsets (or fully transforms) a GraphicObject's geometry locally, independently of its scene transform. Best used as a one-time adjustment - animating its values can cause performance issues, as each change sends updated geometry to the GPU."

"PivotPointAdjuster→position": "The position offset (x, y, z) applied to the graphic relative to the SceneObject's transform origin."

"PivotPointAdjuster→scale": "The scale (x, y, z) applied to the graphic by the PivotPointAdjuster, independent of the SceneObject's own scale."

"PivotPointAdjuster→rotation": "The rotation (x, y, z) in degrees applied to the graphic by the PivotPointAdjuster."

"PivotPointAdjuster→remove PivotPointAdjuster": "Removes the PivotPointAdjuster from the selected GraphicObject(s), restoring default pivot behavior."

"geometryMods→GraphicExpander": "Stretches the nine-slice regions of the graphic asset to fill an expanded area, allowing scalable panel-style graphics."

"GraphicExpander→symmetric": "When enabled, expandable and expanded areas are defined by a single width/height pair. When disabled, each edge is set independently."

"GraphicExpander→expandableWidth": "The width of the nine-slice center region that gets stretched when the graphic expands."

"GraphicExpander→expandableHeight": "The height of the nine-slice center region that gets stretched when the graphic expands."

"GraphicExpander→expandedWidth": "The total width the graphic should expand to fill."

"GraphicExpander→expandedHeight": "The total height the graphic should expand to fill."

"GraphicExpander→expandableAreaLeft": "Left edge of the nine-slice expandable region."

"GraphicExpander→expandableAreaRight": "Right edge of the nine-slice expandable region."

"GraphicExpander→expandableAreaTop": "Top edge of the nine-slice expandable region."

"GraphicExpander→expandableAreaBottom": "Bottom edge of the nine-slice expandable region."

"GraphicExpander→expandedAreaLeft": "Left boundary of the expanded area the graphic should fill."

"GraphicExpander→expandedAreaRight": "Right boundary of the expanded area the graphic should fill."

"GraphicExpander→expandedAreaTop": "Top boundary of the expanded area the graphic should fill."

"GraphicExpander→expandedAreaBottom": "Bottom boundary of the expanded area the graphic should fill."

"GraphicExpander→remove GraphicExpander": "Removes the GraphicExpander from the selected GraphicObject(s)."

"GraphicObject Info→spriteSetter": "The SpriteSetter drives animated sprite playback on a GraphicObject, cycling through frames of a sprite sheet based on a normalized value."

"spriteSetter→add SpriteSetter": "Adds a SpriteSetter to the selected GraphicObject(s) to enable sprite sheet animation."

"spriteSetter→keyGraphicAsset": "The sprite sheet graphic asset used to define the animation frames. Click to open the asset browser."

"spriteSetter→playbackRate": "The speed at which the sprite animation plays back, in frames per second."

"spriteSetter→autoplayMode": "Controls automatic playback: 'none' requires manual control, 'loop' repeats continuously, 'once' plays through and stops."

"spriteSetter→initialValue": "The starting frame value (0–100) for the sprite animation when first activated."

"spriteSetter→remove SpriteSetter": "Removes the SpriteSetter from the selected GraphicObject(s)."

"Object Panel→CustomAddOn Info": "CustomAddOns are project-defined, customizable add-ons that extend SceneObjects with additional behaviors and data. Their registered property values are adjustable here, savable within Constructs, and animatable in Construct Timelines. Applied CustomAddOns can be added, removed, and reordered. Examples can be found and added to the project via the Template Library."

"CustomAddOn Info→add CustomAddOn": "Adds a project-defined CustomAddOn to the selected SceneObject(s). CustomAddOn property values are adjustable, savable in Constructs, and animatable in Construct Timelines. Only add-ons compatible with the selected object type and not already applied are available. Examples can be found and added to the project via the Template Library."

"": ""

"skins:→checkbox": "Applies this skin to the skeleton."

"Object Panel→SpineBone Info": "Displays the slot and attachment structure of the selected SpineBone."

"SpineBone Info→inheritScale": "Amount by which this bone inherits scale from its parent. Range: 0–1."

"SpineBone Info→inheritRotation": "Amount by which this bone inherits rotation from its parent. Range: 0–1."

"SpineBone Info→inheritReflection": "Amount by which this bone inherits reflection from its parent. Range: 0–1."

"SpineBone Info→shearX": "Horizontal shear applied to this bone, in degrees."

"SpineBone Info→shearY": "Vertical shear applied to this bone, in degrees."

"SpineBone Info→slots": "The slots belonging to this SpineBone and their current attachment states."

"SpineBone Info→skins:": "The skins of this skeleton. Check a skin to apply it, and drag to set the order skins are applied in."

"Object Panel→SceneObject Info": "Properties common to all SceneObjects: name, enabled state, position, scale, and rotation."

"SceneObject Info→name": "The name of the currently selected SceneObject(s). Used primarily for reference within the GUI and in code."

"SceneObject Info→enabled": "The enabled state of the currently selected SceneObject(s). When false, the object and all of its descendants are excluded from rendering."

"SceneObject Info→position": "The position (x, y, z) of the selected SceneObject(s) relative to the parent's coordinate space."

"SceneObject Info→scale": "The scale (x, y, z) of the selected SceneObject(s). Values are multiplicative, so a scale of 2 makes the object twice as large along that axis."

"SceneObject Info→rotation": "The rotation (x, y, z) of the selected SceneObject(s) in degrees."

"actions→Set EffectNodes of descendants": "Replaces the EffectNodes on all descendants of the selected object(s) with a chosen set of EffectNodes."

"actions→Add EffectNodes to descendants": "Adds a chosen set of EffectNodes to all descendants of the selected object(s), without removing existing ones."

"actions→Set Layers of descendants": "Sets the layer of all GraphicObject descendants of the selected object(s) to a chosen layer."

"actions→Log object(s) to console": "Logs the currently selected SceneObject(s) to the browser console for inspection."

"Set Layers of descendants→include selected parents": "When enabled, the layer change also applies to the selected parent objects themselves, not just their descendants."

"SceneObject Info→actions": "Batch operations that can be applied to the selected SceneObject(s) and their descendants, such as setting EffectNodes or Layers."

"Object Panel→CustomObject Info": "CustomObjects are project-defined SceneObject types that extend a base SceneObject type with custom behaviors and registered properties. Their property values are adjustable here, savable within Constructs, and animatable in Construct Timelines. Examples can be found and added to the project via the Template Library."

"": ""

"CustomObject Info→baseType": "The SceneObject base type that this CustomObject extends."

"Object Panel→Material Info": "Materials control how the visual surfaces defined in a Geometry are configured and ultimately rendered by WebGL. Each material's EffectNodes, EffectControllers, and blending mode are configurable here."

"Material Info→Material": "Controls the EffectNodes, EffectControllers, and blending mode for this material slot on the selected GraphicObject(s)."

"Material Info→blendingMode": "The blending mode determines how this material composites with what is drawn behind it. 'standard' uses normal alpha blending; 'add' adds this material's color on top of what's behind it, which is useful for glow and fire effects; 'multiply' multiplies this material's color with what's behind it."

"Material Info→EffectControllers": "The EffectControllers driving parameters on the EffectNodes applied to this Material."

"Material Info→draw settings": "The settings that determine how this Material's fragments are written to the frame and depth buffers, and which side of each triangle is drawn at all."

"draw settings→faceCulling": "Names which side of each triangle is culled. 'back' drops the triangles facing away from the camera, 'front' drops the ones facing it, and 'none' draws both."

"draw settings→depthTest": "Tests each fragment against the depths already in the depth buffer, so that only the closest one is drawn. This is useful for geometries with a full 3D shape, such as those from OBJs."

"draw settings→depthWrite": "Writes the depth of each fragment into the depth buffer, allowing this Material to occlude the things drawn after it."

"draw settings→transparent": "Blends each fragment with what is already in the frame buffer rather than replacing it, and draws this Material after the opaque ones. This is independent of depthWrite and depthTest."

"Object Panel→Camera Info": "Properties common to all cameras: view depth range, adaptive sizing mode, precomp target dimensions, cursor interactivity, background color, and auto-render."

"Camera Info→viewNear": "The near clipping plane depth. Objects closer to the camera than this value are not rendered."

"Camera Info→viewFar": "The far clipping plane depth. Objects farther from the camera than this value are not rendered."

"Camera Info→adaptiveCameraMode": "Determines how the camera adapts its view when the canvas aspect ratio or size changes. 'none' keeps the core view fixed; 'maximizeSafeZone' expands the view to fill the canvas while keeping the core view fully visible; 'unitsMatchPixels' (orthographic only) scales so one unit equals one pixel; 'preserveViewAngleVertical' and 'preserveViewAngleHorizontal' (perspective only) lock the specified axis while adjusting the other."

"Camera Info→constructPrecompTargetWidth": "If this camera is the designated PrecompCamera for a Construct, this value sets the width of the associated RenderTarget."

"Camera Info→constructPrecompTargetHeight": "If this camera is the designated PrecompCamera for a Construct, this value sets the height of the associated RenderTarget."

"Camera Info→cursorInteractive": "When enabled, this camera processes cursor events for objects in its view."

"Camera Info→backgroundColor": "The background color rendered behind all objects in this camera's view."

"Camera Info→autoRender": "When enabled, this camera renders its scene automatically each frame."

"Camera Info→coreViewAngleHorizontal": "The initial horizontal field of view in degrees before any adaptiveCameraMode adjustments."

"Camera Info→coreViewAngleVertical": "The initial vertical field of view in degrees before any adaptiveCameraMode adjustments."

"Camera Info→coreViewWidth": "The initial view width in world units before any adaptiveCameraMode adjustments."

"Camera Info→coreViewHeight": "The initial view height in world units before any adaptiveCameraMode adjustments."

"SceneObject Info→Scene Path": "Displays the full ancestor chain of the currently selected scene object, from the scene root down to the selected object itself. Each entry is a clickable button - click to select that ancestor; Shift+click to add it to the current selection; Cmd/Ctrl+click to toggle; right-click to open the full scene-object context menu for that ancestor. Entries are indented to reflect their depth in the hierarchy. Only visible when exactly one object is selected."

"Object Panel→ParticleSystem Info": "The ParticleSystem Info section exposes the properties of ParticleSystem scene objects. A ParticleSystem plays back a particle effect defined by its linked ParticleSystemDefinition; its PlaybackController governs playback state and timing. This section only appears when one or more selected objects are of type ParticleSystem."

"ParticleSystem Info→particleSystemDefinition": "Selects the ParticleSystemDefinition that drives this particle effect. Options are populated from all definitions registered in the current project. Changing the definition swaps the emission rules, particle lifetimes, motion, and visual settings at runtime without resetting the PlaybackController state or autoplayMode. To create or edit a definition, open the Particle System panel."

"ParticleSystem Info→play / pause": "Plays the particle system from its current time position. While playing, this button becomes a pause button - click again to suspend playback without resetting the time. Playback runs between the startTime and endTime of the PlaybackController."

"ParticleSystem Info→play once / pause": "Plays the particle system once with lazyStop enabled, stopping automatically when the endTime is reached. While playing in this mode the button becomes a pause button. Use this to preview a single burst of the effect without looping."

"ParticleSystem Info→stop": "Stops playback immediately and resets the particle system's current time to the startTime of the PlaybackController."

"ParticleSystem Info→playbackRate": "Multiplies the rate at which the PlaybackController's time advances, so 2 plays the effect at twice speed and .5 at half. Negative values run the particle system backwards. This is the PlaybackController's own rate - any SpeedControls affecting it multiply on top of this value."

"ParticleSystem Info→autoplayMode": "Controls whether the particle system starts playing automatically at runtime. 'none' - no automatic playback; the PlaybackController must be triggered manually. 'loop' - begins playing immediately when the object becomes active and repeats continuously from the startTime each time the endTime is reached. 'once' - begins playing immediately and stops at the endTime without repeating. This property lives on the PlaybackController, not the ParticleSystem itself."

"Object Panel→Construct Info": "Timelines defined on this Construct. Each timeline has a weight (blend contribution) and, for non-NeutralState timelines, a playback controller."

"playOnceAndTakeWeight": "Takes weight from all other timelines and plays this timeline from the beginning once."

"viewTimeline": "Connects all open, unlocked Timeline panels to this live, running timeline instance (a temporary view — no changes are saved to the definition)."

"takeWeight": "Animates this timeline's weight to 1 while reducing all other timelines' weights to 0, over 1 second. Hold Shift for 0.25s, or "+(nc.mainModifierKey==="Meta"?"Cmd":"Ctrl")+" for 5s."

"Object Panel→Text Info": "Properties common to all TextBox and TextAssembly objects: the displayed string, phrase ID for localization, layout constraints, text format settings, and the character material's visual effects."

"Text Info→string": "The string displayed by this text object."

"Text Info→phraseID": "Links this text object to a localized string from the ProjectTranscript. When set, the string is automatically updated to reflect the project's current language setting. Phrases are defined in the ProjectTranscript."

"Text Info→add to transcript": "Creates a new phrase in the ProjectTranscript using this object's current string and links the text object to it via phraseID. Only available when no phraseID is assigned."

"Text Info→horizontalJustification": "How text is aligned horizontally within the box. Only has an effect when the box width is wider than the text."

"Text Info→verticalJustification": "How text is aligned vertically within the box. Only has an effect when the box height is taller than the text."

"Text Info→boxWidth": "Defines the width of the area the text is confined to. A value of 0 means no width restriction."

"Text Info→boxHeight": "Defines the height of the area the text is confined to. A value of 0 means no height restriction."

"Text Info→wrapToFit": "When enabled, newlines are automatically inserted to wrap text within the box width."

"Text Info→scaleToFit": "When enabled, the text is scaled down to fit within the box width and height."

"Text Info→baselinePosition": "The vertical position of the baseline within each line of text. 0 is the very bottom of the line; 1 is the top."

"Text Info→pivotPoint": "The anchor point of the text object relative to its center. (0.5, 0.5) corresponds to the top-left corner; (-0.5, -0.5) corresponds to the bottom-right corner."

"Text Info→isTrimmed": "When enabled, the TextBox geometry is reduced to remove excess transparent space around the text."

"Text Info→editingMode": "The current text editing state of this TextBox - determines whether it is idle or in an active editing state."

"Text Info→tabEndEditing": "When enabled, pressing Tab while editing this TextBox commits the edits and ends editing. When disabled, Tab inserts spaces."

"Text Info→returnEndsEditing": "When enabled, pressing Return while editing this TextBox commits the edits and ends editing. When disabled, Return inserts a newline."

"Text Info→numHorizontalGridSegments": "The number of horizontal geometry subdivisions in the TextBox mesh. Increase this for smoother vertex-deforming EffectNodes."

"Text Info→numVerticalGridSegments": "The number of vertical geometry subdivisions in the TextBox mesh. Increase this for smoother vertex-deforming EffectNodes."

"Text Info→Text Format": "Settings for the font, character scale, kerning, vertical shift, and line height of the selected text object(s). Also contains the CharacterMaterial, which controls visual effects on individual characters."

"Text Format→fontName": "The font used to render this text."

"Text Format→characterScaleX": "The horizontal scale applied to each character in this text."

"Text Format→characterScaleY": "The vertical scale applied to each character in this text."

"Text Format→kerning": "The spacing between characters. The value is relative to the font's 'characterWidth' value, which defaults to the width of the null character (Char0) but can be changed in the font definitions section of the project settings."

"Text Format→verticalShift": "A vertical offset applied to the text characters. The value is relative to the font's 'font height', which is defined in the ProjectSettings."

"Text Format→lineHeightMultiplier": "Scales the height of each line. A value of 1 corresponds to the font's native line height."

"Text Format→CharacterMaterial": "Controls the visual effects applied to each individual character in this text object. EffectNodes and EffectControllers can be assigned here just like on any other material."

"Text Format→CharacterMaterial→EffectControllers": "The EffectControllers driving parameters on the EffectNodes applied to the CharacterMaterial."

"Particle System Panel→Particles": "The collection of data specific to each type of particle."

"Particle System Panel→" + this._particleStacks[i].titleTextBox.string: "The data for this particle.  If additional particles are added, the GraphicAssets must be in the same spritesheet."

"Particle System Panel→" + this._particleStacks[i].titleTextBox.string + "→graphicAsset": "The GraphicAsset to add for this particle."

"Particle System Panel→" + this._particleStacks[i].titleTextBox.string + "→particlesPerSecond": "The number of this particle to add every second of 'emissionDuration'."

"Particle System Panel→" + this._particleStacks[i].titleTextBox.string + "→scale": "The scale to apply to each of these particles. Useful for reusing assets with mismatched scales in the same particle system."

"Particle System Panel→" + this._sectionName + "→" + this._label + "→expression": this._expressionToolTip

"Particle System Panel→" + this._sectionName + "→" + this._label + "→ramp→interpolationType": "When a Ramp is sampled at a given time, the values of the surrounding keyframes are interpolated according to this setting.  'smoothStep' eases away from the components of the first keyframe, then changes quickly more quickly, then eases into the components of the second keyframe.  'catmullRom' applies Catmull-Rom smoothing based on the surrounding 4 keyframes.  'linear' linearly interpolates between the components of the surrounding keyframes.  "

"Particle System Panel→" + this._sectionName + "→" + this._label + "→ramp→inputType": "The input type used to evaluate the Ramp. 'ageRatio' uses the particle's age, mapped to the range [0 - 1].  'emissionTime' uses the time at which the particle was emitted, mapped from the range [0 - inputMaximum] to [0 - 1]."

"Particle System Panel→" + this._sectionName + "→" + this._label + "→ramp→inputMaximum": "When inputType is set to 'emissionTime', this is the emission time at which the Ramp ends."

"Particle System Panel→" + this._sectionName + "→" + this._label + "→ramp→Add Keyframe": "Adds a new keyframe to the Ramp."

"Particle System Panel→" + this._sectionName + "→" + this._label + "→ramp→Remove Keyframe": "Removes the selected keyframe from the Ramp."

"Particle System Panel→" + this._sectionName + "→" + this._label + "→constant": this._constantToolTip

"Particle System Panel→" + this._sectionName + "→" + this._label + "→Constant": this._constantToolTip

"Project Settings→fontDefinitions→fontName": "The name of the font this definition applies to."

"Project Settings→fontDefinitions→kerningAdjustment": "Amount to add or subtract to the kerning of all characters within this font. This value is expressed as a multiple of this font's 'characterWidth' value."

"Project Settings→fontDefinitions→lineHeight": "The height of a line of text that uses this font, expressed in world units."

"Project Settings→fontDefinitions→characterWidth": "The width of the 'key' character for this font. This value is what is used for the width of a space in this font. This value also used as a basis for this font's kerning and other spacing related configurations."

"Project Settings→fontDefinitions→alwaysIncludeTheseCharacters": "A list of unicode characters that will always be included with this font, regardless of the current language."

"Project Settings→project info": ""

"Project Settings→latestIncisorUsed": "The latest version of Incisor that was used to make any changes to this project."

"Project Settings→usingTypescript": "Read-only flag denoting if this is a TypeScript project, or a standard JavaScript project."

"Project Settings→publicProjectName": "The public name of the project."

"Project Settings→publicProjectName": "The name of the project as it is used within code. Generally, this name should be more 'code safe', with no spaces, special characters etc..."

"Project Settings→assetConfigurationDefinitions": "This is where the asset configuration values are defined."

"Project Settings→assetPackageScaleDefinition→assetPackageScale": "A comma-separated list containing the numeric values for asset package scale, which determines an automatic scale value applied to all graphics in each configuration. Be sure to include all of the assetPackageScale that you intend to use for any of the development or publishing configurations. Values are expressed on a scale from 1 to 100, where 100 corresponds to 100% graphic scaling (including graphics at source size)."

"Project Settings→assetPackageScaleDefinition→soundQuality": "A comma separated list of items of the format AAA_BBB, where AAA is either 'mono' or 'stereo', and BBB is the bitrate in kilobytes. For example, acceptable values include 'stereo_115' or 'mono_55'."

"Project Settings→assetPackageScaleDefinition→language": "A comma separated list of strings representing language codes. For example 'en,es'."

"Project Settings→projectSetup": "Configure the project here."

"Project Settings→coreCanvasResolutionX": "This value represents the target canvas resolution width. Various scaling features such as 'adaptiveCamera' mode, and 'canvasSizeResolutionScaling' use this number as the 'native' resolution in calculations that react to dynamic resolution changes."

"Project Settings→mainCameraType": "This determines what camera type is used for the main camera."

"Project Settings→coreCanvasResolutionY": "This value represents the target canvas resolution height. Various scaling features such as 'adaptiveCamera' mode, and 'canvasSizeResolutionScaling' use this number as the 'native' resolution in calculations that react to dynamic resolution changes."

"Project Settings→maskingMode": "The amount of information included in the logs. Incisor log files are written to the 'Application Support' directory, which can be accessed from the Incisor menu."

"Project Settings→canvasTransparency": "If any portion of the canvas needs to be transparent, then this setting should be true. Otherwise it should be false."

"Project Settings→canvasTransparency": "If any portion of the canvas needs to be transparent, then this setting should be true. Otherwise it should be false."

"Project Settings→defaultGraphicAssetEffectNodes": "A comma separated list of the EffectNodes which will automatically be included on all GraphicAssets in this project. Please note that the 'ColorMultiply' EffectNode is required by many of the Incisor UI objects (UiButton,UiMenu,etc...)"

"Project Settings→conditionalCodeTagDefinitions": "A comma separated list of code tags that can be included or excluded based on which development or publishing configuration is used. Please note that the code tags must be 'code safe', which means free of spaces, special characters, and leading numbers."

"Project Settings→productivity": "Configure settings that affect the process of development."

"Project Settings→limitPublishBuildsKept": "The number in this feild is the limit on the quantity of published projects that are allowed to exist in the 'Publishing' directory. Once the limit is met, publishing deletes the oldest copy. Set this value to a positive integer to keep you project from getting too bloated..."

"Project Settings→autoClearMetaFiles": "Setting that determines if unused '.ncData' files are automatically cleared from the project."

"Project Settings→enableDynamicDocumentation": "Setting that determines if Incisor automatically updates the 'IncisorAPI' file in the project Utilities diractory so that autocomplete reflects project-specific items such as assets and definitions."

"Project Settings→generateSourceMaps": "Setting that determines if the browser tools can show and step through your original project files while developing. Turning this off may make project reloads slightly faster."

"Project Settings→screenShotDestination": "Provide a project-relative path for where screenshots will be saved."

"Project Settings→defaultTimelineTimeSnap": "The default keyframe-time snap grid (in seconds) that newly created Timelines adopt. Existing timelines keep their own stored value."

"Project Settings→developmentSettings→additionalLiveViewModes": "A comma separated list of view modes for the 'Live View' panel. The listed items are of the format 'AAAxBBB' or 'AAAxBBB_maximize', where AAA is the horizontal resolution, BBB is the vertical resolution, and '_maximize' is included if the view mode is meant to be fitted to fill as much of the Live View panel as possible."

"Project Settings→auxiliaryPublishingPackageDefinitions": "This is where all of the auxiliary publishing packages are defined. These packages can be enabled/disabled within any of the configurations below to activate additional publishing such as Electron publishing for native apps."

"Project Settings→auxiliaryPublishingPackageDefinitions→electron": "This is where all of the Electron auxiliary publishing packages are defined."

"Project Settings→configurations": "Configurations are interchangable sets of project settings that can be used to develop and publish projects in different modes. It is often helpful to have different settings for development, testing, and publishing. For example, in development you may want only a single language active and an active conditionalCodeTag that corresponds to blocks of code for debugging. While in testing you may want to enable all languages and a conditionalCodeTag that corresponds to test scripts. And lastly when publishing, you may want to include more assetPackageScales, enabled code minification, or remove optional code modules. Configurations can also be very useful for managing multiple publishing modes; if your project will be published for 2 or more differnt environments you can customize multiple configurations to meet the exact needs of those environments."

"Project Settings→devModeConfiguration": "This determines which configuration is used while developing in Incisor."

"Project Settings→loadingTierDefinitions": "Groups of lazy-loaded content are defined in these 'loading tiers'."

"Project Settings→fontDefinitions": "Settings for the fonts within this project. Fonts must be added or removed directly within the 'Assets' directory in a project. Including TTF and OTF files automatically generates new fonts sections below, also any graphic asset included that ends in '_Char0' is automatically assumed to be the null character of a new font."

"Project Settings→fontReduction": "Settings for how Incisor manages which characters are included for each font."

"Project Settings→fontReduction→includeStandardCharactersWhenUnPublished": "Setting that determines if Incisor automatically includes all of the characters from the 'standardFontCharacters' in all fonts when the project is in developoment mode."

"Project Settings→fontReduction→includeStandardCharactersWhenPublished": "Setting that determines if Incisor automatically includes all of the characters from the 'standardFontCharacters' in all fonts when the project is published."

"Project Settings→fontReduction→includeTranscriptCharacters": "Setting that determines if Incisor automatically includes all of the characters included in the 'ProjectTranscript.json' file."

"Project Settings→fontReduction→limitTranscriptCharactersByLanguage": "Setting that determines if the characters included from the 'ProjectTranscript.json' are limited by the current language. When true, only characters from phrases in the current language will be included with the associated fonts."

"Project Settings→fontReduction→limitTranscriptCharactersByPhrase": "Setting that determines if the characters included from the 'ProjectTranscript.json' are limited to only characters in the phrases indicated."

"Project Settings→fontReduction→standardFontCharacters": "A list of characters that are included for all fonts, as long as the associated 'includeStandardCharacters' setting indicates inclusion."

"Project Settings→configurations→supportedAssetConfigurations": "Determine which sets of asset configurations are included. When developing in Incisor, the first asset configuration listed is the one used."

"Project Settings→configurations→codeInclusion": "Settings for including and excluding code."

"Project Settings→configurations→conditionalCodeTagsInlcuded": "Check the boxes below to determine which conditional code sections to include in this configuration."

"Project Settings→configurations→optionalCodeModulesExcluded": "Check the boxes below to determine which optional code modules to exclude from Incisor functionality. Excluding as many optional modules as possible can help reduce the download size of your published project."

"Project Settings→configurations→optionalCodeModulesExcluded→"+_codeModule: _optionalCodeModuleDescription

"Project Settings→configurations→publishing": "Settings for publishing projects."

"Project Settings→configurations→publishIndexFile": "Flag determining if the project is published as a complete web-ready package, including the index file. Reasons to disable this could include publishing for an environment that uses the associated JavaScript directly, negating the need for html."

"Project Settings→configurations→removeComments": "Setting to determine if Incisor removes comments from the code when publishing the project."

"Project Settings→configurations→removeWhitespace": "Setting to determine if Incisor removes whitespace from code when publishing the project. It should be noted that whitespace removal requires semi-colons be pre-included in all project code prior to publishing."

"Project Settings→configurations→minification": "Settings for if/how Incisor minifies project and API code. Minification consists of replacing normal code tokens (i.e. variable names etc...) with shorter nonsense tokens. This serves 2 purposes. The first is to reduce the download size of code, and the second is to generally obfuscate the code to make reverse-engineering projects more difficult."

"Project Settings→configurations→minification→enableMinification": "Setting to determine if Incisor applies minification when publishing this project. Minification consists of replacing normal code tokens (i.e. variable names etc...) with shorter nonsense tokens. This serves 2 purposes. The first is to reduce the download size of code, and the second is to generally obfuscate the code to make reverse-engineering projects more difficult."

"Project Settings→configurations→minification→automaticallyMinifyAllKeywords": "This setting determines if minification is automatically applied to all project code tokens that are not marked as excluded from minification. If this flag is true, then you can 'opt-out' to minification on a per-token basis using the doNotMinifyPrefix, the doNotMinifySuffix, or a 'DoNotMinifyList'. If this flag is false, then you can 'opt-in' to minification on a per-token basis using the minifyPrefix, the minifySuffix, or a 'MinifyList'."

"Project Settings→configurations→minification→minifyIncisorApiKeywordsCallback": "Setting to determine if Incisor applies minification to the keywords from the Incisor API when publishing. Minification consists of replacing normal code tokens (i.e. variable names etc...) with shorter nonsense tokens. This serves 2 purposes. The first is to reduce the download size of code, and the second is to generally obfuscate the code to make reverse-engineering projects more difficult."

"Project Settings→configurations→minification→minifyAssetNames": "Setting to determine if Incisor applies minification to names of assets from the project. Minification consists of replacing normal code tokens (i.e. variable names etc...) with shorter nonsense tokens. This serves 2 purposes. The first is to reduce the download size of code, and the second is to generally obfuscate the code to make reverse-engineering projects more difficult."

"Project Settings→configurations→minification→doNotMinifyPrefix": "This field contains a prefix that when included in a code token (var name, class name, etc...), indicates that that code token should not be minified ."

"Project Settings→configurations→minification→minifyPrefix": "This field contains a prefix that when included in a code token (var name, class name, etc...), indicates that that code token should be minified ."

"Project Settings→configurations→minification→doNotMinifySuffix": "This field contains a prefix that when included in a code token (var name, class name, etc...), indicates that that code token should not be minified ."

"Project Settings→configurations→minification→minifyPrefix": "This field contains a prefix that when included in a code token (var name, class name, etc...), indicates that that code token should be minified ."

"Project Settings→configurations→minification→keywordAndStringPairTreatment": "Setting that determines how minification works when a token/string pair is encountered."

"Project Settings→configurations→minification→substituionAssignment": "The amount of information included in the logs. Incisor log files are written to the 'Application Support' directory, which can be accessed from the Incisor menu."

"Project Settings→configurations→auxiliaryPublishingPackages": "Determine which auxiliary publishing packages will be used when publishing with this configuration."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→application": "Settings the generated Electron application."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→icon": "The path to an icon png for an image the the OS uses to represent a specific window. The behaviour associated with this property can vary a lot by platform."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→type": "Determines the type of window created by this app. The effect of this property on the window is OS-dependent."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging": "Settings for how the Electron application is packaged."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→targets": "Each ticked target is built when this package is published, and each gets its own application. When none are ticked, the platform Incisor is running on is built."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→targets": "Each ticked target is built when this package is published, and each gets its own application. When none are ticked, the platform Incisor is running on is built."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→targets": "Each ticked target is built when this package is published, and each gets its own application. When none are ticked, the platform Incisor is running on is built."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→targets": "Each ticked target is built when this package is published, and each gets its own application. When none are ticked, the platform Incisor is running on is built."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→targets": "Each ticked target is built when this package is published, and each gets its own application. When none are ticked, the platform Incisor is running on is built."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→targets": "Each ticked target is built when this package is published, and each gets its own application. When none are ticked, the platform Incisor is running on is built."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→reproducibleBinary": "Determines whether publishing this package from the same project always gives the same application. When enabled, a copy of the Electron runtime (roughly 125 to 160 MB) is kept in the project's auxiliary publishing support folder and every file in the application gets the same timestamp. When disabled, the runtime stored in Application Support is used directly and nothing is copied into the project."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→productName": "The name of the application, used for its file name and in the operating system's menus. When blank the project's public name is used."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→asar": "Determines whether the application's files (the published project, its main and preload scripts, and any node_modules from ElectronExtras) are packed into one app.asar archive instead of being left as separate files. Files that cannot be read from inside an archive, such as native modules (.node) and other libraries or programs, are kept loose beside it. When disabled the files are left as they are."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→asarIntegrity": "Determines whether the application checks its app.asar archive when it starts and refuses to run if the archive has been changed, and whether it refuses to load its code from anywhere other than the archive. The change check is available for Windows and Mac applications, so a Linux application only gets the second protection. Requires asar. An application built this way will not start if anything in its archive is altered, including by the operating system's file handling, so test it before distributing it."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→appId": "The identifier the operating system uses for the application, written in reverse domain form such as com.mycompany.mygame. When blank, com.example followed by the project's code name is used."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→version": "The version number of the application, such as 1.0.0. When blank, 1.0.0 is used."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→copyright": "The copyright line stored in the application, such as Copyright 2026 My Company."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→packaging→appIcon": "The path to the icon of the application file, relative to the project or absolute. It can be one square PNG (1024 by 1024 is best, and the other sizes are made from it), a folder of square PNGs of different sizes (the names do not matter), an .icns file for Mac applications, or an .ico file for Windows applications. Mac and Windows applications use it. Linux applications do not."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→windowPositioning": "Settings for how to position the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→x": "The x position of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→center": "Determines if the Electron window centered in the screen."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→y": "The y position of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→windowScaling": "Settings for how to position the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→width": "The width of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→windowPositionDelay": "The delay (in miliseconds) before positioning and scaling the window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→height": "The initial height of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→minWidth": "The minimum width of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→maxWidth": "The maximum width of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→minHeight": "The minimum height of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→maxHeight": "The maximum width of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→windowFunctionality": "Settings for the functionality of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→resizable": "Determines if the Electron window is resizable."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→minimizable": "Determines if the Electron window is minimizable."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→movable": "Determines if the Electron window is movable."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→maximizable": "Determines if the Electron window is maximizable."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→closable": "Determines if the Electron window is closable."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→focusable": "Determines if the Electron window is focusable."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→fullscreenable": "Determines if the Electron window is fullscreenable."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→level": "This sets the window's stacking level relative to other windows on the system."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→enableContextMenu": "Enables a context menu in the electron window... The details of which are spelled out in the ElectronMain.js file which can be found in the project directory (after publshing with electron at least once) Utilities/auxiliaryPublishingSupport/electron/[MyElectronPublishingPackage]/ElectronMain."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→incisorFileIoLayer": "Determines whether this published Electron build exposes the native fileIO layer, letting nc.fileIO requests be serviced by the Electron runtime (reading and writing within the application's own data directory). Enabled by default. This only has an effect when the 'fileIO' and 'fileIoElectron' optional code modules are also included (see Project Settings, configurations, optionalCodeModulesExcluded). The scope of file access is further governed by the 'allowUniversalFileIO' option below."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→allowUniversalFileIO": "Determines whether this published Electron build may read and write files outside its own application data directory. Disabled by default, in which case fileIO is confined to relative paths within the app's data directory and non-relative paths are refused with an explanatory dialog. When enabled, the published application can access any file on the user's machine - enable with care. This applies only when the native fileIO layer is active (the 'incisorFileIoLayer' option above is enabled and the 'fileIO' and 'fileIoElectron' modules are included). This is the Electron-build equivalent of the application-level 'allowUniversalFileIO' setting that governs FileIO while developing in Incisor."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→windowAppearence": "Settings for the appearance of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→frame": "Determines if the Electron window has a frame."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→transparent": "Determines if the Electron window is transparent."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→backgroundColor": "The background color of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→opacity": "The opacity of the Electron window."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→vibrancy": "The vibrancy option enables a translucent, blurred background effect for windows on macOS. It's a macOS-specific visual effect (similar to 'blur behind') where the window content blends with whatever is behind it.."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→visualEffectState": "Can be used in conjunction with 'vibrancy', and also controls whether the effect stays visible when the app isn't active."

"darkTheme": "Determines if the Electron window uses darkTheme."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→hasShadow": "Determines if the Electron window has a shadow."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→menuBarVisible": "Determines if the Electron window menu bar is visible."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→autoHideMenuBar": "Determines if the Electron window menu bar automatically hidden."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→fullscreen": "Settings for if/when the Electron app enters fullscreen mode."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→simpleFullscreen": "'simpleFullscreen' enables a non-Space-creating fullscreen mode on macOS, and does not affect the generated app on other operating systems."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→fullScreen": "'fullscreen' enables enables native fullscreen mode for the window. Please note that for some versions of linux the 'frame' setting may need to be false for this to work properly."

"ProjectSettings→auxiliaryPublishingPackageDefinitions→electron→kiosk": "This setting is similar to the 'fullscreen' setting, but it goes further by actively preventing the user from leaving your app. Please note that for some versions of linux the 'frame' setting may need to be false for this to work properly."

"Project Settings→loadingTierDefinitions→loadingTier": "The number-designation of this loading tier. Loading tiers are identified via numbers, which gives the auto-loaded tiers an implicit ordering, allowing for built-in duplicate removal accross multiple tiers."

"Project Settings→loadingTierDefinitions→isAutoLoaded": "Flag determining the content associated with this tier is automatically loaded."

"Project Settings→loadingTierDefinitions→incrementalContentProcessing": "Flag determining if the content associated with this loading tier will be processed 'a little at a time' upon loading. This option helps avoid the potential performance hits from processing lazy-loaded content. In most cases this value should be false for tiers that load during a loading screen, and it should be true for tiers that will be loaded while the project is already usable by the end-user."

"Project Settings→loadingTierDefinitions→perfomDuprlicateRemoval": "Flag determining if the content associated with this tier is eligible for duplicate removal."

"Project Settings→loadingTierDefinitions→assetDataFileSizeLimitKB": "A soft limit on the size of asset data files within this tier. This setting can be used to ensure that no lazy-loaded asset data files can get too big; large asset data files can cause performance hits when they first load, as they can require large memory allocations. So for loading tiers that are loaded during a loading screen, this value can be fairly high, but for loading tiers that are lazy-loaded durung runtime set this number to be lower."

Incisor® Release Notes

IncisorReleaseNotes.txt

Incisor® Release Notes
This document is part of the compiled knowledge base for the Incisor® Software Development Platform.
Any use of this content is subject to the INCISOR® end user license and terms of use agreement.
https://www.incisordev.com/eultua
2026.11.05.12.18.12






----------------------------------------------------------
TABLE OF CONTENTS:
----------------------------------------------------------
Section 1: 2026.11.05.00.00.00
Section 2: 2026.11.04.00.00.00
Section 3: 2026.11.02.00.00.00
Section 4: 2026.10.29.00.00.00
Section 5: 2026.10.27.00.00.00
Section 6: 2026.10.26.00.00.00
Section 7: 2026.10.24.00.00.00
Section 8: 2026.10.11.00.00.00
Section 9: 2026.10.05.00.00.00
Section 10: 2026.09.29.00.00.00
Section 11: 2026.09.28.00.00.00
Section 12: 2026.09.27.00.00.00
Section 13: 2026.09.25.00.00.00
Section 14: 2026.09.24.00.00.00
Section 15: 2026.09.22.00.00.00
Section 16: 2026.09.14.00.00.00
Section 17: 2026.09.10.00.00.00
Section 18: 2026.08.26.00.00.00
Section 19: 2026.08.22.00.00.00
Section 20: 2026.08.13.00.00.00
Section 21: 2026.08.07.00.00.00
Section 22: 2026.08.06.00.00.00
Section 23: 2026.08.05.00.00.00
Section 24: 2026.08.04.00.00.00
Section 25: 2026.08.03.00.00.00
Section 26: 2026.07.27.00.00.00
Section 27: 2026.07.25.00.00.00
Section 28: 2026.07.24.00.00.00
Section 29: 2026.07.21.00.00.00
Section 30: 2026.07.15.00.00.00
Section 31: 2026.07.09.00.00.00
Section 32: 2026.07.06.00.00.00
Section 33: 2026.06.30.00.00.00
Section 34: 2026.06.15.00.00.00
Section 35: 2026.05.21.00.00.00
Section 36: 2026.05.18.00.00.00
Section 37: 2026.05.14.00.00.00
Section 38: 2026.05.12.00.00.00
Section 39: 2026.05.09.00.00.00
Section 40: 2026.05.04.00.00.00
Section 41: 2026.05.03.00.00.00
Section 42: 2026.04.30.00.00.00
Section 43: 2026.04.29.00.00.00
Section 44: 2026.04.23.00.00.00
Section 45: 2026.04.21.00.00.00
Section 46: 2026.04.19.00.00.00
Section 47: 2026.04.17.00.00.00
Section 48: 2026.04.15.00.00.00
Section 49: 2026.04.03.00.00.00
Section 50: 2026.03.25.00.00.00
Section 51: 2026.03.20.00.00.00
Section 52: 2026.03.19.00.00.00
Section 53: 2026.03.17.00.00.00
Section 54: 2026.03.14.00.00.00
Section 55: 2026.03.11.00.00.00
Section 56: 2026.03.05.00.00.00
Section 57: 2026.03.03.00.00.00
Section 58: 0000.00.00.00










----------------------------------------------------------
Section 1: 2026.11.05.00.00.00
----------------------------------------------------------


TITLE:
Command Line: Project Screenshots
DESCRIPTION:
The new 'getProjectScreenShot' command saves an image of a running project and returns its path and size.

TITLE:
Keyboard: Simulated Keys
DESCRIPTION:
The new 'nc.simulateKeyDown', 'nc.simulateKeyUp' and 'nc.simulateKeyPress' functions send keyboard input to a project, which makes testing a project from a script possible.

TITLE:
Buttons: simulateCursorPressEvent On Draggable Buttons
DESCRIPTION:
Calling 'simulateCursorPressEvent' on a button with drag callbacks no longer throws an error.











----------------------------------------------------------
Section 2: 2026.11.04.00.00.00
----------------------------------------------------------


TITLE:
Command Line: Incisor From Scripts And AI Assistants
DESCRIPTION:
Run the Incisor executable with '--cli' and a json command, and it carries the command out, prints one json answer, and exits with a code that says how it went. That makes Incisor scriptable by build tools and AI coding assistants, and it stays off until the 'enableCLI' setting is turned on.

TITLE:
Command Line: enableCLI Setting
DESCRIPTION:
The new 'enableCLI' application setting lets Incisor accept commands from the command line, whether it is open or closed. Every command is logged.

TITLE:
Command Line: getSessionInfo
DESCRIPTION:
Returns the application settings and each open project's settings and run state.

TITLE:
Command Line: publish
DESCRIPTION:
Publishes a project with a named configuration, with Incisor open or closed.

TITLE:
Command Line: openProject
DESCRIPTION:
Opens a project in a tab, starting Incisor if it is closed.

TITLE:
Command Line: focusTab
DESCRIPTION:
Brings an open project's tab and the window forward.

TITLE:
Command Line: getInspectorScreenShot
DESCRIPTION:
Saves an image of an open project's whole tab.

TITLE:
Command Line: runNceScript
DESCRIPTION:
Runs a script inside an open project's inspector, with 'nce' available as in extensions.











----------------------------------------------------------
Section 3: 2026.11.02.00.00.00
----------------------------------------------------------


TITLE:
Auto-Refresh: Setting And Extension Pause
DESCRIPTION:
The new 'refreshOnCodeChange' application setting controls whether editing code refreshes the project. Extensions can also hold the refresh off with 'nce.pauseProjectAutoRefresh' and 'nce.resumeProjectAutoRefresh'.

TITLE:
Application Settings: refreshOnAssetChange Removed
DESCRIPTION:
The 'refreshOnAssetChange' setting is gone because it never did anything. Changed assets still show the 'Project Updated' button in the top bar.











----------------------------------------------------------
Section 4: 2026.10.29.00.00.00
----------------------------------------------------------


TITLE:
Inspector: Precomp Graphics Show Again
DESCRIPTION:
Precomp graphics were drawing blank in the Construct editor and the GraphicAsset and Texture selection previews. They draw again.











----------------------------------------------------------
Section 5: 2026.10.27.00.00.00
----------------------------------------------------------


TITLE:
Flows Panel: Excluded Module
DESCRIPTION:
Adding a Flows panel to a project that excludes the flowControllers module no longer breaks the project. The panel now says the module is excluded.











----------------------------------------------------------
Section 6: 2026.10.26.00.00.00
----------------------------------------------------------


TITLE:
Spine Import: Works Without Universal File IO
DESCRIPTION:
Importing a Spine animation no longer requires 'allowUniversalFileIO' to be on, and the recent imports list works with it off.

TITLE:
Panels: Loading Tiers Renamed
DESCRIPTION:
The 'Loading Tiers' panel is now called 'Loading Tier Testing', since it is for testing how a project loads, not for editing tier definitions. If a saved layout shows an empty panel, reselect the panel type.

TITLE:
Hierarchy Panel: Editor Scenes Only While Stopped
DESCRIPTION:
While a project is stopped, the Hierarchy panel lists only editor scenes. Stopping clears its selection if it was on any other scene, even when the selection is locked.

TITLE:
TypeScript: Code Assets Compile While Stopped
DESCRIPTION:
Adding a code asset from the Template Library to a stopped TypeScript project now compiles it right away, so its JavaScript is there when you run.











----------------------------------------------------------
Section 7: 2026.10.24.00.00.00
----------------------------------------------------------


TITLE:
Incisor App: Its Own Window With Tabs
DESCRIPTION:
Incisor is now its own app with tabs, instead of one browser tab per project.

TITLE:
Stability: No Browser Ports Or Sockets
DESCRIPTION:
Incisor is more stable, with no ports or sockets between a browser and Incisor, and it now survives sleep and wake.

TITLE:
Installers: Signed Mac Disk Image And Windows Installer
DESCRIPTION:
Incisor ships as a signed, notarized Mac disk image and a signed Windows installer. The Windows installer is per-user, needs no admin rights, and has an uninstaller.

TITLE:
Editor Debugging: Debug From Your Code Editor
DESCRIPTION:
Turn on the allowEditorDebugging application setting and Visual Studio Code attaches to your running project through a debugging port Incisor opens, so you can stop on breakpoints in your original TypeScript and JavaScript files. Incisor generates the .vscode/launch.json for you.

TITLE:
TypeScript: Built-In Compiler And Type Check
DESCRIPTION:
Incisor compiles and type checks TypeScript itself, with no Node, npm or package.json, and recompiles whenever a code file changes. Type errors show in the log after a project loads.

TITLE:
TypeScript: Type Errors In VS Code
DESCRIPTION:
Type errors appear in the VS Code Problems panel through a task Incisor generates in .vscode/tasks.json.

TITLE:
Debugging: Source Maps
DESCRIPTION:
JavaScript projects have source maps, and TypeScript projects have chained source maps, so the browser developer tools show your original source files.

TITLE:
Red Error: Original Source Locations
DESCRIPTION:
Red Error stacks now show locations in your original JavaScript and TypeScript source files.

TITLE:
Console: Developer Tools Buttons
DESCRIPTION:
Each console log line has new buttons. One opens the developer tools Console tab, and the other opens the source file at that line in the Sources tab.

TITLE:
Electron Publishing: No Node, npm Or electron-builder
DESCRIPTION:
Publishing a desktop app needs no Node, npm or electron-builder. Each target gets its own zip plus a manifest of file hashes.

TITLE:
Electron Publishing: Reproducible Binary
DESCRIPTION:
The new reproducibleBinary option makes publishing the same project give identical files each time.

TITLE:
Electron Publishing: One App Icon For Mac And Windows
DESCRIPTION:
One appIcon setting sets the icon for both Mac and Windows apps. It takes a PNG, a folder of PNGs, an .icns or an .ico.

TITLE:
Electron Publishing: ASAR Packing And Integrity Check
DESCRIPTION:
The new asar option packs your app into a single archive, and asarIntegrity adds a check so a modified archive won't start. Both are off by default.

TITLE:
Electron Publishing: Mac Apps Signed Automatically
DESCRIPTION:
Mac apps are signed automatically when you publish from a Mac.

TITLE:
Acknowledgements: New Third-Party Licenses
DESCRIPTION:
The Acknowledgements menu now covers Electron, Chromium, TypeScript, PdfSharpCore, MigraDocCore, SharpZipLib, ImageSharp, Noto Sans and Inno Setup.

TITLE:
Live View: Run And Stop
DESCRIPTION:
Projects now open stopped, with your code switched off, so a project that crashes on load can no longer take the editor down with it. Press Run in the Live View header to start it, or turn on the new runProjectOnOpen setting to run projects as they open.

TITLE:
Live View: Stopped Project
DESCRIPTION:
A stopped project shows a centered message and a large play button in the Live View. Pause, Step, the magnifier and the camera selector are inactive until it runs.

TITLE:
Live View: Stop On Exceptions
DESCRIPTION:
When your project code throws, Incisor stops the project and links to the console for the error. The new stopProjectOnException setting is on by default. Turn it off and the developer tools pause at the throw instead, with your own frames in the call stack.

TITLE:
Stability: Throwing Callbacks Don't Break Events
DESCRIPTION:
An exception in one event callback used to leave that event dead for the rest of the session. It now keeps firing.

TITLE:
Live View: Refresh Keeps Your State
DESCRIPTION:
Saving code refreshes the project into the state you left it in, running or stopped.

TITLE:
Live View: Control Buttons
DESCRIPTION:
The header buttons are now Run, Pause, Stop and Step, each doing one job, and the set shown changes with the project's state. The header uses the body text size, and the full-screen button sits after the view selector.

TITLE:
Debugging: Errors Point At Your Source
DESCRIPTION:
The first red error now maps to your original files immediately. TypeScript errors in the console are clickable links to the source when editor debugging is off.

TITLE:
Editor Debugging: Your .vscode Files Are Respected
DESCRIPTION:
Incisor adds its own entry to an existing .vscode/tasks.json or launch.json and leaves your tasks and launch configurations untouched. Before, a file you already had blocked it.

TITLE:
Menus: Refresh Incisor Client
DESCRIPTION:
A new item in the View menu and the top bar View menu reloads the front end (Cmd or Ctrl R).

TITLE:
Window: Larger And Remembered
DESCRIPTION:
Incisor opens 20% larger and remembers its size, position, and maximized or full-screen state between launches. If the saved monitor is gone, it opens on a display that exists.

TITLE:
Editor Debugging: Port Setting
DESCRIPTION:
The new editorDebuggingPort setting lets you change the port from 9222. Incisor warns you if another program already holds it.

TITLE:
Application Settings: Save And Restart
DESCRIPTION:
Changing a setting that only takes effect at startup now offers Save and Restart. It lists any projects with unsaved changes first.











----------------------------------------------------------
Section 8: 2026.10.11.00.00.00
----------------------------------------------------------


TITLE:
Data Panel: Export Fixes
DESCRIPTION:
Exported conditional code tags now come out correctly, and TypeScript exports no longer include a stray '!' in their declarations. Paylines are typed as numbers.

TITLE:
TypeScript: SpineCurves Compile Error
DESCRIPTION:
Fixed an error about SpineCurves when compiling TypeScript.

TITLE:
Spine Runtime: Closer Parity With Spine
DESCRIPTION:
Improved Spine runtime parity: constrained bones follow ancestor changes in all inheritance modes, IK no longer writes timeline values, and constraints solve after the timeline pose is applied.

TITLE:
Spine Import: Importer Extended
DESCRIPTION:
Extended the importer: first-key setup-value hold, sequence setup frames, cross-skin linked meshes, atlas repeat wrapping, and deform and draw-order fixes.

TITLE:
Spine Import: Popup Additions
DESCRIPTION:
Added a root drive selector, atlas auto-selection and asset-setting preservation to the import popup.

TITLE:
Spine Skins: Skin List In The Object Panel
DESCRIPTION:
The SpineBone Info section of the Object Panel now lists a skeleton's skins, each with a checkbox to apply it, a summary of what it supplies, and a handle to drag it into a new order.

TITLE:
Spine Skins: Animatable
DESCRIPTION:
Skins can be keyframed on and off from the Animate menu, under SpineBone - skins. A skin whose name contains a dot can't be animated, and the importer now warns about any.

TITLE:
Spine Skins: Grouped By Folder On Import
DESCRIPTION:
Imported skins are now listed grouped by folder. Animations imported earlier keep their old order until they are imported again.

TITLE:
Spine Import: Keep Skin Order On Re-Import
DESCRIPTION:
Re-importing a Spine animation can now keep its skin order and active skins. Skins that no longer exist are dropped, and new skins are placed beside the others from their folder.

TITLE:
Spine Import: Keep Precomp Camera On Re-Import
DESCRIPTION:
Re-importing a Spine animation can now keep its precomp camera, including its type, transform, view and render target size. A camera whose parent no longer exists is placed at the top level of the Construct.

TITLE:
Spine Import: Keep Timeline Settings On Re-Import
DESCRIPTION:
Re-importing a Spine animation can now keep each timeline's autoplayMode and playbackRate, and the Construct's default timeline. Timelines that no longer exist are skipped.

TITLE:
Spine Import: First Skin Starts Active
DESCRIPTION:
An imported Spine animation with no earlier skin data to keep now starts with its first skin active.

TITLE:
SpineBone: setSkinEnabled And setSkinOrder
DESCRIPTION:
SpineBone gains 'setSkinEnabled' to turn a single skin on or off, and 'setSkinOrder' to set the order enabled skins are applied in. All of the SpineBone skin methods are now documented.











----------------------------------------------------------
Section 9: 2026.10.05.00.00.00
----------------------------------------------------------


TITLE:
Fixed: Opening A Directory On Windows
DESCRIPTION:
The 'Open Knowledge Base Directory' and 'Open Application Support Directory' options now work on Windows when the path has a space in it.

TITLE:
Fixed: Empty Effect Controller Rows In The Object Panel
DESCRIPTION:
EffectControllers whose value is a matrix, such as the Spine bone matrices, no longer appear in the Object Panel's material sections, where they could only ever show an empty row. They are rig data a runtime drives rather than values to edit.











----------------------------------------------------------
Section 10: 2026.09.29.00.00.00
----------------------------------------------------------


TITLE:
Live View: Changing A Panel To Live View Selects The MainScene
DESCRIPTION:
Changing any panel to a Live View now selects your project's MainScene, so the panel opens on something rather than on whatever the previous panel type had selected.

TITLE:
Fixed: The Live View's Context Menu Opened Outside Inspection Mode
DESCRIPTION:
Right-clicking the Live View no longer opens the inspection context menu while the cursor belongs to your project. It appears only in inspection mode, alongside the rest of the Live View's selection tools.

TITLE:
Fixed: Right-Clicking The Live View Ignored What Was Under The Cursor
DESCRIPTION:
Right-clicking an object in the Live View selects it before the context menu opens again, so the menu acts on what you clicked rather than on whatever was selected before.











----------------------------------------------------------
Section 11: 2026.09.28.00.00.00
----------------------------------------------------------


TITLE:
Spine Import: Spine 4.3 Runtime Support
DESCRIPTION:
Completed Spine 4.3 runtime support: corrected bone inheritance modes (with trilinear tweening), fixed the shear/scale matrix order, completed IK parity (compress, stretch, and scaleY modes), added transform-constraint property mapping, and made clipping-mask toggling robust. Extended the importer with draw-order-folder timelines, mesh sequences (regular and linked), linked-mesh timelines:false, and a keyframeable clipping inverse, and fixed a crash with deformed clipping. Added a consolidated import issue log with a popup.











----------------------------------------------------------
Section 12: 2026.09.27.00.00.00
----------------------------------------------------------


TITLE:
Fixed: Object Panel Error After Reloading The Project
DESCRIPTION:
Reloading your project after renaming or removing an EffectNode no longer throws an error from the Object Panel. A locked Object Panel now unlocks when the project reloads, so it can't keep showing objects from the previous run.











----------------------------------------------------------
Section 13: 2026.09.25.00.00.00
----------------------------------------------------------


TITLE:
Assets Panel: Rebuilt
DESCRIPTION:
The Assets panel has a new layout with a preview of what is selected, a search field for finding an asset by name, and its settings grouped into sections that only appear for the asset types they apply to. Which directories are open and what is selected are now remembered with the panel.

TITLE:
Assets Panel: Several Assets At Once
DESCRIPTION:
Asset settings can now be edited for a whole selection rather than one asset at a time, and a setting the selected assets disagree about reports that rather than picking one of them.

TITLE:
Assets Panel: Asset Configuration Filters
DESCRIPTION:
Which of the configurations your project is built for an asset is included in can now be set in the panel, with a row per configuration the project defines.

TITLE:
Assets Panel: Sprite Sheets Are Chosen From A Menu
DESCRIPTION:
An asset can be added to a sprite sheet the project already has by picking it from a menu, rather than by typing the sheet's name.

TITLE:
Fixed: Graphic Summary Ignored The Cursor
DESCRIPTION:
Graphics in the Graphic Summary respond to the cursor again, outlining themselves and reporting their details as you move over them.

TITLE:
Live View: Camera Selector
DESCRIPTION:
A new 'camera' menu in the Live View panel shows the view through any standard or precomp camera, with the Heads-Up Display attached for inspection. A toggle button shows a checkerboard behind the camera's transparent areas.

TITLE:
Inspector: Text and Precomps Draw Everywhere
DESCRIPTION:
TextBoxes and precomp graphics now show up wherever the inspector draws your project - the Live View's camera views, the Construct editor, and the GraphicAsset and Texture selection previews. This replaces several separate fixes and has no effect on published projects.

TITLE:
Fixed: Particle Systems Falsely Reported Mixed Sprite Sheets
DESCRIPTION:
A ParticleSystemDefinition whose graphics share a sprite sheet no longer fails validation when one of those graphics is a duplicate of another.

TITLE:
Fixed: First Right-Click Menu Could Get Stuck
DESCRIPTION:
The first right-click menu in the Live View could stay on screen after clicking away.

TITLE:
Control Center: Manage Menu Removed
DESCRIPTION:
The Control Center's top bar no longer shows the Manage menu, which only applies inside the inspector.











----------------------------------------------------------
Section 14: 2026.09.24.00.00.00
----------------------------------------------------------


TITLE:
Loading Tiers: Loading Progress
DESCRIPTION:
Exposed the previously internal 'loadingProgress' on LoadingTierDefinitions - a value from 0 to 1 for driving loading bars. The Loading Tiers panel's progress bars now show this same value.











----------------------------------------------------------
Section 15: 2026.09.22.00.00.00
----------------------------------------------------------


TITLE:
New Window: Project Gallery
DESCRIPTION:
The control center now opens a Project Gallery in place of the plain Open Project dialog, listing example projects by category alongside your recent ones, each with a thumbnail and a description. Clicking an example project that is not on this computer downloads it, 'Browse...' still opens the old dialog for anything the gallery does not list, and Ctrl/Cmd G opens the gallery at any time.

TITLE:
Project Gallery: Blank New Projects
DESCRIPTION:
A blank new project can be started from the gallery as 2D or 3D and in JavaScript or TypeScript, where the 3D option differs only in starting on a perspective main camera.

TITLE:
Project Gallery: Recent Projects Carry a Picture
DESCRIPTION:
Recent projects are now listed with a picture of the inspector as you last left it, taken a few seconds after a project connects and again each time you leave the window.

TITLE:
Project Gallery: Projects Open in a Scratch Directory
DESCRIPTION:
An example or blank new project opened from the gallery is put in a 'Project Scratch' directory rather than asking where it should go first, so there is nothing to answer before trying it. The first save writes in place and then asks where the project should live, and anything left in scratch is cleared out after a week.

TITLE:
Extensions: Project and ToolTip Functions
DESCRIPTION:
'nce.openProject', 'nce.getRecentProjects', 'nce.saveProject' and 'nce.addToolTip' are now available in every extensions scope, along with 'nce.getSearchFilterScore' for scoring text the way Incisor's own search fields do.

TITLE:
PixelsObjects: No Longer an Optional Code Module
DESCRIPTION:
PixelsObjects are no longer an optional code module, and are now always included in every project.

TITLE:
WaitThens: No Longer an Optional Code Module
DESCRIPTION:
WaitThens are no longer an optional code module, and are now always included in every project.











----------------------------------------------------------
Section 16: 2026.09.14.00.00.00
----------------------------------------------------------


TITLE:
Swoopers: Omitted Components Are Left Alone
DESCRIPTION:
A component left undefined in 'swoop.each' is now left untouched, so anything else is free to animate it on its own timing. Previously the Swooper pinned that component to the value it held when the swoop began, silently overriding any other swoop on it.











----------------------------------------------------------
Section 17: 2026.09.10.00.00.00
----------------------------------------------------------


TITLE:
GraphicObjects: Redundant Layer Assignments Are Free
DESCRIPTION:
Setting a GraphicObject's 'layer' or 'subLayer' to the value it already holds no longer triggers a recalculation, so 'setLayers' and 'setSubLayers' across a large subtree cost nothing when nothing has actually changed. Layer values are now also refreshed when an object moves to another Scene or is given new Materials, which could previously leave them stale.

TITLE:
New Panel: Sounds
DESCRIPTION:
A new 'Sounds' panel lists every Sound in the project with playback controls, a mainVolume slider and a mute toggle, so any of them can be auditioned, re-leveled or silenced while the project runs. The list can be searched by name, narrowed to only what is playing, and ordered alphabetically or by what played most or least recently.

TITLE:
New Panel: Loading Tiers
DESCRIPTION:
A new 'Loading Tiers' panel lets you block selected loading tiers so their assets are never requested, or add a delay to every tier's request, so you can watch how a project holds up when its content is late or missing. Unblocking a tier sends its request there and then, and the panel also shows each tier's loading state, its progress, and the AssetComponents it carries.

TITLE:
Template Library: Now Lives on Disk
DESCRIPTION:
The Template Library has moved out of the application and into a 'Template Library' directory inside Incisor's Application Support folder, where every item is an ordinary folder of files that can be read, edited, and added to. Installing an update merges the shipped library into the installed one item by item, so anything you have put there yourself is left alone.

TITLE:
Template Library: Browsed in a Popup
DESCRIPTION:
The top-level 'Template Library' menu has been replaced by 'Project - Import - From Template Library...', which opens a searchable browser with the library's folders on one side and the selected item on the other. It is also reachable directly with Ctrl/Cmd Shift L.

TITLE:
Template Library: Previews, Descriptions and Examples
DESCRIPTION:
Every item now carries a written description, an animated preview of what it does, and example code that runs as-is when pasted into a new project. Items also show badges for whether they can be edited in the GUI, animated in Timelines, and reached from the Code API.

TITLE:
Spine Import: Moved Into the Project Menu
DESCRIPTION:
'Spine Animation...' has moved from its own top-level 'Import' menu to 'Project - Import - Spine Animation...', alongside the Template Library.

TITLE:
Spine Import: No Longer Marked Experimental
DESCRIPTION:
The notice warning that Spine support is experimental and may require animations to be re-imported has been removed from the import windows.











----------------------------------------------------------
Section 18: 2026.08.26.00.00.00
----------------------------------------------------------


TITLE:
Ux Supervisors: Sync On Demand
DESCRIPTION:
Every Ux supervisor now has a 'sync' method, matching the one UxListSupervisor already had, which brings it up to date with the values it supervises instead of waiting for the next fixedUpdate. Use it wherever a value has just been set and the supervisor has to show it before the frame ends.

TITLE:
Timeline: Sound Playback Keyframes No Longer Carry a Volume
DESCRIPTION:
A 'play' or 'playOnce' keyframe no longer takes a mainVolume of its own - keyframe 'mainVolume' directly instead, which blends by weight and returns to its NeutralState as every other animated value does. A playback keyframe previously forced the volume to full whenever it carried no value, so a Sound whose volume you set elsewhere is now left alone.

TITLE:
Tooltips: No Longer Appear Mid-Drag
DESCRIPTION:
A tooltip already counting down when a drag begins no longer surfaces during it, and a drag anywhere suppresses them rather than only one in this software's own scene.

TITLE:
Construct Editing: Fewer Redundant File Updates
DESCRIPTION:
A Construct is no longer written mid-drag. Edits settle for longer before committing, and a drag in progress holds the commit off entirely, so one gesture produces one undo step rather than a run of them.

TITLE:
Timeline Panel: Property Controls Regrouped
DESCRIPTION:
The per-property controls are now divided into groups - the continuation pair, then keyframe navigation and graph mode, then the keyframe dropper on its own.

TITLE:
Timeline: Keyframe Collisions Resolve Correctly
DESCRIPTION:
Dragging a keyframe onto another no longer depends on what happens to be selected, and a keyframe merged away is properly retired rather than left as a stale reference.

TITLE:
Timeline: New Timelines Adopt the Project's Time Step
DESCRIPTION:
A Timeline created with 'New Timeline...' now takes its timeStep from the project's 'defaultTimelineTimeSnap' setting, rather than always being born on the legacy 1/60 grid.

TITLE:
Timeline: Sound Volume Is Keyframed Deliberately
DESCRIPTION:
A Sound's 'mainVolume' is no longer keyframed by watching its value change - a Sound is shared with the whole project, so code, another Construct, or a 'swoopVolume' could each have moved it. Its value field in the Timeline panel now writes keyframes directly instead: adjusting it sets the keyframe at the playhead, or places one there if the property has none.











----------------------------------------------------------
Section 19: 2026.08.22.00.00.00
----------------------------------------------------------


TITLE:
Incisor Is Now Crimson
DESCRIPTION:
Incisor has officially transitioned to the Crimson version set, which has been in development since mid-March, so every release note since then describes work that belongs to Crimson.

TITLE:
FlowController: Flow State Change Callbacks
DESCRIPTION:
'FlowController.addFlowStateChangeCallback' now works as documented, firing on every change of the controller's current FlowState with the new FlowState and the previous one.











----------------------------------------------------------
Section 20: 2026.08.13.00.00.00
----------------------------------------------------------


TITLE:
Select GraphicAsset: Rename the GraphicObject to Match
DESCRIPTION:
The GraphicAsset selection window has a new 'rename GraphicObject' option, checked by default, which renames the object - or every selected object - to the GraphicAsset it is given. It is unavailable where the graphic is not the object's identity, as with a SpriteSetter's keyGraphicAsset or a ParticleSystem's graphic.

TITLE:
Knowledge Base and API Docs Ship with Incisor
DESCRIPTION:
The Knowledge Base and the API documentation now install alongside Incisor itself, so the docs you are reading are always the docs for the version you are running. Updating Incisor updates them with it, and there is no longer any question of which release a page is describing.

TITLE:
Timeline: Animate Sounds
DESCRIPTION:
A Timeline can now drive the project's Sounds. Right-click the Construct's own row in the Timeline panel to find them - 'mainVolume' animates like any other value, and 'play', 'playOnce', 'pause' and 'stop' are invoke properties whose keyframes fire as the playhead crosses them. A play or playOnce keyframe can carry its own mainVolume, and one that names none plays at full volume.

TITLE:
Timeline: Animate Custom AppEvents
DESCRIPTION:
A Timeline can now trigger any AppEvent defined with 'nc.defineAppEvent', which is how an animation hands a moment back to code. These sit on the Construct's own row as well, and 'custom AppEvent...' lets you name one that has yet to be written - the Construct records it as a requirement and reports it when added, so animation never has to wait on code. Incisor's own built-in AppEvents are not offered, as they are all fired by the software itself.

TITLE:
Timeline: Keyframe Parameters
DESCRIPTION:
Keyframes on an invoke property can now carry parameters. A property that already knows its own - a Sound's 'playOnce', for instance - shows a field for each in the keyframe's context menu. A custom AppEvent's parameters are yours to declare: 'add parameter' takes a name, a type and a default, every keyframe of that property then gets a field for it, and the callback receives them all as a single object with defaults filled in for anything a keyframe leaves out.

TITLE:
Timeline: Invocation timing corrected
DESCRIPTION:
Invoke keyframes now fire when they should, and only when they should. A keyframe sitting exactly on a Timeline's start time fires when that Timeline starts playing, where before it was stepped over. Stopping a Timeline, or dragging its playhead, no longer fires every keyframe passed along the way. And a Timeline playing at zero weight no longer banks the invocations it skipped, only to fire them all at once when its weight returns.

TITLE:
Construct: Sound and AppEvent requirements
DESCRIPTION:
A Construct that animates a Sound or an AppEvent now records it as a context requirement, so adding that Construct somewhere the Sound or AppEvent doesn't exist reports it - the same way a missing GraphicAsset or Layer always has.











----------------------------------------------------------
Section 21: 2026.08.07.00.00.00
----------------------------------------------------------


TITLE:
KeyframedValue Supervisor: Add a Keyframe Where You Right-Click
DESCRIPTION:
The graph's own context menu now offers 'add keyframe', placing one at the time and value under the cursor that opened the menu.

TITLE:
KeyframedValue Supervisor: Edit a Keyframe's Time and Value In Its Menu
DESCRIPTION:
Right-clicking a single keyframe now puts its time - and its value, where that value is a number - at the top of the menu as editable fields. Either can be dragged as well as typed, moving the keyframe at the same rate as dragging it on the graph.

TITLE:
KeyframedValue Supervisor: Guides
DESCRIPTION:
A supervisor can now be given vertical and horizontal guide lines, in a color of its own, to mark meaningful times and values behind the curve.

TITLE:
SymbolReels: Per-Property Motion Curves
DESCRIPTION:
A KeyframedValue can drive any property of a symbol as it travels the reel - position, scale, rotation, color - sampled at the symbol's own position, so a keyframe sits on a symbol slot rather than on a moment in time.

TITLE:
SymbolReels: Windup and Bounce
DESCRIPTION:
Separate curves shape the overshoot as a reel starts and as it settles, each with its own duration and magnitude.

TITLE:
SymbolReels: Custom Symbol Motion
DESCRIPTION:
A callback can take symbol placement over entirely, for reels whose motion the built-in path evaluation doesn't cover.

TITLE:
Fixed: Sounds Distorted While a SpeedControl Changed
DESCRIPTION:
Changing a SpeedControl restarted the buffer of every Sound in the project - including Sounds that never subscribed to that SpeedControl, and Sounds whose own rate had not moved. A Sound now only restarts when its own playback rate actually differs. This supersedes the 2026.08.06 fix, whose guard also compared the buffer's start offset against the advancing playhead and so never held for a Sound that was playing.

TITLE:
Constructs Save Their Material Settings
DESCRIPTION:
A Construct now stores each Material's faceCulling, depthTest, depthWrite, transparent and Texture selections, so a Material customized past its GraphicAsset's presets survives a save. Set them in the Object Panel's new 'draw settings' section on each Material.











----------------------------------------------------------
Section 22: 2026.08.06.00.00.00
----------------------------------------------------------


TITLE:
SymbolReels: Spinning and Stopping
DESCRIPTION:
'beginSpin', 'beginStop' and 'slam' move a reel through its states, and 'setTarget' names the symbols it lands on. Its current state can be read at any time, or subscribed to.

TITLE:
SymbolReels: Reel Data
DESCRIPTION:
A reel takes the strip it spins through up front, or assembles it on the fly as it goes.

TITLE:
Fixed: Sounds Glitched When a SpeedControl Was Set
DESCRIPTION:
Setting a SpeedControl or 'nc.softwareSpeed' restarted every playing Sound's buffer, even when the rate and position were unchanged, which was audible as a click. A Sound now only restarts when its rate or position actually differs.

TITLE:
Timeline Panel: Set a Keyframe to its NeutralState Value
DESCRIPTION:
A keyframe's right-click menu can now set the whole keyframe selection back to each property's NeutralState value. A stepped keyframe has both of its sides set, so it stays flat.

TITLE:
Fixed: Precomp Graphics Were Blank In The Editors
DESCRIPTION:
A GraphicObject using a precomp-based GraphicAsset drew as nothing in the Construct and Timeline editor scenes. It now renders.

TITLE:
Timeline Panel: Continuation Controls On Every Property
DESCRIPTION:
Two icon menus on each Animated Property row set how it evaluates outside its keyframe range - hold, extrapolate, loop or ping-pong - for the left and right sides independently.

TITLE:
Timeline Panel: Copy And Paste Animated Properties
DESCRIPTION:
Properties copy without their keyframes. Selected SceneObjects each receive the whole set - with nothing selected, each property returns to the object it came from.

TITLE:
Timeline Panel: Shift-Click Selects a Range
DESCRIPTION:
Shift-clicking selects every row between the first item selected and the one clicked, matching the Hierarchy panel. SceneObjects and Animated Properties select separately.

TITLE:
Animate Menu: Every Property In One Searchable List
DESCRIPTION:
The Animate menu can now be searched instead of navigated. 'search all properties...' opens every animatable property of the selection as one flat list, each named by its full path, so 'mat red' finds Material0's red. Holding Alt while opening the menu goes straight there with the caret already in the field. The organized sub-menus are unchanged.

TITLE:
Fixed: UxMenu Search Field Drew On The Wrong Layer
DESCRIPTION:
A searchable UxMenu builds its search field on demand, and the field was left on the default layer rather than the menu's. It went unnoticed while only drop-down menus used it, and showed up once a context menu became searchable.

TITLE:
Disposal Is Much Faster
DESCRIPTION:
Disposing a large object tree - a deep context menu, a panel, a Construct instance - no longer stalls. Each disposed object used to sweep every callback registered to every AppEvent in the software looking for its own, and a single SceneObject triggers that sweep six or more times once its materials and material master are counted, so the cost scaled with the size of the whole application rather than the size of what was being disposed. An object's callbacks are now found through the index it already keeps on itself. Disposal removes exactly what it removed before. All three edits carry a '2026.08.06' comment and can be found by searching for that date: 'AppEvent._appEvent_dispose' in 'AppEvents.js' is the rewrite, and 'SceneObjects.js' holds a guard in '_disposeThisSceneObject' around the ancestor 'enabledStateChangeDependants' walk plus a fix to 'removeDisposalCallback', which tested its index with 'if(_idx-1)' and so removed the last disposal callback whenever the one being removed was not found.











----------------------------------------------------------
Section 23: 2026.08.05.00.00.00
----------------------------------------------------------


TITLE:
SymbolReels
DESCRIPTION:
A new SceneObject that owns a set of symbol objects and moves them along a reel path to make a spinning reel. It builds, owns and disposes its own symbols, so they never appear in a Construct.

TITLE:
SymbolReels: Symbol Classes
DESCRIPTION:
A reel builds its symbols from a class handed to it in code, which need only implement 'setSymbol'. Until one is supplied a built-in placeholder stands in, so a reel being laid out in the inspector is visible right away.

TITLE:
Inspector: New Panels Adopt the Current Timeline
DESCRIPTION:
A new Timeline or Construct panel opens on whatever its counterpart is already editing.

TITLE:
Timeline Panel: Default Timeline Checkbox
DESCRIPTION:
An 'isDefaultTimeline:' checkbox in the panel header sets which Timeline controls its Construct. Unchecking hands it back to NeutralState.

TITLE:
Inspector: Manage Timelines Rebuilt
DESCRIPTION:
Adding, duplicating, renaming, reordering and removing Timelines now applies immediately and is undoable. A Construct selector at the top lets the window open from the Manage menu as well as from the Construct panel.

TITLE:
Fixed: A Removed Timeline Could Come Back
DESCRIPTION:
A Timeline removed while a panel was still viewing it was written back into its Construct by that panel's next change poll.

TITLE:
Inspector: Manage Constructs Rebuilt
DESCRIPTION:
Adding, duplicating, renaming and removing Constructs now applies immediately rather than requiring a save and reload, and every change is undoable. A new Construct is scrolled to in the list and switches the unlocked Construct and Timeline panels.

TITLE:
Project Files Can Be Deleted And Renamed Undoably
DESCRIPTION:
A deleted project file is marked for removal rather than erased, so an undo brings it back and it only leaves disk on the next save. A rename carries the file's content and its '.ncData' across in a single undo step.

TITLE:
Timeline Panel: Option-Drag Duplicates Keyframes
DESCRIPTION:
Holding Option while dragging a keyframe now duplicates the whole keyframe selection and drags the copies, leaving the originals in place. Copies become the new selection immediately.

TITLE:
KeyframedValue: The 'Keyframe' Class Is Now 'ValueKeyframe'
DESCRIPTION:
The 'Keyframe' class has been renamed to 'ValueKeyframe'. Its old name collided with the DOM's built-in 'Keyframe' interface from the Web Animations API, and since the generated 'IncisorAPI.d.ts' declares its classes globally, TypeScript merged the two and reported six errors against the class in every TypeScript project. Every member and method name is unchanged - 'KeyframedValue.addKeyframe', 'keyframes', 'keyframeType' and 'constants.keyframeTypes' all keep their names. Existing Constructs are unaffected, as the class type tag was never written into serialized blueprints.











----------------------------------------------------------
Section 24: 2026.08.04.00.00.00
----------------------------------------------------------


TITLE:
Older Spine-Imported Constructs Are Detected On Load
DESCRIPTION:
Constructs produced by a Spine importer that predates the 'spineImportVersion' stamp can no longer be built, and previously took the whole project down while loading. They are now detected as predefined Constructs are populated and replaced by empty placeholders so the rest of the project still loads. The inspector lists every affected Construct as soon as it connects, no save path will write over their '.construct' files while they are in that state, and publishing is blocked until they are resolved. Each affected animation must be removed by deleting its imported directory in full — the '.construct' file, the generated '.codeAsset.js', and the images and geometries the import wrote — after which it can be imported again from its original Spine files.

TITLE:
Legacy Spine Code Assets No Longer Break Startup
DESCRIPTION:
The older Spine importer wrote a '<constructName>.codeAsset.js' beside each animation it produced, calling an 'nc.spineManagement' API that has since been removed. Those calls ran early in startup and failed before the incompatible-animation report could be shown. The three functions are restored as a compatibility shim: effect nodes and controllers are handed to the current Spine module, which still produces every name the old importer emitted, and the custom-item call is inert since the classes it registered no longer exist. The code asset sits in the animation's imported directory and is removed along with it.











----------------------------------------------------------
Section 25: 2026.08.03.00.00.00
----------------------------------------------------------


TITLE:
Inspector: New Timeline Panel
DESCRIPTION:
The Timeline panel has been rebuilt: a searchable construct/timeline selector, three columns (names, value + controls, keyframe track), header playback controls, per-property keyframe drop / prev-next nav / graph toggle, filtering and sorting, and a lock for editor or live timelines.

TITLE:
Inspector: Legacy Timeline Panel Removed
DESCRIPTION:
The old Timeline panel and its components are gone; the new panel is now simply 'Timeline'.

TITLE:
Inspector: Timeline Editing Without the Construct Panel
DESCRIPTION:
A construct's timeline can now be edited from a Timeline panel alone — the Construct panel no longer needs to be open.

TITLE:
Inspector: Construct & Timeline Lock and Sync
DESCRIPTION:
The Construct and Timeline panels now stay in sync both ways, each with a lock button to opt out of the automatic connection.

TITLE:
Inspector: Construct Panel Playback Controller
DESCRIPTION:
A playback controller overlays the Construct panel's scene view while editing a timeline state, scrubbing that timeline's playhead.

TITLE:
Inspector: Animate Context Menu
DESCRIPTION:
Right-clicking an object in the Timeline panel lists the properties it can animate, grouped by object type, with materials and components on their own sub-menus.

TITLE:
Inspector: Copy, Cut, and Paste Keyframes
DESCRIPTION:
Keyframes can be copied, cut, and pasted via menus or the keyboard; paste re-anchors to the playhead and matches targets by id then name.

TITLE:
Engine: Animated Property Value Coercion
DESCRIPTION:
Keyframe and property values are coerced to the property's type, so a wrong-type edit or paste no longer stores a mismatched value.

TITLE:
Engine: Animated Property Recipient Validation
DESCRIPTION:
Adding an animated property now checks the path is animatable on the target object; a new nc.incr_internal._getAnimatablePropertyMap enumerates what an object supports.

TITLE:
Engine: Finalized Timeline timeSnap Model
DESCRIPTION:
KeyframedValue timeSnap defaults to 0.02; a Timeline's timeSnap drives all its properties and seeds from the new nc.defaultTimelineTimeSnap setting; absent = legacy 1/60.

TITLE:
Inspector: Timeline Actions Menu
DESCRIPTION:
New actions bake a non-1 playback rate into keyframe times ('Normalize Playback Rate') and re-time all keyframes onto a new grid ('Change Time Step').

TITLE:
Inspector: Layers Panel and Manage Layers Rebuilt
DESCRIPTION:
Both were rebuilt with add/remove/reorder/rename, fixing a bug where a construct's layer vanished on refresh when a same-named layer was added elsewhere.

TITLE:
Inspector: Header-less Panels
DESCRIPTION:
Panels can now have a body with no header strip; the Layers panel uses this for a cleaner full-height list.











----------------------------------------------------------
Section 26: 2026.07.27.00.00.00
----------------------------------------------------------


TITLE:
API: nc.getSearchFilterScore
DESCRIPTION:
New nc.getSearchFilterScore(filterString, candidateStrings, candidateStringWeights) exposes the standardized search scorer. The filter is tokenized on spaces so multi-word searches match across candidates (e.g. 'hero jump' matches 'Hero-JumpTimeline'); candidateStrings may be one or more strings, with optional parallel per-candidate weights.

TITLE:
Inspector: Searchable menus use the standardized search
DESCRIPTION:
Searchable UxMenus, in both regular and large-list mode, now score with the shared token-aware algorithm, so multi-word filters match. A single implementation now backs the menus and the inspector panels' search.











----------------------------------------------------------
Section 27: 2026.07.25.00.00.00
----------------------------------------------------------


TITLE:
KeyframedValue: timeSnap / valueSnap
DESCRIPTION:
'snapInterval' renamed to 'timeSnap' (old name kept as a deprecated alias); new optional 'valueSnap' snaps numeric values to a grid. AnimatedProperties default both to 0.01; existing content is unchanged.

TITLE:
Inspector: Keyframe Tangent Handle Coupling
DESCRIPTION:
Dragging a tangent handle now couples the opposite handle: default keeps it rotation-locked, Option moves only the dragged handle, Cmd/Ctrl also matches its length, Shift flattens it.

TITLE:
Inspector: Dragging Keyframes Onto an Occupied Time
DESCRIPTION:
Dragging a Keyframe across or onto another's time no longer deletes the overlapped one; an intentional drop-on-top still overwrites.

TITLE:
Inspector: Keyframe Tooltip
DESCRIPTION:
Keyframes now show a tooltip covering selection, dragging, steps, handles, and the right-click menu.











----------------------------------------------------------
Section 28: 2026.07.24.00.00.00
----------------------------------------------------------


TITLE:
KeyframedValue: Stepped Keyframes Defined by a Single Keyframe (secondaryValue)
DESCRIPTION:
A stepped discontinuity in a KeyframedValue (or AnimatedProperty) is now expressed with a single Keyframe carrying the new 'secondaryValue' property, rather than a coincident 'left'/'right' Keyframe pair. A Keyframe's 'keyframeType' is still 'standard' (default), 'left', or 'right': for a 'left' keyframe the primary 'value' governs the left side of the step and 'secondaryValue' governs the right; for a 'right' keyframe 'value' governs the right and 'secondaryValue' governs the left. Sampling exactly at a Keyframe's time always returns its primary 'value', for every type. 'secondaryValue' is ignored while 'keyframeType' is 'standard', and falls back to 'value' until explicitly set, so a fresh step reads flat until edited. No two Keyframes may share a time. Left/right bezier handles now measure their value offset from the boundary value on their side (the primary value, or 'secondaryValue' on a step's far side). Blueprints round-trip 'secondaryValue'.

TITLE:
Inspector: Keyframe Graph Shows Both Sides of a Step
DESCRIPTION:
In the keyframe graph, a stepped Keyframe now renders as two dots — its primary value and its secondaryValue — joined by a vertical connector, each independently draggable and each carrying its own bezier handle; the recessive (secondary) side is dimmed to distinguish it from the dominant side. The secondary dot, its hit target, and the connector are created lazily and appear only for a step Keyframe while the graph is drawn. The keyframe right-click menu's 'split' converts a standard Keyframe into a step in place (a 'right' step, flat until dragged), and a new 'type' sub-menu sets the selection to standard, left, or right.

TITLE:
KeyframedValue: continueLeft / continueRight
DESCRIPTION:
New 'continueLeft' and 'continueRight' properties control how a KeyframedValue (or AnimatedProperty) evaluates beyond its keyframe range: 'constant' (default), 'extrapolate', 'loop', or 'pingPong' (see constants.continueModes). Default is not serialized; both round-trip through blueprints.

TITLE:
Inspector: Keyframe Graph — Background Context Menu
DESCRIPTION:
Right-clicking a keyframe graph's empty background opens a whole-KeyframedValue menu at the cursor, with 'continueLeft'/'continueRight' sub-menus (the active mode checkmarked). It is extensible by an owning panel, and the shared context-menu helper gains an opt-in to open at the cursor with no anchor or outline.











----------------------------------------------------------
Section 29: 2026.07.21.00.00.00
----------------------------------------------------------


TITLE:
FileIO: Now an Optional Code Module (no longer subscription-gated)
DESCRIPTION:
nc.fileIO has been converted from a subscription-gated, development-only feature into a standard optional code module named 'fileIO'. The fileIO permission requirement has been removed everywhere, so file IO is now available to all users regardless of subscription tier. Like any optional module, 'fileIO' can be excluded per configuration in ProjectSettings to reduce published download size, and file access remains governed by the application-level 'allowUniversalFileIO' safety setting for paths outside the project directory.

TITLE:
FileIO: Now Available in Published Electron Builds
DESCRIPTION:
nc.fileIO can now be used in published Electron applications, not only while developing in Incisor. Each fileIO call is packaged into a canonical request and routed through a transport layer that targets the Incisor server during development and the Electron runtime (native Node file access) once published — the request and response format is identical in both. To enable it, include the new 'fileIoElectron' optional code module alongside 'fileIO'. In the published app, relative paths resolve within the application's own data directory (Electron's userData location); access to other locations is controlled per-build via the Electron package options below.

TITLE:
Electron Publishing: 'incisorFileIoLayer' and 'allowUniversalFileIO' Package Options
DESCRIPTION:
The Electron auxiliaryPublishingPackage now exposes two options that govern published file IO, both editable in ProjectSettings and documented in the API spec. 'incisorFileIoLayer' (default true) determines whether the build includes the native fileIO layer. 'allowUniversalFileIO' (default false) determines whether the build may read and write outside its own application data directory; when false, non-relative paths are refused with an explanatory dialog. This is the published-Electron counterpart to the existing application-level 'allowUniversalFileIO' setting that governs file IO while developing.

TITLE:
Inspector: Tooltips for All Optional Code Modules
DESCRIPTION:
Every optional code module listed in the ProjectSettings popup now shows a descriptive tooltip explaining what that module provides. The 'fileIO' and 'fileIoElectron' tooltips, together with the Electron 'incisorFileIoLayer' and 'allowUniversalFileIO' option tooltips, cross-reference one another to make clear how published file IO is turned on and scoped.











----------------------------------------------------------
Section 30: 2026.07.15.00.00.00
----------------------------------------------------------


TITLE:
Inspector: Transcript Panel — Detect Pairings
DESCRIPTION:
A new 'detectPairings...' button in the Transcript Panel header opens a popup that scans all project constructs for TextBox and TextAssembly objects, listing any phrase–font pairs not yet registered in font definitions. Pairs can be toggled and applied in bulk.

TITLE:
Inspector: Object Panel — Add to Transcript
DESCRIPTION:
A new 'addToTranscript' button appears in the Text Info section next to the phraseID field, active only when no phraseID is assigned. It prompts for a phrase ID, adds it to the ProjectTranscript using the object's current string, and assigns the phraseID to all selected text objects.

TITLE:
Inspector: Object Panel — Clear phraseID via '(none)'
DESCRIPTION:
The phraseID dropdown in the Object Panel's Text Info section now includes a '(none)' option at the top of the list, which clears the phraseID on all selected text objects back to undefined.











----------------------------------------------------------
Section 31: 2026.07.09.00.00.00
----------------------------------------------------------


TITLE:
Inspector: Filter Fields Overhauled
DESCRIPTION:
A new shared '_filterScore' method on CommonInspectorUiTools tokenizes filter strings by spaces and scores each token against weighted candidates. All inspector filter fields now use it, gaining multi-keyword support and score-ranked results.

TITLE:
Inspector: Transcript Panel Rebuilt
DESCRIPTION:
The Transcript panel has been rebuilt using UxListSupervisor with pooled phrase elements, each exposing an ID field, language dropdown, phrase text field, and a collapsible 'include in fonts' section with per-font toggles. The header adds a multi-keyword filter, open/close all, and Font Reduction shortcut.











----------------------------------------------------------
Section 32: 2026.07.06.00.00.00
----------------------------------------------------------


TITLE:
Inspector: SceneObject Context Menu Overhauled
DESCRIPTION:
The right-click context menu on scene objects in the Inspector — both in the scene object list and in the HUD viewport — has been rebuilt using the UxMenu system. All 'Add' options are now grouped into a single 'Add' submenu, each entry carrying a type icon sourced from the TypeGraphicRegistry. Enable and Disable items have been added to the top-level menu, using the show/hide eye icons, and are automatically deactivated when the entire selection is already in the target state. All top-level items now display a left icon. The item order has been revised to: Add, Duplicate, Copy, Paste, Enable, Disable, Capture as Construct, Remove. The Remove label changes to 'Remove Objects' when multiple objects are selected. Right-clicking in the HUD viewport positions the menu at the cursor rather than at a fixed anchor.











----------------------------------------------------------
Section 33: 2026.06.30.00.00.00
----------------------------------------------------------


TITLE:
PlaybackController: autoplayMode default changed to 'none'
DESCRIPTION:
The default value of PlaybackController.autoplayMode has changed from 'loop' to 'none'. PlaybackControllers added to a Construct will no longer automatically loop on instantiation unless autoplayMode is explicitly set to 'loop' or 'once'.











----------------------------------------------------------
Section 34: 2026.06.15.00.00.00
----------------------------------------------------------


TITLE:
Spine Import Rebuilt
DESCRIPTION:
The Spine importer has been rewritten from the ground up and now covers virtually the whole of Spine's feature set rather than a subset of it. Bone-weighted meshes, deform animation, IK, transform and path constraints, clipping attachments, tint black, linked meshes, sequences, draw order and attachment switching all come across, as do skins that carry bones and constraints of their own. Imports target Spine 4.3, and the skeleton's own exported version is read so that a file authored in an earlier release keeps the behavior it was authored with. Every import is stamped with the importer version that produced it, which is what lets Incisor recognize an animation brought in by an older importer and tell you about it rather than failing at load.

TITLE:
Spine Import: Runtime Physics
DESCRIPTION:
Physics constraints are imported and simulated live, so hair, cloth, capes and anything else driven by physics in Spine behaves the same way in Incisor instead of arriving frozen. Inertia, strength, damping, mass, wind, gravity, mix, limit and the per-axis influences are all carried over, along with the constraint's own simulation rate and its scaleY mode. Damping and inertia defaults changed between Spine 4.2 and 4.3, and an exported file omits a value it considers default - so the defaults are chosen from the version that wrote the skeleton, and a 4.2 animation no longer over-damps when read by a 4.3-aware importer.











----------------------------------------------------------
Section 35: 2026.05.21.00.00.00
----------------------------------------------------------


TITLE:
CustomBlendingMode
DESCRIPTION:
Added support for fully configurable WebGL blending via 'nc.defineCustomBlendingMode'. A CustomBlendingMode exposes independent control over the blend equation and source/destination factors for both RGB and alpha channels, and can be assigned directly to a Material's 'blending' property. Defined modes are stored in 'nc.customBlendingModes' and appear as live entries in the inspector's autocomplete documentation, updated immediately on each call to 'nc.defineCustomBlendingMode'.











----------------------------------------------------------
Section 36: 2026.05.18.00.00.00
----------------------------------------------------------


TITLE:
Object Panel: Timeline Editor Scene Awareness
DESCRIPTION:
When selected objects reside in a Timeline Editor Scene, the Object Panel now dims and deactivates its body section to indicate that direct property editing is unavailable in that context. The type supervisor and lock button are hidden, and the header shows an alert message alongside an 'Edit in NeutralState' button that navigates the scene back to its NeutralState.

TITLE:
Object Panel: Construct Info Hidden for Root Construct Instance
DESCRIPTION:
The Construct Info section is no longer shown when the selected object is the root construct instance of the currently open Construct Editor Scene or Timeline Editor Scene. Because the timelines of that instance are already under artificial weight constraints in those scenes, surfacing them for editing would be misleading.

TITLE:
UxStringSupervisorMenu: Added overrideWidth
DESCRIPTION:
New property that fixes the mainText boxWidth when a real (non-dash) value is displayed. By default the boxWidth is set to 0 when a value is shown, allowing the text to size naturally. Setting overrideWidth to a number forces a consistent fixed width regardless of value content, complementing the existing dashWidth property which controls width in the indeterminate '-' state.

TITLE:
TextBox: upDownArrowEndsEditing and leftRightArrowEndsEditing
DESCRIPTION:
Two new boolean properties on TextBox. When upDownArrowEndsEditing is true, pressing ArrowUp or ArrowDown ends the current editing session; when leftRightArrowEndsEditing is true, ArrowLeft or ArrowRight does the same. In both cases, if a UiKeyboardNavigator is active, the appropriate directional navigation (goTowards) is triggered automatically. Both default to false.

TITLE:
singularFocusButtonPressRequirements: All Non-Listed Button Input Now Suppressed
DESCRIPTION:
When nc.singularFocusButtonPressRequirements is populated, all button input — including cursorIn and hover events — is now ignored for any Button not in the array, in addition to the existing behavior of relinquishing focus when a press occurs outside the listed Buttons. This prevents other interactive elements from visually or functionally responding to the cursor while a TextBox or UiTextField is focused.











----------------------------------------------------------
Section 37: 2026.05.14.00.00.00
----------------------------------------------------------


TITLE:
Inspector: Top Bar Menus Overhauled
DESCRIPTION:
The top bar menus (Incisor®, Project, Manage, View, Template Library, Import, and any extension-added menus) have been rebuilt to more closely mirror standard menu bar UI conventions. Clicking a menu button now sets keyboard focus to the menu bar, enabling hover-to-switch between menus without additional clicks. Arrow-key navigation moves between top-level menu buttons. Pressing a menu button or navigating to it via keyboard while the menu bar is focused opens the associated menu. Clicking the background dimmer closes all open menus and releases focus. Extension-added menus (via nce.addInspectorMenuItem) participate in the same focus, hover-switch, and keyboard navigation behavior as built-in menus.

TITLE:
Keyboard Navigation: Arrow Key Support Added
DESCRIPTION:
UiKeyboardNavigator now supports spatial arrow-key navigation via the new 'goTowards' method. Pressing the left, right, up, or down arrow keys moves the keyboard outline to the nearest UiKeyboardNavigable item in the corresponding direction relative to the currently outlined item. If nothing is currently outlined, arrow navigation falls back to the standard next-item behavior.











----------------------------------------------------------
Section 38: 2026.05.12.00.00.00
----------------------------------------------------------


TITLE:
UxMenu: Added configureLargeListMode
DESCRIPTION:
New method that puts a UxMenu into large-list mode. In this mode, menu items are managed asynchronously by an internal UxListSupervisor rather than being populated manually via addMenuItem or addMenuItemWithSubMenu. The provided callback must return an array; each element is converted to a string and used as a menu item name. Items are created and pooled incrementally across fixed-update frames, avoiding the synchronous performance cost of building a large list on open. Searching works normally in this mode — the filter is applied inside the callback passthrough, and the supervisor handles element activation and deactivation naturally. Must be called before the menu is first opened. addMenuItem, addMenuItemWithSubMenu, and clearMenuItems must not be called once large-list mode is active.

TITLE:
UxMenu: Fixed background collapsing when search filters all items
DESCRIPTION:
When a searchable UxMenu had all of its items filtered out by the search field, the menu background and scrolling panel would collapse to near-zero width because the background size was derived solely from item widths. The layout now enforces a minimum width sufficient to keep the search field fully visible regardless of how many items remain after filtering.











----------------------------------------------------------
Section 39: 2026.05.09.00.00.00
----------------------------------------------------------


TITLE:
Object Panel: Multi-Object Supervision
DESCRIPTION:
The Object Panel has been rebuilt to support supervising multiple selected objects simultaneously. Edits to any supervised property are applied to all selected objects at once. When supervised values diverge across the selection, a '-' placeholder is shown in text fields and an indeterminate state is shown in checkboxes and other binary controls.

TITLE:
Object Panel: Delta Mode
DESCRIPTION:
Numeric supervisors in the Object Panel can now be switched into delta mode when multiple objects are selected. In delta mode, entering a value applies it as an offset relative to each object's current value rather than overwriting all selected objects with the same absolute value.

TITLE:
Object Panel: New Construct Info Section
DESCRIPTION:
A new Construct Info section has been added to the Object Panel. When a Construct instance is selected it lists all timelines defined on that Construct, each with its current weight and a playback controller where applicable. The 'takeWeight' button animates the selected timeline's weight to 1 while reducing all other timelines to 0 over one second (hold Shift for 0.25s or Cmd/Ctrl for 5s). The 'playOnceAndTakeWeight' button takes weight from all other timelines and plays the selected timeline from the beginning once.

TITLE:
Tooltips Overhauled
DESCRIPTION:
Tooltips have been redesigned as self-contained timed popups that appear directly over the hovered element rather than in a dedicated tooltip panel. Multiple tooltips can now be stacked on a single element - all registered entries are displayed together in a single popup, ordered from most to least specific. The tooltip panel is no longer required and has been removed. Tooltips can now be toggled on or off entirely from Application Settings, and the display delay before a tooltip appears can also be adjusted there.

TITLE:
Numeric Supervisors: Mathematical Expression Support
DESCRIPTION:
Numeric supervisor text fields now accept mathematical expressions. Entering an expression containing +, -, *, or / (e.g. '90+45' or '100/3') will evaluate the result and apply it as the new value.











----------------------------------------------------------
Section 40: 2026.05.04.00.00.00
----------------------------------------------------------


TITLE:
Hierarchy Panel: show disabled state is now persistent per panel
DESCRIPTION:
The state of the 'show disabled' toggle in the Hierarchy panel is now saved as part of the panel's stateInfo and restored when the session is reloaded. Each Hierarchy panel instance saves its own setting independently.

TITLE:
PlaybackController.autoplayWhenInConstruct is becoming PlaybackController.autoplayMode [DEPRECATION ID 2026.05.04.00]
DESCRIPTION:
autoplayWhenInConstruct is being replaced by autoplayMode, which accepts a string ('none', 'loop', or 'once') instead of a boolean. Setting true converts to autoplayMode 'loop'; setting false converts to autoplayMode 'none'. The old property still works but logs a deprecation warning. Phase 2 target: end of 2026.

TITLE:
Added SpriteSetter.keyGraphicAsset
DESCRIPTION:
New property on SpriteSetter. The setter calls setKeyGraphicAsset and stores an internal reference to the chosen GraphicAsset; the getter returns that reference. Equivalent to calling setKeyGraphicAsset directly.











----------------------------------------------------------
Section 41: 2026.05.03.00.00.00
----------------------------------------------------------


TITLE:
Added UxPlaybackControllerSupervisor
DESCRIPTION:
New Ux supervisor that provides a play/pause toggle button, a playOnce/pause toggle button, and a stop button for supervising PlaybackController objects. When a single PlaybackController is supervised, a ranged slider is shown with its range driven automatically from the owner's startTime and endTime. When multiple PlaybackControllers are supervised simultaneously, a text field is shown instead. The label displayed next to the value supervisor reads 'time:' for timeline-based controllers and 'value:' for value-based ones. The play and playOnce buttons swap to a pause icon while the relevant owners are in a playing state.

TITLE:
ColorPicker: Fixed live multi-color array editing and Cancel restoration
DESCRIPTION:
The ColorPicker popup now correctly supports being opened with an array of live Color objects. Changes are applied live during editing; pressing Cancel restores all colors to their original values. Alpha channel visibility is now managed dynamically — the alpha row is shown or hidden based on whether the current color mode includes alpha, and the layout is rebuilt cleanly when this changes. The hex field automatically selects its text when the popup opens. A crosshair cursor and input blocker are shown during sample (eyedropper) mode.











----------------------------------------------------------
Section 42: 2026.04.30.00.00.00
----------------------------------------------------------


TITLE:
LayoutStack: Added borderExpansion
DESCRIPTION:
New property that offsets the size of the border in all directions relative to the LayoutStack's content bounds. A positive value expands the border beyond the content bounds; a negative value contracts it. The value is pre-uiZoom and is scaled automatically. Has no effect unless displayBorder is true. Defaults to 0.

TITLE:
LayoutStack: Added backgroundPanelExpansion
DESCRIPTION:
New property that offsets the size of the backgroundPanel in all directions relative to the LayoutStack's content bounds. A positive value expands the panel beyond the content bounds; a negative value contracts it. The value is pre-uiZoom and is scaled automatically. Has no effect unless displayBackgroundPanel is true. Defaults to 0.

TITLE:
Fixed Intermittent Crash on Browser Refresh
DESCRIPTION:
An ObjectDisposedException could occur in the HTTP server when a browser refresh caused the client to disconnect before the server finished sending its response. The response-write path is now guarded against disposed connection objects.

TITLE:
UiTextField: Added displayExButton and exButton
DESCRIPTION:
New properties that add an optional clear button to UiTextField. Setting displayExButton to true lazily creates a UiLinkButton (exButton) at the right edge of the text area. The button is visible only when the field is non-empty and clears the text when pressed.

TITLE:
Added UxStringSupervisorButton
DESCRIPTION:
New Ux supervisor that extends UiButton and displays a supervised string property as its mainText. When multiple diverging values are supervised a '-' is shown. No property manipulation is built in — add a trigger callback to respond to button presses with custom behavior.











----------------------------------------------------------
Section 43: 2026.04.29.00.00.00
----------------------------------------------------------


TITLE:
Added UxVectorSupervisorTextField.singularFocusTarget
DESCRIPTION:
New property that restricts keyboard focus so that only one component text field holds focus at a time within the specified target. Setting this property automatically propagates the value to all current and future component UxNumberSupervisorTextFields.

TITLE:
UxCollapsibleStack: Safety Guard Added to Trigger Callbacks
DESCRIPTION:
A crash that could occur when open/close callbacks were triggered before the callback array was initialized has been fixed.

TITLE:
Fixed Incisor Failing to Launch on Intel-based Macs
DESCRIPTION:
A bug was causing Incisor to fail on OSX machines running Intel processors. This has been fixed.











----------------------------------------------------------
Section 44: 2026.04.23.00.00.00
----------------------------------------------------------


TITLE:
Introducing UxCollapsibleStack
DESCRIPTION:
A vertical LayoutStack with a header row containing an open/close toggle button. Triggering the button enables or disables a body LayoutStack, allowing sections of inspector UI to be neatly collapsed. Supports optional border display and open/close callbacks.

TITLE:
Introducing UxStandardListViewElement
DESCRIPTION:
A horizontal LayoutStack that serves as a standard visual container for a single item within a list view. Exposes a 'bodyStack' for custom item content and optional built-in utility controls for reordering, duplicating, adding, and removing list items.











----------------------------------------------------------
Section 45: 2026.04.21.00.00.00
----------------------------------------------------------


TITLE:
Introducing UxBooleanSupervisorCheckbox
DESCRIPTION:
A supervisor for boolean properties, displayed as a labeled checkbox. Checking or unchecking the box writes the new value to all supervised owners. When multiple diverging values are supervised simultaneously, an indeterminate '-' state is shown.

TITLE:
Introducing UxVectorSupervisorTextField
DESCRIPTION:
A supervisor for Vector properties, displayed as a row of per-component UxNumberSupervisorTextFields (x, y, z, w). Component supervisors are created on demand as the dimensionality of the supervised Vector is determined. Edits component values in-place rather than replacing Vector references.











----------------------------------------------------------
Section 46: 2026.04.19.00.00.00
----------------------------------------------------------


TITLE:
Introducing UxStringSupervisorTextField
DESCRIPTION:
A supervisor for string properties, displayed as an editable text field. Committing a new value writes it to all supervised owners. When multiple diverging values are supervised simultaneously, a '-' placeholder is shown.

TITLE:
Introducing UxStringSupervisorMenu
DESCRIPTION:
A supervisor for string properties that presents its value choices as a UxDropDownMenu. Selecting a menu item writes the chosen value to all supervised owners. When multiple diverging values are supervised simultaneously, a '-' placeholder is shown.











----------------------------------------------------------
Section 47: 2026.04.17.00.00.00
----------------------------------------------------------


TITLE:
Introducing UxNumberSupervisorTextField
DESCRIPTION:
A supervisor for numeric properties, displayed as an editable text field with an optional drag-to-scrub interaction. Supports value validation, custom setters, singular focus targeting, and multi-owner supervision with a '-' shown when supervised values diverge.

TITLE:
Introducing UxNumberSupervisorRangedSlider
DESCRIPTION:
A supervisor for numeric properties that fall within a defined min/max range, displayed as a draggable slider. Provides a visual representation of a value's position within its range and writes changes to all supervised owners.











----------------------------------------------------------
Section 48: 2026.04.15.00.00.00
----------------------------------------------------------


TITLE:
Introducing UxMenu, UxMenuItem, and UxDropDownMenu
DESCRIPTION:
Three new Ux objects that together provide a styled, keyboard-navigable menu system for use in extensions. UxMenu is a vertical LayoutStack that manages a list of UxMenuItems and supports optional search filtering and nested sub-menus. UxMenuItem is the individual row element. UxDropDownMenu is a button that anchors and toggles a UxMenu.











----------------------------------------------------------
Section 49: 2026.04.03.00.00.00
----------------------------------------------------------


TITLE:
Deprecated Timeline.influence, .swoopInfluence, .playOnce_swoopInfluence, .play_swoopInfluence...
DESCRIPTION:
Now use weight, takeWeight, swoopWeight, playOnceAndTakeWeight, playAndTakeWeight...

TITLE:
Added 'maintain current EffectNodes' checkbox to GraphicAssetSelectionPopupWindow
DESCRIPTION:
Allowing user to maintain the EffectNodes currently set on the GraphicObject whose GraphicAsset is being set.











----------------------------------------------------------
Section 50: 2026.03.25.00.00.00
----------------------------------------------------------


TITLE:
Further Bug Fixes to UxListSupervisor
DESCRIPTION:
More edge cases producing visual duplicates are fixed.











----------------------------------------------------------
Section 51: 2026.03.20.00.00.00
----------------------------------------------------------


TITLE:
Additional SlotReel Validation
DESCRIPTION:
A check has been added to ensure that the 'symbolDefinition' provided to SlotReel is a class that implements 'setSymbol'.











----------------------------------------------------------
Section 52: 2026.03.19.00.00.00
----------------------------------------------------------


TITLE:
UxListSupervisor Repeat Item Bug Fix
DESCRIPTION:
Repeated items in source lists were causing bugs with the UxListSupervisor

TITLE:
ScrollingPanel: Camera.autoRender Toggled Based On Enabled State
DESCRIPTION:
The autoRender state of a ScrollingPanel is now dependant on the ScrollingPanel being enabled.

TITLE:
Disallowing Invalid State Changes in SlotReel
DESCRIPTION:
Until now, it was allowed to be in the 'stopping' or 'stopImminent' states and call 'beginStop'. Now in that case the call is disregarded.

TITLE:
Fixed Video Dynamic Documentation Bug
DESCRIPTION:
The text replacement tag was being left in the IncisorAPI reference doc when a project has no compressed videos.











----------------------------------------------------------
Section 53: 2026.03.17.00.00.00
----------------------------------------------------------


TITLE:
Fix to Electron Builds Missing Dependencies
DESCRIPTION:
Now, Incisor automatically runs 'npm install' on the Electron project workspace before building so that any dependencies are installed before every electron publish.











----------------------------------------------------------
Section 54: 2026.03.14.00.00.00
----------------------------------------------------------


TITLE:
Fixed Bug with Layer Validation
DESCRIPTION:
In some cases, using setLayers would report that a layer doesn't exist when it does - this has been fixed.

TITLE:
IncisorAPI Trailing Commas Documentation
DESCRIPTION:
Fixed an issue where dynamic documentation for nc.appEvents, and nc.precomps was including trailing commas.











----------------------------------------------------------
Section 55: 2026.03.11.00.00.00
----------------------------------------------------------


TITLE:
Fixed Issue with ScrollingPanel.ScrollTo
DESCRIPTION:
Scrolling to a disabled SceneObject was causing craziness. A validation warning has been added











----------------------------------------------------------
Section 56: 2026.03.05.00.00.00
----------------------------------------------------------


TITLE:
Bug with Open/Close Hierarchy Items Fixed
DESCRIPTION:
Sometimes the caret would appear to be open or closed erroneously when it is first displayed. This has been fixed.

TITLE:
Electron Publishing Validation and Publishing Stability Refactoring
DESCRIPTION:
There were many issues surrounding Incisor's validation of the electron and electron-builder dependencies that have been fixed.











----------------------------------------------------------
Section 57: 2026.03.03.00.00.00
----------------------------------------------------------


TITLE:
Fixed Live View Layering Issue
DESCRIPTION:
Fixed bug where making a panel small enough so that the body disappears allows the LiveView to show through to the front outside of its panel area.











----------------------------------------------------------
Section 58: 0000.00.00.00
----------------------------------------------------------


TITLE:
Template Change Item
DESCRIPTION:
This is where the description of the change goes...

Incisor® Deprecation Schedule

IncisorDeprecationSchedule.txt

Incisor® Deprecation Schedule
This document is part of the compiled knowledge base for the Incisor® Software Development Platform.
Any use of this content is subject to the INCISOR® end user license and terms of use agreement.
https://www.incisordev.com/eultua
2026.11.05.12.18.12






----------------------------------------------------------
TABLE OF CONTENTS:
----------------------------------------------------------
Section 1: 2024.10.23.00
Section 2: 2024.10.23.01
Section 3: 2024.10.23.02
Section 4: 2024.10.23.03
Section 5: 2024.10.29.00
Section 6: 2024.10.29.01
Section 7: 2024.10.31.00
Section 8: 2024.10.31.01
Section 9: 2024.10.31.02
Section 10: 2024.10.31.03
Section 11: 2024.11.13.00
Section 12: 2025.02.19.00
Section 13: 2025.02.20.00
Section 14: 2025.02.25.00
Section 15: 2025.03.05.00
Section 16: 2025.03.05.01
Section 17: 2025.04.02.00
Section 18: 2025.04.02.01
Section 19: 2025.04.25.00
Section 20: 2025.04.27.00
Section 21: 2025.05.06.00
Section 22: 2025.05.21.00
Section 23: 2025.05.27.00
Section 24: 2025.05.28.00
Section 25: 2025.05.28.01
Section 26: 2025.06.13.00
Section 27: 2025.10.15.00
Section 28: 2025.12.04.00
Section 29: 2026.01.16.00
Section 30: 2026.02.03.00
Section 31: 2026.04.03.00
Section 32: 2026.05.04.00
Section 33: 2026.07.16.00
Section 34: 2026.08.04.00
Section 35: 2026.10.23.00
Section 36: 2026.10.23.01










----------------------------------------------------------
Section 1: 2024.10.23.00
----------------------------------------------------------


Title: 'convertToShape' is becoming 'shapify' within ncData

Description: The system will automatically convert the 'convertToShape' bool within the ncData for assets to 'shapify' until phase2 deprecation. Just save the project to adopt the update.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 2: 2024.10.23.01
----------------------------------------------------------


Title: 'optimizationLevel' is becoming 'shapifyOptimizationLevel' within ncData

Description: The system will automatically convert the 'optimizationLevel' bool within the ncData for assets to 'shapifyOptimizationLevel' until phase2 deprecation.Just save the project to adopt the update.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 3: 2024.10.23.02
----------------------------------------------------------


Title: 'edgeRange' is becoming 'shapifyEdgeRange' within ncData

Description: The system will automatically convert the 'edgeRange' bool within the ncData for assets to 'shapifyEdgeRange' until phase2 deprecation. Just save the project to adopt the update.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 4: 2024.10.23.03
----------------------------------------------------------


Title: 'Shape' and 'shape' are becoming 'Shapify' and 'shapify'

Description: The 'Shape' EffectNode and 'shape' EffectController are becoming 'Shapify' and 'shapify' respectively.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 5: 2024.10.29.00
----------------------------------------------------------


Title: 'Updater' and 'nc.updaters' are becoming 'AppEvent' and 'nc.appEvents'

Description: The 'Updater' type and 'nc.updaters' property are becoming 'AppEvent' and 'nc.appEvents' respectively. It should be noted that the deprecated 'nc.updaters' will not work with minification.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 6: 2024.10.29.01
----------------------------------------------------------


Title: 'nc.getAllUpdaterRecipients' is becoming 'nc.getAllEventRecipients'

Description: As part of the change from 'Updater' to 'Event', 'nc.getAllUpdaterRecipients' is deprecated. It should be noted that the deprecated 'nc.getAllUpdaterRecipients' will not work with minification.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 7: 2024.10.31.00
----------------------------------------------------------


Title: The 'coreCanvasResolution' array in ProjectSettings is becoming two separate values 'coreCanvasResolutionX' and 'coreCanvasResolutionY'

Description: By breaking these finite-length arrays into explicit components, auto-validation will become more robust and user clarity will be improved.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 8: 2024.10.31.01
----------------------------------------------------------


Title: The 'pivotAdjustment_position' array in ncData is becoming separate values 'pivotPointOffsetX', 'pivotPointOffsetY', and 'pivotPointOffsetZ'

Description: By breaking these finite-length arrays into explicit components, auto-validation will become more robust and user clarity will be improved. Just save the project to adopt the update.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 9: 2024.10.31.02
----------------------------------------------------------


Title: The 'resolutionScaling' array in ncData is becoming separate values 'resolutionScaleX' and 'resolutionScaleY'

Description: By breaking these finite-length arrays into explicit components, auto-validation will become more robust and user clarity will be improved. Just save the project to adopt the update.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 10: 2024.10.31.03
----------------------------------------------------------


Title: The 'unitsPerPixel' array in ncData is becoming separate values 'unitsPerPixelX', 'unitsPerPixelY' and 'unitsPerPixeZ'

Description: By breaking these finite-length arrays into explicit components, auto-validation will become more robust and user clarity will be improved. Just save the project to adopt the update.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 11: 2024.11.13.00
----------------------------------------------------------


Title: The 'Inspector' suffix is being removed from the panel names.

Description: The Object Inspector, Hierarchy Inspector, and Particle System Inspector, are all losing thier suffix.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 12: 2025.02.19.00
----------------------------------------------------------


Title: A temporary check has been added to detect duplicate UIDs listed in construct files.

Description: In certain situations in the Jan-Feb 2025 time range, using the 'duplicate' option in the Incisor GUI or even just using copy and paste within a construct hiearchy was resulting in duplicate UIDs within a construct. This check has been added to detect those duplicates and correct them.

State: Phase1: Detection and Correction Functionality in Effect

Phase2Target: 2025.06.01

Phase3Target: 2026.01.01












----------------------------------------------------------
Section 13: 2025.02.20.00
----------------------------------------------------------


Title: Graphic Expander Change: innerWidth and innerHeight are deprecated, and so are the expandableWidth and expandableHeight paremeters of the setup.

Description: Originally expandableWidth, expandableHeight, innerWidth, and innerHeight were each allowed to be either numbers or arrays - this was too easily confusable. Now a 'symmetric' flag determines which mode the GraphicExpander is in, and there is an entirely different set of properties for each mode. In symmetric mode, there is expandableWidth, expandableHeight, expandedWidth, & expandedHeight. In non-symmetric mode, there is expandableAreaLeft, expandableAreaRight, expandableAreaTop, expandableAreaBottom, expandedAreaLeft, expandedAreaRight, expandedAreaTop, & expandedAreaBottom

State: Phase1: Previous Behavior Still Works With Warning

Phase2Target: 2025.06.01

Phase3Target: 2026.01.01












----------------------------------------------------------
Section 14: 2025.02.25.00
----------------------------------------------------------


Title: Timeline.autoplay and Timeline.initialTime have been explicitly added, and the Construct blueprint format has been updated appropriately

Description: Constructs with timelines must be opened and saved before the phase 2 date for the implicit form of the functionality to be transfered into the Construct blueprint.

State: Phase1: Previous Behavior Still Works, and is Automatically Converted

Phase2Target: 2026.01.01

Phase3Target: 2026.01.01












----------------------------------------------------------
Section 15: 2025.03.05.00
----------------------------------------------------------


Title: CodeAsset file format change.

Description: Previously, code asset files ended in '.codeAsset' and the content of the files was placed entirely within the code asset init scope. Now files end in '.codeAsset.js' and their contents is placed by default in the code asset class space, except for 'CODE.runBeforeInit' blocks, which are put into the init scope.

State: Phase1: '.codeAsset' files are detected and automatically converted to '.codeAsset.js' files, with the contents wrapped in 'CODE.runBeforeInit' blocks.

Phase2Target: 2025.06.01

Phase3Target: 2026.01.01












----------------------------------------------------------
Section 16: 2025.03.05.01
----------------------------------------------------------


Title: jsconfig.json update

Description: Previously generated projects contain a jsconfig.json file that lists the 'Assets' directory as a directory to ignore. But this makes the autocomplete in '*.codeAsset.js' files not work. So a bit of code has been added to detect and fix this whenever a project is opened.

State: Phase1: jsconfig.json files will be automatically edited

Phase2Target: 2025.06.01












----------------------------------------------------------
Section 17: 2025.04.02.00
----------------------------------------------------------


Title: Timeline.playOnceAsEvent and Timeline.playOnceWithInfluence are being replaced with Timeline.playOnce_swoopInfluence

Description: For clearer naming and better usability.

State: Fully Deprecated












----------------------------------------------------------
Section 18: 2025.04.02.01
----------------------------------------------------------


Title: Timeline.playWithInfluence is being replaced with Timeline.play_swoopInfluence

Description: For clearer naming and better usability.

State: Fully Deprecated












----------------------------------------------------------
Section 19: 2025.04.25.00
----------------------------------------------------------


Title: Constructs without UID references are being deprecated.

Description: For a time, Constructs used an 'objectAddress' array as a means of identification - this is being entirely replaced with the 'UID' system.

State: Phase: Fully Deprecated.












----------------------------------------------------------
Section 20: 2025.04.27.00
----------------------------------------------------------


Title: New API for masking Graphic Objects - 'GraphicObject.masking'

Description: For GraphicObject, '.makeMasker', '.makeMasked', '.disableMasking', '.maskStatus', and '.maskList' are all being replaced by GraphicObject.masking

State: Phase1: Previous behavior still works with deprecation warnings, and the masking API will be automatically converted in Constructs, which must each be opened and saved in the inspector to commit the update.

Phase2Target: 2025.09.01












----------------------------------------------------------
Section 21: 2025.05.06.00
----------------------------------------------------------


Title: Particle System Random Distribution Type Support

Description: ParticleSystem.radnomnessDistribution no longer supports anything but a numeric value.

State: Phase3: Fully Deprecated












----------------------------------------------------------
Section 22: 2025.05.21.00
----------------------------------------------------------


Title: PlaybackController.autoplay -> PlaybackController.autoplayMode

Description: PlaybackController.autoplay was first deprecated in favor of PlaybackController.autoplayWhenInConstruct, and has now been fully deprecated in favor of PlaybackController.autoplayMode. The property no longer has any effect.

State: Phase2: Doesn't function, warns the user.












----------------------------------------------------------
Section 23: 2025.05.27.00
----------------------------------------------------------


Title: nc.particleSystemDefinitions -> nc.particleSystemDefs

Description: For consistency; definition dictionaries directly nc use the abbreviated 'Defs' to shorten the commonly used reference.

State: Phase1: Previous behavior still works with deprecation warnings.

Phase2Target: 2025.09.01












----------------------------------------------------------
Section 24: 2025.05.28.00
----------------------------------------------------------


Title: Updated Incisor Version Check moved to Standard 'SoftStatus' Update

Description: There used to be a check built in to Incisor to see if there were newer versions of Incisor available. The check has been moved to the server; when a newer version is found, the server sends a message through the standard messaging apparatus. But the 'newnewestVersionOfCurrentSet' is still being sent in the SoftStatusUpdate for backwards compatibility. In the next phase, the newnewestVersionOfCurrentSet will be taken out of the SoftStatusUpdate.

State: Phase1: Both new and old functionality work.

Phase2Target: 2025.09.01












----------------------------------------------------------
Section 25: 2025.05.28.01
----------------------------------------------------------


Title: Internal Remote Extensions Cloud Location Has Changed

Description: The original cloud location for Internal Remote Extensions has changed to include the VersionSet in its path. For now the old location is still being populated with remote extensions files. In the next phase, the old location will be removed.

State: Phase1: Both the old and new internal remote extensions locations work.

Phase2Target: 2025.09.01












----------------------------------------------------------
Section 26: 2025.06.13.00
----------------------------------------------------------


Title: AppEvent.addCallback has a 'callbackArgs' parameter between 'callbackName' and 'pauseImmunity'.

Description: This change helps to entirely unify the internal callbacks system and will future-proof AppEvents.

State: Phase: Fully Deprecated












----------------------------------------------------------
Section 27: 2025.10.15.00
----------------------------------------------------------


Title: SlotReel.symbolCustomAddOnDefinition will be deprecated. Please use SlotReel.symbolDefinition instead.

Description: This change is being made to accomodate SlotReel being able to accept either a CustomAddOn OR a CustomObject for the symbol functionality.

State: Phase1: Old functionality works with warning.

Phase2Target: 2026.06.01












----------------------------------------------------------
Section 28: 2025.12.04.00
----------------------------------------------------------


Title: nc.isTouchCursor will be deprecated, instead see nc.cursorMode

Description: A previous means of determining whether input from a certain device is touch or mouse driven was determined to be unreliable.

State: Phase1: Old functionality works with warning.

Phase2Target: 2026.06.01












----------------------------------------------------------
Section 29: 2026.01.16.00
----------------------------------------------------------


Title: The uv attribute and UV varying vec2 are now built into the Incisor EffectNode system.

Description: Individual EffectNode definitions should no longer include 'attribute vec2 uv;' in the vertex support and should no longer include 'varying vec2 UV;' in the either support for vertex or fragment.

State: Phase1: Old functionality works with warning.

Phase2Target: 2027.01.01












----------------------------------------------------------
Section 30: 2026.02.03.00
----------------------------------------------------------


Title: ProjectSettings files have added a 'auxiliaryPublishingPackageDefinitions' field with a template object, that must be converted to 'ElectronBasic' in validation.

Description: To keep validation from growing indefintely, this validation will be sunset in 2027.

State: Phase1: Old functionality works with warning.

Phase2Target: 2027.06.01












----------------------------------------------------------
Section 31: 2026.04.03.00
----------------------------------------------------------


Title: The 'influence' property, 'swoopInfluence' method, 'playOnce_swoopInfluence' method, and 'play_swoopInfluence' method are being deprecated.

Description: The way that 'influence' property of a given timeline auto-adjusted the influences of other timelines was causing confusion with users. Now use 'weight', 'swoopWeight', 'takeWeight', 'playOnceAndTakeWeight', 'playAndTakeWeight'

State: Phase1: Old functionality works with warning.

Phase2Target: 2026.09.01












----------------------------------------------------------
Section 32: 2026.05.04.00
----------------------------------------------------------


Title: PlaybackController.autoplayWhenInConstruct -> PlaybackController.autoplayMode

Description: PlaybackController.autoplayWhenInConstruct is being replaced by PlaybackController.autoplayMode, which accepts 'none', 'loop', or 'once'. Setting autoplayWhenInConstruct to true converts to autoplayMode 'loop'; setting it to false converts to 'none'. The Construct blueprint format has also been updated from the boolean 'autoplay' field to the string 'autoplayMode' field — existing Constructs are automatically converted on load.

State: Phase1: Previous behavior still works with warning.

Phase2Target: 2026.12.31












----------------------------------------------------------
Section 33: 2026.07.16.00
----------------------------------------------------------


Title: Construct timeline blueprint: the animated property 'binary' type and 'isBezier' flag are being replaced by the KeyframedValue 'boolean' type and 'interpolation' field.

Description: As AnimatedProperty is consolidated into the new KeyframedValue, the Construct timeline blueprint format is updated: an animated property's 'type':'binary' becomes 'type':'boolean', and the separate 'isBezier' boolean flag is folded into an 'interpolation' field ('isBezier':true becomes 'interpolation':'bezier'; its absence becomes the default 'optimizedBezier'). Existing Constructs are automatically converted on load — open and save each Construct in the inspector to commit the new format.

State: Phase1: Previous Behavior Still Works, and is Automatically Converted

Phase2Target: 2027.07.01












----------------------------------------------------------
Section 34: 2026.08.04.00
----------------------------------------------------------


Title: Spine-imported Constructs without 'constructSettings.spineImportVersion' are no longer supported, along with the 'nc.spineManagement' API their code assets call.

Description: The Spine import system was reworked, adding new internal classes and removing older ones, and Constructs produced before 'spineImportVersion' was stamped into their constructSettings can no longer be built. Two such generations exist: the oldest, where bones were CustomObjects driven by 'incr_Spine...' CustomAddOns, and a later one shaped like current output (native SpineBone/SpinePath) but written before the field existed. There is no automatic conversion — each affected animation must be removed from the project by deleting its imported directory in full (the '.construct' file, the generated '.codeAsset.js', and the images and geometries the import wrote), after which it can be imported again from its original Spine files. Each is detected while predefined Constructs are populated and replaced by an empty placeholder so the rest of the project still loads, no save path will write over its '.construct' file while it is in that state, the inspector reports the full list as soon as it connects, and publishing is blocked. The older importer also wrote a '<constructName>.codeAsset.js' beside each Construct whose 'runBeforeInit' block calls 'nc.spineManagement.enableEffectNodes', 'enableEffectControllers' and 'enableCustomItems'; that API was removed, and those calls ran early enough to break the load before it could be reported. A shim restores the three functions — effect nodes and controllers are routed to the current spine module, which still produces every name the old generator emitted, while enableCustomItems is inert because the CustomObject and CustomAddOn classes it registered no longer exist. That code asset sits in the animation's imported directory and is removed along with it. Detection is unpublished-only; when this deprecation is retired, affected projects will fail to load outright again.

State: Phase2: Doesn't function, warns the user.

Phase3Target: 2027.06.01












----------------------------------------------------------
Section 35: 2026.10.23.00
----------------------------------------------------------


Title: Electron Auxiliary Publishing Packages no longer run Node, npm or electron-builder, and 'ElectronPackage/package.json' is no longer used.

Description: Electron packages are now assembled directly from an embedded copy of the Electron runtime, with no Node, npm or electron-builder involved in publishing. The application's name, id, version, copyright and icon come from the package definition's 'packaging' section, and the output is a zip per target platform and architecture. A package folder that still has 'ElectronPackage/package.json' is told it is ignored. Projects that need npm packages place a ready 'node_modules' folder in the package's 'ElectronExtras' folder, prepared on the platform being published for (or per target in 'ElectronExtras/<platform>-<arch>/'). Installers, DMG files and auto-update are not produced.

State: Phase2: Doesn't function, warns the user.

Phase3Target: 2027.10.01












----------------------------------------------------------
Section 36: 2026.10.23.01
----------------------------------------------------------


Title: The Electron package settings 'os' and 'reproducibleBinary' are moving into the package's 'packaging' section as 'targets' and 'reproducibleBinary'

Description: A single 'os' string on an Electron package definition is replaced by the 'targets' list inside 'packaging' (any of win32-x64, win32-arm64, darwin-x64, darwin-arm64, linux-x64, linux-arm64, defaulting to the host platform). A 'reproducibleBinary' value set directly on the package definition moves into 'packaging' as well. Until phase2 the old settings are still read and converted when the package definition is opened, so just save the project to adopt the update.

State: Phase1: Both new and old functionality work.

Phase2Target: 2027.04.01

Incisor® API Documentation

IncisorApiDocumentationRaw.txt

Incisor® API Documentation
This document is part of the compiled knowledge base for the Incisor® Software Development Platform.
Any use of this content is subject to the INCISOR® end user license and terms of use agreement.
https://www.incisordev.com/eultua
2026.11.05.12.18.07






----------------------------------------------------------
TABLE OF CONTENTS:
----------------------------------------------------------
Section 1: GLOBAL
Section 2: UxKeyframedValueSupervisor
Section 3: UiVectorSupervisor_textField
Section 4: UxTableCell
Section 5: Matrix4
Section 6: Matrix4Array
Section 7: UxDropDownMenu
Section 8: UxListSupervisor
Section 9: UxStringSupervisorButton
Section 10: FlowController
Section 11: FlowState
Section 12: FlowStateElement
Section 13: UxMenu
Section 14: UiDropDownMenu
Section 15: Sound
Section 16: VolumeControl
Section 17: UiStyle
Section 18: UiPanel
Section 19: UiOutline
Section 20: AssetComponent
Section 21: SlotReel
Section 22: Texture
Section 23: Motion
Section 24: MotionControllers
Section 25: MotionType
Section 26: MaterialMaster
Section 27: UiButton
Section 28: UiKeyboardNavigator
Section 29: UiKeyboardNavigable
Section 30: UxPlaybackControllerSupervisor
Section 31: SpineBone
Section 32: SpinePath
Section 33: SpineSlot
Section 34: UiZoom
Section 35: UiCollapsibleStack
Section 36: TextAssembly
Section 37: UxNumberSupervisorRangedSlider
Section 38: Video
Section 39: GraphicExpander
Section 40: FontDefinition
Section 41: shapifySwoop
Section 42: shapifyAddMotion
Section 43: shapify
Section 44: shearSwoop
Section 45: shearAddMotion
Section 46: shear
Section 47: EffectControllerDefinition
Section 48: UxCollapsibleStack
Section 49: PivotPointAdjuster
Section 50: Paths
Section 51: UiText
Section 52: UxStandardListViewElement
Section 53: ProjectConfiguration
Section 54: AssetConfiguration
Section 55: AppEvent
Section 56: PauseEvent
Section 57: SpeedControl
Section 58: FocusChangeInfo
Section 59: GeometryEditor
Section 60: LayoutObject
Section 61: ParticleSystemDefinition
Section 62: ParticleSystem
Section 63: ParticleSystemRamp
Section 64: ParticleSystemRamp1
Section 65: ParticleSystemRamp2
Section 66: ParticleSystemRamp3
Section 67: ParticleSystemRamp4
Section 68: ParticleInfo
Section 69: ParticleSystemDefinitions
Section 70: FileIO
Section 71: IncrCommsResponseObject
Section 72: PathInfo
Section 73: UiVisualFocus
Section 74: SceneObject
Section 75: EffectNode
Section 76: Button
Section 77: ProjectSettings
Section 78: ProjectSettingsConfiguration
Section 79: ProjectSettingsMinification
Section 80: ProjectSettingsFontDefinition
Section 81: ProjectSettingsLoadingTierDefinition
Section 82: ProjectSettingsElectronPackageDefinition
Section 83: ProjectSettingsElectronPackaging
Section 84: ProjectSettingsElectronWebPreferences
Section 85: GraphicObject
Section 86: Masking
Section 87: MaskGroup
Section 88: SpriteSetter
Section 89: UxTable
Section 90: Camera
Section 91: OrthographicCamera
Section 92: PerspectiveCamera
Section 93: Intersection
Section 94: LoadingTierDefinition
Section 95: IncisorExtensions
Section 96: ProcessResult
Section 97: InspectorPanel
Section 98: FileBrowser
Section 99: PrePublishInfoObject
Section 100: PostPublishInfoObject
Section 101: ProcessConfiguration
Section 102: ColorSupervisorButton
Section 103: PixelsObject
Section 104: PixelsObjects
Section 105: UiGraphicButton
Section 106: Scene
Section 107: Layer
Section 108: LayersByScene
Section 109: TimeStamp
Section 110: UxStringSupervisorTextField
Section 111: UxNumberSupervisorTextField
Section 112: UxBooleanSupervisorCheckbox
Section 113: AncillaryDevInfo
Section 114: ScrollingPanel
Section 115: Material
Section 116: ConstructDefinition
Section 117: Blueprint
Section 118: Construct
Section 119: UrlParameterIterator
Section 120: UiLinkButton
Section 121: TimePlaybackController
Section 122: ValuePlaybackController
Section 123: PlaybackController
Section 124: UiBooleanSupervisor_checkbox
Section 125: Publishing
Section 126: Precomp
Section 127: AnimatedProperty
Section 128: CustomBlendingMode
Section 129: UiTextField
Section 130: WaitThen
Section 131: UiStringSupervisor_menu
Section 132: GraphicAsset
Section 133: MaterialPreset
Section 134: CustomAddOnDefinition
Section 135: RegisteredProperty
Section 136: CustomAddOnBase
Section 137: CustomAddOn_SceneObject
Section 138: CustomAddOn_GraphicObject
Section 139: CustomAddOn_Button
Section 140: CustomAddOn_TextBox
Section 141: CustomAddOn_TextAssembly
Section 142: CustomAddOn_ParticleSystem
Section 143: CustomAddOn_Construct
Section 144: RenderTarget
Section 145: ApplicationSettings
Section 146: ApplicationColorTheme
Section 147: LayoutStack
Section 148: UxStringSupervisorMenu
Section 149: UiStringSupervisor_textField
Section 150: UiNumberSupervisor_textField
Section 151: LazyUpdater
Section 152: KeyframedValue
Section 153: ValueKeyframe
Section 154: Code
Section 155: Timeline
Section 156: CustomObjectDefinition
Section 157: TextFormat
Section 158: CharacterMaterial
Section 159: IncisorApp
Section 160: IncisorAppBasic
Section 161: Swooper
Section 162: TweenType
Section 163: TweenControllers
Section 164: Curve
Section 165: CurvePoint
Section 166: Vector1Swoop
Section 167: Vector2Swoop
Section 168: Vector3Swoop
Section 169: Vector4Swoop
Section 170: ColorSwoop
Section 171: Vector1AddMotion
Section 172: Vector2AddMotion
Section 173: Vector3AddMotion
Section 174: Vector4AddMotion
Section 175: ColorAddMotion
Section 176: Vector4Base
Section 177: Vector4
Section 178: Color
Section 179: Vector3Base
Section 180: Vector3
Section 181: Vector2Base
Section 182: Vector2
Section 183: VectorBase
Section 184: Vector1
Section 185: Geometry
Section 186: SymbolReel
Section 187: UxVectorSupervisorTextField
Section 188: TextBox
Section 189: HtmlBacking
Section 190: RangeInfo
Section 191: Pdf
Section 192: PdfSection
Section 193: PdfParagraph
Section 194: PdfHeader
Section 195: PdfFooter
Section 196: PdfImage
Section 197: PdfTable
Section 198: PdfRow
Section 199: PdfCell
Section 200: PdfTextFrame
Section 201: CursorInputOverrideButton
Section 202: UiMenu
Section 203: UiMenuItem
Section 204: Constants
Section 205: UiPopupWindow
Section 206: INCISOR
Section 207: Supervisor
Section 208: UxMenuItem










----------------------------------------------------------
Section 1: GLOBAL
----------------------------------------------------------


GLOBAL
[type: scope] 
The global scope of a given Incisor project.





nce
[type: IncisorExtensions] [requires: unpublished only] 
Object housing all of the Incisor Extensions functionality. In general, this object has much of the same functionality as nc/INCISOR and is therefore documented as extending that object but not all of the same functionality is available through this object, so auto-complete may show some non-existent members on this object. 





CODE
[type: Code] 
Object housing tools for pre-process manipulation of code.





nc
[type: INCISOR] 
Object housing all of the main Incisor functionality. Accessible via 'nc' from anywhere within project code, excluding code within the 'PreloadConfiguration.js' file (that code is executed before 'nc' is instantiated).





pr
[type: ProjectMain] 
Object housing the main entry-point for the entire project





constants
[type: Constants] 
Object housing predefined constant values for various Incisor® options and modes.










----------------------------------------------------------
Section 2: UxKeyframedValueSupervisor
----------------------------------------------------------


UxKeyframedValueSupervisor
[type: class] [extends: SceneObject] [requires: unpublished only, extensions scope] 
A specialized user interface object for use within the Incisor Inspector and Inspector extensions. This displays a single KeyframedValue as an editable row of keyframes, either as a one line dope sheet or as a curve graph. The supervisor is owner agnostic - it only ever reports which ValueKeyframe was acted on, so a KeyframedValue with nothing driving it is served exactly as one owned by a Timeline is. Use 'nce.addUxKeyframedValueSupervisor' to create a UxKeyframedValueSupervisor from within an extensions scope.





UxKeyframedValueSupervisor.keyframedValue
[type: KeyframedValue] [default: undefined] 
The KeyframedValue this supervisor displays and edits. Setting this to undefined leaves the supervisor blank.





UxKeyframedValueSupervisor.displayLeft
[type: number] [default: 0] 
The time at the left edge of the display, in the keyframedValue's own time units.





UxKeyframedValueSupervisor.displayRight
[type: number] [default: 1] 
The time at the right edge of the display, in the keyframedValue's own time units.





UxKeyframedValueSupervisor.displayGraph
[type: boolean] [default: false] 
Plots value on the vertical axis as a curve graph, rather than showing a single line of keyframes. Only meaningful for a keyframedValue whose valueType is 'floatingPoint'.





UxKeyframedValueSupervisor.width
[type: number] [default: 300] 
The logical width of the display, before uiZoom is applied.





UxKeyframedValueSupervisor.height
[type: number] 
The logical height of the display, before uiZoom is applied. Outside of graph mode this is held at the height of a single line of body text. In graph mode it may be set taller, and is never allowed below twice a single line.





UxKeyframedValueSupervisor.backgroundColor
[type: Color] [default: nc.uiStyle.color_darkPanelBackground] 
The colour painted behind the keyframes. Mutate this in place - 'backgroundColor.copy(someColor)' or 'backgroundColor.red = 1'.





UxKeyframedValueSupervisor.graphColor
[type: Color] [default: nc.uiStyle.color_mainText] 
The colour the curve is drawn in, in graph mode. Mutate this in place - 'graphColor.copy(someColor)' or 'graphColor.red = 1'.





UxKeyframedValueSupervisor.verticalGuides
[type: Array] [default: []] 
The times at which faint vertical reference lines are drawn, behind the keyframes. These show in both modes. A guide outside the displayed range is not drawn, and guides never take part in working out the displayed value range.





UxKeyframedValueSupervisor.horizontalGuides
[type: Array] [default: []] 
The values at which faint horizontal reference lines are drawn, behind the keyframes. These only show while displayGraph is true, since it is graph mode that gives the vertical axis a value. A guide outside the displayed range is not drawn, and guides never take part in working out the displayed value range.





UxKeyframedValueSupervisor.guideColor
[type: Color] [default: a translucent grey] 
The colour the vertical and horizontal guides are drawn in. Mutate this in place - 'guideColor.copy(someColor)' or 'guideColor.alpha = .5'.





UxKeyframedValueSupervisor.boxSelectEnabled
[type: boolean] [default: false] 
Allows a drag across the background to draw a marquee that selects the keyframes inside it. Leave this false where an owner runs a single box selection across several supervisors of its own.





UxKeyframedValueSupervisor.selectionGroup
[type: object] [default: undefined] 
Which keyframes may be selected together. Any object serves as the group token. Leave this undefined to allow selection only within this supervisor's own keyframedValue.





UxKeyframedValueSupervisor.keyframeDragStretchesGroup
[type: boolean] [default: false] 
Dragging a keyframe while more than one is selected stretches the selection in time, rather than moving it.





UxKeyframedValueSupervisor.keyframeRepPool
[type: Array] 
The array the supervisor draws spare keyframe representations from and returns them to. Point several supervisors at one array to have them share a single pool.





UxKeyframedValueSupervisor.overscanRatio
[type: number] [default: .1] 
The fraction of the displayed span that is also built beyond each edge, so that small scrubs do not exhaust the pool.





UxKeyframedValueSupervisor.deferGraphTargetResize
[type: boolean] [default: false] 
Leaves the graph's render target at its current size while width and height change. Set this true for the duration of a resize, then false to commit the size that was reached.





UxKeyframedValueSupervisor.hasOwnMask
[type: boolean] [default: true] 
Confines the keyframes to the supervisor's own box with a stencil mask.





UxKeyframedValueSupervisor.maskGroup
[type: MaskGroup] [default: undefined] 
The MaskGroup the supervisor's contents are masked into. Leave this undefined to have a self masking supervisor fall back to nc.maskGroups.MainMaskGroup.





UxKeyframedValueSupervisor.keyframeReps
[type: Array] 
The live keyframe representations, in time order.





UxKeyframedValueSupervisor.minValue
[type: number] 
The lowest value held by any of the keyframedValue's keyframes, or undefined when there are none.





UxKeyframedValueSupervisor.maxValue
[type: number] 
The highest value held by any of the keyframedValue's keyframes, or undefined when there are none.





UxKeyframedValueSupervisor.displayTop
[type: number] 
The value at the top edge of the display.





UxKeyframedValueSupervisor.displayBottom
[type: number] 
The value at the bottom edge of the display.





UxKeyframedValueSupervisor.pixelsPerTime
[type: number] 
The number of world units one time unit occupies across the display.





UxKeyframedValueSupervisor.pixelsPerValue
[type: number] 
The number of world units one unit of value occupies down the display.





UxKeyframedValueSupervisor.backgroundPanel
[type: Button] 
The Button drawn behind the keyframes, which in graph mode also carries the rendered curve. This is built when the supervisor is first enabled, and always exists after that.





UxKeyframedValueSupervisor.maskGraphic
[type: Button] 
The Button that writes the supervisor's stencil mask. This is built when the supervisor is first enabled, and only when hasOwnMask is true.





UxKeyframedValueSupervisor.layer
[type: number] 
The layer the supervisor's managed graphics are on, or undefined before any of them are built.





UxKeyframedValueSupervisor.addKeyframeContextMenuCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that contributes items to a keyframe's context menu, on top of the ones the supervisor supplies. The UxMenu and the ValueKeyframe that was right clicked are sent to the callback as its first two parameters.

UxKeyframedValueSupervisor.addKeyframeContextMenuCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that contributes items to a keyframe's context menu.

UxKeyframedValueSupervisor.addKeyframeContextMenuCallback parameter: callbackName
[type: string] 
The name of the callback function that contributes items to a keyframe's context menu.

UxKeyframedValueSupervisor.addKeyframeContextMenuCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function, supplied after the UxMenu and the ValueKeyframe.





UxKeyframedValueSupervisor.removeKeyframeContextMenuCallback(callbackOwner, callbackName)
[type: function] 
Removes a previously added keyframe context menu callback.

UxKeyframedValueSupervisor.removeKeyframeContextMenuCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UxKeyframedValueSupervisor.removeKeyframeContextMenuCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





UxKeyframedValueSupervisor.addKeyframeDoubleTapCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that runs when a keyframe is double tapped. The event, the viewing Camera, and the ValueKeyframe that was tapped are sent to the callback as its first three parameters.

UxKeyframedValueSupervisor.addKeyframeDoubleTapCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that runs when a keyframe is double tapped.

UxKeyframedValueSupervisor.addKeyframeDoubleTapCallback parameter: callbackName
[type: string] 
The name of the callback function that runs when a keyframe is double tapped.

UxKeyframedValueSupervisor.addKeyframeDoubleTapCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function, supplied after the event, the Camera and the ValueKeyframe.





UxKeyframedValueSupervisor.removeKeyframeDoubleTapCallback(callbackOwner, callbackName)
[type: function] 
Removes a previously added keyframe double tap callback.

UxKeyframedValueSupervisor.removeKeyframeDoubleTapCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UxKeyframedValueSupervisor.removeKeyframeDoubleTapCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





UxKeyframedValueSupervisor.addKeyframedValueContextMenuCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that contributes items to the whole KeyframedValue's context menu, which is opened by right clicking the background. The UxMenu is sent to the callback as its first parameter.

UxKeyframedValueSupervisor.addKeyframedValueContextMenuCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that contributes items to the KeyframedValue's context menu.

UxKeyframedValueSupervisor.addKeyframedValueContextMenuCallback parameter: callbackName
[type: string] 
The name of the callback function that contributes items to the KeyframedValue's context menu.

UxKeyframedValueSupervisor.addKeyframedValueContextMenuCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function, supplied after the UxMenu.





UxKeyframedValueSupervisor.removeKeyframedValueContextMenuCallback(callbackOwner, callbackName)
[type: function] 
Removes a previously added KeyframedValue context menu callback.

UxKeyframedValueSupervisor.removeKeyframedValueContextMenuCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UxKeyframedValueSupervisor.removeKeyframedValueContextMenuCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





UxKeyframedValueSupervisor.syncKeyframeReps()
[type: function] 
Brings the displayed keyframes back into agreement with the keyframedValue. This runs on its own every fixed update while the supervisor is enabled, so it is only worth calling directly to read a change back within the same tick.





UxKeyframedValueSupervisor.timeToX(time)
[type: function] [returns: number] 
Returns the horizontal position, in world units from the supervisor's own origin, that the given time sits at.

UxKeyframedValueSupervisor.timeToX parameter: time
[type: number] 
A time in the keyframedValue's own time units.





UxKeyframedValueSupervisor.xToTime(x)
[type: function] [returns: number] 
Returns the time that the given horizontal position, in world units from the supervisor's own origin, sits at.

UxKeyframedValueSupervisor.xToTime parameter: x
[type: number] 
A horizontal position in world units.





UxKeyframedValueSupervisor.valueToY(value)
[type: function] [returns: number] 
Returns the vertical position, in world units from the supervisor's own origin, that the given value sits at. Outside of graph mode every value sits on the centre line. A boolean plots on the true and false rails.

UxKeyframedValueSupervisor.valueToY parameter: value
[type: number, boolean, string] 
The value to find the vertical position of (a number, boolean, or string depending on the keyframedValue's valueType).





UxKeyframedValueSupervisor.yToValue(y)
[type: function] [returns: number] 
Returns the value that the given vertical position, in world units from the supervisor's own origin, sits at. Returns undefined outside of graph mode, where the vertical axis carries no value.

UxKeyframedValueSupervisor.yToValue parameter: y
[type: number] 
A vertical position in world units.



























































































































































































































































































































----------------------------------------------------------
Section 3: UiVectorSupervisor_textField
----------------------------------------------------------


UiVectorSupervisor_textField
[type: class] [extends: UiCollapsibleStack] [requires: module - extendedUi] 
A specialized UiCollapsibleStack that includes a group of UiTextFields and a Superivor member, enabling it to monitor and adjust a Vector property's value during runtime. To use this class, configure the 'supervisedPropertyGetter' and 'supervisedPropertySetter' callbacks on the Supervisor. Once configured, the included UiTextFields will be updated every fixed update to reflect the most current values of the supervised Vector components, and the component values will also be 'adjustable' via direct editing of the UiTextFields, as well as through cursor interaction.





UiVectorSupervisor_textField.supervisor
[type: Supervisor] 
Supervisor with callbacks that enable this UiStringSupervisor_textField to monitor and adjust a Vector's component values during runtime.





UiVectorSupervisor_textField.defaultDimension
[type: number] [default: 3] 
The number of components shown by default - i.e. this is the number of components that will be shown when the supervisedPropertyGetter returns undefined.





UiVectorSupervisor_textField.displayPrecision
[type: number] [default: 3] 
The number of digits shown to the right of the decimal within the component UiTextFields of this UiVectorSupervisor_textField.





UiVectorSupervisor_textField.getComponentTextFields()
[type: function] [returns: [UiTextField]] 
Returns an array of the UiTextFields in this UiVectorSupervisor_textField.





UiVectorSupervisor_textField.setDragMultiplier(componentIndex, multiplierValue)
[type: function] 
Sets a value that multiplies the affect of dragging the component label. For reference, a value of 1 is fitting for a component whose range is roughly 500.

UiVectorSupervisor_textField.setDragMultiplier parameter: componentIndex
[type: number] 
The index of the component that the given multiplier will be applied to (0=x,1=y,2=z,3=w).

UiVectorSupervisor_textField.setDragMultiplier parameter: multiplierValue
[type: number] 
The value that will multiply the affect of dragging the label associated with the given component.






















































































































































































































































































































































































































































































----------------------------------------------------------
Section 4: UxTableCell
----------------------------------------------------------


UxTableCell
[type: class] [extends: UiText] [NON-INSTANTIABLE] [requires: unpublished only, extensions scope] 
The cell type used within a UxTable. UxTableCell instances are provided by UxTable and cannot be instantiated directly. All cells default to editingMode='editable', horizontalJustification='center', wrapToFit=true, and scaleToFit=false. All arrow-key and return/tab editing-end properties default to true, making cells fully keyboard-navigable out of the box.





UxTableCell.row
[type: number] 
The zero-based row index of this cell within its parent UxTable.





UxTableCell.column
[type: number] 
The zero-based column index of this cell within its parent UxTable.





UxTableCell.parentTable
[type: UxTable] 
The UxTable that contains this cell.





































































































































































































































































































































































































































































































































































































































































































































































































































----------------------------------------------------------
Section 5: Matrix4
----------------------------------------------------------


Matrix4
[type: class] 
A 4x4 Matrix, typically used as a transformation matrix for SceneObjects.





Matrix4.elements
[type: [number]] 
The 16 elements of the 4x4 matrix, stored in column major order. Defaults to the identity matrix.





Matrix4.copy(matrix)
[type: function] 
Sets all of this Matrix4's element values to the element values of the givem Matrix4.

Matrix4.copy parameter: matrix
[type: Matrix4] 
The matrix to copy element values from.





Matrix4.set(element00, element01, element02, element03, element10, element11, element12, element13, element20, element21, element22, element23, element30, element31, element32, element33)
[type: function] 
Sets this Matrix4's elements to the provided values.

Matrix4.set parameter: element00
[type: number] 
Element at column 0, row 0.

Matrix4.set parameter: element01
[type: number] 
Element at column 0, row 1.

Matrix4.set parameter: element02
[type: number] 
Element at column 0, row 2.

Matrix4.set parameter: element03
[type: number] 
Element at column 0, row 3.

Matrix4.set parameter: element10
[type: number] 
Element at column 1, row 0.

Matrix4.set parameter: element11
[type: number] 
Element at column 1, row 1.

Matrix4.set parameter: element12
[type: number] 
Element at column 1, row 2.

Matrix4.set parameter: element13
[type: number] 
Element at column 1, row 3.

Matrix4.set parameter: element20
[type: number] 
Element at column 2, row 0.

Matrix4.set parameter: element21
[type: number] 
Element at column 2, row 1.

Matrix4.set parameter: element22
[type: number] 
Element at column 2, row 2.

Matrix4.set parameter: element23
[type: number] 
Element at column 2, row 3.

Matrix4.set parameter: element30
[type: number] 
Element at column 3, row 0.

Matrix4.set parameter: element31
[type: number] 
Element at column 3, row 1.

Matrix4.set parameter: element32
[type: number] 
Element at column 3, row 2.

Matrix4.set parameter: element33
[type: number] 
Element at column 3, row 3.





Matrix4.clone()
[type: function] [returns: Matrix4] 
Returns a new Matrix4 with the same elements as this Matrix4.





Matrix4.getInverse(matrix)
[type: function] 
Sets this Matrix4 to the inverse of the givem Matrix4. If the Matrix can not be inverted, all elements will be set to 0.

Matrix4.getInverse parameter: matrix
[type: Matrix4] 
The matrix to invert.





Matrix4.multiply(matrix)
[type: function] 
Postmultiplies this Matrix4 by the provided Matrix4.

Matrix4.multiply parameter: matrix
[type: Matrix4] 
The matrix by which this Matrix4 is multiplied.





Matrix4.premultiply(matrix)
[type: function] 
Premultiplies this Matrix4 by the provided Matrix4.

Matrix4.premultiply parameter: matrix
[type: Matrix4] 
The matrix by which this Matrix4 is premultiplied.





Matrix4.multiplyMatrices(matrixA, matrixB)
[type: function] 
Sets this Matrix4 to the result of multiplying the provided Matrix4 parameters.

Matrix4.multiplyMatrices parameter: matrixA
[type: Matrix4] 
The first of the multiplied matrices.

Matrix4.multiplyMatrices parameter: matrixB
[type: Matrix4] 
The second of the multiplied matrices.





Matrix4.toArray(array, offset)
[type: function] [returns: [number]] 
Copies the numbers in the 'elements' array into the provided Array.

Matrix4.toArray parameter: array
[type: [number]] [default: [] [optional] 
The Array to copy the elements into.]

Matrix4.toArray parameter: offset
[type: number] [default: 0] [optional] 
The index in 'array' at which to place the first element.





Matrix4.identity()
[type: function] 
Sets this Matrix4 to the identity matrix.





Matrix4.compose(position, rotation, scale)
[type: function] 
Sets this Matrix4 to a transformation matrix representing the provided position, rotation, and scale.

Matrix4.compose parameter: position
[type: Vector3] 
The position represented by the transformation matrix.

Matrix4.compose parameter: rotation
[type: Vector3] 
The rotation represented by the transformation matrix.

Matrix4.compose parameter: scale
[type: Vector3] 
The scale represented by the transformation matrix.





Matrix4.decompose(position, rotation, scale, forceRotation, forceScale)
[type: function] 
Extracts the position, rotation and scale represented by this Matrix4. Note that it is not always possible to correctly decompose a Matrix4 into these components, such as when the Matrix4 contains skewing/shearing. Also note that multiple valid decompositions of a Matrix4 are possible. For example, a rotation of 180 degrees around the Z axis creates the same Matrix4 as a scale of -1 on the X and Y axes. To address this, the forceRotation and forceScale parameters can be used to indicate that the resulting rotation or scale are already known, and are already contained in the rotation or scale parameters.

Matrix4.decompose parameter: position
[type: Vector3] 
The resulting position.

Matrix4.decompose parameter: rotation
[type: Vector3] 
The resulting rotation. If 'forceRotation' is true, this value is used as input to improve the extraction of scale.

Matrix4.decompose parameter: scale
[type: Vector3] 
The resulting scale. If 'forceScale' is true, this value is used as input to improve the extraction of rotation.

Matrix4.decompose parameter: forceRotation
[type: boolean] [default: false] [optional] 
Determines whether the value in 'rotation' is already set to the known rotation to improve the extraction of scale.

Matrix4.decompose parameter: forceScale
[type: boolean] [default: false] [optional] 
Determines whether the value in 'scale' is already set to the known scale to improve the extraction of rotation.





Matrix4.determinant()
[type: function] [returns: number] 
Returns the determinant of this Matrix4. If this is 0, this Matrix4 can not be inverted.





Matrix4.applyToVector3(vector)
[type: function] 
Applies this Matrix4's transformation to the provided Vector3.

Matrix4.applyToVector3 parameter: vector
[type: Vector3] 
The Vector3 to be transformed by this Matrix4. This vector is modified in place.





Matrix4.applyToVector4(vector)
[type: function] 
Applies this Matrix4's transformation to the provided Vector4.

Matrix4.applyToVector4 parameter: vector
[type: Vector4] 
The Vector4 to be transformed by this Matrix4. This vector is modified in place.










----------------------------------------------------------
Section 6: Matrix4Array
----------------------------------------------------------


Matrix4Array
[type: class] 
An internal specialized type used for Spine Animation EffectControllers.










----------------------------------------------------------
Section 7: UxDropDownMenu
----------------------------------------------------------


UxDropDownMenu
[type: class] [extends: UiButton] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, participate in the standardized inspector keyboard-navigation system, and are uiZoom-enabled. This particular object is a specialized UiButton that displays and manages a UxMenu anchored to itself. Triggering this button toggles the open state of the associated UxMenu.





UxDropDownMenu.uxMenu
[type: UxMenu] 
The UxMenu displayed and managed by this UxDropDownMenu. This menu is automatically created during construction, anchored to this UxDropDownMenu, and configured to use this UxDropDownMenu as its singularFocusTarget. Triggering this UxDropDownMenu toggles the 'isOpen' state of this menu.







































































































































































































































































































































































































































































----------------------------------------------------------
Section 8: UxListSupervisor
----------------------------------------------------------


UxListSupervisor
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. This is a specialized LayoutStack that can easily be set up to supervise a list of any type of items. A class definition extending any of the main Ui/Ux items (UiButton, UiText, LayoutStack, etc...) is provided to this object and instances of that class are populated to represent the items in the list being supervised.





UxListSupervisor.autoSync
[type: boolean] [default: true] 
Boolean determining if the UxListSupervisor automatically updates the visualization of the list every fixed update (as long as isEnabledWithInheritance is true).





UxListSupervisor.pool
[type: Array] [default: []] 
The array to be used as the pool for inactive ListViewElements. If you want to have a group of UxListSupervisors all share the same pool, assign this property on each of the UxListSupervisors to the same pool array.





UxListSupervisor.getListCallbackOwner
[type: object] [default: undefined] 
The object owning the callback that is used to get the current list of items being supervised by this UxListSupervisor. This value must be set before this UxListSupervisor attempts to sync.





UxListSupervisor.getListCallbackName
[type: string] [default: undefined] 
The name of the callback that is used to get the current list of items being supervised by this UxListSupervisor. This value must be set before this UxListSupervisor attempts to sync.





UxListSupervisor.getListCallbackArgs
[type: string] [default: undefined] 
Optional parameters for the callback that is used to get the current list of items being supervised by this UxListSupervisor.





UxListSupervisor.listViewElementDefinition
[type: object] [default: undefined] 
The class definition for the 'ListViewElement', which is the representation of each of the items in the list (whatever they are). This class must extend one of the main UI items (UiButton, UiText, LayoutStack, etc...). This class must also implement the methods activateListViewElement, deactivateListViewElement, and syncListViewElement, all of which take an item from the list and this UxListSupervisor as their first two parameters. This value must be set before this UxListSupervisor attempts to sync.





UxListSupervisor.visibilityCamera
[type: OrthographicCamera] [default: undefined] 
An OrthographicCamera that can be connected as an optimization - elements not within the camera's view will be auto-disabled. This can be used for when large lists (100+ items) are represented by this UxListSupervisor. By disabling none-visible items, non-essential CPU object traversal tasks are reduced. In order to keep the visibility computation streamlined, it is assumed that the camera is in an identical spacial context to that of the UxListSupervisor (no scaling, no offsets, etc..)





UxListSupervisor.newObjectPerSyncLimit
[type: number] [default: 25] 
A number that can limit the number of new objects created per invocation of the sync method. When a UxListSupervisor represents large lists (100+ items) the initial creation of ListViewElements can be a substantial performance burden. Setting this value to a non-zero positive number can break up the initial creation of objects and enable visual feedback during startup.





UxListSupervisor.activatedObjectsPerSyncLimit
[type: number] [default: 100] 
A number that can limit the number of new objects 'activated' per invocation of the sync method. When a UxListSupervisor represents large lists (500+ items) the activation of ListViewElements can be a substantial performance burden. Setting this value to a non-zero positive number can break up the initial creation of objects and enable visual feedback during startup.





UxListSupervisor.syncingWithinLimits
[type: boolean] [default: true] 
Read-only boolean reporting if the latest sync method performed without hitting the newObjectPerSyncLimit or the activatedObjectsPerSyncLimit. This is a means to be able to provide visual feedback when the UxListSupervisor is running into limits while syncing.





UxListSupervisor.logWhenRebuildingList
[type: boolean] [default: false] 
Boolean determining if a message is sent to the console each time the UxListSupervisor has to rebuild the visual representation of the list. This can be an important debugging tool, as it can be a performance impact to have large lists rebuilt excessively.





UxListSupervisor.sync()
[type: function] 
Method tells the UxListSupervisor to sync with the list (as acquired using getListCallbackOwner and getListCallbackName) by displaying one of the ListViewElements (as defined by listViewElementDefinition) for each of the items in the list. When UxListSupervisor.autoSync is true, this method is automatically called every fixedUpdate.





















































































































































































































































































































































































































----------------------------------------------------------
Section 9: UxStringSupervisorButton
----------------------------------------------------------


UxStringSupervisorButton
[type: class] [extends: UiButton] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. Supervisors provide the means for users to both monitor and manipulate properties within the project during runtime. This particular object is meant to display a supervised string property as the mainText of a UiButton. When multiple diverging values are supervised, a '-' is shown. No property manipulation is built in — add a trigger callback to respond to button presses with custom behaviour. 'Ux' supervisors operate exclusively on arrays of values, ensuring support for supervising multiple values at once.





UxStringSupervisorButton.propertyOwners
[type: Array] [default: undefined] 
Array of objects owning the properties being supervised. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorButton.propertyPath
[type: string] [default: ""] 
A period-separated string representing the 'dot path' or 'dereference chain' from each owner object to the property being supervised. For example if you are supervising the fontName of the TextFormat on a TextBox this value would be 'textFormat.fontName'. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorButton.propertyGetterOwner
[type: object] [default: undefined] 
The object owning the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorButton.propertyGetterName
[type: string] [default: undefined] 
The name of the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorButton.propertyGetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorButton.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body.clone()] 
The TextFormat of all of the text items within the supervisor, which is also used to scale graphical components.





UxStringSupervisorButton.dashWidth
[type: number] [default: 65] 
The boxWidth applied to mainText when the supervisor is displaying '-' (no supervised value or diverging values). Set to 0 automatically when a real value is displayed. Prevents the button from appearing too narrow.





UxStringSupervisorButton.sync()
[type: function] 
Method brings this UxStringSupervisorButton up to date with the values it supervises, without waiting for the next fixedUpdate. This method is automatically called every fixedUpdate.







































































































































































































































































































































































































































































----------------------------------------------------------
Section 10: FlowController
----------------------------------------------------------


FlowController
[type: class] [requires: module - flowControllers] 
FlowControllers provide a way to organize the general flow of state-based items in a project. For example if your project is a game with an intro, a menu, and several levels, you could create a FlowController named "GameFlowController" and then define and add an 'Intro' FlowState, a 'Menu' FlowState, and 'LevelXX' FlowStates to that FlowController. Within each FlowState in the FlowController, timed callback elements can be added to help define the sequencing within each FlowState. Once created, FlowControllers, FlowStates, and FlowStateElements can be accessed via 'nc.flows'.





FlowController.name
[type: string] 
The name of the FlowController.





FlowController.inheritedTypes
[type: any] 
Dictionary object listing all of the types this object is compatible with.





FlowController.type
[type: string] 
Type identifier.





FlowController.currentFlowState
[type: FlowState] 
The current FlowState of this FlowController. Monitor or change the FlowState using this property. This property can also be set via 'nc.flows.[FlowControllerName].[FlowStateName].setToCurrentState'.





FlowController.isActive
[type: boolean] [default: true] 
Flag determining if this FlowController is actively updating the time of the current FlowState and evaluating which FlowStateElements to execute.





FlowController.pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] 
The PauseEvent or Array of PauseEvents that this FlowController will be immune to. Set this parameter to [] for this FlowController to have no pause immunity.





FlowController.speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] 
The SpeedControl or Array of SpeedControls that this FlowController is affected by.





FlowController.playbackRate
[type: number] [default: 1] 
Value multiplying the progression of the 'time' value. To play twice as fast use 2, for items that can play backwards, use negative values.





FlowController.netPlaybackRate
[type: number] 
Read-only value denoting the net playbackRate, including the effects of this FlowController's SpeedControls.





FlowController.addFlowState(flowStateDefinition)
[type: function] [returns: FlowState] 
Adds a the given FlowState to this FlowController. To build a FlowState, define a class that extends the FlowState class, then provide that definition to this method to add it to this FlowController.

FlowController.addFlowState parameter: flowStateDefinition
[type: object] 
The class definition of the FlowState to add to this FlowController. The provided class definition must inherit from FlowState.





FlowController.setState(flowState, performFollowupEvaluation)
[type: function] 
Sets the 'currentFlowState' of this FlowController to the provided FlowState. This can also be achieved by calling 'setToCurrentState' on the given FlowState.

FlowController.setState parameter: flowState
[type: FlowState] 
The FlowState to set as this FlowController's current FlowState.

FlowController.setState parameter: performFollowupEvaluation
[type: boolean] [default: false] [optional] 
Flag determining if another evaluation of which FlowStateElement callbacks to execute will be done immediately (without waiting a fixedUpdate) after the state change.





FlowController.addFlowStateChangeCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever the current FlowState of this FlowController is changed. The new FlowState and the previous FlowState are sent to the callback as its first two parameters.

FlowController.addFlowStateChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever the FlowState changes.

FlowController.addFlowStateChangeCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever the FlowState changes.

FlowController.addFlowStateChangeCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever the FlowState changes.





FlowController.removeFlowStateChangeCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

FlowController.removeFlowStateChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

FlowController.removeFlowStateChangeCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.










----------------------------------------------------------
Section 11: FlowState
----------------------------------------------------------


FlowState
[type: class] [NON-INSTANTIABLE] [requires: module - flowControllers] 
This object represents a state within a FlowController. FlowControllers provide a way to organize the general flow of state-based items in a project. For example if your project is a game with an intro, a menu, and several levels, you could create a FlowController named "GameFlowController" and then define and add an 'Intro' FlowState, a 'Menu' FlowState, and 'LevelXX' FlowStates to that FlowController. Within each FlowState in the FlowController, timed callback elements can be added to help define the sequencing within each FlowState. Once created, FlowControllers, FlowStates, and FlowStateElements can be accessed via 'nc.flows'. This class is not meant to be instantiated or provided directly to 'FlowController.addFlowState', rather it is meant to be a class for user-defined FlowStates to extend. Call 'nc.defineFlowController' to create a new FlowController, then use 'nc.flows' to access it. 





FlowState.name
[type: string] 
The name of the FlowState.





FlowState.owner
[type: FlowController] 
The FlowController that owns this FlowState.





FlowState.time
[type: number] 
The current time of this FlowState.





FlowState.setTime(time, performFollowupEvaluation)
[type: function] 
Sets the current time of this FlowState

FlowState.setTime parameter: time
[type: number] 
The new time to set the FlowState to.

FlowState.setTime parameter: performFollowupEvaluation
[type: boolean] [default: false] [optional] 
Flag determining if another evaluation of which FlowStateElement callbacks to execute will be done immediately (without waiting a fixedUpdate) after the time change.





FlowState.setToCurrentState(performFollowupEvaluation)
[type: function] 
Sets the owning FlowController's 'currentFlowState' property equal to this FlowState.

FlowState.setToCurrentState parameter: performFollowupEvaluation
[type: boolean] [default: false] [optional] 
Flag determining if another evaluation of which FlowStateElement callbacks to execute will be done immediately (without waiting a fixedUpdate) after the state change.





FlowState.addElement(time, callbackName, callbackArgs, variableOffsets)
[type: function] [returns: FlowStateElement] 
Adds a new FlowStateElement to this FlowState. Such elements are essentially timed callbacks to functions within this FlowState, which are used to create the sequencing for this FlowState.

FlowState.addElement parameter: time
[type: number] 
The time within this FlowState at which the associated callback will occur.

FlowState.addElement parameter: callbackName
[type: string] 
The name of the function within this FlowState that will be called at the given time.

FlowState.addElement parameter: callbackArgs
[type: [any], any] [optional] 
Parameters for the callback associated with the new FlowStateElement.

FlowState.addElement parameter: variableOffsets
[type: [string], string] [optional] 
The name(s) of the numeric properties that can be adjusted to dynamically offset this FlowStateElement's time. These offset properties will be automatically added to the parent FlowState for easy manipulation of the timing of its FlowStateElements.





FlowState.addPause(time, callbackName, callbackArgs, variableOffsets)
[type: function] [returns: FlowStateElement] 
Adds a new 'pause' FlowStateElement to this FlowState. When the FlowState encounters this particular FlowStateElement, its 'time' property will not progress until the provided callback returns true.

FlowState.addPause parameter: time
[type: number] 
The time within this FlowState that the pause will take effect.

FlowState.addPause parameter: callbackName
[type: string] 
The name of the pause function within this FlowState that will control the pausing. When the function returns true, the FlowState resumes.

FlowState.addPause parameter: callbackArgs
[type: [any], any] [optional] 
Parameters for the callback associated with the new pause FlowStateElement.

FlowState.addPause parameter: variableOffsets
[type: [string], string] [optional] 
The name(s) of the numeric properties that can be adjusted to dynamically offset the FlowStateElement's time. These offset properties will be automatically added to the parent FlowState for easy manipulation of the timing of its FlowStateElements.





FlowState.getElements()
[type: function] [returns: [FlowStateElement]] 
Returns a shallow copy of the list of this FlowState's elements.










----------------------------------------------------------
Section 12: FlowStateElement
----------------------------------------------------------


FlowStateElement
[type: class] [NON-INSTANTIABLE] [requires: module - flowControllers] 
This object represents one of the sequencing elements within a FlowState. Its properties define a timed callback within the FlowState. 





FlowStateElement.time
[type: number] 
The base time for when this FlowStateElement occurs within it's FlowState.





FlowStateElement.callbackName
[type: string] 
The name of the callback function that this FlowStateElement is associated with. The function must be within the owning FlowState class.





FlowStateElement.callbackArgs
[type: string] 
Parameters for this FlowStateElement's callback function.





FlowStateElement.isPauseElement
[type: boolean] 
Flag determining if this FlowStateElement is a pause element. When a pause element is encountered by the FlowState, its time will not incremented until the associated callback returns true.





FlowStateElement.netTime
[type: boolean] 
Read-only property denoting the aggregated callback time within the owning FlowState. This time is the sum of the 'time' base time together with each of the associated 'variableOffset' values.










----------------------------------------------------------
Section 13: UxMenu
----------------------------------------------------------


UxMenu
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, participate in the standardized inspector keyboard-navigation system, and are uiZoom-enabled. This particular object is a specialized vertical LayoutStack that displays and manages a list of UxMenuItems, supports optional searching, anchored placement, and nested sub-menus.





UxMenu.isOpen
[type: boolean] [default: false] 
Boolean determining if the UxMenu is currently open. Opening the menu enables it and creates the ScrollingPanel used to house the menu body. Focus management is not handled automatically; use addOpenCloseCallback to manage focus as needed.





UxMenu.searchable
[type: boolean] [default: false] 
Boolean determining if a search UiTextField appears at the top of the UxMenu. When true, end-users can type to filter the displayed UxMenuItems.





UxMenu.focusSearchFieldOnOpen
[type: boolean] [default: false] 
Boolean determining if the search UiTextField begins editing as soon as the UxMenu opens. The field is focused on the traversal after the menu opens rather than immediately, so it survives a caller that assigns nc.singularFocusObject right after setting isOpen. Setting this on a menu that is already open focuses the field on the next traversal. This has no effect while searchable is false, as there is no field to focus.





UxMenu.searchField
[type: UiTextField] 
The UiTextField used for searching/filtering menu items. This item is created lazily the first time it is accessed or when searchable is enabled.





UxMenu.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body.clone()] 
The TextFormat applied to the text within this UxMenu and its UxMenuItems. Setting this also updates any existing subMenus and the searchField text/icons.





UxMenu.parentMenuItem
[type: UxMenuItem] 
If this UxMenu belongs to a menu item as a subMenu, this property contains the parent UxMenuItem. Otherwise this value is undefined.





UxMenu.anchorObject
[type: SceneObject] [default: undefined] 
A SceneObject with a defined layoutObject that this UxMenu will anchor itself to when opened.





UxMenu.anchoredPlacement
[type: string] [default: "right"] 
String determining how the UxMenu is positioned relative to the anchorObject. Accepted values are "right" and "bottom".





UxMenu.singularFocusTarget
[type: SceneObject] [default: this] 
Optional reference to a SceneObject that represents the intended focus target for this UxMenu. This property is not acted upon automatically; it is provided as a convenience for use within openClose callbacks or other focus-management logic.





UxMenu.background
[type: UiPanel] 
The UiPanel shown behind the contents of this UxMenu.





UxMenu.onOpenClose()
[type: function, undefined] [default: undefined] 
Optional shortcut hook called every time this UxMenu opens or closes, before any registered addOpenCloseCallback callbacks. Assign a function directly to this property. The UxMenu is passed as the first parameter.

example:
myMenu.onOpenClose = function(_menu){ console.log(_menu.isOpen); }





UxMenu.onFirstOpen()
[type: function, undefined] [default: undefined] 
Optional shortcut hook called the first time this UxMenu opens, before onOpenClose and any registered callbacks. Assign a function directly to this property. The UxMenu is passed as the first parameter. Once called, this hook is never called again for this UxMenu instance.

example:
myMenu.onFirstOpen = function(_menu){ myMenu.addMenuItem("Option A"); }





UxMenu.addOpenCloseCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever this UxMenu is opened or closed. The UxMenu itself is sent to the callback as its first parameter.

UxMenu.addOpenCloseCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this UxMenu is opened or closed.

UxMenu.addOpenCloseCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this UxMenu is opened or closed.

UxMenu.addOpenCloseCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever this UxMenu is opened or closed.





UxMenu.removeOpenCloseCallback(callbackOwner, callbackName)
[type: function] 
Removes the given open/close callback.

UxMenu.removeOpenCloseCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UxMenu.removeOpenCloseCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





UxMenu.addMenuItemTriggerCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever one of this UxMenu's UxMenuItems is triggered. The triggered UxMenuItem is sent to the callback as its first parameter.

UxMenu.addMenuItemTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever one of this UxMenu's UxMenuItems is triggered.

UxMenu.addMenuItemTriggerCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever one of this UxMenu's UxMenuItems is triggered.

UxMenu.addMenuItemTriggerCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever one of this UxMenu's UxMenuItems is triggered.





UxMenu.removeMenuItemTriggerCallback(callbackOwner, callbackName)
[type: function] 
Removes the given menu-item trigger callback.

UxMenu.removeMenuItemTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UxMenu.removeMenuItemTriggerCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





UxMenu.addMenuItem(name, index)
[type: function] [returns: UxMenuItem] 
Adds a new UxMenuItem to this UxMenu.

UxMenu.addMenuItem parameter: name
[type: string] 
The main string that will appear in the UxMenuItem.

UxMenu.addMenuItem parameter: index
[type: number] [optional] 
Optional array index at which to insert the new UxMenuItem.





UxMenu.clearMenuItems()
[type: function] 
Clears all UxMenuItems from this UxMenu.





UxMenu.addMenuItemWithSubMenu(name, index)
[type: function] [returns: UxMenuItem] 
Adds a new UxMenuItem to this UxMenu and automatically creates a subMenu for it. The returned UxMenuItem will have its 'subMenu' property populated and will display a caret icon on the right side.

UxMenu.addMenuItemWithSubMenu parameter: name
[type: string] 
The main string that will appear in the UxMenuItem.

UxMenu.addMenuItemWithSubMenu parameter: index
[type: number] [optional] 
Optional array index at which to insert the new UxMenuItem.





UxMenu.configureLargeListMode(getListCallbackOwner, getListCallbackName, getListCallbackArgs)
[type: function] 
Puts this UxMenu into large-list mode, where menu items are managed asynchronously by an internal UxListSupervisor rather than being added manually via addMenuItem or addMenuItemWithSubMenu. This prevents the performance hit of creating many menu items synchronously on open. The provided callback must return an array; each element is converted to a string and used as a UxMenuItem name. Items are created and pooled incrementally across fixed-update frames. Must be called before the menu is first opened. addMenuItem, addMenuItemWithSubMenu, and clearMenuItems must not be called once large-list mode is active.

UxMenu.configureLargeListMode parameter: getListCallbackOwner
[type: object] 
The object owning the callback that returns the list of items.

UxMenu.configureLargeListMode parameter: getListCallbackName
[type: string] 
The name of the callback that returns the list of items.

UxMenu.configureLargeListMode parameter: getListCallbackArgs
[type: Array, any] [optional] 
Optional args forwarded to the callback.





















































































































































































































































































































































































































----------------------------------------------------------
Section 14: UiDropDownMenu
----------------------------------------------------------


UiDropDownMenu
[type: class] [extends: UiButton] [requires: module - extendedUi] 
A specialized UiButton that displays a UiMenu. UI functionality includes:  • pre-configured with LayoutObject functionality.  • uiStyle TextFormats and Colors applied.  • pre-configured with 'UiKeyboardNavigable' functionality.  • uiZoom-enabled.  • nearestPixelRendering-enabled.





UiDropDownMenu.uiMenu
[type: UiMenu] 
The UiMenu that is displayed when the this button is triggered.







































































































































































































































































































































































































































































----------------------------------------------------------
Section 15: Sound
----------------------------------------------------------


Sound
[type: class] [extends: TimePlaybackController] [NON-INSTANTIABLE] [requires: module - sounds] 
A specialized PlaybackController that manages the playback of sound assets. 





Sound.name
[type: string] 
The Sounds's name. This must be unique among Sounds.





Sound.isLoaded
[type: boolean] 
Boolean indicating if this Sound is currently loaded.





Sound.loadingTierRequirements
[type: [number]] 
The LoadingTier that this Sound belongs too. LoadingTiers are a means to organize AssetComponents into separately downloadable groups.





Sound.duplicateSource
[type: string] [default: undefined] 
String indicating the source of this Sound if it is a duplicate. Incisor® automatically detects when two or more AssetComponents are identical, ensuring that only one copy of the associated data is loaded to reduce the loaded size of the project. Those AssetComponents that are duplicates are marked by indicating the name of the source of their data. This member is undefined for AssetComponents that are not duplicates.





Sound.mainVolume
[type: number] 
The current volume setting for this Sound, where 0 is quiet and 1 is full volume.





Sound.volumeControl
[type: [VolumeControl]] [default: [nc.volumeControls.MainVolumeControl]] 
The VolumeControls that this Sounds currently subscribes to. VolumeControls are a way to control the volumes of groups of sounds, much like a 'audio bus'.





Sound.netVolume
[type: number] 
The net volume, including the mainVolume of the Sound, and all of the volumes of the Sound's VolumeControls.





Sound.swoopVolume(volume, duration, completionCallbackOwner, completionCallbackName, completionCallbackArgs)
[type: function] [returns: Swooper] 
Interpolates the mainVolum over the designated period of time.

Sound.swoopVolume parameter: volume
[type: number] 
The target volume to swoop to.

Sound.swoopVolume parameter: duration
[type: number] [default: 0] 
The duration of the volume change

Sound.swoopVolume parameter: completionCallbackOwner
[type: object] 
The object owning the function that will be called when the swoop is complete.

Sound.swoopVolume parameter: completionCallbackName
[type: string] 
The name of the function that will be called when the swoop is complete.

Sound.swoopVolume parameter: completionCallbackArgs
[type: Array, any] 
Parameters for the function that will be called when the swoop is complete.












































































































































----------------------------------------------------------
Section 16: VolumeControl
----------------------------------------------------------


VolumeControl
[type: class] [NON-INSTANTIABLE] [requires: module - sounds] 
VolumeControls are a way to control the volumes of groups of sounds, much like a 'audio bus'. To make a particular Sound subscribe to a VolumeControl, add the VolumeControl to the Sound's 'volumeControl' array. 





VolumeControl.type
[type: string] 
Type identifier.





VolumeControl.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





VolumeControl.name
[type: string] 
The VolumeControl's name. This must be unique among VolumeControls.





VolumeControl.volume
[type: number] 
The volume value for this VolumeControl. The volume values for Sounds typically range from 0 to 1.










----------------------------------------------------------
Section 17: UiStyle
----------------------------------------------------------


UiStyle
[type: class] [NON-INSTANTIABLE] 
Object housing default TextFormats, and Colors for various Gui objects such as 'UiButton', 'DropDownMenu' and 'PopUpWindow'. 





UiStyle.type
[type: string] 
Type identifier.





UiStyle.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





UiStyle.textFormat_heading
[type: TextFormat] 
The default TextFormat for heading text in the Gui.





UiStyle.textFormat_subHeading
[type: TextFormat] 
The default TextFormat for sub-heading text in the Gui.





UiStyle.textFormat_body
[type: TextFormat] 
The default TextFormat for body text in the Gui.





UiStyle.textFormat_technical
[type: TextFormat] 
The default TextFormat for technical text in the Gui.





UiStyle.textFormat_tiny
[type: TextFormat] 
The default TextFormat for tiny text in the Gui.





UiStyle.color_appHeader
[type: Color] 
The default color for the application header.





UiStyle.color_headerTitle
[type: Color] 
The default color for the title in the header.





UiStyle.color_mainText
[type: Color] 
The default color for text.





UiStyle.color_inactiveText
[type: Color] 
The default color for text that is not active.





UiStyle.color_interactiveText
[type: Color] 
The default color for interactive text.





UiStyle.color_semiInteractiveText
[type: Color] 
The default color for semi-interactive text.





UiStyle.color_editorBackgroundDark
[type: Color] 
The default color for the dark parts of editor backgrounds.





UiStyle.color_editorBackgroundLight
[type: Color] 
The default color for the light parts of editor backgrounds.





UiStyle.color_highlightedInteractiveText
[type: Color] 
The default color for highlighted interactive text.





UiStyle.color_mainPanelBackground
[type: Color] 
The default color for background panels.





UiStyle.color_lightPanelBackground
[type: Color] 
The default color for light background panels.





UiStyle.color_darkPanelBackground
[type: Color] 
The default color for dark background panels.





UiStyle.color_panelHeader
[type: Color] 
The default color for panel headers.





UiStyle.color_panelBorder
[type: Color] 
The default color for panel borders.





UiStyle.color_panelHeaderHighlight
[type: Color] 
The default color for highlighted header panels.





UiStyle.color_buttonPanel
[type: Color] 
The default color for button panels.





UiStyle.color_highlightedButtonPanel
[type: Color] 
The default color for highlighted button panels.





UiStyle.color_builtInHeaderMenu
[type: Color] 
The default color for the built in header menus.





UiStyle.color_popupWindowHeader
[type: Color] 
The default color for popup window headers.





UiStyle.color_brightHighlightedButtonPanel
[type: Color] 
The default color for bright highlighted button panels.





UiStyle.color_navigationOutline
[type: Color] 
The default color for navigation outlining and highlighting.





UiStyle.color_selection
[type: Color] 
The default color for selected UI objects.





UiStyle.color_selectionOutlineBase
[type: Color] 
A deeper, more saturated version of 'color_selection'.





UiStyle.graphicAssetName_caret
[type: string] 
The name of the GraphicAsset to use wherever a closed caret icon (basically an arrow) is needed in UI components, such as the pointers of a UxNumberSupervisorRangedSlider.





UiStyle.graphicAssetName_opencaret
[type: string] 
The name of the GraphicAsset to use wherever an open caret icon is needed in UI components, such as the caret of a UiCollapsibleStack or UxCollapsibleStack, and the sub-menu indicator of a UiMenu or UxMenu item.





UiStyle.graphicAssetName_magnifyingglass
[type: string] 
The name of the GraphicAsset to use wherever a magnifying glass icon (like next to a search bar) is needed in UI components.





UiStyle.graphicAssetName_checkmark
[type: string] 
The name of the GraphicAsset to use wherever a checkmark icon is needed in UI components.





UiStyle.graphicAssetName_ex
[type: string] 
The name of the GraphicAsset to use wherever an 'X' icon is needed in UI components.





UiStyle.graphicAssetName_minus
[type: string] 
The name of the GraphicAsset to use wherever an '-' icon is needed in UI components.





UiStyle.graphicAssetName_delta
[type: string] 
The name of the GraphicAsset to use wherever an 'Δ' icon is needed in UI components.





UiStyle.graphicAssetName_pause
[type: string] 
The name of the GraphicAsset to use wherever an '⏸️' icon is needed in UI components.





UiStyle.graphicAssetName_sliderarrows
[type: string] 
The name of the GraphicAsset to use wherever an '↕' icon is needed in UI components.





UiStyle.graphicAssetName_sliderarrowsapart
[type: string] 
The name of the GraphicAsset to use wherever an '↕' icon with the arrows further apart is needed in UI components.





UiStyle.graphicAssetName_toend
[type: string] 
The name of the GraphicAsset to use wherever a 'to end' (skip-to-end arrow) icon is needed in UI components.





UiStyle.spacer_tiny
[type: number] 
The standard 'tiny' spacer for the gui.





UiStyle.spacer_small
[type: number] 
The standard 'small' spacer for the gui.





UiStyle.spacer_medium
[type: number] 
The standard 'medium' spacer for the gui.





UiStyle.spacer_large
[type: number] 
The standard 'large' spacer for the gui.





UiStyle.addUiPanelCallbackOwner
[type: object] 
The owner of the callback function responsible for returning a UiPanel, which is a customizable rectangle of color. UiPanels are used throughout the various gui objects, like UiButton, UiTextField, DropdownMenu, PopupMenu etc., and generally contribute to the look of the gui. The provided callback must return an instance of this UiPanel, which is a SceneObject that has 2 additional properties (probably built with getter/setters) 'width' and 'height'. Also, the object produced from this callback will need to have EffectNodes that respond to the 'colorMultiply' EffectController, as that EffectController is used to set the color for the UiPanel for its different uses throughout the ui. This callback is defaults to an internal function that returns a UiPanel that is essentially a WhiteBox, but can be changed to customize the look of the gui.





UiStyle.addUiPanelCallbackName
[type: string] 
The name of the callback function responsible for returning a UiPanel, which is a customizable rectangle of color. UiPanels are used throughout the various gui objects, like UiButton, UiTextField, DropdownMenu, PopupMenu etc., and generally contribute to the look of the gui. The provided callback must return an instance of this UiPanel, which is a SceneObject that has 2 additional properties (probably built with getter/setters) 'width' and 'height'. Also, the object produced from this callback will need to have EffectNodes that respond to the 'colorMultiply' EffectController, as that EffectController is used to set the color for the UiPanel for its different uses throughout the ui. This callback is defaults to an internal function that returns a UiPanel that is essentially a WhiteBox, but can be changed to customize the look of the gui.





UiStyle.addUiOutlineCallbackOwner
[type: object] 
The owner of the callback function responsible for returning a UiOutline, which is a customizable rectangular outline. UiOutlines are used throughout the various gui objects, like UiButton, UiTextField, DropdownMenu, PopupMenu etc., and generally contribute to the look of the gui. The provided callback must return an instance of this UiOutline, which is a SceneObject that has 2 additional properties (probably built with getter/setters) 'width' and 'height'. Also, the object produced from this callback will need to have EffectNodes that respond to the 'colorMultiply' EffectController, as that EffectController is used to set the color for the UiPanel for its different uses throughout the ui. This callback is defaults to an internal function that returns a UiOutline that is essentially a rectangle made of 4 WhiteBoxes, but can be changed to customize the look of the gui.





UiStyle.addUiOutlineCallbackName
[type: string] 
The name of the callback function responsible for returning a UiOutline, which is a customizable rectangular outline. UiOutlines are used throughout the various gui objects, like UiButton, UiTextField, DropdownMenu, PopupMenu etc., and generally contribute to the look of the gui. The provided callback must return an instance of this UiOutline, which is a SceneObject that has 2 additional properties (probably built with getter/setters) 'width' and 'height'. Also, the object produced from this callback will need to have EffectNodes that respond to the 'colorMultiply' EffectController, as that EffectController is used to set the color for the UiPanel for its different uses throughout the ui. This callback is defaults to an internal function that returns a UiOutline that is essentially a rectangle made of 4 WhiteBoxes, but can be changed to customize the look of the gui.





UiStyle.addUiPanel(parent, name)
[type: function] [returns: UiPanel] 
Adds a new UiPanel to the given parent SceneObject.

UiStyle.addUiPanel parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The parent SceneObject that the new UiPanel will become a child of.

UiStyle.addUiPanel parameter: name
[type: string] [default: 'UiPanel'] [optional] 
The name of the new UiPanel.





UiStyle.addUiOutline(parent, name)
[type: function] [returns: UiOutline] 
Adds a new UiOutline to the given parent SceneObject.

UiStyle.addUiOutline parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The parent SceneObject that the new UiOutline will become a child of.

UiStyle.addUiOutline parameter: name
[type: string] [default: 'UiOutline'] [optional] 
The name of the new UiOutline.





UiStyle.standardVisualFeedback(sceneObject, duration)
[type: function] 
Provides a standardized visual feedback consisting of a fast burst of brightness. This feedback is used for most standardized trigger events such as Button presses and keynavigation triggers.

UiStyle.standardVisualFeedback parameter: sceneObject
[type: SceneObject] 
The SceneObject that the visual feedback will be applied to.

UiStyle.standardVisualFeedback parameter: duration
[type: number] [default: 0.11] [optional] 
The time the burst takes to fall back to the SceneObject's own colorMultiply.










----------------------------------------------------------
Section 18: UiPanel
----------------------------------------------------------


UiPanel
[type: class] [extends: SceneObject] 
This is a customizable panel of color used throughout the various gui objects such as UiButton, UiTextField, DropdownMenu, PopupMenu etc., which generally contributes to the look of the gui. The nature of this object can be customized by supplying a new callback function to 'nc.uiStyle.addUiPanelCallbackOwner' and 'nc.uiStyle.addUiPanelCallbackName'.





UiPanel.width
[type: number] 
Number controlling the width of the UiPanel.





UiPanel.height
[type: number] 
Number controlling the height of the UiPanel.





UiPanel.colorMultiply
[type: Color] 
Color controlling the coloring of the UiPanel.






















































































































































































































































































































----------------------------------------------------------
Section 19: UiOutline
----------------------------------------------------------


UiOutline
[type: class] [extends: SceneObject] [NON-INSTANTIABLE] 
This is a customizable rectangular outline used throughout the various gui objects such as UiButton, UiTextField, DropdownMenu, PopupMenu etc., which generally contributes to the look of the gui. The nature of this object can be customized by supplying a new callback function to 'nc.uiStyle.addUiOutlineCallbackOwner' and 'nc.uiStyle.addUiOutlineCallbackName'. 





UiOutline.width
[type: number] 
Number controlling the width of the UiOutline.





UiOutline.height
[type: number] 
Number controlling the height of the UiOutline.





UiOutline.colorMultiply
[type: Color] 
Color controlling the coloring of the UiOutline.






















































































































































































































































































































----------------------------------------------------------
Section 20: AssetComponent
----------------------------------------------------------


AssetComponent
[type: class] [NON-INSTANTIABLE] 
The base object defining the fundamental content builing-blocks for Incisor® such as Textures, Geometry, and Sounds. 





AssetComponent.type
[type: string] 
Type identifier





AssetComponent.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





AssetComponent.name
[type: string] 
The AssetComponent's name. This must be unique among AssetComponents of its type.





AssetComponent.isLoaded
[type: boolean] 
Boolean indicating if this AssetComponent is currently loaded.





AssetComponent.loadingTierRequirements
[type: [number]] 
The LoadingTier that this AssetComponent belongs too. LoadingTiers are a means to organize AssetComponents into separately downloadable groups.





AssetComponent.duplicateSource
[type: string] [default: undefined] 
String indicating the source of this AssetComponent if it is a duplicate. Incisor® automatically detects when two or more AssetComponents are identical, ensuring that only one copy of the associated data is loaded to reduce the loaded size of the project. Those AssetComponents that are duplicates are marked by indicating the name of the source of their data. This member is undefined for AssetComponents that are not duplicates.










----------------------------------------------------------
Section 21: SlotReel
----------------------------------------------------------


SlotReel
[type: class] [extends: SceneObject] [requires: module - slotReels] 
A specialized SceneObject which populates and manipulates 'symbol' objects to create a spinning reel to be used for slot games. The 'spinning' effect is created by moving each GraphicObject along a modulus-style path, where the represented symbol changes when each GraphicObject reaches the 'jump' point in the path. The symbols can be customized by supplying a CustomObjectDefinition or CustomAddOnDefinition, which will be used in the population of each symbol.





SlotReel.defaultSymbolPathTravelY
[type: number] [default: 200] 
If no 'symbolPathConstructDefinition' is connected to this SlotReel, then the defaultSymbolPathTravelX and defaultSymbolPathTravelY define the spinning motion of this SlotReel. The defaultSymbolPathTravelY value determines the amount of vertical travel per 'symbolPosition'. The symbolPosition property value is populated by the SlotReel as the symbols move, and it corresponds to each symbol's location along the symbol path, where a value of 0 corresponds to the center of the first main visible symbol, 1 corresponds to the next main visible symbol, and -1 corresponds to the top buffer symbol just above the symbol in position 0. So, the default value of 200 for this property means that each symbol will be 200 vertical world units from the next.





SlotReel.defaultSymbolPathTravelX
[type: number] 
If no 'symbolPathConstructDefinition' is connected to this SlotReel, then the defaultSymbolPathTravelX and defaultSymbolPathTravelY define the spinning motion of this SlotReel. The defaultSymbolPathTravelX value determines the amount of horizontal travel per 'symbolPosition'. The symbolPosition property value is populated by the SlotReel as the symbols move, and it corresponds to each symbol's location along the symbol path, where a value of 0 corresponds to the center of the first main visible symbol, 1 corresponds to the next main visible symbol, and -1 corresponds to the top buffer symbol just above the symbol in position 0. So, the default value of 0 for this property means that each symbol does not travel horizontally as it moves along the symbol path.





SlotReel.spinSpeed
[type: number] [default: -0.25] 
The spinSpeed property represents the rate of motion for each symbol object during the reel spin. The value corresponds to the amount of travel per 60th of a second, where a value of 1 indicates that each symbol will move one full symbol position each 60th of a second.





SlotReel.windupMotionFunctionOwner
[type: object] 
The owner of the function that defines this SlotReel's motion during the 'windup' state. The windup motion for this SlotReel can be customized by providing a bespoke function here. The windup function should take 2 numeric parameters (progress and windupMagnitude), and return a symbolPostion offset value. The progress parameter sent to the windup function will interpolate smoothly from 0 to 1 over a time corresponding to this SlotReel's 'windupDuration' property. The windupMagnitude value sent to the windup function will be taken directly from ths SlotReel's 'windupMagnitude' property, and can be used (optionally) in the function to change the motion dynamically. The windup function should return a value corresponding to the 'symbolPosition' offset that all of the symbols will experience given the current 'progress' value, so for a windup function to make the symbols move up half a symbol position, the provided windup function should return a value of 0.5 at its peak.





SlotReel.windupMotionFunctionName
[type: string] 
The name of the function that defines this SlotReel's motion during the 'windup' state. The windup motion for this SlotReel can be customized by providing a bespoke function here. The windup function should take 2 numeric parameters (progress and windupMagnitude), and return a symbolPostion offset value. The progress parameter sent to the windup function will interpolate smoothly from 0 to 1 over a time corresponding to this SlotReel's 'windupDuration' property. The windupMagnitude value sent to the windup function will be taken directly from ths SlotReel's 'windupMagnitude' property, and can be used (optionally) in the function to change the motion dynamically. The windup function should return a value corresponding to the 'symbolPosition' offset that all of the symbols will experience given the current 'progress' value; so for a windup function to make the symbols move up half a symbol position, the provided windup function should return a value of 0.5 at its peak.





SlotReel.windupDuration
[type: number] 
The amount of time that this SlotReel will spend in the 'windup' state.





SlotReel.windupMagnitude
[type: number] 
A value sent to the windup motion function that can be used (optionally) within the function to enable the windup motion to be manipulated dynamically.





SlotReel.bounceMotionFunctionOwner
[type: object] 
The owner of the function that defines this SlotReel's motion during the 'bounce' state. The bounce motion for this SlotReel can be customized by providing a bespoke function here. The bounce function should take 2 numeric parameters (progress and bounceMagnitude), and return a symbolPostion offset value. The progress parameter sent to the bounce function will interpolate smoothly from 0 to 1 over a time corresponding to this SlotReel's 'bounceDuration' property. The bounceMagnitude value sent to the bounce function will be taken directly from ths SlotReel's 'bounceMagnitude' property, and can be used (optionally) in the function to change the motion dynamically. The bounce function should return a value corresponding to the 'symbolPosition' offset that all of the symbols will experience given the current 'progress' value; so for a bounce function to make the symbols move up half a symbol position, the provided bounce function should return a value of 0.5 at its peak.





SlotReel.bounceMotionFunctionName
[type: string] 
The name of the function that defines this SlotReel's motion during the 'bounce' state. The bounce motion for this SlotReel can be customized by providing a bespoke function here. The bounce function should take 2 numeric parameters (progress and bounceMagnitude), and return a symbolPostion offset value. The progress parameter sent to the bounce function will interpolate smoothly from 0 to 1 over a time corresponding to this SlotReel's 'bounceDuration' property. The bounceMagnitude value sent to the bounce function will be taken directly from ths SlotReel's 'bounceMagnitude' property, and can be used (optionally) in the function to change the motion dynamically. The bounce function should return a value corresponding to the 'symbolPosition' offset that all of the symbols will experience given the current 'progress' value; so for a bounce function to make the symbols move up half a symbol position, the provided bounce function should return a value of 0.5 at its peak.





SlotReel.bounceDuration
[type: number] 
The amount of time that this SlotReel will spend in the 'bounce' state.





SlotReel.bounceMagnitude
[type: number] 
A value sent to the bounce motion function that can be used (optionally) within the function to enable the bounce motion to be manipulated dynamically.





SlotReel.assembleReelDataOnTheFly
[type: boolean] [default: false] 
Boolean indicating if this SlotReel is in 'assembleReelDataOnTheFly' mode. When true, the data for this reel is initially only seeded with a small portion of of reel data, and each reel spin adds its symbols (as provided to the 'setTarget' function) to the end of the reel data array. The reel data continues to grow with each spin until it meets the 'reelDataAssemblyMax' threshold, at which point the additional symbols overwrite a random portion of the existing reel data. When false, the entire reel must be provided initially.





SlotReel.reelDataAssemblyMax
[type: number] [default: 200] 
When 'assembleReelDataOnTheFly' for this SlotReel is true, this property acts a reel data length cap. Once the reel data length reaches this value additional symbols provided in the 'setTarget' call are randomly placed within the reel data, overwriting previously placed reel data.





SlotReel.reelState
[type: string] 
Read-only string indicating which state this SlotReel is in. States include 'stopped', 'windup', 'spinFree', 'stopping', 'stopImminent', and 'bounce', which can be found in constants.slotReelStates. - The 'stopped' state corresponds when the SlotReel is stopped. - The 'windup' state corresponds just before the main portion of the spin, when the SlotReel is 'winding up'. - The 'spinFree' state corresponds to when SlotReel is freely spinning, which will continue indefinitely until 'beginStop' or 'slam' are called. - The 'stopping' state corresponds to the time during the spin after 'beginStop' has been called; the SlotReel will continue in this state until the final stopping symbols have been found. - The 'stopImminent' state corresponds to when the final stopping symbols are active/visible on the SlotReel, and they just need to travel into their final position. - The 'bounce' state corresponds to right before the SlotReel spin is over, and the symbols are bouncing around to simulate a physical recoil action.





SlotReel.pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] 
The PauseEvent or Array of PauseEvents that this SlotReel will be immune to. Set this parameter to [] for this Swooper to have no pause immunity.





SlotReel.speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] 
The SpeedControl or Array of SpeedControls that this SlotReel is affected by.





SlotReel.numMainSymbols
[type: number] 
The number of 'symbol' GraphicObjects that are meant to be the main visible symbols for this SlotReel. This property is read-only since its value is set once in the constructor.





SlotReel.numTopBufferSymbols
[type: number] 
The number of symbol objects that will be populated 'above' the main visible symbols for this SlotReel. It should be noted that since the motion of the symbols in this SlotReel is completely customizable, these buffer symbols will not necessarily be above the main symbols. This property is read-only since its value is set once in the constructor.





SlotReel.numBottomBufferSymbols
[type: number] 
The number of symbol objects that will be populated 'below' the main visible symbols for this SlotReel. It should be noted that since the motion of the symbols in this SlotReel is completely customizable, these buffer symbols will not necessarily be below the main symbols. This property is read-only since its value is set once in the constructor.





SlotReel.numSymbols
[type: number] 
The total number of symbol objects that will be populated for this SlotReel, which includes the numMainSymbols, numTopBufferSymbols, and numBottomBufferSymbols. This property is read-only since its value is effectively set once in the constructor.





SlotReel.symbolDefinition
[type: CustomAddOnDefinition] 
The definition of the CustomObject CustomAddOn that was used to populate each of the symbol objects. The CustomObject or CustomAddOn in question should implement the 'setSymbol' function, which takes a single string parameter which will be passed whenever the associated symbol is altered. It can also implement the 'symbolPosition' numeric property, which will be updated by the SlotReel as each symbol moves along the symbol path for this SlotReel. The definition of this object is also where further customization of each symbol can be defined. This property is read-only since its value is set once in the constructor.





SlotReel.symbolPathOverrideMode
[type: boolean] [default: false] 
Boolean determining if the SlotReel's positioning of its symbol objects along the reel path is overriden. To entirely override reel path positioning of the symbols, set this property to true, and be sure to implement an 'updateSymbolPosition' function within the symbolDefinition object. Within that function, you can create custom positioning for each symbol based on the 'symbolPosition' property, which indicates the relative or 'unit' position of each symbol (ie a reel with 3 main symbols and a single buffer on top and bottom would have symbols with symbolPosition values of -1, 0, 1, 2, 3). Using the 'symbolPosition' property, you can write functionality to position each symbol as desired based on its relative position.





SlotReel.populateInitialReelData(reelData, initialSymbols)
[type: function] 
Call this function to provide this SlotReel with its initial reel data, and the symbols that will appear when the SlotReel is first displayed. Reel data consists of an array of strings that represent the designation of each symbol on the 'reel strip'. The data that is provided depends on whether or not the SlotReel is in 'assembleReelDataOnTheFly' mode. If assembleReelDataOnTheFly is true, then only a small portion of reel data need be provided, as each subsequent call to 'setTarget' will add to the reel data. If assembleReelDataOnTheFly is false, then the entire reel data set must be provided here.

SlotReel.populateInitialReelData parameter: reelData
[type: [string]] 
The set of initial reel data to provide to this SlotReel. If assembleReelDataOnTheFly is true, only a small portion of reel data need be provided, otherwise the entire reel data set must be provided here.

SlotReel.populateInitialReelData parameter: initialSymbols
[type: [string]] [optional] 
An array of strings representing the initial symbols to populate on the reel when it is first displayed. If left undefined, starting symbols will be taken directly from the reelData provided.





SlotReel.setTarget(target)
[type: function] 
Sets the target position in the reel data (the reel stop), or the target group of symbols to be displayed to be displayed when the SlotReel comes to a stop. If assembleReelDataOnTheFly is false, then provide an index in the reel data here, and the symbol at that index will be displayed in this SlotReel's first main visible position (position 0) spin ends, with the subsequent symbols displayed below respectively. If assembleReelDataOnTheFly is true, then provide an array of strings corresponding to the symbols to be displayed when the SlotReel spin stops - in this case be sure to provide enough symbol strings for the top buffer symbols, the main symbols, and the bottom buffer symbols.

SlotReel.setTarget parameter: target
[type: number, [string]] 
If assembleReelDataOnTheFly is false provide the final stopping reel data index, if it's true provide final stopping set of symbols in an array.





SlotReel.beginSpin()
[type: function] 
Function that begins the spin sequence for this SlotReel, changing the reelState from 'stopped' to 'windup'. The SlotReel will perform the windup sequence, and then the reelState will be changed to 'spinFree', which will lead the SlotReel to spin until further interaction.





SlotReel.beginStop(performSplice)
[type: function] 
Function the starts the process of stopping a reel from spinning, changing the reelState from 'spinFree' to 'stopping'. While the reelState is 'stopping', the SlotReel will continue to spin until it encounters the set of symbols it needs for the final stopped position. A 'performSplice' boolean (when true) will tell the SlotReel to jump to the position in the reel data such that each new symbol made visible during the spin will be one of the final symbols needed - this expedites the stopping process. This value should be false if the reel is meant to spin just a finite number of positions (i.e. 1 position), as a value of true would only extend the stopping process in this case.

SlotReel.beginStop parameter: performSplice
[type: boolean] [default: true] [optional] 
Boolean indicating if the SlotReel should jump to a place in the reel data such that the very next symbols made visible will be the final stopping symbols needed to stop the spin.





SlotReel.slam()
[type: function] 
Function that can be called during the SlotReel spin sequence to abruptly skip to the 'bounce' reelState.





SlotReel.getSymbol(index)
[type: function] [returns: SceneObject] 
Returns the 'symbol' object at the given index. Any index in [-numTopBufferSymbols, numMainSymbols+numBottomBufferSymbols-1] can be provided, as that is the set of available symbolPositions. If the SlotReel is currently in any reelState other than 'stopped' then the 'symbol' GraphicObject with the symbolPosition that is nearest to the index provided will be returned. It should be noted that the type of the returned object depends on the original 'symbolDefinition' supplied to the SlotReel's constructor. If a CustomObjectDefinition was provided, then the returned object will have that type, otherwise the returned object will be of type GraphicObject.

SlotReel.getSymbol parameter: index
[type: number] 
The index of the 'symbol' GraphicObject to fetch. Any index in [-numTopBufferSymbols, numMainSymbols+numBottomBufferSymbols-1] can be provided, as that is the set of available symbolPositions.





SlotReel.getSymbols(presortBySymbolPosition)
[type: function] [returns: [SceneObject]] 
Returns an Array with all of the 'symbol' objects in this SlotReel. It should be noted that the type of the objects in the returned array depends on the original 'symbolDefinition' supplied to the SlotReel's constructor. If a CustomObjectDefinition was provided, then the returned array will contain objects of that type, otherwise the the array will contain GraphicObjects.

SlotReel.getSymbols parameter: presortBySymbolPosition
[type: boolean] [optional] 
Boolean indicating if the returned symbols should be sorted by their 'symbolPosition' values.





SlotReel.addReelStateChangeCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever the 'reelState' of this SlotReel is changed. The new reelState and the previous reelState are sent to the callback as its first two parameters. - The 'stopped' state corresponds when the SlotReel is stopped. - The 'windup' state corresponds just before the main portion of the spin, when the SlotReel is 'winding up'. - The 'spinFree' state corresponds to when SlotReel is freely spinning, which will continue indefinitely until 'beginStop' or 'slam' are called. - The 'stopping' state corresponds to the time during the spin after 'beginStop' has been called; the SlotReel will continue in this state until the final stopping symbols have been found. - The 'stopImminent' state corresponds to when the final stopping symbols are active/visible on the SlotReel, and they just need to travel into their final position. - The 'bounce' state corresponds to right before the SlotReel spin is over, and the symbols are bouncing around to simulate a physical recoil action.

SlotReel.addReelStateChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever the FlowState changes.

SlotReel.addReelStateChangeCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever the FlowState changes.

SlotReel.addReelStateChangeCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever the FlowState changes.





SlotReel.removeReelStateChangeCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

SlotReel.removeReelStateChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

SlotReel.removeReelStateChangeCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.



























































































































































































































































































































----------------------------------------------------------
Section 22: Texture
----------------------------------------------------------


Texture
[type: class] [extends: AssetComponent] [NON-INSTANTIABLE] 
A Texture is a pixel map used for filling the surface of Geometry during rendering. 





Texture.wrapModeHorizontal
[type: string] 
Mode denoting how this Texture will behave beyond its horizontal bounds. The acceptable wrap modes can be found in 'nc.constants.wrapModes'.





Texture.wrapModeVertical
[type: string] 
Mode denoting how this Texture will behave beyond its vertical bounds. The various wrap modes can be found in 'nc.constants.wrapModes'.





Texture.downscalingMode
[type: string] 
Mode denoting how this Texture will be sampled when it is smaller than it's native size. The various downscaling modes can be found in 'nc.constants.textureDownscalingModes'.





Texture.upscalingMode
[type: string] 
Mode denoting how this Texture will be sampled when it is larger than it's native size. The various upscaling modes can be found in 'nc.constants.textureUpscalingModes'.





Texture.spriteSheet
[type: string] [default: undefined] 
The name of the SpriteSheet that this Texture is a part of (if applicable).





Texture.getResolution()
[type: function] [returns: Vector2] 
Returns a Vector2 with the pixel dimensions of this Texture.





Texture.dispose()
[type: function] 
Removes internal Incisor® references to this Geometry.








































----------------------------------------------------------
Section 23: Motion
----------------------------------------------------------


Motion
[type: class] [NON-INSTANTIABLE] 
Object controlling a 'motion' (continuous change) on a given numeric property or properties (using fixedUpdate). An object of this type is returned from all 'addMotion' calls, providing a means to manage the given motion process. 





Motion.type
[type: string] 
Type identifier.





Motion.name
[type: string] 
Name of the Motion.





Motion.numProperties
[type: number] 
The number of properties being affected by this Motion.





Motion.influence
[type: number] [default: 1] 
Number determining the influence of this Motion over the associated numeric properties where a value of 0 corresponds to the property remaining at its baseValue with no change, and a value of 1 corresponds to the value of the property being entirely determined by the Motion.





Motion.motionSpeed
[type: number] [default: 1] 
Number informing the Motion's rate of increase on its 'progress' value, affecting the overall speed of the motion experienced by the associated properties.





Motion.progress
[type: number] [default: 0] 
The number driving the motionFunction for this motion. In a defined motion over time, this number is equivalent to time. This value is not meant to be manipulated as it is automatically changed over time via the internal fixedUpdate used by this Motion.





Motion.motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] 
The MotionType for this Motion. A MotionType defines a method of continuous change for a given set of numeric properties within a set of bounds over time. The default MotionType is 'Pendulum', which defines a smooth sinusoidal oscillation between the lower and upper bounds. MotionTypes can define any set of continuous motions for a set of numeric properties.





Motion.baseValues
[type: [number]] 
Array containing the base values for this Motion. These are the values that the properties being manipulated will return to if the 'influence' of this Motion is set to 0. Upon initiating a Motion for a given set numeric properties, their current values are stored in this array and used as 'home base' values and blended with the defined motion according to 'influence'.





Motion.currentValues
[type: [number]] 
Array containing the current values for this Motion. These are the values that the MotionType motion function manipulate based its 'progress' property to create the desired movement.





Motion.controllers
[type: MotionControllers] 
Dictionary of dictionaries (per MotionType) of values that can be used to control this motion dynamically.





Motion.lowerBounds
[type: [number]] 
Array containing the lower bound or bounds for the Motion. The length of this array depends on this Motion's 'numProperties'. While MotionType definitions are not all required to adhere to bounds, it is a common practice for MotionTypes result in property motion that is confined to these bounds.





Motion.upperBounds
[type: [number]] 
Array containing the upper bound or bounds for the Motion. The length of this array depends on this Motion's 'numProperties'. While MotionType definitions are not all required to adhere to bounds, it is a common practice for MotionTypes result in property motion that is confined to these bounds.





Motion.workspace
[type: object] 
An un-specified JS object of 'any' type to enable the user to stash persistant elements of their Motion within the motionFunction.





Motion.updaterCallbackOwner
[type: object] [default: undefined] 
The object owning the optional callback function invoked continuously (every fixedUpdate) during the motion process. This callback is only performed while the influence value is larger than 0.





Motion.updaterCallbackName
[type: string] [default: undefined] 
The name of the optional callback function invoked continuously (every fixedUpdate) during the motion process. This callback is only performed while the influence value is larger than 0.





Motion.pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] for this Motion to have no pause immunity.





Motion.speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.





Motion.swoopInfluence(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) the Motion's influence from its current value to the given end value over the duration.

Motion.swoopInfluence parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

Motion.swoopInfluence parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

Motion.swoopInfluence parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

Motion.swoopInfluence parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

Motion.swoopInfluence parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

Motion.swoopInfluence parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

Motion.swoopInfluence parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Motion.swoopInfluence parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

Motion.swoopInfluence parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

Motion.swoopInfluence parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.










----------------------------------------------------------
Section 24: MotionControllers
----------------------------------------------------------


MotionControllers
[type: class] [NON-INSTANTIABLE] 
Dictionary of all registered MotionControllers. 










----------------------------------------------------------
Section 25: MotionType
----------------------------------------------------------


MotionType
[type: class] [NON-INSTANTIABLE] 
Object defining a particular type of motion that can be added to any property or group of properties via 'nc.addMotion' or 'Vector.addMotion'. 





MotionType.type
[type: string] 
Type identifier.





MotionType.name
[type: string] 
Name of the Motion.





MotionType.motionFunction()
[type: function] 
A reference to the function that defines the nature of the motion.





MotionType.motionControllerNames
[type: [string]] 
A list of optional motion controllers. These can be used to dynamically affect the nature of the motion.





MotionType.motionControllerDefaultValues
[type: [number]] 
A list of optional motion controller default values.





MotionType.description
[type: string] 
The description of the MotionType - this will appear in the autocomplete documentation.





MotionType.controllerDescriptions
[type: [string]] 
The description of the MotionType controllers - these descriptions will appear in the autocomplete documentation.










----------------------------------------------------------
Section 26: MaterialMaster
----------------------------------------------------------


MaterialMaster
[type: class] [NON-INSTANTIABLE] 
The MaterialMaster is a convenience-based object that represents all of the Materials on a given GraphicObject. To manipulate all of the Materials on a GraphicObject at the same time, you can simply manipulate its MaterialMaster. It should be noted that querying values from the MaterialMaster can be misleading, as the returned values only refer to the last values set on the MaterialMaster itself, and would not reflect individual changes made to the Materials themselves. 





MaterialMaster.type
[type: string] 
Type identifier.





MaterialMaster.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





MaterialMaster.blending
[type: string] 
Sets the 'blending' value for all of this GraphicObject's Materials.





MaterialMaster.faceCulling
[type: string] 
Sets the 'faceCulling' value for all of this GraphicObject's Materials. Acceptable values are in nc.constants.faceCullingModes. Reading this returns the value held by the first Material, which may not represent the others if one of them was set individually.





MaterialMaster.depthTest
[type: boolean] 
Sets the 'depthTest' value for all of this GraphicObject's Materials. Reading this returns the value held by the first Material, which may not represent the others if one of them was set individually.





MaterialMaster.depthWrite
[type: boolean] 
Sets the 'depthWrite' value for all of this GraphicObject's Materials. Reading this returns the value held by the first Material, which may not represent the others if one of them was set individually.





MaterialMaster.transparent
[type: boolean] 
Sets the 'transparent' value for all of this GraphicObject's Materials. Reading this returns the value held by the first Material, which may not represent the others if one of them was set individually.





MaterialMaster.auxShaderSegment_vertexSupport
[type: string] 
Sets the 'auxShaderSegment_vertexSupport' value for all of this GraphicObject's Materials.





MaterialMaster.shaderSegment_matrixMath
[type: string] 
Sets the 'shaderSegment_matrixMath' value for all of this GraphicObject's Materials.





MaterialMaster.auxShaderSegment_postMatrixMath
[type: string] 
Sets the 'auxShaderSegment_postMatrixMath' value for all of this GraphicObject's Materials.





MaterialMaster.fillColor
[type: Color] 
The EffectController for the 'FillColor' EffectNode, which entirely fills the associated Geometry with the red, green, blue, and alpha color values provided. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





MaterialMaster.mainTexture
[type: Texture] 
The EffectController for the 'SampleMainTexture' EffectNode that tells it which Texture to render.





MaterialMaster.colorMultiply
[type: Color] 
The EffectController for the 'ColorMultiply' EffectNode, which multiplies the red, green, blue, and alpha color values of the Material it is applied to. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





MaterialMaster.shapify
[type: shapify] 
The EffectController for the 'Shapify' EffectNode. The Shapify EffectNode converts edge data stored in a 'shapified' Texture into a presentable image with edges that stay sharp regardless of the scale of the associated GraphicObject. This is an instance of the dynamically defined EffectController 'shapify' (base type: 'Vector2'). To get a new instance, use "nc.effectControllers['shapify'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





MaterialMaster.incr_TwoColorGradient
[type: incr_TwoColorGradient] 
The incr_TwoColorGradient EffectController. This is an instance of the dynamically defined EffectController 'incr_TwoColorGradient' (base type: 'Vector4'). To get a new instance, use "nc.effectControllers['incr_TwoColorGradient'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





MaterialMaster.incr_TwoColorGradient_color0
[type: Color] 
The incr_TwoColorGradient_color0 EffectController. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





MaterialMaster.incr_TwoColorGradient_color1
[type: Color] 
The incr_TwoColorGradient_color1 EffectController. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





MaterialMaster.shear
[type: shear] 
EffectController for the Shear EffectNode, which distorts the shape to appear slanted or skewed. This is an instance of the dynamically defined EffectController 'shear' (base type: 'Vector3'). To get a new instance, use "nc.effectControllers['shear'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





MaterialMaster.shear_center
[type: Vector2] 
EffectController for the Shear EffectNode, which distorts the shape to appear slanted or skewed. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





MaterialMaster.setEffectNodes(effectNodes)
[type: function] 
Sets the EffectNodes for all of this GraphicObject's Materials.

MaterialMaster.setEffectNodes parameter: effectNodes
[type: [EffectNode], EffectNode] 
The new list of EffectNodes that will apply to all of this GraphicObject's Materials.





MaterialMaster.addEffectNodes(effectNodes)
[type: function] 
Adds EffectNodes to all of this GraphicObject's Materials.

MaterialMaster.addEffectNodes parameter: effectNodes
[type: [EffectNode], EffectNode] 
The EffectNodes that will be added to all of this GraphicObject's Materials.










----------------------------------------------------------
Section 27: UiButton
----------------------------------------------------------


UiButton
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A ui-specialized horizontal LayoutStack housing a text-based Button (including a UiPanel background) with various UI functionalities and defaults applied. UI functionality includes:  • pre-configured with LayoutObject functionality.  • uiStyle TextFormats and Colors applied.  • pre-configured with 'UiKeyboardNavigable' functionality.  • uiZoom-enabled.  • nearestPixelRendering-enabled.





UiButton.isActive
[type: boolean] [default: true] 
Boolean determining if the UiButton is available for end-user-internaction, or if it is unavailable and 'grayed out'.





UiButton.mainText
[type: TextBox] 
The TextBox with main text for this UiButton. The size of the text informs the button's size and layout.





UiButton.displayLabel
[type: boolean] [default: false] 
Boolean determining if a label TextBox is displayed to the left of the UiButton.





UiButton.label
[type: UiText] [default: undefined] 
A UiText that acts as a label for the UiButton. Please note that this item is undefined until the 'displayLabel' property is set to true.





UiButton.mainButton
[type: Button] 
The main Button for the UiButton, this object is a UiPanel which also implements Button.





UiButton.outline
[type: UiOutline] 
The outline of the button, which is used to indicate when the end-user outlines this UiButton using keyboard navigation (tab, arrows, etc...).





UiButton.buttonBackgroundColor
[type: Color] [default: nc.uiStyle.color_buttonPanel] 
The Color of the Button background.





UiButton.highlightedButtonBackgroundColor
[type: Color] [default: nc.uiStyle.color_highlightedButtonPanel] 
The Color of the Button background when it's highlighted.





UiButton.addTriggerCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever this UiButton is triggered via the cursor or keyboard navigation. The triggering browser-created event, and the UiButton itself are sent to the callback as its first two parameters.

UiButton.addTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this UiButton is triggered via the cursor or keyboard navigation.

UiButton.addTriggerCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this UiButton is triggered via the cursor or keyboard navigation.

UiButton.addTriggerCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever this UiButton is triggered via the cursor or keyboard navigation.

example:
// Objective: Add a TriggerCallback to a button
// Expected Result: You will see a button with the button text "Press Me". Pressing it will display text that says "You pressed the button."

// Add a callback function.
this.myCallback = function(args) {
    let txt = new UiText( nc.mainScene, "ButtonMessageText" );
    txt.position.x = 100;
    txt.string = "You pressed the button."
}

let button = new UiButton( nc.mainScene, "MyButton" );
button.mainText.string = "Press Me";
button.displayLabel = false;
// add the trigger callback
button.addTriggerCallback( this, "myCallback" );





UiButton.removeTriggerCallback(callbackOwner, callbackName)
[type: function] 
Removes the given trigger callback.

UiButton.removeTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UiButton.removeTriggerCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.

example:
// Objective: Remove a TriggerCallback to a button
// Expected Result: The "Press Me" button will increment the press count. Upon pressing the "Stop Counting" button, the "Press Me" button will no longer function.

let presses = 0;
let txt = new UiText( nc.mainScene, "ButtonMessageText" );
txt.position.x = 100;
txt.string = "You pressed the button 0 times.";

// Add a callback function ti increment the press count.
this.counter = function(args) {
   presses++;
   txt.string = "You pressed the button " + presses + " times.";
}

// Add a callback function to stop the counter callback
this.stopper = function(args) {
    pressMeButton.removeTriggerCallback( this, "counter" );
}

// the button that will increment the press count
let pressMeButton = new UiButton( nc.mainScene, "PressMeButton" );
pressMeButton.mainText.string = "Press Me";
pressMeButton.displayLabel = false;
// add the trigger callback
pressMeButton.addTriggerCallback( this, "counter" );

// the button that will remove the counter callback
let stopCountingButton = new UiButton( nc.mainScene, "StopCountingButton" );
stopCountingButton.mainText.string = "Stop Counting";
stopCountingButton.displayLabel = false;
stopCountingButton.position.x = -150;
// add the trigger callback
stopCountingButton.addTriggerCallback( this, "stopper" );





















































































































































































































































































































































































































----------------------------------------------------------
Section 28: UiKeyboardNavigator
----------------------------------------------------------


UiKeyboardNavigator
[type: class] [NON-INSTANTIABLE] [requires: module - extendedUi] 
Object housing functionality that enables for keyboard navigation of this SceneObject's ui-related descendants. Keyboard navigation enables the end-user to press the tab, space, and enter keys to outline and trigger any 'uiKeyboardNavigable' descendants of the SceneObject owning this UiKeyboardNavigator when it is 'in focus' according to 'nc.singularFocusObject'. SceneObjects have a member named "uiKeyboardNavigator", which defaults to undefined, but can be enabled, by calling 'SceneObject.configureUiKeyboardNavigator()'.





UiKeyboardNavigator.type
[type: string] 
Type identifier.





UiKeyboardNavigator.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





UiKeyboardNavigator.defaultOutlined
[type: SceneObject] 
If defined, this SceneObject will automatically be outlined when the SceneObject owning this UiKeyboardNavigator is the 'singularFocusObject'.





UiKeyboardNavigator.arrowNavigationEnabled
[type: boolean] [default: true] 
Flag determining whether the arrow keys navigate, in addition to the tab and shift+tab keys. When false, this UiKeyboardNavigator responds only to tab and shift+tab, leaving the arrow keys unhandled so that they remain available to other keyboard consumers. Tab and shift+tab navigation is unaffected either way.





UiKeyboardNavigator.gotoNext(direction)
[type: function] 
Instructs to the UiKeyboardNavigator to outline the next, current, or previous UiKeyboardNavigable descendant, based on the 'direction' paramter supplied.

UiKeyboardNavigator.gotoNext parameter: direction
[type: number] [default: 0] [optional] 
Value supplied determining the direction of the navigation. 1 goes to next item, 0 outlines the current item, and -1 outlines the previous item.





UiKeyboardNavigator.goTowards(direction)
[type: function] 
Navigates to the nearest UiKeyboardNavigable descendant in the given spatial direction relative to the currently outlined item. "left" navigates to the next item to the left, "right" to the right, "up" upward, and "down" downward. If nothing is currently outlined, falls back to gotoNext(0).

UiKeyboardNavigator.goTowards parameter: direction
[type: string] 
The spatial direction to navigate toward. Options: "left", "right", "up", "down".





UiKeyboardNavigator.dispose()
[type: function] 
Disposes this UiKeyboardNavigator, disabling keyboard navigation for the SceneObject owning it, and freeing object for garbage collection.










----------------------------------------------------------
Section 29: UiKeyboardNavigable
----------------------------------------------------------


UiKeyboardNavigable
[type: class] [NON-INSTANTIABLE] [requires: module - extendedUi] 
Object housing functionality that enables for this SceneObject to be accessible via keyboard navigation. Keyboard navigation enables the end-user to press the arrow keys, tab, space, and enter keys to outline and trigger any 'uiKeyboardNavigable' SceneObjects within a UiKeyboardNavigator-enabled parent that is currently 'in focus' according to 'nc.singularFocusObject'. SceneObjects have a member named "uiKeyboardNavigable", which defaults to undefined, but can be enabled, by calling 'SceneObject.configureUiKeyboardNavigable()'.





UiKeyboardNavigable.type
[type: string] 
Type identifier.





UiKeyboardNavigable.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





UiKeyboardNavigable.anyKeyTriggers
[type: boolean] [default: false] 
Flag determining if any key triggers the currently outlined UiKeyboardNavigable item. Standard UiKeyboardNavigable items are triggered by the "Enter" key and "Spacebar" key, when this flag is true, any key will trigger. Since the triggering keyboard event is sent through to the UiKeyboardNavigable item's 'trigger' callback, further costumizations can be added to the triggering key within the item itself (for example certain keys can be ignored etc...).





UiKeyboardNavigable.defaultOutlined
[type: SceneObject] 
Optional SceneObject that will automatically be outlined the first time the owner of this UiKeyboardNavigation becomes the 'singularFocusObject'.





UiKeyboardNavigable.isActive
[type: boolean] [default: true] 
Boolean determining if this UiKeyboardNavigable is currently active.





UiKeyboardNavigable.addSetOutlineCallback(callbackOwner, callbackName)
[type: function] 
Adds a callback that occurs whenever this UiKeyboardNavigable item is in need of outlining or unoutlining. A boolean indicating the outline status is sent to the callback as its first parameter.

UiKeyboardNavigable.addSetOutlineCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this UiKeyboardNavigable item is in need of outlining or unoutlining.

UiKeyboardNavigable.addSetOutlineCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this UiKeyboardNavigable item is in need of outlining or unoutlining.





UiKeyboardNavigable.removeSetOutlineCallback(callbackOwner, callbackName)
[type: function] 
Removes the given setOutline callback.

UiKeyboardNavigable.removeSetOutlineCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UiKeyboardNavigable.removeSetOutlineCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





UiKeyboardNavigable.addTriggerCallback(callbackOwner, callbackName)
[type: function] 
Adds a callback that occurs whenever this UiKeyboardNavigable item triggered via the enter key or the space bar. The triggering browser-generated event is sent to the callback as its first parameter.

UiKeyboardNavigable.addTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this UiKeyboardNavigable item triggered via the enter key or the space bar.

UiKeyboardNavigable.addTriggerCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this UiKeyboardNavigable item triggered via the enter key or the space bar.





UiKeyboardNavigable.removeTriggerCallback(callbackOwner, callbackName)
[type: function] 
Removes the given trigger callback.

UiKeyboardNavigable.removeTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UiKeyboardNavigable.removeTriggerCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





UiKeyboardNavigable.outlineThisNow()
[type: function] 
Instructs the nearest parent UiKeyboardNavigator to outline this item immediately, unoutlining any currently outlined item.





UiKeyboardNavigable.getCurrentNavigator()
[type: function] [returns: UiKeyboardNavigator] 
Returns the nearest ancestor UiKeyboardNavigator that governs this navigable item, or undefined if none exists. Traverses ancestors with awareness of ScrollingPanel boundaries.





UiKeyboardNavigable.dispose()
[type: function] 
Disposes this UiKeyboardNavigable, disabling keyboard navigation for the SceneObject owning it, and freeing object for garbage collection.










----------------------------------------------------------
Section 30: UxPlaybackControllerSupervisor
----------------------------------------------------------


UxPlaybackControllerSupervisor
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. Supervisors provide the means for users to both monitor and manipulate properties within the project during runtime. This particular object is meant to supervise a PlaybackController — providing play, playOnce, and stop buttons, as well as a value/time supervisor that displays a ranged slider when a single PlaybackController is supervised, and a text field when multiple PlaybackControllers are supervised simultaneously. The label shown next to the value supervisor reads 'time:' for timeline-based PlaybackControllers and 'value:' for value-based ones. The play and playOnce buttons swap to a pause icon when the supervised PlaybackControllers are in a playing state. 'Ux' supervisors operate exclusively on arrays of values, ensuring support for supervising multiple values at once.





UxPlaybackControllerSupervisor.propertyOwners
[type: Array] [default: undefined] 
Array of PlaybackController objects being supervised. Setting this property propagates the value to both the internal value supervisor slider and text field. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxPlaybackControllerSupervisor.propertyPath
[type: string] [default: "value"] 
A period-separated string representing the 'dot path' or 'dereference chain' from each owner object to the property being supervised. For example, to supervise the current playback position use 'value'. Setting this property propagates the value to both the internal value supervisor slider and text field. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxPlaybackControllerSupervisor.propertyGetterOwner
[type: object] [default: undefined] 
The object owning the function used to get the array of supervised values. Setting this property propagates the value to both the internal value supervisor slider and text field. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxPlaybackControllerSupervisor.propertyGetterName
[type: string] [default: undefined] 
The name of the function used to get the array of supervised values. Setting this property propagates the value to both the internal value supervisor slider and text field. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxPlaybackControllerSupervisor.propertyGetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to get the array of supervised values. Setting this property propagates the value to both the internal value supervisor slider and text field. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxPlaybackControllerSupervisor.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body.clone()] 
The TextFormat of all text items within the supervisor, also used to scale the play, playOnce, and stop buttons. Setting this property propagates the format to both sub-supervisors and resizes the three buttons to match the text scale.





UxPlaybackControllerSupervisor.playButton
[type: UiGraphicButton] 
The play / pause toggle button. When all supervised PlaybackControllers are playing (without lazyStop), this button displays the pause icon instead of the play icon. Pressing it calls play() on all supervised owners, or pause() if it is currently displaying the pause icon.





UxPlaybackControllerSupervisor.playOnceButton
[type: UiGraphicButton] 
The playOnce / pause toggle button. When all supervised PlaybackControllers are playing with lazyStop enabled, this button displays the pause icon instead of the playOnce icon. Pressing it calls playOnce() on all supervised owners, or pause() if it is currently displaying the pause icon.





UxPlaybackControllerSupervisor.stopButton
[type: UiGraphicButton] 
The stop button. Pressing it calls stop() on all supervised PlaybackControllers.





UxPlaybackControllerSupervisor.valueSupervisorSlider
[type: UxNumberSupervisorRangedSlider] 
A UxNumberSupervisorRangedSlider used to display and edit the supervised value when exactly one PlaybackController is supervised. Its range is automatically updated each frame from the owner's startTime and endTime. This sub-supervisor is inactive and hidden when multiple owners are supervised.





UxPlaybackControllerSupervisor.valueSupervisorTextField
[type: UxNumberSupervisorTextField] 
A UxNumberSupervisorTextField used to display and edit the supervised value when multiple PlaybackControllers are supervised simultaneously. This sub-supervisor is inactive and hidden when exactly one owner is supervised.





UxPlaybackControllerSupervisor.maskGroup
[type: MaskGroup] [default: undefined] 
The MaskGroup the controller's play/playOnce/stop buttons and its slider's value pointers are clipped to. Setting it forwards the group to valueSupervisorSlider. Drag pointers are never masked.





UxPlaybackControllerSupervisor.sync()
[type: function] 
Method brings this UxPlaybackControllerSupervisor up to date with the PlaybackController it supervises, without waiting for the next fixedUpdate. This method is automatically called every fixedUpdate.





















































































































































































































































































































































































































----------------------------------------------------------
Section 31: SpineBone
----------------------------------------------------------


SpineBone
[type: class] [extends: SceneObject] 
A SceneObject representing a single bone within an imported Spine skeleton. SpineBones form the hierarchical transform structure of Spine animations and are automatically created by the Spine import system.





SpineBone.slots
[type: object] 
Dictionary of SpineSlots belonging to this bone. Each key is a slot name as defined in the originating Spine file.





SpineBone.constraints
[type: object] 
Dictionary of constraint objects belonging to this bone. Each key is the constraint name as defined in the originating Spine file.





SpineBone.skinNames
[type: [string]] 
Array of skin name strings available on this skeleton. A skin in a folder is named by its full path, such as 'weapon/sword'. Use 'setSkin' to apply one or more of these skins. The order of this array is the order the active skins are applied in when 'setSkinEnabled' rebuilds them, and 'setSkinOrder' changes it.





SpineBone.inheritScale
[type: number] [default: 1] 
Amount by which this bone inherits scale from its parent. Range: 0–1. A value of 1 inherits full parent scale; 0 ignores parent scale entirely.





SpineBone.inheritRotation
[type: number] [default: 1] 
Amount by which this bone inherits rotation from its parent. Range: 0–1. A value of 1 inherits full parent rotation; 0 ignores parent rotation entirely.





SpineBone.inheritReflection
[type: number] [default: 1] 
Amount by which this bone inherits reflection (negative scale) from its parent. Range: 0–1. A value of 1 inherits full reflection; 0 ignores parent reflection entirely.





SpineBone.shearX
[type: number] [default: 0] 
Horizontal shear applied to this bone, in degrees.





SpineBone.shearY
[type: number] [default: 0] 
Vertical shear applied to this bone, in degrees.





SpineBone.setSkin(skinNames)
[type: function] 
Sets the active skin or skins for this skeleton. All non-default skin attachments are first deactivated, then the requested skin's attachments are enabled.

SpineBone.setSkin parameter: skinNames
[type: string, [string]] 
The name or array of names of the skin(s) to activate.





SpineBone.setSkins(skinNames)
[type: function] 
Replaces the active skins with the given skin or skins. Where skins overlap, the last one given is applied on top.

SpineBone.setSkins parameter: skinNames
[type: string, [string]] 
The name or array of names of the skin(s) to activate.





SpineBone.addSkin(skinName)
[type: function] 
Adds a skin to the active skins, applied on top of the others. Does nothing if the skin is already active.

SpineBone.addSkin parameter: skinName
[type: string] 
The name of the skin to add.





SpineBone.removeSkin(skinName)
[type: function] 
Removes a skin from the active skins. Does nothing if the skin is not active.

SpineBone.removeSkin parameter: skinName
[type: string] 
The name of the skin to remove.





SpineBone.clearSkins()
[type: function] 
Deactivates every skin, returning the skeleton to its setup pose.





SpineBone.setSkinInCategory(skinName)
[type: function] 
Activates a skin after removing any active skin in the same folder, meaning the text before the last '/' in its name. Skins with no folder share one group.

SpineBone.setSkinInCategory parameter: skinName
[type: string] 
The name of the skin to activate.





SpineBone.setSkinEnabled(skinName, enabled)
[type: function] 
Enables or disables a single skin. The active skins are rebuilt in the order of 'skinNames', so skins enabled this way are applied in that order no matter when each was enabled. Does nothing if the skin is already in the requested state.

SpineBone.setSkinEnabled parameter: skinName
[type: string] 
The name of the skin to enable or disable.

SpineBone.setSkinEnabled parameter: enabled
[type: boolean] 
True to enable the skin, false to disable it.





SpineBone.setSkinOrder(skinNames)
[type: function] 
Sets the order of 'skinNames', which decides how active skins are applied whenever 'setSkinEnabled' rebuilds them. The active skins are only reordered if the new order changes how they sit relative to each other. This is mainly used by the Incisor inspector when a skin order is edited.

SpineBone.setSkinOrder parameter: skinNames
[type: [string]] 
Every one of this skeleton's skin names exactly once, in the new order.





SpineBone.getActiveSkins()
[type: function] [returns: [string]] 
Returns the active skins, in the order they are applied.





SpineBone.getSkinInfo()
[type: function] [returns: [any]] 
Returns a description of every skin on this skeleton, in 'skinNames' order. Each entry has the skin's full path as 'name', its folder as 'category', and counts of the attachments, bones and constraints it supplies. This is mainly used by the Incisor inspector to list a skeleton's skins.





SpineBone.resetPhysics()
[type: function] 
Restarts the skeleton's physics constraints from the current pose, so that no momentum carries over from before. Only valid on the root bone.



























































































































































































































































































































----------------------------------------------------------
Section 32: SpinePath
----------------------------------------------------------


SpinePath
[type: class] [extends: Curve] 
A Curve representing a Spine path attachment within an imported Spine skeleton. SpinePaths are automatically created by the Spine import system and are used by Spine path constraints.





SpinePath.closed
[type: boolean] [default: false] 
Whether this path forms a closed loop.




























































----------------------------------------------------------
Section 33: SpineSlot
----------------------------------------------------------


SpineSlot
[type: class] [NON-INSTANTIABLE] 
An object belonging to a SpineBone that manages a set of interchangeable attachments. SpineSlots are automatically created by the Spine import system. 





SpineSlot.attachments
[type: object] 
Dictionary of attachment objects belonging to this slot. Each key is the attachment name. Attachments are typically GraphicObjects or SpinePaths.





SpineSlot.attachmentStates
[type: object] 
Dictionary of numeric attachment state scores for this slot. Each key is an attachment name. The attachment with the highest score greater than 0 is shown; all others are hidden. Setting a score to 1 activates that attachment; setting all others to 0 deactivates them.





SpineSlot.restAttachmentName
[type: string] 
The name of this slot's default (rest pose) attachment.





SpineSlot.setActiveAttachment(name)
[type: function] 
Forces a single named attachment to become the active (visible) one, setting all others in the slot to disabled.

SpineSlot.setActiveAttachment parameter: name
[type: string] 
The name of the attachment to activate.





SpineSlot.getActiveAttachmentName()
[type: function] [returns: string, undefined] 
Returns the name of the currently active (visible) attachment in this slot. Returns undefined if no attachment is currently active.










----------------------------------------------------------
Section 34: UiZoom
----------------------------------------------------------


UiZoom
[type: class] [NON-INSTANTIABLE] 
Object housing functionality associated with the user interface zoom, which enables end-users to increase or decrease the overall size of text and other user interface items (when those items have uiZoom functionality enabled). 





UiZoom.zoomValue
[type: number] [default: 1] 
The number associated with the zoom level of user interface items.





UiZoom.totalZoom
[type: number] [default: 1] 
The read-only value associated with the overall zoom level of user interface items, including the 'devicePixelRatio', which is set by the browser. For UI items to accurately adjust to both the zoomValue and the browser's devicePixelRatio, use this value.





UiZoom.autoEnableStandardUiZoomFunctionality
[type: boolean] [default: false] 
Flag determining if certain uiZoom-capable objects will have the 'standard' uiZoom functionality automatically enabled upon their instantiation. Objects affected by this include TextBox, TextAssembly, LayoutStack, SrollingPanel, UiButton, UiTextField, UiCollapsibleStack, DropDownMenu, DropSideMenu, and PopupWindow. This flag works on a 'state-machine' basis; newly instantiated objects will automatically have the standard uiZoom functionality enabled while this flag is true. Otherwise, uiZoom functionality will not be automatically enabled on any objects, and would instead need to be manually enabled either using 'nc.uiZoom.enableStandardUiZoomFunctionality' or by implementing custom uiZoom functionality using 'nc.appEvents.uiZoomChange.addCallback'.





UiZoom.enableStandardUiZoomFunctionality(obj)
[type: function] 
Certain built-in Incisor® objects have standard uiZoom functionality that can be enabled. For example, TextBox objects have a standard uiZoom implementation that can be enabled, which consists of applying the 'nc.uiZoom.totalZoom' multiplier to the individual characters' scale, as well as the maxWidth, and maxHeight. The list of objects that have standard uiZoom implementations include SceneObject, GraphcObject, TextBox, TextAssembly, LayoutStack, SrollingPanel, UiButton, UiTextField, UiCollapsibleStack, DropDownMenu, DropSideMenu, and PopupWindow. Provide any of these objects as a parameter to this function, and their uiZoom functionality will be enabled. You can also set the 'autoEnableStandardUiZoomFunctionality' flag to true, which tells Incisor® to automatically enable the standard uiZoom functionality upon instantiation for some objects. If you want to create custom uiZoom functionality, just add a callback using 'nc.appEvents.uiZoomChange.addCallback', and perform the desired custom operations in that function.

UiZoom.enableStandardUiZoomFunctionality parameter: obj
[type: object] 
The object to enable the standard UiZoom functionality on.










----------------------------------------------------------
Section 35: UiCollapsibleStack
----------------------------------------------------------


UiCollapsibleStack
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A ui-specialized vertical LayoutStack with an interactive title header that toggles the visibility of a main LayoutStack. UI functionality includes:  • pre-configured with LayoutObject functionality.  • uiStyle TextFormats and Colors applied.  • pre-configured with 'UiKeyboardNavigable' functionality.  • uiZoom-enabled.  • nearestPixelRendering-enabled.





UiCollapsibleStack.bodyStack
[type: LayoutStack] 
The LayoutStack containing the main body of this UiCollapsibleStack. This LayoutStack is what is shown/expanded or hidden/collapsed by toggling the title header button.





UiCollapsibleStack.titleStack
[type: LayoutStack] 
The LayoutStack containing the title header UiCollapsibleStack. This LayoutStack holds the interactive text/button that collapses and expands the content of this UiCollapsibleStack.





UiCollapsibleStack.titleTextBox
[type: TextBox] 
The header title TextBox for this UiCollapsibleStack.





UiCollapsibleStack.caretIcon
[type: GraphicObject] 
An caret image that indicates if the UiCollapsibleStack is collapsed or expanded.





UiCollapsibleStack.caretIconScaleFactor
[type: number] 
A scale multiplier for the caretIcon GraphicObject. Use this property instead of directly scaling the caretIcon GraphicObject to preserve UiZoom and LayoutObject functionality.





UiCollapsibleStack.mainButton
[type: Button] 
The main Button for the UiCollapsibleStack title heaader button, this object is a UiPanel which also implements Button. This item defaults to 'visible=false'.





UiCollapsibleStack.outline
[type: UiOutline] 
The outline of the button, which is used to indicate when the end-user outlines this UiCollapsibleStack using keyboard navigation (tab, arrows, etc...).





UiCollapsibleStack.isExpanded
[type: boolean] [default: false] 
Boolean determining if the UiCollapsibleStack is collapsed or expanded.





UiCollapsibleStack.buttonTextColor
[type: Color] [default: nc.uiStyle.color_interactiveText] 
The base Color of the titleTextBox for this UiCollapsibleStack.





UiCollapsibleStack.highlightedButtonTextColor
[type: Color] [default: nc.uiStyle.color_highlightedInteractiveText] 
The highlighted Color of the titleTextBox for this UiCollapsibleStack.





UiCollapsibleStack.buttonIncludesTitle
[type: boolean] [default: true] 
Boolean indicating if the mainButton for this UiCollapsibleStack spans over the titleTextBox. When false the mainButton for this UiCollapsibleStack only encapsulates the caretIcon.





UiCollapsibleStack.addTriggerCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever this UiCollapsibleStack is triggered via the cursor or keyboard navigation. In this case, 'triggering' also toggles the collapsed/expanded state of this UiCollapsibleStack, making this callback a good means to update the contents of the LayoutStack. The triggering browser-created event, and the UiCollapsibleStack itself are sent to the callback as its first two parameters.

UiCollapsibleStack.addTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this UiCollapsibleStack is triggered via the cursor or keyboard navigation.

UiCollapsibleStack.addTriggerCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this UiCollapsibleStack is triggered via the cursor or keyboard navigation.

UiCollapsibleStack.addTriggerCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever this UiCollapsibleStack is triggered via the cursor or keyboard navigation.





UiCollapsibleStack.removeTriggerCallback(callbackOwner, callbackName)
[type: function] 
Removes the given trigger callback.

UiCollapsibleStack.removeTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UiCollapsibleStack.removeTriggerCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





















































































































































































































































































































































































































----------------------------------------------------------
Section 36: TextAssembly
----------------------------------------------------------


TextAssembly
[type: class] [extends: SceneObject] 
Specialized SceneObject that presents a group of GraphicObjects as text. TextAssemblies tend to be less performant that TextBoxes, as they result in more SceneObjects being rendered, But TextAssemblies have the adventage of being able to manipulate indivual characters freely.





TextAssembly.type
[type: string] 
Type identifier.





TextAssembly.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





TextAssembly.string
[type: string] [default: ""] 
The string value of the text to be displayed by this TextAssembly.





TextAssembly.phraseID
[type: string] [default: undefined] 
Property to set this TextAssembly's string based on the associated phrase in the ProjectTranscript, which is updated based on the current language setting of the project. See 'nc.phraseIDs' for a list of available phrases.

example:
// Objective: Set the text of a TextAssembly based on a phrase defined in the ProjectTranscript.
// Expected Result: You will see "Hello World" on screen if the project language is 'en', or "Hola Mundo" if the language is 'es'.

this.textAssembly = new TextAssembly();
this.textAssembly.phraseID = nc.phraseIDs["Hello World"];





TextAssembly.boxWidth
[type: number] [default: 0] 
The maximum width that the laid out text will adhere to if 'wrapToFit' or 'scaleToFit' are true. When greater than 0, this value also determines the positioning of left or right justified text. A value of 0 corresponds to no limits on the width of the text.





TextAssembly.boxHeight
[type: number] [default: 0] 
The maximum height that the laid out text will adhere to if 'scaleToFit' is true. When greater than 0, this value also determines the positioning of top-justified or bottom-justified text. A value of 0 corresponds to no limits on the height of the text.





TextAssembly.wrapToFit
[type: boolean] [default: true] 
Bool determining if text will automatically flow onto new lines in order to fit the text within the designated 'boxWidth' value.





TextAssembly.scaleToFit
[type: boolean] [default: true] 
Bool determining if the text will automatically be scaled down to fit within the boxWidth and/or boxHeight.





TextAssembly.horizontalJustification
[type: string] [default: "left"] 
The horizontalJustification of this TextAssembly. For acceptable values, see 'nc.constants.justfications'. Setting this value will change the horizontal justification for all of the text in this TextAssembly, but the value can be set for individual sections of the text using 'TextAssembly.setHorizontalJustification'.





TextAssembly.verticalJustification
[type: string] [default: "top"] 
The verticalJustification of this TextAssembly. For acceptable values, see 'nc.constants.justfications'. Setting this value will change the vertical justification for all of the text in this TextAssembly.





TextAssembly.textWidth
[type: number] 
The read-only width of the text (once laid out). This number encapsulates the final width of the laid out text, including all of the TextFormats, the boxWidth and boxHeight, scaleToFit, wrapToFit etc...





TextAssembly.textHeight
[type: number] 
The read-only height of the text (once laid out). This number encapsulates the final height of the laid out text, including all of the TextFormats, the boxWidth and boxHeight, scaleToFit, wrapToFit etc...





TextAssembly.scaleToFitFactor
[type: number] 
For Texts or Textboxes with 'scaleToFit' set to true, this number denotes the multiplier that was applied in order for the given text to fit within the boxWidth, and boxHeight.





TextAssembly.baselinePosition
[type: number] [default: .22] 
Number representing the vertical placement of the baseline within each line of text in this TextAssembly. A value of 0 corresponds to the baseline of the text being positioned at the very bottom of each line, and a value of .5 corresponds to the baseline of the text being positioned in the middle of each line.





TextAssembly.textFormat
[type: TextFormat] [default: new TextFormat()] 
Object housing information about the customization of the characters within this TextAssembly. This includes font, scale, baseline shift, kerning, line height, as well as information about EffectNodes and EffectController values used on the characters. Setting or adjusting this value will set the TextFormat for all of the characters in this TextAssembly. See 'TextAssembly.setTextFormat' to set the TextFormat for individual sections of this TextAssembly.





TextAssembly.layoutLazyUpdater
[type: LazyUpdater] 
The LazyUpdater ultimately responsible for initiating the layout of the text. The setting of 'needsUpdate' and the calling of 'updateIfNeeded' is magaged as much as is possible internally by Incisor®, but if the need to force an update arises, set 'needsUpdate' to true, and call 'updateIfNeeded'.





TextAssembly.showWhiteSpace
[type: boolean] [default: false] 
Boolean indicating if whitespace characters will be visible in this TextAssembly.





TextAssembly.setSubstitutionCharacter(characterToSubstitute, graphicAsset, textFormat)
[type: function] 
Method used to swap all instances of the given character with a designated GraphicAsset. A TextFormat can also be supplied to help position and format the substituted GraphicAsset within the text.

TextAssembly.setSubstitutionCharacter parameter: characterToSubstitute
[type: string] 
The the character that will be replaced with the designated GraphicAsset.

TextAssembly.setSubstitutionCharacter parameter: graphicAsset
[type: GraphicAsset] [optional] 
The GraphicAsset that will substitute for the given characters. When this parameter is undefined, any previously defined substitution using the provided character will be disposed. The formats for previously substituted characters will need to be dealt with separately.

TextAssembly.setSubstitutionCharacter parameter: textFormat
[type: TextFormat] [optional] 
Optional TextFromat to apply to the substituted GraphicAsset, which can be used to adjust its positioning and formating.





TextAssembly.setTextFormat(textFormat, startIdx, numChars)
[type: function] 
Sets the text format of the designated portion of text within a TextAssembly.

TextAssembly.setTextFormat parameter: textFormat
[type: TextFormat] 
The TextFormat that the specified characters will adopt.

TextAssembly.setTextFormat parameter: startIdx
[type: number] [optional] 
The index of the first character in the segment affected by this change. If left undefined, the given textFormat will be applied to all characters.

TextAssembly.setTextFormat parameter: numChars
[type: number] [default: infinity] [optional] 
The length of the segment affected by this change.





TextAssembly.setHorizontalJustification(justification, startIdx, numChars)
[type: function] 
Sets the horizontal justification of the given range of characters. It should be noted that when characters are laid out into multiple lines, the horizontal justification for a given line is determined by the horizontal horizontalJustification value associated with the first character on that line.

TextAssembly.setHorizontalJustification parameter: justification
[type: string] 
The horizontal justification that the specified characters will adopt. See 'nc.constants.justifications' for justification values.

TextAssembly.setHorizontalJustification parameter: startIdx
[type: number] [optional] 
The index of the first character in the segment affected by this change. If left undefined, the given horizontalJustification will be applied to all characters.

TextAssembly.setHorizontalJustification parameter: numChars
[type: number] [default: infinity] [optional] 
The length of the segment affected by this change.





TextAssembly.insert(startIndex, stringToInsert)
[type: function] 
Inserts the given string at the given index.

TextAssembly.insert parameter: startIndex
[type: number] 
The index that the first character of the inserted string.

TextAssembly.insert parameter: stringToInsert
[type: string] 
The string to insert.





TextAssembly.delete(startIndex, count)
[type: function] 
Deletes the given range of characters.

TextAssembly.delete parameter: startIndex
[type: number] 
The index of the first character to delete.

TextAssembly.delete parameter: count
[type: number] 
The number of characters to delete.





TextAssembly.addStringUpdateCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever this TextBox string changed. The updated string is sent to the callback as its first parameter.

TextAssembly.addStringUpdateCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this TextBox string changed.

TextAssembly.addStringUpdateCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this TextBox string changed.

TextAssembly.addStringUpdateCallback parameter: callbackArgs
[type: any] [optional] 
Args for the callback function that occurs whenever this TextBox string changed.





TextAssembly.removeStringUpdateCallback(callbackOwner, callbackName)
[type: function] 
Removes the given stringUpdate callback.

TextAssembly.removeStringUpdateCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

TextAssembly.removeStringUpdateCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





TextAssembly.clearPools()
[type: function] 
Several object-pooling techniques are used internally within the TextAssembly and TextBox objects. Displaying/rendering text with large numbers of characters can leave a significant memory-footprint in these pools. This memory can be freed by calling this method - though the call itself may result in a one-time performance hit if large strings have been displayed/rendered previously.





TextAssembly.getCharacters()
[type: function] [returns: [GraphicObject]] 
Returns a new array containing the list of GraphicObjects that comprise the TextAssembly's current string.

















































































































































































































































































































----------------------------------------------------------
Section 37: UxNumberSupervisorRangedSlider
----------------------------------------------------------


UxNumberSupervisorRangedSlider
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. Supervisors provide the means for users to both monitor and manipulate properties within the project during runtime. This particular object is meant to supervise a number property, and assumes that the number in question is usually between a given max and min value, and can therefore be represented by sliding a pointer around along a slider scale. 'Ux' supervisors operate exclusively on arrays of values, ensuring support for supervising multiple values at once. 





UxNumberSupervisorRangedSlider.displayPrecision
[type: number] [default: 3] 
The number of digits shown to the right of the decimal within the UiTextField for this UxNumberSupervisorRangedSlider.





UxNumberSupervisorRangedSlider.displayLabel
[type: boolean] [default: false] 
Boolean determining if a label UiText is displayed to the left of the UxNumberSupervisorRangedSlider.





UxNumberSupervisorRangedSlider.label
[type: UiText] 
A UiText that acts as a label for the UxNumberSupervisorRangedSlider. Please note that this item is undefined until the 'displayLabel' property is set to true.





UxNumberSupervisorRangedSlider.sliderWidth
[type: number] [default: 200] 
The width of the slider (before uiZoom is applied).





UxNumberSupervisorRangedSlider.rangeMin
[type: number] [default: 0] 
The value associated with the leftmost position on the slider.





UxNumberSupervisorRangedSlider.rangeMax
[type: number] [default: 1] 
The value associated with the rightmost position on the slider.





UxNumberSupervisorRangedSlider.clampSlider
[type: boolean] [default: true] 
Boolean determining if the slider will block the user from setting the supervised property to a value outside of the given range.





UxNumberSupervisorRangedSlider.maskGroup
[type: MaskGroup] [default: undefined] 
The MaskGroup that this slider's static graphics and lazily-created value pointers are clipped to. The drag pointer is intentionally never masked (it is a drag-to-cursor feedback line that must reach outside any mask).





UxNumberSupervisorRangedSlider.isActive
[type: boolean] [default: true] 
Boolean determining if the supervisor is interactive. When false, the supervisor has a dim appearance and all buttons are disabled.





UxNumberSupervisorRangedSlider.propertyOwners
[type: Array] [default: undefined] 
Array of objects owning the properties being supervised. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorRangedSlider.propertyPath
[type: string] [default: ""] 
A period-separated string representing the 'dot path' or 'dereference chain' from each owner object to the property being supervised. For example if you are supervising the x position of a SceneObject this value would be 'position.x'. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorRangedSlider.propertyGetterOwner
[type: object] [default: undefined] 
The object owning the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorRangedSlider.propertyGetterName
[type: string] [default: undefined] 
The name of the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorRangedSlider.propertyGetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorRangedSlider.propertySetterOwner
[type: object] [default: undefined] 
The object owning the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorRangedSlider.propertySetterName
[type: string] [default: undefined] 
The name of the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorRangedSlider.propertySetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter, these parameters will be appended. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorRangedSlider.valueValidationOwner
[type: object] [default: undefined] 
The owner of the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the values to integers, you can write a validation function that takes a value as a parameter and returns the rounded value.





UxNumberSupervisorRangedSlider.valueValidationName
[type: string] [default: undefined] 
The name of the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the values to integers, you can write a validation function that takes a value as a parameter and returns the rounded value.





UxNumberSupervisorRangedSlider.valueValidationArgs
[type: Array, any] [default: undefined] 
Parameters for the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the values to integers, you can write a validation function that takes a value as a parameter and returns the rounded value.





UxNumberSupervisorRangedSlider.deltaTriangle
[type: UiText] 
The UiText containing the triangle that indicates when the supervisor is in 'deltaMode', which is an altered state of functionality in which the user interface adjustments are made in terms of the amount of change to the values as opposed to the standard state in which the values are set in absolute terms.





UxNumberSupervisorRangedSlider.textField
[type: UiTextField] 
The UiTextField where the user can monitor or edit the current supervised property value.





UxNumberSupervisorRangedSlider.pointers
[type: [GraphicObject]] 
Array of pointer GraphicObjects used to indicate the supervised property value/values.





UxNumberSupervisorRangedSlider.dragPointer
[type: GraphicObject] 
A GraphicObject that serves as a 'visual teather' between the cursor and the label while the value is being dragged. This member will remain undefined until dragging occurs, at which point the object is created on the fly if needed.





UxNumberSupervisorRangedSlider.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body.clone()] 
the TextFormat of all of the text items within the supervisor, which is also used to scale graphical components.





UxNumberSupervisorRangedSlider.singularFocusTarget
[type: SceneObject] [default: this] 
The SceneObject used as the singular focus requirement when the drag escape keydown callback is registered. The default value is this UxNumberSupervisorRangedSlider itself, but another SceneObject can be supplied when it would be a better singular-focus recipient.





UxNumberSupervisorRangedSlider.sync()
[type: function] 
Method brings this UxNumberSupervisorRangedSlider up to date with the values it supervises, without waiting for the next fixedUpdate. This method is automatically called every fixedUpdate.





















































































































































































































































































































































































































----------------------------------------------------------
Section 38: Video
----------------------------------------------------------


Video
[type: class] [extends: TimePlaybackController] [NON-INSTANTIABLE] [requires: module - videos] 
A specialized PlaybackController that manages the playback of video assets. When compressed video assets (mp4 or webm) are included in a project a Texture, Geometry, GraphicAsset, and Video with that same name are created in Incisor. Once included, any GraphicObject can be set to the corresponding GraphicAsset, and the associated Video object can control the video's playback. It should be noted that the visual content of any instance or use of the GraphicAsset will be same everywhere - as video's content is pushed to the associated texture, all objects using that Texture will see the same content. Videos in Incisor rely entirely on the browser's decoding and playback capabilities, which typically don't support rapid/repeated changes to video properties. In practice, videos perform well when playing once normally or free-running, but do not do well with a lot of rapid time jumps or scrubbing. Video formats are not uniformly supported for use within all browsers, and their use is not advised within projects meant to be universally accessible. Acceptable extensions for video files include ".mp4" and ".webm", and while webm (VP8 or VP9) typically supports transparency, there are currently no video formats that support transparency on any Apple mobile or desktop products. 





Video.name
[type: string] 
The Sounds's name. This must be unique among Videos, GraphicAssets, Textures, and Geometries.





Video.isLoaded
[type: boolean] 
Boolean indicating if this Video is currently loaded.





Video.loadingTierRequirements
[type: [number]] 
The LoadingTier that this Video belongs to. LoadingTiers are a means to organize AssetComponents into separately downloadable groups.





Video.duplicateSource
[type: string] [default: undefined] 
String indicating the source of this Video if it is a duplicate. Incisor® automatically detects when two or more AssetComponents are identical, ensuring that only one copy of the associated data is loaded to reduce the loaded size of the project. Those AssetComponents that are duplicates are marked by indicating the name of the source of their data. This member is undefined for AssetComponents that are not duplicates.





Video.videoElement
[type: HTMLVideoElement] 
Videos in Incisor are backed by actual video HTML elements in the DOM, and this property provides direct access to the associated element. It should be noted that this property will remain null until the video is loaded.












































































































































----------------------------------------------------------
Section 39: GraphicExpander
----------------------------------------------------------


GraphicExpander
[type: class] [NON-INSTANTIABLE] 
A GraphicExpander allows a region of a GraphicObject to be specified as expandable to a new size. When a new size is specified, this region of the GraphicObject will change size, but the area outside the expandable region will move and stretch to keep aligned to the expanded region. 





GraphicExpander.type
[type: string] 
Type identifier.





GraphicExpander.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





GraphicExpander.symmetric
[type: boolean] 
Flag determining if the GraphicExpander's expandable area and expanded area are both in the middle of the GraphicObject. When this value is true, the interface to configure the GraphicExpander includes expandableWidth, expandableHeight, expandedWidth, and expandedHeight. When this value is false, the interface to configure the GraphicExpander includes expandableAreaLeft, expandableAreaRight, expandableAreaBottom, expandableAreaTop, expandedAreaLeft, expandedAreaRight, expandedAreaBottom, and expandedAreaTop.





GraphicExpander.expandableWidth
[type: number] [default: 0] 
Value that determines the portion of the GraphicObject that will be affected by this GraphicExpander. This property is only applicable if the 'symmetric' property is true.





GraphicExpander.expandableHeight
[type: number] [default: 0] 
Value that determines the portion of the GraphicObject that will be affected by this GraphicExpander. This property is only applicable if the 'symmetric' property is true.





GraphicExpander.expandedWidth
[type: number] [default: 100] 
The expanded width of the GraphicExpander. Set this value to stretch or shrink the associated GraphicObject horizontally. This property is only applicable if the 'symmetric' property is true.





GraphicExpander.expandedHeight
[type: number] [default: 100] 
The expanded height of the GraphicExpander. Set this value to stretch or shrink the associated GraphicObject vertically. This property is only applicable if the 'symmetric' property is true.





GraphicExpander.expandableAreaLeft
[type: number] [default: 0] 
Value that defines the left bound of the portion of the GraphicObject that will be affected by this GraphicExpander. This property is only applicable if the 'symmetric' property is false.





GraphicExpander.expandableAreaRight
[type: number] [default: 0] 
Value that defines the right bound of the portion of the GraphicObject that will be affected by this GraphicExpander. This property is only applicable if the 'symmetric' property is false.





GraphicExpander.expandableAreaBottom
[type: number] [default: 0] 
Value that defines the bottom bound of the portion of the GraphicObject that will be affected by this GraphicExpander. This property is only applicable if the 'symmetric' property is false.





GraphicExpander.expandableAreaTop
[type: number] [default: 0] 
Value that defines the top bound of the portion of the GraphicObject that will be affected by this GraphicExpander. This property is only applicable if the 'symmetric' property is false.





GraphicExpander.expandedAreaLeft
[type: number] [default: -50] 
Value that determines where the left bound of the expansion area will be after the expansion. Set this value to stretch or shrink the associated GraphicObject's left side. This property is only applicable if the 'symmetric' property is false.





GraphicExpander.expandedAreaRight
[type: number] [default: 50] 
Value that determines where the right bound of the expansion area will be after the expansion. Set this value to stretch or shrink the associated GraphicObject's right side. This property is only applicable if the 'symmetric' property is false.





GraphicExpander.expandedAreaBottom
[type: number] [default: -50] 
Value that determines where the bottom bound of the expansion area will be after the expansion. Set this value to stretch or shrink the associated GraphicObject's bottom side. This property is only applicable if the 'symmetric' property is false.





GraphicExpander.expandedAreaTop
[type: number] [default: 50] 
Value that determines where the top bound of the expansion area will be after the expansion. Set this value to stretch or shrink the associated GraphicObject's top side. This property is only applicable if the 'symmetric' property is false.





GraphicExpander.dispose()
[type: function] 
Removes and destroys the GraphicExpander, restoring the original Geometry if possible.










----------------------------------------------------------
Section 40: FontDefinition
----------------------------------------------------------


FontDefinition
[type: class] [NON-INSTANTIABLE] 
Object defining a font within this project. Fonts originate from files within a project's "Assets" directory, Either by including '.ttf' or '.otf' files, or by including a specialized group of pngs whose names end with '_Char[X]' that must include '_Char0'. 





FontDefinition.kerningAdjustment
[type: number] 
A number that affects the layout width of all of the characters in this font. The number is expressed in terms of multiples 'characterWidth' value.





FontDefinition.lineHeight
[type: number] 
Number determining the line height of this font. This value originally defaults to the height of the null character provided (Char0), but can be changed.





FontDefinition.characterWidth
[type: number] 
Number determining the basic width of a character in this font. Some of the values used by TextFormats, Texts, and TextBoxes to arrange characters in fonts are denoted in terms of a proportion of this value. For example if the kerning of a given TextBox's TextFormat is .5, then all characters within the TextBox will be spaced apart by half of this 'characterWidth' value. This value originally defaults to the width of the null character provided (Char0), but can be changed in ProjectSettings or runtime.










----------------------------------------------------------
Section 41: shapifySwoop
----------------------------------------------------------


shapifySwoop
[type: class] 
The shapify Swoop object - contains the swoopers for this EffectController's components.





shapifySwoop.edgeOffset(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) 'edgeOffset' component from its current value to the given end value over the duration.

shapifySwoop.edgeOffset parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

shapifySwoop.edgeOffset parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

shapifySwoop.edgeOffset parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

shapifySwoop.edgeOffset parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

shapifySwoop.edgeOffset parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

shapifySwoop.edgeOffset parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

shapifySwoop.edgeOffset parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

shapifySwoop.edgeOffset parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

shapifySwoop.edgeOffset parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

shapifySwoop.edgeOffset parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.





shapifySwoop.edgeFeather(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) 'edgeFeather' component from its current value to the given end value over the duration.

shapifySwoop.edgeFeather parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

shapifySwoop.edgeFeather parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

shapifySwoop.edgeFeather parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

shapifySwoop.edgeFeather parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

shapifySwoop.edgeFeather parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

shapifySwoop.edgeFeather parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

shapifySwoop.edgeFeather parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

shapifySwoop.edgeFeather parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

shapifySwoop.edgeFeather parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

shapifySwoop.edgeFeather parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.










----------------------------------------------------------
Section 42: shapifyAddMotion
----------------------------------------------------------


shapifyAddMotion
[type: class] 
The shapify AddMotion object - contains the 'addMotion' functions for this EffectController's components.





shapifyAddMotion.edgeOffset(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the 'edgeOffset' component and returns a Motion object, which can be used to control the motion dynamically.

shapifyAddMotion.edgeOffset parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

shapifyAddMotion.edgeOffset parameter: upperBound
[type: number] 
The upper bound for the motion being added.

shapifyAddMotion.edgeOffset parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

shapifyAddMotion.edgeOffset parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

shapifyAddMotion.edgeOffset parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

shapifyAddMotion.edgeOffset parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

shapifyAddMotion.edgeOffset parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

shapifyAddMotion.edgeOffset parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.





shapifyAddMotion.edgeFeather(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the 'edgeFeather' component and returns a Motion object, which can be used to control the motion dynamically.

shapifyAddMotion.edgeFeather parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

shapifyAddMotion.edgeFeather parameter: upperBound
[type: number] 
The upper bound for the motion being added.

shapifyAddMotion.edgeFeather parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

shapifyAddMotion.edgeFeather parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

shapifyAddMotion.edgeFeather parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

shapifyAddMotion.edgeFeather parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

shapifyAddMotion.edgeFeather parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

shapifyAddMotion.edgeFeather parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.










----------------------------------------------------------
Section 43: shapify
----------------------------------------------------------


shapify
[type: class] [extends: Vector2] 
The EffectController for the 'Shapify' EffectNode. The Shapify EffectNode converts edge data stored in a 'shapified' Texture into a presentable image with edges that stay sharp regardless of the scale of the associated GraphicObject. This class is a dynamically created EffectController (with base type 'Vector2'), and is therefore non-instantiable. To create a new instance, use "nc.effectControllers['shapify'].new". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





shapify.edgeOffset
[type: number] 
This 'shapify' component determines how far to expand or contract the shape's edge from the position of the edge in the source image. This is a pseudonym for the x vector component.





shapify.edgeFeather
[type: number] 
This 'shapify' component determines the how many pixels the image's edge transition spans. For example, a value of 5 would lead to a soft edge, as the transition from inside the image's shape to outside the shape would take place over 5 pixels. This is a pseudonym for the y vector component.





shapify.swoop
[type: shapifySwoop] 
Object containing the swoopers for this EffectController's components.





shapify.addMotion
[type: shapifyAddMotion] 
Object containing the 'addMotion' functions for this EffectController's components.




























































----------------------------------------------------------
Section 44: shearSwoop
----------------------------------------------------------


shearSwoop
[type: class] 
The shear Swoop object - contains the swoopers for this EffectController's components.





shearSwoop.xAngle(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) 'xAngle' component from its current value to the given end value over the duration.

shearSwoop.xAngle parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

shearSwoop.xAngle parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

shearSwoop.xAngle parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

shearSwoop.xAngle parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

shearSwoop.xAngle parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

shearSwoop.xAngle parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

shearSwoop.xAngle parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

shearSwoop.xAngle parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

shearSwoop.xAngle parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

shearSwoop.xAngle parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.





shearSwoop.yAngle(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) 'yAngle' component from its current value to the given end value over the duration.

shearSwoop.yAngle parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

shearSwoop.yAngle parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

shearSwoop.yAngle parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

shearSwoop.yAngle parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

shearSwoop.yAngle parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

shearSwoop.yAngle parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

shearSwoop.yAngle parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

shearSwoop.yAngle parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

shearSwoop.yAngle parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

shearSwoop.yAngle parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.





shearSwoop.preserveArea(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) 'preserveArea' component from its current value to the given end value over the duration.

shearSwoop.preserveArea parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

shearSwoop.preserveArea parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

shearSwoop.preserveArea parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

shearSwoop.preserveArea parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

shearSwoop.preserveArea parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

shearSwoop.preserveArea parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

shearSwoop.preserveArea parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

shearSwoop.preserveArea parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

shearSwoop.preserveArea parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

shearSwoop.preserveArea parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.










----------------------------------------------------------
Section 45: shearAddMotion
----------------------------------------------------------


shearAddMotion
[type: class] 
The shear AddMotion object - contains the 'addMotion' functions for this EffectController's components.





shearAddMotion.xAngle(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the 'xAngle' component and returns a Motion object, which can be used to control the motion dynamically.

shearAddMotion.xAngle parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

shearAddMotion.xAngle parameter: upperBound
[type: number] 
The upper bound for the motion being added.

shearAddMotion.xAngle parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

shearAddMotion.xAngle parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

shearAddMotion.xAngle parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

shearAddMotion.xAngle parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

shearAddMotion.xAngle parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

shearAddMotion.xAngle parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.





shearAddMotion.yAngle(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the 'yAngle' component and returns a Motion object, which can be used to control the motion dynamically.

shearAddMotion.yAngle parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

shearAddMotion.yAngle parameter: upperBound
[type: number] 
The upper bound for the motion being added.

shearAddMotion.yAngle parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

shearAddMotion.yAngle parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

shearAddMotion.yAngle parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

shearAddMotion.yAngle parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

shearAddMotion.yAngle parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

shearAddMotion.yAngle parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.





shearAddMotion.preserveArea(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the 'preserveArea' component and returns a Motion object, which can be used to control the motion dynamically.

shearAddMotion.preserveArea parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

shearAddMotion.preserveArea parameter: upperBound
[type: number] 
The upper bound for the motion being added.

shearAddMotion.preserveArea parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

shearAddMotion.preserveArea parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

shearAddMotion.preserveArea parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

shearAddMotion.preserveArea parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

shearAddMotion.preserveArea parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

shearAddMotion.preserveArea parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.










----------------------------------------------------------
Section 46: shear
----------------------------------------------------------


shear
[type: class] [extends: Vector3] 
EffectController for the Shear EffectNode, which distorts the shape to appear slanted or skewed. This class is a dynamically created EffectController (with base type 'Vector3'), and is therefore non-instantiable. To create a new instance, use "nc.effectControllers['shear'].new". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





shear.xAngle
[type: number] 
The amount in degrees to rotate the X axis. This is a pseudonym for the x vector component.





shear.yAngle
[type: number] 
The amount in degrees to rotate the Y axis. This is a pseudonym for the y vector component.





shear.preserveArea
[type: number] 
How much to preserve the original area. 1 preserves area exactly. 0 allows the area to approach 0 as the axes approach each other. This is a pseudonym for the z vector component.





shear.swoop
[type: shearSwoop] 
Object containing the swoopers for this EffectController's components.





shear.addMotion
[type: shearAddMotion] 
Object containing the 'addMotion' functions for this EffectController's components.

































































----------------------------------------------------------
Section 47: EffectControllerDefinition
----------------------------------------------------------


EffectControllerDefinition
[type: class] [NON-INSTANTIABLE] 
Object housing the info about a particular EffectController. EffectControllers provide the ability to dynamically control EffectNodes and their resulting visual effects. EffectControllers are generally one of 3 base types, Vectors, numbers, and Textures. Once defined, EffectControllers will be generally available on all SceneObjects, Materials, MaterialMaster, CharacterMaterial objects; It should be noted that while these objects will have all EffectControllers as members, only the EffectControllers tied to the objects' current EffectNodes will cause any change visually. It should also be noted EffectControllers with 'mixMode=materialOnly' will not be available on SceneObjects for inheritance, and will instead only be on Material and MaterialMaster objects for direct manipulation. 





EffectControllerDefinition.name
[type: string] 
The name of the EffectController





EffectControllerDefinition.baseType
[type: string] 
The base type of the EffectController





EffectControllerDefinition.componentNames
[type: [string], string] 
The names of the components of this EffectController.





EffectControllerDefinition.defaultValues
[type: [number], number] 
The default component values for this EffectController.





EffectControllerDefinition.mixMode
[type: string] 
The mixMode for this EffectController. Mix modes determined the manner in which the values of EffectControllers are transfered to descendants in the hierarchy. So if the "multiplication" mixMode is chosen, a SceneObject's values for the given EffectController multiply the values of all of its descendants. The "materialOnly" mixMode indicates that a given EffectController will only be on Materials (not parent SceneObjects), so no mixing of EffectController value occurs.





EffectControllerDefinition.likelyRanges
[type: [[number]], [number]] 
An array of likely ranges for the component values of this EffectController. These likely ranges help to inform the 'scrollSpeed' of GUI controllers for this EffectController - if the likely range is much larger, than the scroll speeds default to be higher etc... A 'number' EffectController takes a flat range such as [0,10], while a Vector takes one range per component such as [[0,1],[0,180]]. A flat range given to a Vector applies to every component.





EffectControllerDefinition.effectControllerDescription
[type: string] 
The description of the EffectController. This will inform the descriptions as they appear in the autocomplete for this project.





EffectControllerDefinition.componentDescriptions
[type: [string]] 
The description of the components of this EffectController. These descriptions will inform the component descriptions as they appear in the autocomplete for this project.










----------------------------------------------------------
Section 48: UxCollapsibleStack
----------------------------------------------------------


UxCollapsibleStack
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. This particular object is a specialized vertical LayoutStack with a header LayoutStack containing an open/close Button that toggles the enabled state of a body LayoutStack.





UxCollapsibleStack.headerStack
[type: LayoutStack] 
The LayoutStack at the top of this UxCollapsibleStack that contains the open/close button and is always enabled.





UxCollapsibleStack.bodyStack
[type: LayoutStack] 
The LayoutStack containing the main body of this UxCollapsibleStack whose enabled state is toggled by the openCloseButton.





UxCollapsibleStack.openCloseButton
[type: Button] 
A Button appearing as a 'caret' that toggles the enabled state of the bodyStack.





UxCollapsibleStack.openCloseButtonScaleFactor
[type: number] 
A scale multiplier for the openCloseButton. Use this property instead of directly scaling the openCloseButton to preserve UiZoom and LayoutObject functionality.





UxCollapsibleStack.outline
[type: UiOutline] 
An outline around the openCloseButton, which is used to indicate when the end-user navigates to this UxCollapsibleStack via the keyboard (using tab or arrow keys).





UxCollapsibleStack.isOpen
[type: boolean] [default: false] 
Boolean determining if the UxCollapsibleStack is open/expanded.





UxCollapsibleStack.openCloseButtonColor
[type: Color] [default: nc.uiStyle.color_interactiveText] 
The base Color of the openCloseButton.





UxCollapsibleStack.highlightedOpenCloseButtonColor
[type: Color] [default: nc.uiStyle.color_highlightedInteractiveText] 
The highlighted Color of the openCloseButton.





UxCollapsibleStack.addOpenCloseCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever this UxCollapsibleStack is opened or closed. The UxCollapsibleStack itself is sent to the callback as its first parameter.

UxCollapsibleStack.addOpenCloseCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this UxCollapsibleStack is opened or closed.

UxCollapsibleStack.addOpenCloseCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this UxCollapsibleStack is opened or closed.

UxCollapsibleStack.addOpenCloseCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever this UxCollapsibleStack is opened or closed.





UxCollapsibleStack.removeOpenCloseCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

UxCollapsibleStack.removeOpenCloseCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UxCollapsibleStack.removeOpenCloseCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





















































































































































































































































































































































































































----------------------------------------------------------
Section 49: PivotPointAdjuster
----------------------------------------------------------


PivotPointAdjuster
[type: class] [NON-INSTANTIABLE] 
A PivotPointAdjuster gives a GraphicObject a unique copy of its Geometry, which can then be modified using the PivotPointAdjuster's position, rotation, and scale members. Note that changing the position, rotation, or scale at run time causes a costly rebuild of the Geometry data and is only recommended during initialization. 





PivotPointAdjuster.type
[type: string] 
Type identifier.





PivotPointAdjuster.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PivotPointAdjuster.position
[type: Vector3] 
The position offset to apply to every vertex in the Geometry. Note that changing this at run time causes a costly rebuild of the Geometry data and is only recommended during initialization.





PivotPointAdjuster.rotation
[type: Vector3] 
The rotation to apply to every vertex in the Geometry. Note that changing this at run time causes a costly rebuild of the Geometry data and is only recommended during initialization.





PivotPointAdjuster.lazyUpdater
[type: LazyUpdater] 
The lazy updater responsible for updating the GraphicObject's Geometry.





PivotPointAdjuster.dispose()
[type: function] 
Removes and destroys the PivotPointAdjuster, restoring the original Geometry if possible.










----------------------------------------------------------
Section 50: Paths
----------------------------------------------------------


Paths
[type: class] [NON-INSTANTIABLE] 
Object housing functionality manipulate paths including 'splitPath', 'getFileName', and 'getParentDirectory'. 





Paths.projectPath
[type: string] [requires: unpublished only] 
The path to the project directory.





Paths.applicationSupportPath
[type: string] [requires: unpublished only] 
The path to the application support directory.





Paths.desktopPath
[type: string] [requires: unpublished only] 
The path to the desktop.





Paths.userDirectoryPath
[type: string] [requires: unpublished only] 
The path to the current user directory.





Paths.splitPath(path)
[type: function] [returns: [string]] 
Returns an array of separated path components. All paths in Incisor® use '\' as a path separator.

Paths.splitPath parameter: path
[type: string] 
The path to split.





Paths.getFileName(path)
[type: function] [returns: string] 
Returns the name of the last path component of the provided path. All paths in Incisor® use '\' as a path separator.

Paths.getFileName parameter: path
[type: string] 
The path to return the last path component of.





Paths.getParentDirectory(path)
[type: function] [returns: string] 
Returns the provided path minus the last path component. All paths in Incisor® use '\' as a path separator.

Paths.getParentDirectory parameter: path
[type: string] 
The path to return the last path component of.










----------------------------------------------------------
Section 51: UiText
----------------------------------------------------------


UiText
[type: class] [extends: TextBox] [requires: module - extendedUi] 
A ui-specialized TextBox with various UI functionalities and defaults applied. UI functionality includes:  • pre-configured with LayoutObject functionality.  • uiStyle TextFormats and Colors applied.  • uiZoom-enabled.  • nearestPixelRendering-enabled.





































































































































































































































































































































































































































































































































































































































































































































































































































----------------------------------------------------------
Section 52: UxStandardListViewElement
----------------------------------------------------------


UxStandardListViewElement
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. This is a specialized horizontal LayoutStack intended to serve as a standard visual container for one item within a list view. The 'bodyStack' member is a child LayoutStack where custom item content can be added, and optional utility controls can be enabled to support reordering, duplicating, adding, and removing list items.





UxStandardListViewElement.bodyStack
[type: LayoutStack] 
The LayoutStack intended to contain the custom body content for this UxStandardListViewElement. Built-in controls such as the drag handle, duplicate button, add button, and remove button are added as siblings of this bodyStack, while user-defined visual content should generally be added to this bodyStack.





UxStandardListViewElement.dragHandle
[type: UiGraphicButton] 
The UiGraphicButton used as the interactive drag handle when makeOrderable has been called. This member will remain undefined unless makeOrderable has been called.





UxStandardListViewElement.addButton
[type: UiGraphicButton] 
The UiGraphicButton used to invoke the add item callback when makeAddible has been called. This member will remain undefined unless makeAddible has been called.





UxStandardListViewElement.removeButton
[type: UiGraphicButton] 
The UiGraphicButton used to invoke the remove item callback when makeRemovable has been called. This member will remain undefined unless makeRemovable has been called.





UxStandardListViewElement.duplicateButton
[type: UiGraphicButton] 
The UiGraphicButton used to invoke the duplicate item callback when makeDuplicable has been called. This member will remain undefined unless makeDuplicable has been called.





UxStandardListViewElement.reorderPointerVerticalBuffer
[type: number] [default: 0] 
The vertical buffer applied to the reorder pointer when this UxStandardListViewElement is being used as a possible drop target. The value is multiplied by nc.uiZoom.totalZoom before being applied.





UxStandardListViewElement.reorderPointerIndentSize
[type: number] [default: nc.uiStyle.spacer_medium] 
The horizontal indent applied to the reorder pointer when the current drop target position is "within". The value is multiplied by nc.uiZoom.totalZoom before being applied.





UxStandardListViewElement.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body.clone()] 
The TextFormat used to scale graphical components such as the drag handle, duplicate button, add button, and remove button.





UxStandardListViewElement.makeOrderable(orderingIncludesWithin, reorderItemsCallbackOwner, reorderItemsCallbackName, reorderItemsCallbackArgs, dragInitiationCallbackOwner, dragInitiationCallbackName, dragInitiationCallbackArgs)
[type: function] 
Adds a drag handle and configures this UxStandardListViewElement to participate in drag-based ordering within its parent LayoutStack. The parent LayoutStack receives a shared internal ordering manager the first time one of its UxStandardListViewElements is made orderable. When dragging begins, the optional drag initiation callback receives an array of the currently dragged UxStandardListViewElements as its first parameter. When a drop occurs, the reorder items callback receives the array of dragged UxStandardListViewElements as its first parameter, the UxStandardListViewElement nearest to the drop position as its second parameter, and the relative position string ("above", "below", or "within") as its third parameter.

UxStandardListViewElement.makeOrderable parameter: orderingIncludesWithin
[type: boolean] [optional] 
Boolean determining if the reorder interaction can target a "within" position in addition to "above" and "below".

UxStandardListViewElement.makeOrderable parameter: reorderItemsCallbackOwner
[type: object] [optional] 
The object owning the callback invoked when a drop occurs. The associated callback will recieve the array of dragged UxStandardListViewElements, the nearest UxStandardListViewElement, and the relative position string as its first three parameters.

UxStandardListViewElement.makeOrderable parameter: reorderItemsCallbackName
[type: string] [optional] 
The name of the callback invoked when a drop occurs. The associated callback will recieve the array of dragged UxStandardListViewElements, the nearest UxStandardListViewElement, and the relative position string as its first three parameters.

UxStandardListViewElement.makeOrderable parameter: reorderItemsCallbackArgs
[type: Array, any] [optional] 
Optional parameters appended when invoking the reorder items callback. The associated callback will recieve the array of dragged UxStandardListViewElements, the nearest UxStandardListViewElement, and the relative position string as its first three parameters.

UxStandardListViewElement.makeOrderable parameter: dragInitiationCallbackOwner
[type: object] [optional] 
The object owning the optional callback invoked when dragging begins. The associated callback will recieve a list of the UxStandardListViewElements being dragged as its first parameter - the associated callback can append to this list if the situation calls for it.

UxStandardListViewElement.makeOrderable parameter: dragInitiationCallbackName
[type: string] [optional] 
The name of the optional callback invoked when dragging begins. The associated callback will recieve a list of the UxStandardListViewElements being dragged as its first parameter - the associated callback can append to this list if the situation calls for it.

UxStandardListViewElement.makeOrderable parameter: dragInitiationCallbackArgs
[type: Array, any] [optional] 
Optional parameters appended when invoking the drag initiation callback. The associated callback will recieve a list of the UxStandardListViewElements being dragged as its first parameter - the associated callback can append to this list if the situation calls for it.





UxStandardListViewElement.makeDuplicable(duplicateItemCallbackOwner, duplicateItemCallbackName, duplicateItemCallbackArgs)
[type: function] 
Adds a duplicate button and configures this UxStandardListViewElement to invoke a duplicate item callback. The duplicate item callback receives this UxStandardListViewElement as its first parameter.

UxStandardListViewElement.makeDuplicable parameter: duplicateItemCallbackOwner
[type: object] [optional] 
The object owning the callback used to duplicate the represented item. The associated callback will recieve the initiating UxStandardListViewElement as its first parameter.

UxStandardListViewElement.makeDuplicable parameter: duplicateItemCallbackName
[type: string] [optional] 
The name of the callback used to duplicate the represented item. The associated callback will recieve the initiating UxStandardListViewElement as its first parameter.

UxStandardListViewElement.makeDuplicable parameter: duplicateItemCallbackArgs
[type: Array, any] [optional] 
Optional parameters appended when invoking the duplicate item callback. The associated callback will recieve the initiating UxStandardListViewElement as its first parameter.





UxStandardListViewElement.makeAddible(addItemCallbackOwner, addItemCallbackName, addItemCallbackArgs)
[type: function] 
Adds an add button and configures this UxStandardListViewElement to invoke an add item callback. The add item callback receives this UxStandardListViewElement as its first parameter and the string "below" as its second parameter.

UxStandardListViewElement.makeAddible parameter: addItemCallbackOwner
[type: object] [optional] 
The object owning the callback used to add an item. The associated callback will recieve the UxStandardListViewElement as its first parameter. The associated callback will recieve the initiating UxStandardListViewElement as its first parameter.

UxStandardListViewElement.makeAddible parameter: addItemCallbackName
[type: string] [optional] 
The name of the callback used to add an item. The associated callback will recieve the initiating UxStandardListViewElement as its first parameter.

UxStandardListViewElement.makeAddible parameter: addItemCallbackArgs
[type: Array, any] [optional] 
Optional parameters appended when invoking the add item callback. The associated callback will recieve the initiating UxStandardListViewElement as its first parameter.





UxStandardListViewElement.makeRemovable(removeItemCallbackOwner, removeItemCallbackName, removeItemCallbackArgs)
[type: function] 
Adds a remove button and configures this UxStandardListViewElement to invoke a remove item callback. The remove item callback receives this UxStandardListViewElement as its first parameter.

UxStandardListViewElement.makeRemovable parameter: removeItemCallbackOwner
[type: object] [optional] 
The object owning the callback used to remove the represented item. The associated callback will recieve the initiating UxStandardListViewElement as its first parameter.

UxStandardListViewElement.makeRemovable parameter: removeItemCallbackName
[type: string] [optional] 
The name of the callback used to remove the represented item. The associated callback will recieve the initiating UxStandardListViewElement as its first parameter.

UxStandardListViewElement.makeRemovable parameter: removeItemCallbackArgs
[type: Array, any] [optional] 
Optional parameters appended when invoking the remove item callback. The associated callback will recieve the initiating UxStandardListViewElement as its first parameter.





















































































































































































































































































































































































































----------------------------------------------------------
Section 53: ProjectConfiguration
----------------------------------------------------------


ProjectConfiguration
[type: class] [NON-INSTANTIABLE] 
Object housing the configuration settings for this project. Accessible via 'nc.projectConfiguration'. Many of the members of this object are customizable on a 'per configuration' basis by editing the ProjectSettings. The user-customizable 'PreloadConfiguration' code is executed within this object, so members created within that code will be accessible on this object. 





ProjectConfiguration.incisorVersion
[type: string] 
The specific 'version number' designation of the version of Incisor® that generated this project code.





ProjectConfiguration.incisorVersionSet
[type: string] 
The 'version set' designation of the version of Incisor® that generated this project code.





ProjectConfiguration.projectName
[type: string] 
The name of the current Incisor® project as determined in the 'ProjectSettings'.





ProjectConfiguration.publishTimestamp
[type: string] 
The date when the current project was published using the format "YYYY.MM.DD.hh.mm.ss". For unpublished projects, this value will be 'devMode'.





ProjectConfiguration.coreCanvasResolutionX
[type: number] [default: 1920] 
The core canvas pixel width. This represents the pixel width of the canvas RenderTarget at it's native scale. Runtime changes to this value must be made in PreloadConfiguration code, which is located in the 'ProjectCode/PreloadConfiguration' local directory.





ProjectConfiguration.coreCanvasResolutionY
[type: number] [default: 1080] 
The core canvas pixel height. This represents the pixel height of the canvas RenderTarget at it's native scale. Runtime changes to this value must be made in PreloadConfiguration code, which is located in the 'ProjectCode/PreloadConfiguration' local directory.





ProjectConfiguration.canvasTransparency
[type: boolean] [default: false] 
Boolean determining if any portion of the canvas will be transparent, enabling the html page to be partially viewed "through" the canvas.





ProjectConfiguration.mainCameraType
[type: string] [default: 'orthographic'] 
String value denoting the default camera type used for the 'mainCamera' in the 'mainScene'. Runtime changes to this value must be made in PreloadConfiguration code, which is located in the 'ProjectCode/PreloadConfiguration' local directory. Possible values for this property are 'orthographic' or 'perspective'.





ProjectConfiguration.maskingMode
[type: string] [default: 'overlapping'] 
String value denoting the masking mode for this project. The masking mode determines how different MaskGroups interact with eachother. Possible values for this property are 'overlapping' or 'disjoint'. When the maskingMode is 'overlapping', up to 8 MaskGroups can be defined and GraphicObjects can subscribe to any combination of those MaskGroups. When the maskingMode is 'disjoint', up to 255 MaskGroups can be defined, but GraphicObjects can only subscribe to one mask at a time.





ProjectConfiguration.preserveDrawingBuffer
[type: boolean] [default: true] 
Boolean value determining if the drawing buffer is preserved for reading. Preserving the drawing buffer enables several useful development features, but may cause performance issues in published software on some devices. It is therefore recommended that this flag be set to true for when the project is unpublished, and false for when the project is published. This can be done using a 'CODE.includeIf___published' within the 'preloadConfiguration' method in the PreloadConfiguration code.





ProjectConfiguration.canvasParent
[type: object] [default: document.body] 
DOM object that the canvas will be made a child of. For many projects the best value for this item is the default. Changes to this value must be made in PreloadConfiguration code, which is located in the 'ProjectCode/PreloadConfiguration' local directory.





ProjectConfiguration.isProjectPublished
[type: boolean] 
Ready-only bool indicating if the project that is currently running is published.





ProjectConfiguration.ancillaryDevInfo
[type: AncillaryDevInfo] [requires: unpublished only] 
Object housing ancillary development-environment information (host paths, platform, drives, etc.). Undefined in published builds — always guard access with 'nc.projectConfiguration.isProjectPublished'.





ProjectConfiguration.urlParams
[type: object] 
URL parameters. URL parameters included in the url used to access this project are automatically parsed and provided in this object.





ProjectConfiguration.defaultGraphicAssetEffectNodes
[type: [string]] 
List of Nodes added to the presets for all GraphicAssets. This item is determined by the associated field in the ProjectSettings.





ProjectConfiguration.assetConfiguration
[type: AssetConfiguration] 
Object housing the details of the current asset configuration. Runtime changes to this value must be made in PreloadConfiguration code, which is located in the 'ProjectCode/PreloadConfiguration' local directory. When setting these values, ensure the chosen values exist within the 'assetConfigurationDefinitions' in the 'ProjectSettings.json' file, and the overall assetConfiguration must in the list of 'supportedAssetConfigurations' listed within the current configuration within the 'ProjectSettings.json' file.





ProjectConfiguration.loadingTierDefinitions
[type: dictionary] 
Object housing information about the loading tiers in this project. Loading tiers are a means to organize AssetComponents into separately downloadable groups.


ProjectConfiguration.loadingTierDefinitions.100
[type: LoadingTierDefinition] 
Information about the 100 loading tier.





ProjectConfiguration.fontDefinitions
[type: dictionary] 
Object housing information about the fonts in this project.


ProjectConfiguration.fontDefinitions.NullFont
[type: FontDefinition] 
Information about the NullFont font.


ProjectConfiguration.fontDefinitions.incr_inspectorFont
[type: FontDefinition] 
Information about the incr_inspectorFont font.


ProjectConfiguration.fontDefinitions.MonoSpace
[type: FontDefinition] 
Information about the MonoSpace font.





ProjectConfiguration.refreshWithUpdatedParams()
[type: function] 
Refreshes the project within the browser, applying current/updated values of 'ProjectConfiguration.urlParams'. For example, a project could have functionality to allow the end-user to change a custom configuration (e.i. themeColor) of the project from within the published project runtime, and this could be done by calling "nc.projectConfiguration.urlParams.themeColor = 'purple';", and then calling "nc.projectConfiguration.refreshWithUpdatedParams();". The browser would then refresh, the url would include the suffix "?themeColor=purple", and the nc.projectConfiguration.urlParams would be updated from the very beginning of the project runtime, allowing the configuration to inform the loading and setup process.





ProjectConfiguration.canvasPositionOverride(canvasElement, left, top, width, height)
[type: function] 
An function that can override Incisor's built-in placement of the canvasElement, which as a default behaviour simply stretches the canvas over the entire browser window. This function is initially undefined, and can be defined to create custom canvas layout behaviours. This function is automatically called if the browser window is resized but it can also be called directly (if defined) in the event that the canvas needs to be moved for reasons not stemming from something other than a browser resize event.

ProjectConfiguration.canvasPositionOverride parameter: canvasElement
[type: HTMLCanvasElement] 
The main canvas element for this project (accessable via 'nc.canvasElement').

ProjectConfiguration.canvasPositionOverride parameter: left
[type: number] 
The input position of the left side of the canvas within the page window.

ProjectConfiguration.canvasPositionOverride parameter: top
[type: number] 
The input position of the top side of the canvas within the page window.

ProjectConfiguration.canvasPositionOverride parameter: width
[type: number] 
The input width of the canvas within the page window.

ProjectConfiguration.canvasPositionOverride parameter: height
[type: number] 
The inpu height of the canvas within the page window.










----------------------------------------------------------
Section 54: AssetConfiguration
----------------------------------------------------------


AssetConfiguration
[type: class] [NON-INSTANTIABLE] 
Dictionary of asset configurations. 





AssetConfiguration."assetPackageScale"
[type: string] 
Asset configuration for 'assetPackageScale'. Available options for this asset configuration can be found in the 'assetConfigurationDefinitions' item in the 'ProjectSettings'. This asset configuration is a built-in configuration. This is the current value for the 'assetPackageScale' configuration. This configuration changes the base resolution for all image assets loaded within the project.' Image assets can opt out of adherence to 'assetPackageScale' by changing the 'applyAssetPackageScaling' in the asset settings to false.





AssetConfiguration."soundQuality"
[type: string] 
Asset configuration for 'soundQuality'. Available options for this asset configuration can be found in the 'assetConfigurationDefinitions' item in the 'ProjectSettings'. This asset configuration is a built-in configuration. This is the current value for the 'soundQuality' configuration. This configuration changes the compression bitrate and the number of channels for all sound assets loaded within the project.'





AssetConfiguration."language"
[type: string] 
Asset configuration for 'language'. Available options for this asset configuration can be found in the 'assetConfigurationDefinitions' item in the 'ProjectSettings'. This asset configuration is a built-in configuration. This is the current value for the 'language' configuration. The language configuration determines which phrases are referenced in the 'ProjectTranscript.json.' This configuration can also be used to determine which language-specific assets to load based on flags within the given asset settings.










----------------------------------------------------------
Section 55: AppEvent
----------------------------------------------------------


AppEvent
[type: class] [NON-INSTANTIABLE] 
Object housing functionality for a system of method callbacks that are triggered by a given type of event. There are AppEvents for automatically recurring events such as the 'fixedUpdate' and 'screenUpdate', as well as user-input driven events such as keyboard and mouse events. Access Incisor®'s AppEvents via 'nc.appEvents', and use them to add custom functionality that responds to these events. 





AppEvent.type
[type: string] 
Type identifier





AppEvent.name
[type: string] 
Name of AppEvent

example:
// Objective: Get the name of an AppEvent.
// Expected Result: The console should read "myAppEvent name keyboardEvent".

// Get an instance of the keyboardEvent AppEvent.
let myAppEvent = nc.appEvents.keyboardEvent;
console.log("myAppEvent name", myAppEvent.name);





AppEvent.hasSingularFocusScheme
[type: boolean] [default: false] 
Readonly flag indicating if this AppEvent has a 'singular focus scheme' which is a system that restricts callback invocation to items associated with the currently 'focused' object as determined by nc.singularFocusObject.





AppEvent.isOrdered
[type: boolean] [default: false] 
Readonly flag indicating if this AppEvent is 'ordered', which allows callbacks added to this AppEvent to be provided a callback order number, which is then used to sort the callbacks when the AppEvent is triggered. Built-in AppEvents with this flag true include start, lateFixedUpdate, and lateScreenUpdate.





AppEvent.hasConsumableCallbacks
[type: boolean] [default: false] 
Readonly flag indicating if this AppEvent removes callbacks after one invocation.





AppEvent.addCallback(callbackOwner, callbackName, callbackArgs, pauseImmunity, singularFocusRequirements, callbackOrder)
[type: function] 
Adds the provided function to the list of functions called with the associated AppEvent occurs.

AppEvent.addCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

AppEvent.addCallback parameter: callbackName
[type: string] 
The name of the callback function.

AppEvent.addCallback parameter: callbackArgs
[type: [any], any] [optional] 
Extra parameters for the callback function. It should be noted that some AppEvents are triggered with 'event-wide' args. In this case, these extra args are appended to the event-wide args.

AppEvent.addCallback parameter: pauseImmunity
[type: [PauseEvent], PauseEvent] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this AppEvent callback will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

AppEvent.addCallback parameter: singularFocusRequirements
[type: [object], object] [default: undefined] [optional] 
If this AppEvent's 'hasSingularFocusScheme' property is true, supplying this object or Array of objects is a way of requiring the correct focus context for this callback to occur. If left undefined, the callback will be invoked with any triggering event. If supplied, one of the objects in the singularFocusRequirements must be 'in focus' for the callback to be invoked.

AppEvent.addCallback parameter: callbackOrder
[type: number] [default: 0] [optional] 
If this AppEvent's 'isOrdered' property is true, this number will be used to sort the callbacks before they are invoked. An early number corresponds to the callback being called earlier.

example:
// Objective: Add a callback to an AppEvent.
// Action: Press a key on the keyboard. For this example, press the letter 'a'.
// Expected Result: The console should have 2 log messages as follows:
//   callback type: keydown a
//   callback type: keyup a

// Add a callback function.
this.myCallback = function(args) {
    console.log('callback type:', args.type, args.key);
}

// Get an instance of the keyboardEvent AppEvent.
let myAppEvent = nc.appEvents.keyboardEvent;
// Add the callback.
myAppEvent.addCallback( this, "myCallback" );





AppEvent.removeCallback(callbackOwner, callbackName)
[type: function] 
Removes the provided function from the list of functions called with the associated AppEvent occurs.

AppEvent.removeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function to be removed.

AppEvent.removeCallback parameter: callbackName
[type: string] 
The name of the callback function to be removed.

example:
// Objective: Remove a callback from an AppEvent.
// Actions: 
// 1. Press a key on the keyboard. For this example, press the letter 'a'.
// 1. Expected Result: The console should have 2 log messages as follows:
//   callback type: keydown a
//   callback type: keyup a
//
// 2. Click the white box to remove the AppEvent.
// 2. Expected Result: Upon clicking the white box, the console should read "removing the callback". You will no longer see console log messages upon  pressing the keyboard.

// Add a callback function and name it 'myEventCallback'.
this.myEventCallback = function(args) {
    console.log('callback type:', args.type, args.key);
}
// Get an instance of the keyboardEvent AppEvent.
let myAppEvent = nc.appEvents.keyboardEvent;
// Add the callback.
myAppEvent.addCallback( this, "myEventCallback" );

// Create a button to use to remove the callback. Use the WhiteBox GraphicAsset.
this.removeButton = nc.addButton( nc.graphicAssets.WhiteBox, nc.mainScene, "RemoveButton" );
// Create a callback function that handles the click of the white box and executes removeCallback(). Name the callback function "myButtonCallback".
this.myButtonCallback = function(args) {
    console.log('removing the callback');
    // Inside this press callback, remove the callback
    myAppEvent.removeCallback( this, "myEventCallback" );
}
// Add the PressCallback to handle the clicking of the white box
this.removeButton.addPressCallback( this, "myButtonCallback" );





AppEvent.getRecipients()
[type: function] [returns: [object]] 
Returns an Array listing all of the callbacks currently connected to this AppEvent. The returned Array lists objects containing the callbackOwner, callbackName, and paused state for each callback.

example:
// Objective: List all of the callbacks currently connected to this AppEvent.
// Expected Result: The console should have 2 log messages as follows:
//   recipient myCallback1
//   recipient myCallback2
//   recipient myCallback3

// Make 3 callbacks.
this.myCallback1 = function(args) {
    console.log('myCallback1 callback type:', args.type, args.key);
}
this.myCallback2 = function(args) {
    console.log('myCallback2 callback type:', args.type, args.key);
}
this.myCallback3 = function(args) {
    console.log('myCallback3 callback type:', args.type, args.key);
}

// Get an instance of the keyboardEvent AppEvent.
let myAppEvent = nc.appEvents.keyboardEvent;
// Add all 3 callbacks to this AppEvent.
myAppEvent.addCallback( this, "myCallback1" );
myAppEvent.addCallback( this, "myCallback2" );
myAppEvent.addCallback( this, "myCallback3" );

// Iterate and console log the array of recipients.
let recipients = myAppEvent.getRecipients();
for ( let r of recipients ) {
    console.log('recipient', r.callbackName);
}





AppEvent.trigger(callbackArgs)
[type: function] 
Method that 'Triggers' the AppEvent, invoking all of the callback functions that have been added to it.

AppEvent.trigger parameter: callbackArgs
[type: Array, any] [optional] 
Parameter or Array of parameters that will be sent to this AppEvent's callback functions. It should be noted that if an Array is supplied, the individual members of the Array will be sent to callback functions as individual parameters.





AppEvent.asyncTrigger(callbackArgs)
[type: function] 
Method that 'Triggers' the AppEvent, invoking all of the callback functions that have been added to it, and asyncronously awaiting each of them.

AppEvent.asyncTrigger parameter: callbackArgs
[type: Array, any] [optional] 
Parameter or Array of parameters that will be sent to this AppEvent's callback functions. It should be noted that if an Array is supplied, the individual members of the Array will be sent to callback functions as individual parameters.










----------------------------------------------------------
Section 56: PauseEvent
----------------------------------------------------------


PauseEvent
[type: class] [NON-INSTANTIABLE] 
A PauseEvent can be used as a parameter in 'nc.pause' and 'nc.resume' to pause and resume various time-based and user-interaction processes. Pausable processes react to pausing or resuming with PauseEvents unless those processes have a given PauseEvent as part of their designated 'pauseImmunity', which can determined in the parameters of a pausable-process-initiating method. Use 'nc.definePauseEvent' to create a new PauseEvent. 





PauseEvent.type
[type: string] 
Type identifier





PauseEvent.name
[type: string] 
Name of PauseEvent

example:
// Objective: Get the name of an AppEvent.
// Expected Result: The console should read "myAppEvent name keyboardEvent".

// Get an instance of the keyboardEvent AppEvent.
let myAppEvent = nc.appEvents.keyboardEvent;
console.log("myAppEvent name", myAppEvent.name);










----------------------------------------------------------
Section 57: SpeedControl
----------------------------------------------------------


SpeedControl
[type: class] [NON-INSTANTIABLE] 
SpeedControls can be used to control the speed of time-based sequencing processes such as Motions, Swoops, or Timelines. Applicable processes can subscribe to multiple SpeedControls; the 'speed' values of all of the SpeedControls a process subscribes to are multiplied together to determine the overall pacing of the given time-based process. Use 'nc.defineSpeedControl' to create a new SpeedControl. 





SpeedControl.type
[type: string] 
Type identifier





SpeedControl.name
[type: string] 
Name of SpeedControl

example:
// Objective: Get the name of an AppEvent.
// Expected Result: The console should read "myAppEvent name keyboardEvent".

// Get an instance of the keyboardEvent AppEvent.
let myAppEvent = nc.appEvents.keyboardEvent;
console.log("myAppEvent name", myAppEvent.name);





SpeedControl.speed
[type: number] [default: 1] 
The speed value. This value multiplies the speed of processes that subscribe to this SpeedControl

example:
// Objective: Adjust the motion speed of a "bouncing" white box.
// Expected Result: The white box will bounce, gradually slowing down over a period of 5 seconds, then it will gradually speed back up over a period of 5 seconds.

// Create a GraphicObject using the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "MyGraphicObject" );
// Give the box motion along the y axis. Set the speed to 2.
myGraphicObject.position.addMotion.y(-300,300,2);
 
// Swoop the 'speed' property of the MainSpeedControl down to .05 over a period of 5 seconds and provide callback arguments to swoop the 'speed' property again back up to speed 1 over a period of 10 seconds.
nc.swoopValue( 
            nc.speedControls.MainSpeedControl, 
            "speed", 
            .05, 
            5, 
            undefined, 
            nc, 
            "swoopValue", 
            [nc.speedControls.MainSpeedControl, "speed", 1, 10] 
            );










----------------------------------------------------------
Section 58: FocusChangeInfo
----------------------------------------------------------


FocusChangeInfo
[type: class] [NON-INSTANTIABLE] 
Object containing information about a change to the 'nc.singularFocusObject' value. An instance of this object is sent as a first parameter to all callbacks registered with the nc.appEvents.focusChange AppEvent. 





FocusChangeInfo.objectLosingFocus
[type: object] 
A reference to the previous nc.singularFocusObject.

example:
// Objective: Add a callback to the focusChange AppEvent.
// Expected Result: After waiting 5 seconds, the console should have 3 log messages as follows:
//    changing focus to Scene2
//    object gaining focus Scene2
//    object losing focus Scene1

// Create 2 scenes, "Scene1" and "Scene2"
this.scene1 = new Scene("Scene1");
this.scene2 = new Scene("Scene2");
// Set the singular focus to "Scene1"
nc.singularFocusObject = this.scene1;

// Create a callback to handle the focus change. Name is "focusChangeCallback".
this.focusChangeCallback = function(args) {
   console.log("object gaining focus", args.objectGainingFocus.name);
   console.log("object losing focus", args.objectLosingFocus.name);
}
// Get an instance of the focusChange AppEvent and add the focus change callback.
this.focusChangeEvent = nc.appEvents.focusChange;
this.focusChangeEvent.addCallback( this, "focusChangeCallback" );

// Create a focus changer that will change the singular focus.
this.focusChanger = function(args) {
   console.log("changing focus to Scene2");
   nc.singularFocusObject = this.scene2;
}
// Use nc.waitThen() to wait 5 seconds before executing the focus changer.
nc.waitThen( 5, this, "focusChanger" );





FocusChangeInfo.objectGainingFocus
[type: object] 
A reference to the new nc.singularFocusObject.

example:
// Objective: Add a callback to the focusChange AppEvent.
// Expected Result: After waiting 5 seconds, the console should have 3 log messages as follows:
//    changing focus to Scene2
//    object gaining focus Scene2
//    object losing focus Scene1

// Create 2 scenes, "Scene1" and "Scene2"
this.scene1 = new Scene("Scene1");
this.scene2 = new Scene("Scene2");
// Set the singular focus to "Scene1"
nc.singularFocusObject = this.scene1;

// Create a callback to handle the focus change. Name is "focusChangeCallback".
this.focusChangeCallback = function(args) {
   console.log("object gaining focus", args.objectGainingFocus.name);
   console.log("object losing focus", args.objectLosingFocus.name);
}
// Get an instance of the focusChange AppEvent and add the focus change callback.
this.focusChangeEvent = nc.appEvents.focusChange;
this.focusChangeEvent.addCallback( this, "focusChangeCallback" );

// Create a focus changer that will change the singular focus.
this.focusChanger = function(args) {
   console.log("changing focus to Scene2");
   nc.singularFocusObject = this.scene2;
}
// Use nc.waitThen() to wait 5 seconds before executing the focus changer.
nc.waitThen( 5, this, "focusChanger" );










----------------------------------------------------------
Section 59: GeometryEditor
----------------------------------------------------------


GeometryEditor
[type: class] [NON-INSTANTIABLE] 
Object connected to a Geometry allowing changes to be made to that Geometry. Make the desired changes, then call 'commitChanges'. 





GeometryEditor.type
[type: string] 
Type identifier.





GeometryEditor.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





GeometryEditor.attributes
[type: object] 
Contains a key for each attribute added to this GeometryEditor. The value at each key is an Array of numbers containing the attribute data.





GeometryEditor.indices
[type: [[number]]] 
Each element in this Array corresponds to the elements in the materials Array of the Graphic that will use the resulting Geometry. Each element contains an Array of numbers containing the index data.





GeometryEditor.attributeDuplicateThresholds
[type: object] 
Contains a key for each attribute added to this GeometryEditor. The value at each key is the threshold used to determine if an attribute value should be considered to match another value in the same attribute Array. When a new vertex is added to the GeometryAccesor, its attribute values are compared to the existing vertices, by checking if the difference between the values is lower than this threshold.  If all attributes are considered to match, the existing vertex is re-used as an optimization. A threshold of 0 on any attribute will ensure that no vertices are ever considered to match each other, effectively disabling this optimization.





GeometryEditor.connectedGeometry
[type: Geometry] 
The Geometry that this GeometryEditor is connected to.





GeometryEditor.copyGeometry(geometry, callbackOwner, callbackName, callbackArgs)
[type: function] 
Copies the vertex, attribute, and material information from the given Geometry into this GeometryEditor. Please note that in many cases, this function operates asyncronously since the Geometry being copied may no be loaded yet. Consequently, using this GeometryEditor to operate on the copied Geometry will need to wait until the source Geomtry loads. This can be achieved by asyncronously awaiting this function, or by supplying a callback, which will be called when the source Geometry loads. The callback will receive the iniating GeometryEditor as its first parameter.

GeometryEditor.copyGeometry parameter: geometry
[type: Geometry] 
The source Geometry whose info will be copied into this GeometryEditor.

GeometryEditor.copyGeometry parameter: callbackOwner
[type: object] [optional] 
The object owning the callback that will be called when the source Geometry loads.

GeometryEditor.copyGeometry parameter: callbackName
[type: string] [optional] 
The name of the callback that will be called when the source Geometry loads.

GeometryEditor.copyGeometry parameter: callbackArgs
[type: Array, any] [optional] 
The arguments for the callback that will be called when the source Geometry loads.





GeometryEditor.addVertex(vertex)
[type: function] [returns: number] 
Adds a vertex that may be referenced by the indices.  The vertex's position in the attribute arrays is returned, and is the value that should be used by the indices to refer to this vertex. Note that the length of the attributes may not increase after this call completes if the vertex was found to be a duplicate of an existing vertex. In this scenario, the index of the existing vertex will be returned.

GeometryEditor.addVertex parameter: vertex
[type: object] 
Each key in this Object should be the name of an attribute in this GeometryEditor. The value should be a number, Vector2, Vector3, or Vector4 containing the value of the attribute at this vertex. The type of the value must correspond to the 'size' specified in 'addAttribute'. Duplicate vertices will be automatically handled according to the values in attributeDuplicateThresholds.





GeometryEditor.addTriangle(vertex0, vertex1, vertex2, materialIndex)
[type: function] 
Adds a triangle that will use the Material at 'materialIndex' of the Graphic that will use the resulting Geometry.

GeometryEditor.addTriangle parameter: vertex0
[type: object] 
Each key in this Object should be the name of an attribute in this GeometryEditor. The value should be a number, Vector2, Vector3, or Vector4 containing the value of the attribute at this vertex. Duplicate vertices will be automatically handled according to the values in attributeDuplicateThresholds.

GeometryEditor.addTriangle parameter: vertex1
[type: object] 
Each key in this Object should be the name of an attribute in this GeometryEditor. The value should be a number, Vector2, Vector3, or Vector4 containing the value of the attribute at this vertex. Duplicate vertices will be automatically handled according to the values in attributeDuplicateThresholds.

GeometryEditor.addTriangle parameter: vertex2
[type: object] 
Each key in this Object should be the name of an attribute in this GeometryEditor. The value should be a number, Vector2, Vector3, or Vector4 containing the value of the attribute at this vertex. Duplicate vertices will be automatically handled according to the values in attributeDuplicateThresholds.

GeometryEditor.addTriangle parameter: materialIndex
[type: number] 
The index into the materials Array of the Graphic that will use the resulting Geometry. Defaults to 0.





GeometryEditor.addAttribute(name, type, size)
[type: function] 
Adds a new attribute.  If an attribute aleady exists with this name, the attribute is re-initialized and will be empty.

GeometryEditor.addAttribute parameter: name
[type: string] 
The name of the attribute.

GeometryEditor.addAttribute parameter: type
[type: string] 
The type of number that should be used to store this attribute.

GeometryEditor.addAttribute parameter: size
[type: number] 
Specifies the number of components on this attribute. Must be 1, 2, 3, or 4.





GeometryEditor.deleteAllAttributesAndIndices()
[type: function] 
Deletes all attributes. This is typically used if the default attributes of 'position' and 'uv' are unneeded on a new GeometryEditor.





GeometryEditor.convertGeometryToGrid(horizontalSegments, verticalSegments)
[type: function] 
Converts the connected Geometry to a grid of triangles oriented on the XY plane. Attribute values at each new point will be interpoloted linearly across the grid, using the attribute values at the minimum and maximum vertices of the original geometry.

GeometryEditor.convertGeometryToGrid parameter: horizontalSegments
[type: number] 
The number of horizontal segments of the grid.

GeometryEditor.convertGeometryToGrid parameter: verticalSegments
[type: number] 
The number of vertical segments of the grid.





GeometryEditor.newGrid(width, height, horizontalSegments, verticalSegments)
[type: function] 
Creates a new grid of triangles oriented on the XY plane, centered around 0 on each axis.

GeometryEditor.newGrid parameter: width
[type: number] 
The width of the grid.

GeometryEditor.newGrid parameter: height
[type: number] 
The height of the grid.

GeometryEditor.newGrid parameter: horizontalSegments
[type: number] 
The number of horizontal segments of the grid.

GeometryEditor.newGrid parameter: verticalSegments
[type: number] 
The number of vertical segments of the grid.





GeometryEditor.translate(translation, attributeName)
[type: function] 
Translates all of the values of an attribute by the given translation amount.

GeometryEditor.translate parameter: translation
[type: number, Vector2, Vector3, Vector4] 
The amount the values of the attribute are translated. This parameter should be a number, Vector2, Vector3, or Vector4. The type should correspond to the size of the attribute. For example, the default 'position' attribute should be translated by a Vector3, and the default 'uv' attribute should be translated by a Vector2.

GeometryEditor.translate parameter: attributeName
[type: string] 
The name of the attribute data to be translated. Defaults to 'position'.





GeometryEditor.getVertexTemplate()
[type: function] 
Returns a new object structured appropriately to pass into the addVertex and addTriangle functions. For each currently defined attribute, a member of type number, Vector2, Vector3, or Vector4 is added.





GeometryEditor.getBounds(lowerBounds, upperBounds, attributeName)
[type: function] 
Calculates the lowest and highest values seen on each dimension of the attribute's data.

GeometryEditor.getBounds parameter: lowerBounds
[type: Array] 
The array to populate with the lowest value found in each dimension of the attribute data.

GeometryEditor.getBounds parameter: upperBounds
[type: Array] 
The array to populate with the highest value found in each dimension of the attribute data.

GeometryEditor.getBounds parameter: attributeName
[type: string] 
The name of the attribute data to search for bounds. Defaults to 'position'.





GeometryEditor.commitChanges()
[type: function] 
Applies the changes performed by this GeometryEditor to the connectect Geometry. To optimize performance, this should be called once after all changes have been performed, as this function can have a performance impact.










----------------------------------------------------------
Section 60: LayoutObject
----------------------------------------------------------


LayoutObject
[type: class] [NON-INSTANTIABLE] 
Object housing information about this particular SceneObject's LayoutObject functionality. LayoutObject functionality applies to SceneObjects that have been added as elements to a LayoutStack, which is responsible for organizing visual content (TextBoxes, Graphics, Buttons, etc...) into dynamic vertical or horizontal stacks. Until a SceneObject has been configured with LayoutObject functionality (either by calling 'SceneObject.configureLayoutObject' or by adding the SceneObject as an element to a LayoutStack), the 'SceneObject.layoutObject' member will be undefined. 





LayoutObject.type
[type: string] 
Type identifier.





LayoutObject.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





LayoutObject.width
[type: number] 
The width of this LayoutObject.





LayoutObject.height
[type: number] 
The height of this LayoutObject.





LayoutObject.leftBuffer
[type: number] [default: 0] 
A buffer that is included when this LayoutObject is laid out within a LayoutStack. This buffer is multiplied by nc.uiZoom.totalZoom if the containing LayoutStack is configured to be affected by iuZoom.





LayoutObject.rightBuffer
[type: number] [default: 0] 
A buffer that is included when this LayoutObject is laid out within a LayoutStack. This buffer is multiplied by nc.uiZoom.totalZoom if the containing LayoutStack is configured to be affected by iuZoom.





LayoutObject.bottomBuffer
[type: number] [default: 0] 
A buffer that is included when this LayoutObject is laid out within a LayoutStack. This buffer is multiplied by nc.uiZoom.totalZoom if the containing LayoutStack is configured to be affected by iuZoom.





LayoutObject.topBuffer
[type: number] [default: 0] 
A buffer that is included when this LayoutObject is laid out within a LayoutStack. This buffer is multiplied by nc.uiZoom.totalZoom if the containing LayoutStack is configured to be affected by iuZoom.





LayoutObject.justification
[type: string] [default: "left"] 
The justification of this LayoutObject within the LayoutStack that contains it (if applicable). See 'nc.constants.justifications' for a list of available values.





LayoutObject.overrideWidth
[type: number] [default: undefined] 
An override to the width value of this LayoutObject, which would otherwise be set by the 'refreshLayoutCallback' callback function connected to this LayoutObject.





LayoutObject.overrideHeight
[type: number] [default: undefined] 
An override to the height value of this LayoutObject, which would otherwise be set by the 'refreshLayoutCallback' callback function connected to this LayoutObject.





LayoutObject.refreshLayoutCallbackOwner
[type: object] 
The owner of the function that will be called automatically to refresh the layout of this LayoutObject and determine its layout dimensions. This function is responsible for laying out the LayoutObject's content and returning a Vector2 containing its dimensions, which will then be used to position this LayoutObject within the LayoutStack that contains it. GrapicObjects and TextBoxes automatically perform these functions internally without the need for this callback... Set this value to customize the process of laying out this SceneObject's content, and/or determining its layout width/height.





LayoutObject.refreshLayoutCallbackName
[type: string] 
The name of the function that will be called automatically to refresh the layout of this LayoutObject and determine its layout dimensions. This function is responsible for laying out the LayoutObject's content and returning a Vector2 containing its dimensions, which will then be used to position this LayoutObject within the LayoutStack that contains it. GrapicObjects and TextBoxes automatically perform these functions internally without the need for this callback... Set this value to customize the process of laying out this SceneObject's content, and/or determining its layout width/height.





LayoutObject.refreshLayoutCallbackArgs
[type: any] 
Parameters for the function that will be called automatically to refresh the layout of this LayoutObject and determine its layout dimensions. This function is responsible for laying out the LayoutObject's content and returning a Vector2 containing its dimensions, which will then be used to position this LayoutObject within the LayoutStack that contains it. GrapicObjects and TextBoxes automatically perform these functions internally without the need for this callback... Set this value to customize the process of laying out this SceneObject's content, and/or determining its layout width/height.





LayoutObject.layoutLazyUpdater
[type: LazyUpdater] 
The LazyUpdater in charge of laying out the contents of the SceneObject that owns this LayoutObject.





LayoutObject.informParentsOfLayoutChange()
[type: function] 
Informs the containing LayoutStack of a change in this LayoutObject's dimensions, telling the LayoutStack that it will need to refresh its Layout. Call this function whenever a custom LayoutObject's dimensions change.





LayoutObject.addSecondaryLayoutCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds an optional callback that occurs after this LayoutObject's layout is refreshed. This callback can be used to perform further actions that use the new layout after it is updated. It should be noted that this callback will not affect the width or height of this LayoutObject, it is only meant to be used for 'additonal styling' of the layout object using the updated layout.

LayoutObject.addSecondaryLayoutCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs after this LayoutObject's layout is refreshed

LayoutObject.addSecondaryLayoutCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs after this LayoutObject's layout is refreshed

LayoutObject.addSecondaryLayoutCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered after this LayoutObject's layout is refreshed





LayoutObject.removeSecondaryLayoutCallback(callbackOwner, callbackName)
[type: function] 
Removes the given secondaryLayout callback.

LayoutObject.removeSecondaryLayoutCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

LayoutObject.removeSecondaryLayoutCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.










----------------------------------------------------------
Section 61: ParticleSystemDefinition
----------------------------------------------------------


ParticleSystemDefinition
[type: class] [NON-INSTANTIABLE] [requires: module - particleSystems] 
A ParticleSystemDefinition defines the parameters of a ParticleSystem. To decrease the memory needed and time required to instantiate multiple ParticleSystems that use the same parameters, a single definition is created that one or more ParticleSystems then reference.





ParticleSystemDefinition.type
[type: string] 
Type identifier.





ParticleSystemDefinition.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





ParticleSystemDefinition.emissionDuration
[type: number] 
The length of time over which to emit particles. Set to 0 to emit particles forever. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.particleLifetime
[type: number] 
The amount of time after its emission that each particle dies. Must not be a negative number. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.particleLifetimeRandomness
[type: number] 
A per particle perturbation of particleLifetime. Each particle chooses a random amount, limited to ± this value, to add to the base value. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.emissionTimeRandomness
[type: number] 
A per particle perturbation of that particle's emission time. By default, particles are emitted at evenly spaced intervals. A random number between 0 and this value will added to the default emission time of each particle. Must not be a negative number. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.alpha
[type: number, string, ParticleSystemRamp1] 
The alpha (transparency) to apply to each particle. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.alphaRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'alpha'. Each particle chooses a random amount, limited to ± this value, to modify the alpha. For example, if the value is .2, each particle generates a random number in the range [.8 - 1.2] to multiply with 'alpha' and generate its own unique version of 'alpha'. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.color
[type: Vector3, string, ParticleSystemRamp3] 
The color to apply to each particle. This may be set to a Vector3 to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp3 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.brightnessRandomness
[type: number, string, ParticleSystemRamp3] 
A per particle perturbation of 'color'. Each particle chooses a random amount, limited to ± this value, to modify the color. For example, if the value is .2, each particle generates a random number in the range [.8 - 1.2] to multiply with 'color' and generate its own unique version of 'color'. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp3 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.particleHueShift
[type: number, string, ParticleSystemRamp1] 
The amount to hue shift each particle. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.particleparticleHueShiftRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'particleHueShift'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.emitterShape
[type: string] 
The shape of the area in which a particle may be created. See nc.constants.particleSystemEmitterShapes for valid values. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.customEmitterShapeExpression
[type: string] 
If emitterShape is set to nc.constants.particleSystemEmitterShapes.Custom, this expression will be used to choose a position for each emitted particle. Note that precomputed random numbers are available as vec4s named rand0 through rand5, though typically rand2.x and rand2.y are used in this context. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.emitterShapeDimensions
[type: Vector2, string, ParticleSystemRamp2] 
The dimensions of the emitter shape. Use different values for X and Y to create oblong shapes. This may be set to a Vector2 to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp2 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.emissionVelocity
[type: Vector2, string, ParticleSystemRamp2] 
The velocity with which particles are emitted away from their initial position. The magnitude of this vector indicates the initial speed of the particles. Note that 'emissionConeAngle' causes particles to emit in a cone centered around this direction. This may be set to a Vector2 to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp2 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.emissionVelocityRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of the magnitude of 'emissionVelocity'. Each particle chooses a random amount, limited to ± this value, to modify the magnitude of 'emissionVelocity'. For example, if the value is .2, each particle generates a random number in the range [.8 - 1.2] to multiply with 'emissionVelocity' and generate its own unique version of 'emissionVelocity'. Thus, particles are emitted with varying velocities. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.emissionConeAngle
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of the angle of 'emissionVelocity'. Each particle chooses a random amount, limited to ± half of this value in degrees, to modify the angle of 'emissionVelocity'. For example, if the value is 90 degrees, each particle will generate a unique version of 'emissionVelocity' randomly placed within ±45 degrees of 'emissionVelocity'. Thus, particles are emitted in a 90 degree cone. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.emitterPosition
[type: Vector2, string, ParticleSystemRamp2] 
The position with respect to the ParticleSystem's origin from which to emit particles. Note that when moving the ParticleSystem SceneObject itself, particles previoiusly emitted are also moved, which can look unnatural. By expressiong the emitter position as an expression or ParticleSystemRamp2, the ParticleSystem is able to maintain the trajectories of previously emitted particles while the emitter moves. This may be set to a Vector2 to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp2 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.force
[type: Vector2, string, ParticleSystemRamp2] 
The force constantly applied to each particle. Commonly used to simulate gravity. This may be set to a Vector2 to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp2 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.forceRandomness
[type: number, string, ParticleSystemRamp2] 
A per particle perturbation of 'force'. Each particle chooses a random amount, limited to ± this value, to modify the force. For example, if the value is .2, each particle generates a random number in the range [.8 - 1.2] to multiply with 'force' and generate its own unique version of 'force'. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp2 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.extraVelocityX
[type: number, string, ParticleSystemRamp1] 
An extra amount always added to the X component of each particle's velocity. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.extraVelocityXRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'extraVelocityX'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization. Second line





ParticleSystemDefinition.extraVelocityY
[type: number, string, ParticleSystemRamp1] 
An extra amount always added to the Y component of each particle's velocity. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.extraVelocityYRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'extraVelocityY'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.motionStretch
[type: number, string, ParticleSystemRamp1] 
The amount by which to stretch each particle in the direction in which is is moving. Particles that are moving faster stretch further. This is typically used as a high performance approximation of motion blur. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.motionStretchAlphaInfluence
[type: number, string, ParticleSystemRamp1] 
The amount by which a particle's stretch, as caused by 'motionStretch', reduces its alpha. This is typically used as a high performance approximation of motion blur. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.ageRemap
[type: string] 
An expression used to remap particle age values to a new value. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.rotationSpeed
[type: number, string, ParticleSystemRamp1] 
The speed at which each particle rotates, in degrees per second. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.rotationSpeedRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'rotationSpeed'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.initialRotation
[type: number, string, ParticleSystemRamp1] 
The rotation in degrees of each particle when it is emitted. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.initialRotationRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'initialRotation'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.rotationSwayStrength
[type: number, string, ParticleSystemRamp1] 
The maximum rotation, in degrees, that a particle will reach by oscillating its rotation. Note that this is additively combined with the result of 'rotationSpeed'. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.rotationSwayStrengthRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'rotationSwayStrength'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.rotationSwaySpeed
[type: number, string, ParticleSystemRamp1] 
The speed at which to oscillate, in cycles/second, if rotationSwayStrength is not 0. Note that this is additively combined with the result of 'rotationSpeed'. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.rotationSwaySpeedRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'rotationSwaySpeed'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.rotationSwayPhase
[type: number, string, ParticleSystemRamp1] 
A phase shift to the oscillation, if rotationSwayStrength is not 0. Effectively skips to a different point in the oscillation pattern. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.rotationSwayPhaseRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'rotationSwayPhase'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.rotationAxis
[type: Vector3, string, ParticleSystemRamp3] 
The 3D axis around which particle rotation will occur. This may be set to a Vector3 to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp3 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.rotationAxisRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'rotationAxis'. Each particle generates a random 3D axis, and interpolates between 'rotationAxis' and the random axis using this value. A value of 0 will therefore cause rotation around 'rotationAxis' and a value of 1 will cause rotation around a random axis. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.wiggleStrengthX
[type: number, string, ParticleSystemRamp1] 
The distance to wiggle the particle in the X direction around the point where it would otherwise be. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.wiggleStrengthXRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'wiggleStrengthX'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.wiggleStrengthY
[type: number, string, ParticleSystemRamp1] 
The distance to wiggle the particle in the Y direction around the point where it would otherwise be. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.wiggleStrengthYRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'wiggleStrengthY'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.wiggleSpeedX
[type: number, string, ParticleSystemRamp1] 
The speed at which to wiggle the particle in the X direction around the point where it would otherwise be. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.wiggleSpeedXRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'wiggleSpeedX'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.wiggleSpeedY
[type: number, string, ParticleSystemRamp1] 
The speed at which to wiggle the particle in the Y direction around the point where it would otherwise be. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.wiggleSpeedYRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of 'wiggleSpeedY'. Each particle chooses a random amount, limited to ± this value, to add to the base value. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.wiggleCircularStrength
[type: number, string, ParticleSystemRamp1] 
Used to constrain wiggling particles to a circle shape. At a 'wiggleCircularStrength' of 0, a particle wiggling eqully on X and Y is allowed to move within the bounds of a square. At a 'wiggleCircularStrength' of 1, a particle wiggling eqully on X and Y is only allowed to move within the bounds of a circle. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.particleScale
[type: Vector2, string, ParticleSystemRamp2] 
The scale to apply to each particle. This may be set to a Vector2 to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp2 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.particleScaleRandomness
[type: number, string, ParticleSystemRamp1] 
A per particle perturbation of the magnitude of 'particleScale'. Each particle chooses a random amount, limited to ± this value, to modify the magnitude of 'particleScale'. For example, if the value is .2, each particle generates a random number in the range [.8 - 1.2] to multiply with 'particleScale' and generate its own unique version of 'particleScale'. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.randomnessDistribution
[type: number, string, ParticleSystemRamp1] 
The amount to bias all random numbers toward the center of their range. Typically ranges from 0 (no bias) to 1 (random numbers from -1 to 1 are squared, pulling them toward 0). However, values outside this range may be used for varying effects. This may be set to a number to apply a constant value, a string to apply a GLSL expression, or a ParticleSystemRamp1 to apply a value that changes based on a particle's age or time of emission. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleSystemDefinition.randomizeOnPlay
[type: boolean] 
This is the default value of randomizeOnPlay for any ParticleSystem instantiated using this ParticleSystemDefinition. Note that the value of randomizeOnPlay for each ParticleSystem instance can then be changed independently. When true, the ParticleSystem will automatically call randomize() each time it is restarted, including when playback loops.





ParticleSystemDefinition.particlePoolCount
[type: number] 
The total number of particles that are required by this ParticleSystemDefinition. Because particles that have 'died' can often be reused as later particles, this number will often be less than the total number seen throughout the ParticleSystem's playback.





ParticleSystemDefinition.effectNodeName
[type: string] 
The name of the EffectNode automatically created by this ParticleSystemDefinition. Useful when altering the EffectNodes of a ParticleSystem, because without this EffectNode applied, the ParticleSystem behavior will be lost.





ParticleSystemDefinition.particleDrawOrderSeed
[type: number] 
When 'graphicAssets' contains multiple GraphicAssets, the draw order of all the particles is shuffled to randomly interleave the particles. This seed will deterministically alter the outcome of this shuffle, creating a different draw order of the particles. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization. To randomize the behavior of a ParticleSystem without this costly rebuild, see ParticleSystem.randomize().





ParticleSystemDefinition.getParticleInfo()
[type: function] [returns: [ParticleInfo]] 
Returns the ParticleInfo objects used to populate the ParticleSystem.





ParticleSystemDefinition.setParticleInfo(particleInfo)
[type: function] 
Sets the ParticleInfo objects used to populate the ParticleSystem.

ParticleSystemDefinition.setParticleInfo parameter: particleInfo
[type: [ParticleInfo], ParticleInfo] 
Array of ParticleInfo objects used to populate the ParticleSystem.










----------------------------------------------------------
Section 62: ParticleSystem
----------------------------------------------------------


ParticleSystem
[type: class] [extends: GraphicObject] [requires: module - particleSystems] 
A ParticleSystem uses the Geometry and EffectNode create by a ParticleSystemDefinition to manage the behavior of many particles contained within a single SceneObject. To reduce the number of SceneObjects, all particles in a single ParticleSystem are merged into one SceneObject and their behavior is controlled by the EffectNode created by the ParticleSystemDefinition.





ParticleSystem.type
[type: string] 
Type identifier.





ParticleSystem.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





ParticleSystem.definition
[type: ParticleSystemDefinition] 
Dictionary object listing all of the types this object is compatible with.





ParticleSystem.playbackController
[type: PlaybackController] 
The PlaybackController managing the ParticleSystem's playback.





ParticleSystem.randomize()
[type: function] 
Randomly picks a new value for the material's particleSystemRandomSeed EffectController, which seeds the random number generation used in the ParticleSystem's EffectNode. The particleSystemRandomSeed EffectController can also be directly set to a desired value. Suggested values are in the range [0, 10].





ParticleSystem.stopEmitting(disableAfterParticlesDie)
[type: function] 
Forces the ParticleSystem to stop creating new particles. Previously emitted particles will not be affected and will be allowed to proceed to the end of their life. Commonly used to dynamically decide the duration of a ParticleSystem that is emitting infinitely, but can also stop a ParticleSystem with a known duration early.

ParticleSystem.stopEmitting parameter: disableAfterParticlesDie
[type: boolean] 
If true, the ParticleSystem will be automatically disabled at the latest possible time one of the existing particles could die.




























































































































































































































































































































































































----------------------------------------------------------
Section 63: ParticleSystemRamp
----------------------------------------------------------


ParticleSystemRamp
[type: class] [NON-INSTANTIABLE] [requires: module - particleSystems] 






ParticleSystemRamp.inputType
[type: string] 
The input type used when evaluating. See nc.particleSystemRampInputTypes for valid values.





ParticleSystemRamp.inputMaximum
[type: number] 
When using inputType equal to 'EmissionTime', the emission time is divided by this number and the fractional component of the result is used to look up a value in the ramp. This means that particles emitted after this time will use values that wrap around to the beginning of the ramp. When using a non-infinite emissionDuration, it is common to set this value to emissionDuration + emissionTimeRandomness so that the ramp applies over the duration of the particle emission.





ParticleSystemRamp.interpolationType
[type: string] 
The type of interpolation to apply between the keyframes. See nc.constants.particleSystemRampInterpolationTypes for valid values.





ParticleSystemRamp.type
[type: string] 
Type identifier.





ParticleSystemRamp.refreshKeyframeOrder()
[type: function] 
Refreshes the order of the keyframes, ensuring they are stored in order of increasing time.





ParticleSystemRamp.removeKeyframe(x)
[type: function] 
Removes the keyframe with the given time value.

ParticleSystemRamp.removeKeyframe parameter: x
[type: number] 
The time value of the keyframe to remove. If no such keyframe exists, nothing is removed.










----------------------------------------------------------
Section 64: ParticleSystemRamp1
----------------------------------------------------------


ParticleSystemRamp1
[type: class] [requires: module - particleSystems] 
Object representing keyframes with number values used by ParticleSystemDefinition members.





ParticleSystemRamp1.values
[type: Array] 
Array of keyframes representing the ramp. Each keyframe is specified as an array with two elements. The first element must be a number representing the time of the keyframe. Ramp evaluations are performed in the range 0-1, but keyframes may specify times outside this range. The second element must be a number.]





ParticleSystemRamp1.addKeyframe(x, y)
[type: function] 
Adds a new keyframe. If a keyframe already exists at this time value, it is overwritten.

ParticleSystemRamp1.addKeyframe parameter: x
[type: number] 
The time value for this keyframe.

ParticleSystemRamp1.addKeyframe parameter: y
[type: number] 
The value stored at this keyframe.





ParticleSystemRamp1.isEqual(particleSystemRamp1)
[type: function] [returns: boolean] 
Tests whether another ParticleSystemRamp1 has identical contents to this ParticleSystemRamp1.

ParticleSystemRamp1.isEqual parameter: particleSystemRamp1
[type: ParticleSystemRamp1] 
The ParticleSystemRamp1 to compare to.










----------------------------------------------------------
Section 65: ParticleSystemRamp2
----------------------------------------------------------


ParticleSystemRamp2
[type: class] [extends: ParticleSystemRamp] [requires: module - particleSystems] 
Object representing keyframes with Vector2 values used by ParticleSystemDefinition members.





ParticleSystemRamp2.values
[type: Array] 
Array of keyframes representing the ramp. Each keyframe is specified as an array with two elements. The first element must be a number representing the time of the keyframe. Ramp evaluations are performed in the range 0-1, but keyframes may specify times outside this range. The second element must be a Vector2.]





ParticleSystemRamp2.addKeyframe(x, y)
[type: function] 
Adds a new keyframe. If a keyframe already exists at this time value, it is overwritten.

ParticleSystemRamp2.addKeyframe parameter: x
[type: number] 
The time value for this keyframe.

ParticleSystemRamp2.addKeyframe parameter: y
[type: Vector2] 
The value stored at this keyframe.





ParticleSystemRamp2.isEqual(particleSystemRamp2)
[type: function] [returns: boolean] 
Tests whether another ParticleSystemRamp2 has identical contents to this ParticleSystemRamp2.

ParticleSystemRamp2.isEqual parameter: particleSystemRamp2
[type: ParticleSystemRamp2] 
The ParticleSystemRamp2 to compare to.








































----------------------------------------------------------
Section 66: ParticleSystemRamp3
----------------------------------------------------------


ParticleSystemRamp3
[type: class] [extends: ParticleSystemRamp] [requires: module - particleSystems] 
Object representing keyframes with Vector3 values used by ParticleSystemDefinition members.





ParticleSystemRamp3.values
[type: Array] 
Array of keyframes representing the ramp. Each keyframe is specified as an array with two elements. The first element must be a number representing the time of the keyframe. Ramp evaluations are performed in the range 0-1, but keyframes may specify times outside this range. The second element must be a Vector3.]





ParticleSystemRamp3.addKeyframe(x, y)
[type: function] 
Adds a new keyframe. If a keyframe already exists at this time value, it is overwritten.

ParticleSystemRamp3.addKeyframe parameter: x
[type: number] 
The time value for this keyframe.

ParticleSystemRamp3.addKeyframe parameter: y
[type: Vector3] 
The value stored at this keyframe.





ParticleSystemRamp3.isEqual(particleSystemRamp3)
[type: function] [returns: boolean] 
Tests whether another ParticleSystemRamp3 has identical contents to this ParticleSystemRamp3.

ParticleSystemRamp3.isEqual parameter: particleSystemRamp3
[type: ParticleSystemRamp3] 
The ParticleSystemRamp3 to compare to.








































----------------------------------------------------------
Section 67: ParticleSystemRamp4
----------------------------------------------------------


ParticleSystemRamp4
[type: class] [extends: ParticleSystemRamp] [requires: module - particleSystems] 
Object representing keyframes with Vector4 values used by ParticleSystemDefinition members.





ParticleSystemRamp4.values
[type: Array] 
Array of keyframes representing the ramp. Each keyframe is specified as an array with two elements. The first element must be a number representing the time of the keyframe. Ramp evaluations are performed in the range 0-1, but keyframes may specify times outside this range. The second element must be a Vector4.]





ParticleSystemRamp4.addKeyframe(x, y)
[type: function] 
Adds a new keyframe. If a keyframe already exists at this time value, it is overwritten.

ParticleSystemRamp4.addKeyframe parameter: x
[type: number] 
The time value for this keyframe.

ParticleSystemRamp4.addKeyframe parameter: y
[type: Vector4] 
The value stored at this keyframe.





ParticleSystemRamp4.isEqual(particleSystemRamp4)
[type: function] [returns: boolean] 
Tests whether another ParticleSystemRamp4 has identical contents to this ParticleSystemRamp4.

ParticleSystemRamp4.isEqual parameter: particleSystemRamp4
[type: ParticleSystemRamp4] 
The ParticleSystemRamp4 to compare to.








































----------------------------------------------------------
Section 68: ParticleInfo
----------------------------------------------------------


ParticleInfo
[type: class] [requires: module - particleSystems] 
Object to allow adding graphics to a ParticleSystem with different emission rates and relative scales.





ParticleInfo.graphicAsset
[type: GraphicAsset, string] 
The GraphicAsset to add for this particle. Set this with either a GraphicAsset or the name of one, and it reads back as the GraphicAsset of that name, or as undefined for as long as no GraphicAsset by that name has been defined. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleInfo.particlesPerSecond
[type: number] 
The number of this particle to add ever second of 'emissionDuration'. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleInfo.scale
[type: number] 
The scale to apply to each of these particles. Useful for reusing assets with mismatched scales in the same particle system. Note that changing this value at run time causes a costly rebuild of the particle system and is only recommended during initialization.





ParticleInfo.clone()
[type: function] 
Returns a deep copy of this ParticleInfo instance.










----------------------------------------------------------
Section 69: ParticleSystemDefinitions
----------------------------------------------------------


ParticleSystemDefinitions
[type: class] [NON-INSTANTIABLE] 
Dictionary of all registered ParticleSystemDefinitions. 










----------------------------------------------------------
Section 70: FileIO
----------------------------------------------------------


FileIO
[type: class] [NON-INSTANTIABLE] [requires: module - fileIO] 
Object housing functionality to perform file IO tasks such as 'writeTextFile', 'moveTo', 'createDirectory' an more. Can also be made available in published Electron builds via the 'fileIoElectron' optional module and the Electron auxiliaryPublishingPackage's 'incisorFileIoLayer' option.





FileIO.fileExists(filePath, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Returns an IncrCommsResponseObject with a '.payload' bool stating if the file at the given path exists. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.fileExists parameter: filePath
[type: string] 
This is the relative or absolute path to the file in question.

FileIO.fileExists parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.readTextFile(filePath, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Returns an IncrCommsResponseObject with a '.payload' string containing the contents of the text file at the given path. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.readTextFile parameter: filePath
[type: string] 
The relative or absolute path to the file in question.

FileIO.readTextFile parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.readFileBase64(filePath, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Returns an IncrCommsResponseObject with a '.payload' string containing the contents of the file at the given path in Base64 format. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.readFileBase64 parameter: filePath
[type: string] 
The relative or absolute path to the file in question.

FileIO.readFileBase64 parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.rename(path, newName, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Renames the file or folder at the given path. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.rename parameter: path
[type: string] 
The relative or absolute path to the file in question.

FileIO.rename parameter: newName
[type: string] 
The new name (not including the path) of the item you wish to rename.

FileIO.rename parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.writeTextFile(filePath, fileContent, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Writes text content to a file at the given path. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.writeTextFile parameter: filePath
[type: string] 
The relative or absolute path to the file in question.

FileIO.writeTextFile parameter: fileContent
[type: string] [default: ""] [optional] 
This is the text content that will be written in the file.

FileIO.writeTextFile parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.writeFileFromBase64(filePath, base64, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Writes a file from a base64 string. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.writeFileFromBase64 parameter: filePath
[type: string] 
The relative or absolute path to the file in question.

FileIO.writeFileFromBase64 parameter: base64
[type: string] 
The source base64 string to write the file from.

FileIO.writeFileFromBase64 parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.appendTextFile(filePath, additionalContent, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Appends text content to the text file at the given file path. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.appendTextFile parameter: filePath
[type: string] 
The relative or absolute path to the file in question.

FileIO.appendTextFile parameter: additionalContent
[type: string] 
This is the text content that will be written in the file.

FileIO.appendTextFile parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.directoryExists(directoryPath, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Returns an IncrCommsResponseObject with a '.payload' bool stating if the directory at the given path exists. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.directoryExists parameter: directoryPath
[type: string] 
This is the relative or absolute path to the directory in question.

FileIO.directoryExists parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.getDirectoryContents(directoryPath, isPathRelative, recurseSubdirectories, includeHiddenFiles)
[type: function] [returns: [PathInfo]] 
Returns an IncrCommsResponseObject with a '.payload' array containing the paths to the directories and files within the given directory. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.getDirectoryContents parameter: directoryPath
[type: string] 
This is the relative or absolute path to the directory in question.

FileIO.getDirectoryContents parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

FileIO.getDirectoryContents parameter: recurseSubdirectories
[type: boolean] [default: false] [optional] 
Bool stating if list of paths returned should include all sub-directories.

FileIO.getDirectoryContents parameter: includeHiddenFiles
[type: boolean] [default: false] [optional] 
Bool stating if list of paths returned should include hidden files.





FileIO.createDirectory(directoryPath, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Creates a directory at the given path. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.createDirectory parameter: directoryPath
[type: string] 
The relative or absolute path to the directory in question.

FileIO.createDirectory parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.copyTo(sourcePath, destinationPath, isPathRelative, newName)
[type: function] [returns: IncrCommsResponseObject] 
Copies the provided file or directory into the designated directory, with an option to rename the item while copying. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.copyTo parameter: sourcePath
[type: string] 
The relative or absolute path to the source item.

FileIO.copyTo parameter: destinationPath
[type: string] 
The relative or absolute path for the destination directory.

FileIO.copyTo parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

FileIO.copyTo parameter: newName
[type: string] [default: ""] [optional] 
The new name (not including the path) of the item you wish to rename. If "" is provided, then no rename occurs.





FileIO.moveTo(sourcePath, destinationPath, isPathRelative, newName)
[type: function] [returns: IncrCommsResponseObject] 
Moves the provided file or directory into the designated directory, with an option to rename the item while moving. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.moveTo parameter: sourcePath
[type: string] 
The relative or absolute path to the source item.

FileIO.moveTo parameter: destinationPath
[type: string] 
The relative or absolute path for the destination directory.

FileIO.moveTo parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

FileIO.moveTo parameter: newName
[type: string] [default: ""] [optional] 
The new name (not including the path) of the item you wish to rename. If "" is provided, then no rename occurs.





FileIO.delete(path, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Deletes the provided file or directory it it exists. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.delete parameter: path
[type: string] 
The relative or absolute path of the item to delete.

FileIO.delete parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.compress(sourcePath, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Compresses the given file or directory into a zip file. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.compress parameter: sourcePath
[type: string] 
The relative or absolute path to the file or directory in question. If a directory path is provided, the directory must contain at least one file or an error will be encountered.

FileIO.compress parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.





FileIO.decompress(sourcePath, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Decompresses the zip file at the given path into its source format. If an error is encountered, related information will be stored in the '.error' member of the returned IncrCommsResponseObject. This function is asynchronous and will return a promise if not 'awaited'.

FileIO.decompress parameter: sourcePath
[type: string] 
The relative or absolute path to the file or directory in question.

FileIO.decompress parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.










----------------------------------------------------------
Section 71: IncrCommsResponseObject
----------------------------------------------------------


IncrCommsResponseObject
[type: class] [NON-INSTANTIABLE] 
Standardized Incisor® communications protocol object that is returned from methods that incorporate external functionality. This serves as a 'wrapper' object to the desired return value. This object contains a 'payload' member and an 'error' member. If no issues are encountered during the external portion of the functionality, the desired return value can be found in the 'payload' member, otherwise the 'error' member will contain applicable information about the encountered issues. For example, if nc.fileIO.readTextFile('MyDrive/SomeDirectory/myFile.txt') is successful, then the returned text from the file will be in the 'payload' member of the returned IncrCommsResponseObject object, but if nc.fileIO.readTextFile('MyDrive/SomeDirectoryWithRestrictedAccess/myFile.txt') is unsuccessful, then the 'error' member of the returned IncrCommsResponseObject object may be something 'Could not read file in restricted directory...'. 





IncrCommsResponseObject.payload
[type: any] 
The desired return value from the method that returns this object.





IncrCommsResponseObject.error
[type: string] 
A string containing information about issues/errors/exceptions encountered during the performance of the external functionality that is required by the method that returns this object. If no issues were encountered, this value will default to an empty string.










----------------------------------------------------------
Section 72: PathInfo
----------------------------------------------------------


PathInfo
[type: class] 
Class containing a 'path' and a 'type' (where type is 'file' or 'directory')





PathInfo.path
[type: string] 
The path string.





PathInfo.type
[type: string] 
The type of the item at the given path. Value will either be 'file' or 'directory'.










----------------------------------------------------------
Section 73: UiVisualFocus
----------------------------------------------------------


UiVisualFocus
[type: class] [NON-INSTANTIABLE] [requires: module - extendedUi] 
Object housing functionality that enables for the SceneObject owning it to be 'visually focused', which focuses the end-user's attention the given SceneObject by placing it in front of a dimmer layer whenever the object is the the current 'singularFocusObject'. Calling 'configureUiVisualFocus' populates the 'uiVisualFocus' member for the owning SceneObject. It should be noted that the dimmer layer that the newly focused item is placed in front of is actually a button which, when pressed, calls the 'attemptExitUiVisualFocus' member of the current singularFocusObject if that member is defined.





UiVisualFocus.dispose()
[type: function] 
Disposes this UiVisualFocus, disabling the visual focus functionality for the SceneObject owning it, and freeing the object for garbage collection.










----------------------------------------------------------
Section 74: SceneObject
----------------------------------------------------------


SceneObject
[type: class] 
SceneObjects are the fundamental objects that populate a given project's world/hierarchy. Every object in a Scene's hierarchy inherits from SceneObject.





SceneObject.type
[type: string] 
Type identifier.

example:
// Objective: Determine the type of a SceneObject
// Expected Result: The console should have 3 log messages as follows:
//   MySceneObject is of type SceneObject
//   MyGraphicObject is of type GraphicObject
//   MyButton is of type Button

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Create a GraphicObject using the GraphicObject constructor adding it to "mySceneObject".
let myGraphicObject = new GraphicObject( nc.graphicAssets.WhiteBox, mySceneObject, "MyGraphicObject" );
// Create a Button using the Button constructor and adding it to myGraphicObject.
let myButton = new Button( nc.graphicAssets.WhiteTriangle, myGraphicObject, "MyButton" );

console.log(mySceneObject.name + ' is of type ' + mySceneObject.type);
console.log(myGraphicObject.name + ' is of type ' + myGraphicObject.type);
console.log(myButton.name + ' is of type ' + myButton.type);





SceneObject.inheritedTypes
[type: any] 
Dictionary object listing all of the types this object is compatible with.

example:
// Objective: Determine the inherited types of a Button.
// Expected Result: The console log should read "inherited types {"SceneObject":true,"GraphicObject":true,"Button":true}".

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Add a Button named "MyButton" to the SceneObject.
let myButton = new Button( nc.graphicAssets.WhiteBox, mySceneObject, "MyButton" );
console.log("inherited types", JSON.stringify( myButton.inheritedTypes ) );





SceneObject.name
[type: string] [default: 'SceneObject'] 
The name of the SceneObject.

example:
// Objective: Set and Get the name of a SceneObject.
// Expected Result: The console should have 2 log messages as follows:
//    original name is MySceneObject
//    new name is MyDifferentSceneObject
 
// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
console.log("original name is", mySceneObject.name );
// Update the name of the SceneObject.
mySceneObject.name = "MyDifferentSceneObject";
console.log("new name is", mySceneObject.name );





SceneObject.enabled
[type: boolean] [default: true] 
Boolean determining if this SceneObject is enabled. Enabled SceneObjects are shown normally within the Scene while disabled SceneObjects are not shown. If a SceneObject is disabled, all of its children inherit its disabled state, but if it is enabled all of its childrens' states depend on their own 'enabled' properties.

example:
// Objective: Disable a SceneObject to disable its children.
// Expected Result: You do not see the white box.

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Add a GraphicObject to the SceneObject using the GraphicObject constructor.
new GraphicObject( nc.graphicAssets.WhiteBox, mySceneObject, "WhiteBox" );
// Set mySceneObject to enabled = false.
mySceneObject.enabled = false;





SceneObject.children
[type: [SceneObject]] 
The the array of this SceneObject's children SceneObjects in the hierarchy.

example:
// Objective: Add children to a SceneObject.
// Expected Result: The console log should read "children count 2".

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Add 2 GraphicObjects to the SceneObject using the GraphicObject constructor.
new GraphicObject( nc.graphicAssets.WhiteBox, this.mySceneObject, "WhiteBox" );
new GraphicObject( nc.graphicAssets.WhiteTriangle, this.mySceneObject, "WhiteTriangle" );
console.log("children count", mySceneObject.children.length); 





SceneObject.parent
[type: SceneObject] 
The SceneObject that is this SceneObject's parent in the hierarcy. If this SceneObject is of type 'Scene', this value is left undefined. Set this property to change the parent of this SceneObject, or use 'SceneObject.setParent' to do the same thing but with the 'maintainGlobalPostion' optional parameter.

example:
// Objective: Get the parent of a scene object.
// Expected Result: The console log should read "parent name is MySceneObject".

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Add a GraphicObject to the SceneObject using the GraphicObject constructor.
let myGraphicObject = new GraphicObject( nc.graphicAssets.WhiteBox, this.mySceneObject, "WhiteBox" );
// Console log the parent name of this GraphicObject.
console.log("parent name is", myGraphicObject.parent.name);





SceneObject.containingScene
[type: Scene] 
The Scene in which this SceneObject resides.

example:
// Objective: Determine the containing scene of a SceneObject.
// Expected Result: The console should have 2 log messages as follows:
//    The containing scene for 'MyMainSceneObject' is MainScene
//    The containing scene for 'MyOtherSceneObject' is MyScene

// Create a SceneObject using the SceneObject constructor. This will add "MyMainSceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MyMainSceneObject" );
console.log("The containing scene for 'MyMainSceneObject' is", mySceneObject.containingScene.name);

// Create a new Scene and name it "MyScene".
let myScene = new Scene("MyScene");
// Create a SceneObject using the SceneObject constructor. This will add "MyOtherSceneObject" to myScene ("MyScene").
let myOtherSceneObject = new SceneObject( myScene, "MyOtherSceneObject" );
console.log("The containing scene for 'MyOtherSceneObject' is", myOtherSceneObject.containingScene.name);





SceneObject.position
[type: Vector3] [default: new Vector3(0,0,0)] 
The position of this SceneObject relative to it's parent.

example:
// Objective: Move the position of the "WhiteTriangle" relative to the "WhiteBox".
// Expected Result: The "WhiteTriangle" is 300 world units above and 300 world units to the right of the "WhiteBox".

// Note: To use a custom graphic, add your image file to the assets directory and access it using nc.graphicAssets['MyImage']

// Add a GraphicObject to the main scene using the GraphicObject constructor.
new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "WhiteBox" );
// Add another GraphicObject to the main scene using the GraphicObject constructor, this time using the WhiteTriangle GraphicAsset.
let whiteTriangleGraphicObject =  new GraphicObject( nc.graphicAssets.WhiteTriangle, nc.mainScene, "WhiteTriangle" );
// Update the position of the "WhiteTriangle", moving it 300 world units above and 300 world units to the right of the "WhiteBox".
whiteTriangleGraphicObject.position.x = 300;
whiteTriangleGraphicObject.position.y = 300;





SceneObject.scale
[type: Vector3] [default: new Vector3(1,1,1)] 
The scale of this SceneObject relative to it's parent.

example:
// Objective: Using the scale property, increase the size of a GraphicObject.
// Expected Result: You will see a blue box in the center of the screen and a larger red box, now in the shape of a rectangle, to the right of it.

// Note: To use a custom graphic, add your image file to the assets directory and access it using nc.graphicAssets['MyImage']

// Add a GraphicObject to the main scene using the GraphicObject constructor. 
let blueBox = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "BlueBox" );
// Use fillColor to make it blue.
blueBox.fillColor = new Color( 0, 0, 1, 1 ); // blue

// Add another GraphicObject to the main scene using the GraphicObject constructor.
let redBox = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "RedBox" );
// Use fillColor to make it red.
redBox.fillColor = new Color( 1, 0, 0, 1 ); // red
// Use position to move the red box to the right 500 world units.
redBox.position.x = 500;
// Use scale to make the red box a larger rectangle 
redBox.scale.x = 2;
redBox.scale.y = 4;





SceneObject.rotation
[type: Vector3] [default: new Vector3(0,0,0)] 
The rotation (in degrees) of this SceneObject relative to it's parent. Positive values correspond to counter-clockwise rotation around the given axis.

example:
// Objective: Create a SceneObject with a graphic and rotate it.
// Expected Result: The white box has rotated 45 degrees into a diamond shape.

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Add a GraphicObject to the SceneObject using the GraphicObject constructor.
// Note: To use a custom graphic, add your image file to the assets directory and access it using nc.graphicAssets['MyImage']
new GraphicObject( nc.graphicAssets.WhiteBox, mySceneObject, "MyGraphicObject" );
// Rotate the SceneObject 45 degrees around the z axis.
mySceneObject.rotation.z = 45;





SceneObject.isEnabledWithInheritance
[type: boolean] 
Boolean that reflects if the overall state of this SceneObject is 'enabled', incorporating the state of its anscesters.

example:
// Objective: Use isEnabledWithInheritance to determine the enabled value at various levels of the heirarchy.
// Expected Result: The console should have 2 log messages as follows:
//   Top level scene object, enabled is true
//   Bottom level scene object, enabled is false

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject1" to the SceneObject.
let myGraphicObject1 = new GraphicObject( nc.graphicAssets.WhiteBox, mySceneObject, "GraphicObject1" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject2" to the GraphicObject myGraphicObject1 (GraphicObject1). 
let myGraphicObject2 = new GraphicObject( nc.graphicAssets.WhiteTriangle, myGraphicObject1, "GraphicObject2" );

// Set myGraphicObject1 to enabled = false. ("GraphicObject1").
myGraphicObject1.enabled = false;
// Console log the isEnabledWithInheritance value of the top level SceneObject ("MySceneObject").
console.log("Top level scene object, enabled is", mySceneObject.isEnabledWithInheritance); // true
// Console log the isEnabledWithInheritance value of the bottom level SceneObject ("GraphicObject2").
console.log("Bottom level scene object, enabled is", myGraphicObject2.isEnabledWithInheritance); // false





SceneObject.hierarchyDepth
[type: number] 
Number indicating how many ancesters this SceneObject has.

example:
// Objective: Retrieve the hierarchy depth of a SceneObject.
// Expected Result: The console log should read "myGraphicObject2 hierarchy depth is 3".

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject1" to the SceneObject.
let myGraphicObject1 = new GraphicObject( nc.graphicAssets.WhiteBox, mySceneObject, "GraphicObject1" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject2" to the GraphicObject myGraphicObject1 (GraphicObject1). 
let myGraphicObject2 = new GraphicObject( nc.graphicAssets.WhiteTriangle, myGraphicObject1, "GraphicObject2" );
// Console log the hierarchy depth of myGraphicObject2 ("GraphicObject2").
console.log("myGraphicObject2 hierarchy depth is", myGraphicObject2.hierarchyDepth);





SceneObject.layoutObject
[type: LayoutObject] [NON-INSTANTIABLE] 
Object housing information about this particular SceneObject's LayoutObject functionality. LayoutObject functionality applies to SceneObjects that have been added as elements to a LayoutStack, which is responsible for organizing visual content (TextBoxes, Graphics, Buttons, etc...) into dynamic vertical or horizontal stacks. Until a SceneObject has been configured with LayoutObject functionality (either by calling 'SceneObject.configureLayoutObject' or by adding the SceneObject as an element to a LayoutStack), the 'SceneObject.layoutObject' member will be undefined. 

example:
// Objective: Configure a layout object.
// Expected Result: The console should read "layout object width and height after configuration: 20 10".

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
this.mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );

// Add a callback function.
this.myCallback = function(args) {
    // return a Vector2 with a width of 20 and a height of 10
    return new Vector2( 20, 10 ); 
}

// Add a reference to a callback function passing the owner of the function and the function name.
this.mySceneObject.configureLayoutObject( this, "myCallback" );
console.log('layout object width and height after configuration:', this.mySceneObject.layoutObject.width, this.mySceneObject.layoutObject.height);





SceneObject.uiKeyboardNavigator
[type: UiKeyboardNavigator] [NON-INSTANTIABLE] [requires: module - extendedUi] 
Object housing functionality that enables for keyboard navigation of this SceneObject's ui-related descendants. Keyboard navigation enables the end-user to press the tab, space, and enter keys to outline and trigger any 'uiKeyboardNavigable' descendants of the SceneObject owning this UiKeyboardNavigator when it is 'in focus' according to 'nc.singularFocusObject'. This property defaults to undefined, but can be enabled, by calling 'SceneObject.configureUiKeyboardNavigator()'.





SceneObject.uiKeyboardNavigable
[type: UiKeyboardNavigable] [NON-INSTANTIABLE] [requires: module - extendedUi] 
Object housing functionality that enables for this SceneObject to be accessible via keyboard navigation. Keyboard navigation enables the end-user to press the arrow keys, tab, space, and enter keys to outline and trigger any 'uiKeyboardNavigable' SceneObjects within a UiKeyboardNavigator-enabled parent that is currently 'in focus' according to 'nc.singularFocusObject'. This property defaults to undefined, but can be enabled, by calling 'SceneObject.configureUiKeyboardNavigable()'.





SceneObject.uiVisualFocus
[type: UiVisualFocus] [NON-INSTANTIABLE] [requires: module - extendedUi] 
Object housing functionality that enables for the SceneObject owning it to be 'visually focused', which focuses the end-user's attention the given SceneObject by placing it in front of a dimmer layer whenever the object is the the current 'singularFocusObject'. Calling 'configureUiVisualFocus' populates the 'uiVisualFocus' member for the owning SceneObject. It should be noted that the dimmer layer that the newly focused item is placed in front of is actually a button which, when pressed, calls the 'attemptExitUiVisualFocus' member of the current singularFocusObject if that member is defined.





SceneObject.snapToNearestWorldPosition
[type: boolean] [default: false] 
Flag that determines if this SceneObject's global position is always snapped to the nearest integer (for x and y only). This property is mainly used to help provide pixel-perfect rendering for TextBoxes, see 'TextBox.useNearestPixelRendering' for more information.





SceneObject.focusFallback
[type: SceneObject] [default: nc.defaultFocusFallback] 
Sets up a 'focus fallback' for this SceneObject. Once set, if 'nc.relinquishFocus' is called while this SceneObject is focused, then the fallback object will automatically become the new focused object.





SceneObject.customAddOns
[type: dictionary] 
A dictionary of the CustomAddOns included on a given SceneObject. It should be noted that by default, each of the CustomAddOns are undefined, and that their member will be populated once they are added to a SceneObject in the Incisor inspector or directly through code.





SceneObject.customObjectDefinition
[type: CustomObjectDefinition] [default: undefined] 
A reference to the CustomObjectDefinition associated with this SceneObject's class. This property is only present on instances of classes that have been registered as CustomObjects via 'nc.registerCustomObject'. For all other SceneObjects it will be undefined. It is set automatically on the class prototype at registration time, so all instances of a given CustomObject class share the same reference.





SceneObject.excludeChildrenFromBlueprint
[type: boolean] [default: false] 
Flag that determines if this SceneObject's children will be ignored during any 'gatherObjectBlueprint' calls. This flag should be set to true for objects that dynamically generate their own children objects so that those children are not mistakenly duplicated when a blueprint is used to reproduce a collection of objects. This flag general defaults to false, except with Construct instances and TextAssemblies, since those obects produce their own children on the fly. You would also want to set this flag to true if you are making a CustomObject that produces it's own children or a CustomAddOn that produces children within its owner.





SceneObject.localMatrix
[type: Matrix4] [default: Matrix4()] 
Matrx4 representing the transformation of this SceneObject with respect to its parent. If 'localMatrixOverrideMode' is false, this is automatically calculated based on the position, rotation, and scale of the SceneObject.





SceneObject.worldMatrix
[type: Matrix4] [default: Matrix4()] 
Matrx4 representing the transformation of the SceneObject with respect to the Scene that contains it. If 'worldMatrixOverrideMode' is false, this is automatically calculated by multiplying this SceneObject's parent's worldMatrix by this SceneObject's localMatrix. Because the same calculation is done for all ancestors, this Matrix4 accumulates the transformations of all ancestor SceneObjects.





SceneObject.localMatrixOverrideMode
[type: boolean] [default: false] 
If true, this SceneObejct's localMatrix will no longer be automatically be updated to reflect the SceneObejct's position, rotation, and scale. This is useful if the localMatrix is being calculated manually, so automatic updates are undesired.





SceneObject.worldMatrixOverrideMode
[type: boolean] [default: false] 
If true, this SceneObejct's worldMatrix will no longer be automatically be updated to reflect the transformations of itself and its ancestors. This is useful if the worldMatrix is being calculated manually, so automatic updates would interfere.





SceneObject.isDisposed
[type: boolean] [default: undefined] 
Flag indicating if this SceneObject has been disposed. If the SceneObject has not been disposed, this property will be undefined.





SceneObject.fillColor
[type: Color] 
The EffectController for the 'FillColor' EffectNode, which entirely fills the associated Geometry with the red, green, blue, and alpha color values provided. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





SceneObject.colorMultiply
[type: Color] 
The EffectController for the 'ColorMultiply' EffectNode, which multiplies the red, green, blue, and alpha color values of the Material it is applied to. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





SceneObject.shapify
[type: shapify] 
The EffectController for the 'Shapify' EffectNode. The Shapify EffectNode converts edge data stored in a 'shapified' Texture into a presentable image with edges that stay sharp regardless of the scale of the associated GraphicObject. This is an instance of a dynamically defined EffectController with base type 'Vector2'. To get a new instance, use "nc.effectControllers['shapify'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





SceneObject.shear
[type: shear] 
EffectController for the Shear EffectNode, which distorts the shape to appear slanted or skewed. This is an instance of a dynamically defined EffectController with base type 'Vector3'. To get a new instance, use "nc.effectControllers['shear'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





SceneObject.shear_center
[type: Vector2] 
EffectController for the Shear EffectNode, which distorts the shape to appear slanted or skewed. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





SceneObject.enable()
[type: function] 
Sets this SceneObject's 'enabled' value to true.

example:
// Objective: Call enable() on a previously disabled SceneObject.
// Expected Result: The console should have 2 log messages as follows:
//    enabled state is false
//    enabled state is true

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
this.mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );

// Add a callback function.
this.myCallback = function(args) {
    console.log('enabled state is', args);
}

// Add a reference to a callback function passing the owner of the function and the function name.
this.mySceneObject.addEnabledStateChangeCallback( this, "myCallback" );
// Set the enabled state of mySceneObject to false.
this.mySceneObject.enabled = false;
// Call enable() on mySceneObject. This will fire an enabled state change callback.
this.mySceneObject.enable();





SceneObject.disable()
[type: function] 
Sets this SceneObject's 'enabled' value to false.

example:
// Objective: Call disable() on a previously enabled SceneObject.
// Expected Result: The console should read "enabled state is false".

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
this.mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );

// Add a callback function.
this.myCallback = function(args) {
    console.log('enabled state is', args);
}

// Add a reference to a callback function passing the owner of the function and the function name.
this.mySceneObject.addEnabledStateChangeCallback( this, "myCallback" );
// By default, the SceneObject is already enabled. Call disable() on mySceneObject. This will fire an enabled state change callback.
this.mySceneObject.disable();





SceneObject.addEnabledStateChangeCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback function to the list of callbacks that occur whenever the state of this SceneObject's 'enabled' property changes. The true/false enabled state is sent to the callback as its first paremeter, followed by any 'callbackArgs' provided.

SceneObject.addEnabledStateChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that is called when this SceneObject's enabled state changes.

SceneObject.addEnabledStateChangeCallback parameter: callbackName
[type: string] 
The name of the function that is called when this SceneObject's enabled state changes.

SceneObject.addEnabledStateChangeCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when this SceneObject's enabled state changes.

example:
// Objective: Add an 'Enabled State Change' callback.
// Expected Result: The console should have 2 log messages as follows:
//    enabled state is false
//    enabled state is true

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
this.mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );

// Add a callback function.
this.myCallback = function(args) {
   console.log('enabled state is', args);
}

// Add a reference to a callback function passing the owner of the function and the function name.
this.mySceneObject.addEnabledStateChangeCallback( this, "myCallback" );
// Set mySceneObject to enabled = false. This will fire an enabled state change callback.
this.mySceneObject.enabled = false;
// Set mySceneObject to enabled = true. This will fire an enabled state change callback.
this.mySceneObject.enabled = true;





SceneObject.addUiZoomCallback(callbackOwner, callbackName, callbackArgs, additionalCallbackOrder)
[type: function] 
Adds a callback for when this SceneObject encounters a change in uiZoom. This is similar to adding a callback to the general uiZoomChange AppEvent, but with the added benefit that these callbacks happen in hierarchy-depth order from greatest to least. This means that callbacks associated with an object having 7 ancestors will occur before that of an object with 2 ancestors. This hierarchy-depth sorting enables layout changes to happen in a way that works better with LazyUpdaters. The nc.uiZoom.totalZoom value is sent to the callback as its first paremeter, followed by any 'callbackArgs' provided.

SceneObject.addUiZoomCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that is called upon uiZoom change.

SceneObject.addUiZoomCallback parameter: callbackName
[type: string] 
The name of the function that is called upon uiZoom change.

SceneObject.addUiZoomCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called upon uiZoom change.

SceneObject.addUiZoomCallback parameter: additionalCallbackOrder
[type: number] [default: 0] [optional] 
An additional sorting value affecting when this callback will happen relative to other such callbacks associated with this SceneObject.





SceneObject.removeUiZoomCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

SceneObject.removeUiZoomCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

SceneObject.removeUiZoomCallback parameter: callbackName
[type: string] 
The name of the function.





SceneObject.removeEnabledStateChangeCallback(callbackOwner, callbackName)
[type: function] 
Removes an 'enabledStateChange' callback.

SceneObject.removeEnabledStateChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function to remove.

SceneObject.removeEnabledStateChangeCallback parameter: callbackName
[type: string] 
The name of the callback function to remove.

example:
// Objective: Add an 'Enabled State Change' callback.
// Expected Result: The console should have 2 log messages as follows:
//    enabled state is false
//    enabled state is true

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
this.mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );

// Add a callback function.
this.myCallback = function(args) {
    console.log('enabled state is', args);
}

// Add a reference to a callback function passing the owner of the function and the function name.
this.mySceneObject.addEnabledStateChangeCallback( this, "myCallback" );
// Set mySceneObject to enabled = false. This will fire an enabled state change callback.
this.mySceneObject.enabled = false;
// Set mySceneObject to enabled = true. This will fire an enabled state change callback.
this.mySceneObject.enabled = true;
// Remove the reference to a callback function passing the owner of the function and the function name.
this.mySceneObject.removeEnabledStateChangeCallback( this, "myCallback" );
// Set mySceneObject to enabled = false. This will NO LONGER fire an enabled state change callback and no console message will be logged.
this.mySceneObject.enabled = false;





SceneObject.dispose()
[type: function] 
Removes this SceneObject and its descendants from the hierarchy, and removes internal Incisor® references to aid memory management.

example:
// Objective: Call dispose() on a SceneObject.
// Expected Result: The console should have 2 log messages as follows:
//    descendants before disposal 3
//    after wait descendants after disposal 1 

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject1" to the SceneObject.
let myGraphicObject1 = new GraphicObject( nc.graphicAssets.WhiteBox, mySceneObject, "GraphicObject1" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject2" to myGraphicObject1.
let myGraphicObject2 = new GraphicObject( nc.graphicAssets.WhiteTriangle, myGraphicObject1, "GraphicObject2" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject3" to myGraphicObject2.
let myGraphicObject3 = new GraphicObject( nc.graphicAssets.WhiteTriangle, myGraphicObject2, "GraphicObject3" );

// Log the number of descendants of mySceneObject before calling dispose().
console.log( "descendants before disposal", mySceneObject.getDescendants().length );
// Call dispose() on myGraphicObject2.
myGraphicObject2.dispose();

// The call to dispose() can take some time to complete so lets wait 2 seconds before we log again.

// Create a callback function to log the descendants after calling dispose().
this.myWait = function() {
    console.log( "after wait descendants after disposal", mySceneObject.getDescendants().length );
}
// Using nc.WaitThen, wait 2 seconds before attempting to log the descendants again.
nc.waitThen( 2, this, "myWait" );





SceneObject.addDisposalCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback function to the list of callbacks that occur when this SceneObject is disposed.

SceneObject.addDisposalCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that is called when this SceneObject is disposed.

SceneObject.addDisposalCallback parameter: callbackName
[type: string] 
The name of the function that is called when this SceneObject is disposed.

SceneObject.addDisposalCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when this SceneObject is disposed.

example:
// Objective: Add a 'Disposal' callback.
// Expected Result: The console should read "disposal callback: myDisposalData".

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
this.mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );

// Add a callback function.
this.myCallback = function(args) {
   console.log('disposal callback:', args);
}

// Add a reference to a callback function passing the owner of the function, the function name, and any additional data we want.
this.mySceneObject.addDisposalCallback( this, "myCallback", ["myDisposalData"] );
// Call dispose() on mySceneObject. This will fire a disposal callback.
this.mySceneObject.dispose();





SceneObject.removeDisposalCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback function from the list of callbacks that occur when this SceneObject is disposed.

SceneObject.removeDisposalCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that is called when this SceneObject is disposed.

SceneObject.removeDisposalCallback parameter: callbackName
[type: string] 
The name of the function that is called when this SceneObject is disposed.





SceneObject.addRenderCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback function to the list of callbacks that occur when this SceneObject is 'rendered'.

SceneObject.addRenderCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that is called when this SceneObject is rendered.

SceneObject.addRenderCallback parameter: callbackName
[type: string] 
The name of the function that is called when this SceneObject is rendered.

SceneObject.addRenderCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when this SceneObject is rendered.





SceneObject.removeRenderCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback function.

SceneObject.removeRenderCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

SceneObject.removeRenderCallback parameter: callbackName
[type: string] 
The name of the function.





SceneObject.setParent(parent, maintainGlobalPosition)
[type: function] 
Makes this SceneObject the child of the given SceneObject in the hierachy.

SceneObject.setParent parameter: parent
[type: SceneObject] 
The SceneObject that will become this SceneObject's new parent.

SceneObject.setParent parameter: maintainGlobalPosition
[type: boolean] [default: false] [optional] 
Boolean determining if the global position, scale, and rotation should be preserved during the change in hierarchy. Note that this preservation is not always possible during a parent change.

example:
// Objective: Set the parent of a SceneObject
// Expected Result: The console should have 2 log messages as follows:
//    GraphicObjectChild's parent is GraphicObjectA
//    GraphicObjectChild's parent is now GraphicObjectB

// Create a GraphicObject using the GraphicObject constructor. Name it "GraphicObjectA".
let graphicObjectA = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "GraphicObjectA" );
// Create a second GraphicObject using the GraphicObject constructor. Name it "GraphicObjectB".
let graphicObjectB = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "GraphicObjectB" );
// Create a third GraphicObject using the GraphicObject constructor. This time, make its parent graphicObjectA. Name it "GraphicObjectChild".
let graphicObjectChild = new GraphicObject( nc.graphicAssets.WhiteBox, graphicObjectA, "GraphicObjectChild" );
// Console log the parent.
console.log("GraphicObjectChild's parent is", graphicObjectChild.parent.name);
// Set the parent to graphicObjectB.
graphicObjectChild.setParent( graphicObjectB );
// Console log the parent.
console.log("GraphicObjectChild's parent is now", graphicObjectChild.parent.name);





SceneObject.getAncestors()
[type: function] [returns: [SceneObject]] 
Returns a list of this SceneObject's ancesters.

example:
// Objective: Get the ancestors of a SceneObject.
// Expected Result: The console should have 2 log messages as follows:
//    myGraphicObject3 ancestors count 4
//    myGraphicObject1 ancestors count 2

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject1" to the SceneObject.
let myGraphicObject1 = new GraphicObject( nc.graphicAssets.WhiteBox, mySceneObject, "GraphicObject1" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject2" to the GraphicObject myGraphicObject1 (GraphicObject1). 
let myGraphicObject2 = new GraphicObject( nc.graphicAssets.WhiteTriangle, myGraphicObject1, "GraphicObject2" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject3" to the GraphicObject myGraphicObject2 (GraphicObject2). 
let myGraphicObject3 = new GraphicObject( nc.graphicAssets.WhiteTriangle, myGraphicObject2, "GraphicObject3" );
// Console log the ancestors count.
console.log( "myGraphicObject3 ancestors count", myGraphicObject3.getAncestors().length );
console.log( "myGraphicObject1 ancestors count", myGraphicObject1.getAncestors().length );





SceneObject.getDescendants(enabledOnly, includeEnclosedScenes)
[type: function] [returns: [SceneObject]] 
Returns a list of this SceneObject's descendants.

SceneObject.getDescendants parameter: enabledOnly
[type: boolean] [default: true] [optional] 
Boolean determining if only enabled SceneObjects are added to the returned list.

SceneObject.getDescendants parameter: includeEnclosedScenes
[type: boolean] [default: false] [optional] 
Boolean determining if sub-descendants of ScrollingPanels' Scenes will be included in the returned list.

example:
// Objective: Get the descendants of a SceneObject.
// Expected Result: The console should have 2 log messages as follows:
//    myGraphicObject3 descendants count 0
//    myGraphicObject1 descendants count 2

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject1" to the SceneObject.
let myGraphicObject1 = new GraphicObject( nc.graphicAssets.WhiteBox, mySceneObject, "GraphicObject1" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject2" to the GraphicObject myGraphicObject1 (GraphicObject1). 
let myGraphicObject2 = new GraphicObject( nc.graphicAssets.WhiteTriangle, myGraphicObject1, "GraphicObject2" );
// Using the GraphicObject constructor, add a GraphicObject named "GraphicObject3" to the GraphicObject myGraphicObject2 (GraphicObject2). 
let myGraphicObject3 = new GraphicObject( nc.graphicAssets.WhiteTriangle, myGraphicObject2, "GraphicObject3" );
// Console log the descendants count.
console.log( "myGraphicObject3 descendants count", myGraphicObject3.getDescendants().length );
console.log( "myGraphicObject1 descendants count", myGraphicObject1.getDescendants().length );





SceneObject.getGlobalPosition(returnVector3)
[type: function] [returns: Vector3] 
Returns a Vector3 with the global position of this SceneObject within the Scene.

SceneObject.getGlobalPosition parameter: returnVector3
[type: Vector3] [optional] 
Optional Vector3 that can be supplied to avoid the generation of a new Vector3 object for efficiency.

example:
// Objective: Get the global position of a SceneObject.
// Expected Result: 'InnerSceneObject' global position x,y 200 200

// Create a new Scene and name it "MyScene".
let myScene = new Scene("MyScene");
// Create a SceneObject using the SceneObject constructor. This will add "OuterSceneObject" to "MyScene".
let outerSceneObject = new SceneObject( myScene, "OuterSceneObject" );
// Create a SceneObject using the SceneObject constructor. This will add "InnerSceneObject" to "OuterSceneObject".
let innerSceneObject = new SceneObject( outerSceneObject, "InnerSceneObject" );
// Update the position of the outerSceneObject, moving it up and to the right, 100 world units.
outerSceneObject.position.x = 100;
outerSceneObject.position.y = 100;   
// Update the position of the innerSceneObject, moving it up and to the right, 100 world units.
innerSceneObject.position.x = 100;
innerSceneObject.position.y = 100;  
// Console log the x and y of mySceneObject using getGlobalPosition(). 
console.log( "'InnerSceneObject' global position x,y", innerSceneObject.getGlobalPosition().x, innerSceneObject.getGlobalPosition().y );





SceneObject.swoopGlobalPosition(endValues, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl)
[type: function] [returns: Swooper] 
Swoops this SceneObject's position using global coordinates.

SceneObject.swoopGlobalPosition parameter: endValues
[type: [number]] 
The array of target global position values [x,y,z].

SceneObject.swoopGlobalPosition parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation in seconds.

SceneObject.swoopGlobalPosition parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

SceneObject.swoopGlobalPosition parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

SceneObject.swoopGlobalPosition parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

SceneObject.swoopGlobalPosition parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

SceneObject.swoopGlobalPosition parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

SceneObject.swoopGlobalPosition parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

example:
// Objective: "Swoop" the position of the white box.
// Expected Result: The white box moves up and to the right, 300 world units, over a duration of 10 seconds.
 
// Add a GraphicObject to the main scene using the GraphicObject constructor.  
let whiteBox = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "WhiteBox" );
// Call swoopGlobalPosition() giving it the array of x,y,z values to swoop to over a duration of 10 seconds.
whiteBox.swoopGlobalPosition( [300,300,0], 10 );





SceneObject.getGlobalScale(returnVector3)
[type: function] [returns: Vector3] 
Returns a Vector3 with the global scale of this SceneObject within the Scene.

SceneObject.getGlobalScale parameter: returnVector3
[type: Vector3] [optional] 
Optional Vector3 that can be supplied to avoid the generation of a new Vector3 object for efficiency.

example:
// Objective: Get the global scale of a SceneObject.
// Expected Result: The console should read "scale x,y 2 2.
   
// Add a GraphicObject to the main scene using the GraphicObject constructor. 
let whiteBox = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "WhiteBox" );
// Use scale to make the "WhiteBox" twice as large
whiteBox.scale.x = 2;
whiteBox.scale.y = 2;

console.log( "scale x,y", whiteBox.getGlobalScale().x, whiteBox.getGlobalScale().y );





SceneObject.swoopGlobalScale(endValues, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl)
[type: function] [returns: Swooper] 
Swoops this SceneObject's scale using global coordinates.

SceneObject.swoopGlobalScale parameter: endValues
[type: [number]] 
The array of target global scale values [x,y,z].

SceneObject.swoopGlobalScale parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

SceneObject.swoopGlobalScale parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

SceneObject.swoopGlobalScale parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

SceneObject.swoopGlobalScale parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

SceneObject.swoopGlobalScale parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

SceneObject.swoopGlobalScale parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

SceneObject.swoopGlobalScale parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

example:
// Objective: "Swoop" the scale of the white box.
// Expected Result: The white box expands to 5 times its original size over a duration of 10 seconds.
  
// Add a GraphicObject to the main scene using the GraphicObject constructor.  
let whiteBox = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "WhiteBox" );
// Call swoopGlobalScale() giving it the array of x,y,z values to expand to over a duration of 10 seconds.
whiteBox.swoopGlobalScale( [5,5,0], 10 );





SceneObject.getViewPosition(camera, returnVector3)
[type: function] [returns: Vector3] 
Returns a Vector3 containing the coordinates for this SceneObject within the given Camera's view area. The camera's view area bounds are confined to x within [-.5, .5] and y within [-.5, .5] where -.5 corresponds to left and bottom.

SceneObject.getViewPosition parameter: camera
[type: Camera] [default: nc.mainCamera] 
The Camera to 'look through' when obtaining the view position of this SceneObject.

SceneObject.getViewPosition parameter: returnVector3
[type: Vector3] [optional] 
Optional Vector3 that can be supplied to avoid the generation of a new Vector3 object for efficiency.

example:
// Objective: Get the view position of a SceneObject within a Camera's view area
// Expected Result: The console should have 2 log messages that look something like the following:
//    'MyGraphicObject' view position x,y 0.030978934324659233 0
//    'MyGraphicObject' view position x,y 0.061957868649318466 0
//
// NOTE: Because view position is relative to the Camera's view area, your x value will depend on the resolution of your screen. 
//       Try resizing your screen and running the test again. You will notice your x value has changed.
//

// Using the GraphicObject constructor, add a GraphicObject named "MyGraphicObject" to the main scene
let myGraphicObject = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "MyGraphicObject" );
// Update the x position of myGraphicObject, moving it to the right 100 world units.
myGraphicObject.position.x = 100;
// Console log the x and y of "MyGraphicObject" using getViewPosition(). 
console.log( "'MyGraphicObject' view position x,y", myGraphicObject.getViewPosition().x, myGraphicObject.getViewPosition().y );
// Update the x position of myGraphicObject again, moving it to the right 200 world units.
myGraphicObject.position.x = 200;
// Console log the x and y of "MyGraphicObject" using getViewPosition(). 
console.log( "'MyGraphicObject' view position x,y", myGraphicObject.getViewPosition().x, myGraphicObject.getViewPosition().y );





SceneObject.getGlobalRotation(returnVector3)
[type: function] [returns: Vector3] 
Returns a Vector3 with the global rotation of this SceneObject within the Scene.

SceneObject.getGlobalRotation parameter: returnVector3
[type: Vector3] [optional] 
Optional Vector3 that can be supplied to avoid the generation of a new Vector3 object for efficiency.





SceneObject.swoopGlobalRotation(endValues, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl)
[type: function] [returns: Swooper] 
Swoops this SceneObject's rotation using global coordinates.

SceneObject.swoopGlobalRotation parameter: endValues
[type: [number]] 
The array of target global scale values [x,y,z].

SceneObject.swoopGlobalRotation parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

SceneObject.swoopGlobalRotation parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

SceneObject.swoopGlobalRotation parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

SceneObject.swoopGlobalRotation parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

SceneObject.swoopGlobalRotation parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

SceneObject.swoopGlobalRotation parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

SceneObject.swoopGlobalRotation parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.





SceneObject.setEffectNodes(effectNodes, alsoSetDescendants)
[type: function] 
Sets the EffectNodes for the Materials associated with this SceneObject.  EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. Each EffectNode can be manipulated dynamically by one or more EffectControllers, which are accessable as direct members of the given SceneObject or Material. When a GraphicObject is set to a particular GraphicAsset, it's Materials adopt the GraphicAsset's EffectNode and EffectController presets by default, but they can be customized at any time.

SceneObject.setEffectNodes parameter: effectNodes
[type: [EffectNode], EffectNode] 
The new list of EffectNodes that will apply to the Materials associated with this SceneObject.

SceneObject.setEffectNodes parameter: alsoSetDescendants
[type: boolean] [default: true] [optional] 
Boolean determining if this SceneObject's descendants' Materials will also adopt the provided list of EffectNodes.





SceneObject.addEffectNodes(effectNodes, alsoAddToDescendants)
[type: function] 
Adds the given EffectNodes to the Materials associated with this SceneObject. EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. Each EffectNode can be manipulated dynamically by one or more EffectControllers, which are accessable as direct members of the given SceneObject or Material. When a GraphicObject is set to a particular GraphicAsset, it's Materials adopt the GraphicAsset's EffectNode and EffectController presets by default, but they can be customized at any time.

SceneObject.addEffectNodes parameter: effectNodes
[type: [EffectNode], EffectNode] 
The EffectNodes to add to this SceneObject and its Materials.

SceneObject.addEffectNodes parameter: alsoAddToDescendants
[type: boolean] [default: true] [optional] 
Boolean determining if the given EffectNodes will also be added to the SceneObject's descendants' Materials.





SceneObject.setLayers(layer, sceneObjectList)
[type: function] 
Sets the Layers of all of the GraphicObject descendants of this SceneObject to the supplied Layer.

SceneObject.setLayers parameter: layer
[type: Layer] 
The layer to change this SceneObject's descendants to.

SceneObject.setLayers parameter: sceneObjectList
[type: [SceneObject]] [optional] 
Optional list designating exactly which decendants to set the layers for. If left undefined, all GraphicObject descendants' layers will be updated.

example:
// Objective: Swap the position of GraphicObjects using setLayers().
// Action: Click the white triangle Button to swap the layering of the red and white boxes.
// Expected Result: Upon clicking the white triangle Button, the red and white boxes will swap positions.

// Start by creating 2 different GraphicObjects, red and white.
let redBox = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "RedBox" );
redBox.fillColor = new Color( 1,0,0,1 ); // make the white box red

let whiteBox = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "WhiteBox" );
// Offset the White Box, 25 world units, down and to the right.
whiteBox.position.x = 25;
whiteBox.position.y = -25;

// Define a new Layer named "LayerA" and set the red box to "LayerA".
nc.defineLayer( "LayerA", nc.mainScene );
redBox.layer = nc.layers.LayerA;
// Define a new Layer named "LayerB" and set the white box to "LayerB".
nc.defineLayer( "LayerB", nc.mainScene );
whiteBox.layer = nc.layers.LayerB;

// Using the nc factory method, create a white triangle button to handle the action of swapping layers.
let button = nc.addButton( nc.graphicAssets.WhiteTriangle, nc.mainScene, "MyButton" );
button.position.x = -120; // offset the button to the left
// Add a button callback function.
this.mySwapCallback = function(args) {
    // Swap the red and white Layers of the boxes.
    if ( redBox.layer === nc.layers.LayerA ) {
        redBox.setLayers( nc.layers.LayerB );
        whiteBox.setLayers( nc.layers.LayerA );
    } else {
        redBox.setLayers( nc.layers.LayerA );
        whiteBox.setLayers( nc.layers.LayerB );
    }
}
// Add a reference to a callback function passing the owner of the function and the function name.
button.addReleaseCallback( this, "mySwapCallback" );





SceneObject.setSubLayers(subLayer, sceneObjectList)
[type: function] 
Sets the SubLayer values of all of the GraphicObject descendants of this SceneObject to the supplied subLayer value.

SceneObject.setSubLayers parameter: subLayer
[type: Layer] 
The subLayer to change this SceneObject's descendants to.

SceneObject.setSubLayers parameter: sceneObjectList
[type: [SceneObject]] [optional] 
Optional list designating exactly which decendants to set the layers for. If left undefined, all GraphicObject descendants' layers will be updated.





SceneObject.configureLayoutObject(refreshLayoutCallbackOwner, refreshLayoutCallbackName, refreshLayoutCallbackArgs)
[type: function] 
Function to configure the SceneObject with LayoutObject functionality, which prepares it to be added as an element to a LayoutStack. Once configured, the configuration information can be found (and adjusted if necessary) in the SceneObject.layoutObject. Most SceneObject-inheriting objects have standard LayoutObject functionality that is automatically configured when they are added as elements to a LayoutStack, so this method is mainly for creating custom LayoutObject functionality. Configuration consists of supplying a callback to a user-defined function that refreshes the layout of the SceneObject in question and returns a Vector2 containing the resulting dimensions.

SceneObject.configureLayoutObject parameter: refreshLayoutCallbackOwner
[type: object] 
The object owning the callback function that is called by the LayoutStack containing this LayoutObject when the layout is refreshed.

SceneObject.configureLayoutObject parameter: refreshLayoutCallbackName
[type: string] 
The name of the callback function that is called by the LayoutStack containing this LayoutObject when the layout is refreshed.

SceneObject.configureLayoutObject parameter: refreshLayoutCallbackArgs
[type: Array, any] 
Arguments for the callback function that is called by the LayoutStack containing this LayoutObject when the layout is refreshed.

example:
// Objective: Configure a layout object.
// Expected Result: The console should read "layout object width and height after configuration: 20 10".

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
this.mySceneObject = new SceneObject( nc.mainScene, "MySceneObject" );

// Add a callback function.
this.myCallback = function(args) {
    // return a Vector2 with a width of 20 and a height of 10
    return new Vector2( 20, 10 ); 
}

// Add a reference to a callback function passing the owner of the function and the function name.
this.mySceneObject.configureLayoutObject( this, "myCallback" );
console.log('layout object width and height after configuration:', this.mySceneObject.layoutObject.width, this.mySceneObject.layoutObject.height);





SceneObject.configureUiKeyboardNavigator()
[type: function] 
Function to configure the SceneObject with UiKeyboardNavigator functionality, which enables the end-user to press the tab, space, and enter keys to outline and trigger any 'uiKeyboardNavigable' descendants of the SceneObject owning this UiKeyboardNavigator when it is 'in focus' according to 'nc.singularFocusObject'. Calling 'configureUiKeyboardNavigator' populates the 'uiKeyboardNavigator' member for the owning SceneObject.





SceneObject.configureUiKeyboardNavigable(setOutlineCallbackOwner, setOutlineCallbackName, triggerCallbackOwner, triggerCallbackName)
[type: function] 
Function to configure the SceneObject with UiKeyboardNavigable functionality, which enables the end-user access the SceneObject using keyboard navigation.  Calling 'configureUiKeyboardNavigable' populates the 'uiKeyboardNavigable' member for the owning SceneObject.

SceneObject.configureUiKeyboardNavigable parameter: setOutlineCallbackOwner
[type: object] 
The owner of the callback that occurs whenever keyboard navigation changes the 'outline' state of the UiKeyboardNavigable object. The outline state will be sent to the callback as its first parameter.

SceneObject.configureUiKeyboardNavigable parameter: setOutlineCallbackName
[type: string] 
The name of the callback that occurs whenever keyboard navigation changes the 'outline' state of the UiKeyboardNavigable object. The outline state will be sent to the callback as its first parameter.

SceneObject.configureUiKeyboardNavigable parameter: triggerCallbackOwner
[type: object] 
The owner of the callback that occurs whenever keyboard navigation triggers the UiKeyboardNavigable object via the spacebar or enter keys.

SceneObject.configureUiKeyboardNavigable parameter: triggerCallbackName
[type: string] 
The name of the callback that occurs whenever keyboard navigation triggers the UiKeyboardNavigable object via the spacebar or enter keys





SceneObject.configureUiVisualFocus()
[type: function] 
Function to configure the SceneObject with UiVisualFocus functionality, which focuses the end-user's attention on the given SceneObject by placing it in front of a dimmer layer whenever the object is the the current 'singularFocusObject'. Calling 'configureUiVisualFocus' populates the 'uiVisualFocus' member for the owning SceneObject. It should be noted that the dimmer layer that the newly focused item is placed in front of is actually a button which, when pressed, calls the 'attemptExitUiVisualFocus' member of the current singularFocusObject if that member is defined.





SceneObject.updateWorldMatrix(updateAncestors, updateDescendants)
[type: function] 
The worldMatrix is normally updated during scene traversal for rendering. If an updated worldMatrix is needed before then, this function forces the worldMatrix to be updated.

SceneObject.updateWorldMatrix parameter: updateAncestors
[type: boolean] [default: false] [optional] 
If true, the world matrices of all ancestors whose 'worldMatrixOverrideMode' is false will first be updated. This is useful if the worldMatrix is being updated to account for an ancestor's transformation changing.

SceneObject.updateWorldMatrix parameter: updateDescendants
[type: boolean] [default: false] [optional] 
If true, the world matrices of all descendants whose 'worldMatrixOverrideMode' is false with also be updated. This is useful if the world matrices of descendants need to immediately account for this SceneObejct's updated worldMatrix.










----------------------------------------------------------
Section 75: EffectNode
----------------------------------------------------------


EffectNode
[type: class] [NON-INSTANTIABLE] 
EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. Each EffectNode can be manipulated dynamically by one or more EffectControllers, which are accessable as direct members of the given SceneObject or Material. When a GraphicObject is set to a particular GraphicAsset, it's Materials adopt the GraphicAsset's EffectNode and EffectController presets by default, but they can be customized at any time. Ultimately, the EffectNodes on any given Material are compiled and determine the final GLSL code that comprises the associated shader for WebGL to use when rendering the associated surface. 





EffectNode.type
[type: string] 
Type identifier





EffectNode.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





EffectNode.name
[type: string] 
The EffectContoller's name. This must be unique among EffectControllers.





EffectNode.description
[type: string] [default: ""] 
An optional human-readable description of what this EffectNode does, shown in the inspector tooltip.





EffectNode.vertexNodeSupport
[type: [string], string] 
The portion of the GLSL shader code for this EffectNode above the 'vertex main'. This segment of code is where uniform and varying variables for the vertex portion of this effect are likely to be declared. Support components between EffectNodes are consolidated, so if a segment of code will be used in more than on EffectNode, be sure to provide it as its own distinct array entry in each EffectNode.





EffectNode.vertexNode
[type: string] 
The portion of the GLSL shader code for this EffectNode within the 'vertex main'. This segment of code is where this effect can make its adjustments to the 'vertex' vec3.





EffectNode.fragmentNodeSupport
[type: [string], string] 
The portion of the GLSL shader code for this EffectNode above the 'fragment main'. This segment of code is where uniform and varying variables for the fragment portion of this effect are likely to be declared. Support components between EffectNodes are consolidated, so if a segment of code will be used in more than on EffectNode, be sure to provide it as its own distinct array entry in each EffectNode.





EffectNode.fragmentNode
[type: string] 
The portion of the GLSL shader code for this EffectNode within the 'fragment main'. This segment of code is where this effect can make its adjustments to the 'fragment' vec4.





EffectNode.requiresDerivativesShaderExtension
[type: boolean] 
Boolean determining if the shader of any Material with this EffectNode is compiled to support the 'Derivatives' extension.





EffectNode.requiresFragDepthShaderExtension
[type: boolean] 
Boolean determining if the shader of any Material with this EffectNode is compiled to support the 'FragDepth' extension.





EffectNode.requiresDrawBuffersShaderExtension
[type: boolean] 
Boolean determining if the shader of any Material with this EffectNode is compiled to support the 'DrawBuffers' extension.





EffectNode.requiresTextureLODShaderExtension
[type: boolean] 
Boolean determining if the shader of any Material with this EffectNode is compiled to support the 'TextureLOD' extension.





EffectNode.getAssociatedEffectControllers()
[type: function] [returns: [string]] 
Returns the list of EffectControllers that are associated with this EffectNode.





EffectNode.setAssociatedEffectControllers(effectControllers)
[type: function] 
Updates the list of EffectControllers associated with this EffectNode.

EffectNode.setAssociatedEffectControllers parameter: effectControllers
[type: [string]] 
An array of the EffectControllers that this EffectNode is associated with. The associated EffectControllers will be the means of dynamic manipulation for this EffectNode's visual effects. See 'nc.effectControllers' for a list of available EffectControllers.










----------------------------------------------------------
Section 76: Button
----------------------------------------------------------


Button
[type: class] [extends: GraphicObject] 
Buttons are specialized GraphicObjects that can provide callbacks for cursor interactions. Buttons adhere to layering - only the frontmost Button receives cursor input. To clip a Button's cursor input with a MaskGroup, make the Button masked and make the mask a Button as well. A mask that is a plain GraphicObject clips what is drawn but leaves the masked Button with no input at all.





Button.buttonActive
[type: boolean] [default: true] 
Flag that determines if this Button responds to cursor interaction. If false, this Button acts no differently than a GraphicObject.





Button.rolloverFlag
[type: boolean] 
Flag that reports if the cursor is currently directly over this Button. It should be noted that Buttons adhere to layering - only the frontmost active Button receives input.





Button.buttonDown
[type: boolean] 
Flag that reports if the Button is currently being 'pressed'.





Button.pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] 
The PauseEvent or Array of PauseEvents that this Button will be immune to. Set the value to [] to create callbacks with no immunity. This property defaults to the value currently in nc.defaultPauseImmunity, which can be changed at any time.





Button.addCursorMoveCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback for when the cursor is moved over this Button.

Button.addCursorMoveCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addCursorMoveCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addCursorMoveCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, and the viewing Camera will automatically be prepended to this list of arguments, so the callback implementation must be written to receive those as its first two parameters.

example:
// Objective: Add a CursorMoveCallback to a Button.
// Action: Move your mouse pointer in and out of the white box.
// Expected Result: As you move your mouse pointer inside the box it will flash different colors.
 
// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Add a reference to a callback function passing the owner of the function and the function name.
this.button.addCursorMoveCallback( this, "myCallback", ["myArgs0", "myArgs1"] );

// Add a callback function. Your first 2 parameters will always be the browser event and the camera.
this.myCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.red   = Math.random();
    this.button.fillColor.blue  = Math.random();
    this.button.fillColor.green = Math.random();
}





Button.removeCursorMoveCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when the cursor is moved over this Button.

Button.removeCursorMoveCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removeCursorMoveCallback parameter: callbackName
[type: string] 
The name of the callback function.





Button.simulateCursorMoveCallback(simulatedEvent, simulatedCamera)
[type: function] 
Manually triggers the 'cursorMove' callback for this Button.

Button.simulateCursorMoveCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulateCursorMoveCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.





Button.addCursorInCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback for when the cursor is moved into this Button's bounds.

Button.addCursorInCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addCursorInCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addCursorInCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, and the viewing Camera will automatically be prepended to this list of arguments, so the callback implementation must be written to receive those as its first two parameters.

example:
// Objective: Add a CursorInCallback and CursorOutCallback to a Button.
// Action: Move your mouse pointer in and out of the box.
// Expected Result: When you move your mouse pointer into the box, the box becomes blue. When you move it out, it will become red.
 
// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Add a reference to a callback function passing the owner of the function and the function name.
this.button.addCursorInCallback( this, "myInCallback", ["myArgs0", "myArgs1"] );
this.button.addCursorOutCallback( this, "myOutCallback", ["myArgs0", "myArgs1", "myArgs2"] );

// Add callback functions. Your first 2 parameters will always be the browser event and the camera.
this.myInCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.red   = 0;
    this.button.fillColor.blue  = 1;
    this.button.fillColor.green = 0;
}
this.myOutCallback = function( event, camera, callbackArgs0, callbackArgs1, callbackArgs2 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1, callbackArgs2);
    this.button.fillColor.red   = 1;
    this.button.fillColor.blue  = 0;
    this.button.fillColor.green = 0;
}





Button.removeCursorInCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when the cursor is moved into this Button's bounds.

Button.removeCursorInCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removeCursorInCallback parameter: callbackName
[type: string] 
The name of the callback function.

example:
// Objective: Remove a CursorInCallback from a Button.
// Actions: 
// 1. Move your mouse pointer in and out of the white box.
// 1. Expected Result: The console should read "action: mousemove" each time your mouse enters the white box.

// 2. Click the white triangle to remove the CursorInCallback.
// 2. Expected Result: Upon clicking the white triangle, the console should read "removing the callback". Moving the mouse in and out of the white box no longer generates any console messages
  
// Create a button to use to remove the callback. Use the WhiteTriangle GraphicAsset.
this.removeCallbackButton = nc.addButton( nc.graphicAssets.WhiteTriangle, nc.mainScene, "RemoveCallbackButton" );
// Move the white triangle to the right 200 world units.
this.removeCallbackButton.position.x = 200;
// Create a callback function that handles the click of the white triangle and executes removeCursorInCallback() 
this.myRemovePressCallback = function(args) {
    console.log('removing the callback');
    // Inside this press callback, remove the CursorInCallback
    this.button.removeCursorInCallback( this, "myActionCallback" );
}
// Add the PressCallback to handle the clicking of the white triangle
this.removeCallbackButton.addPressCallback( this, "myRemovePressCallback" );

// Create a button using the "nc" factory method.
this.button = nc.addButton( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );

// Create a callback function.
this.myActionCallback = function(args) {
    console.log('action:', args.type);
}

// Add a CursorInCallback
this.button.addCursorInCallback( this, "myActionCallback" );





Button.simulateCursorInCallback(simulatedEvent, simulatedCamera)
[type: function] 
Manually triggers the 'cursorIn' callback for this Button.

Button.simulateCursorInCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulateCursorInCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.





Button.addCursorOutCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback for when the cursor is moved out of this Button's bounds.

Button.addCursorOutCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addCursorOutCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addCursorOutCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, and the viewing Camera will automatically be prepended to this list of arguments, so the callback implementation must be written to receive those as its first two parameters.

example:
// Objective: Add a CursorInCallback and CursorOutCallback to a Button.
// Action: Move your mouse pointer in and out of the box.
// Expected Result: When you move your mouse pointer into the box, the box becomes blue. When you move it out, it will become red.
 
// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Add a reference to a callback function passing the owner of the function and the function name.
this.button.addCursorInCallback( this, "myInCallback", ["myArgs0", "myArgs1"] );
this.button.addCursorOutCallback( this, "myOutCallback", ["myArgs0", "myArgs1", "myArgs2"] );

// Add callback functions. Your first 2 parameters will always be the browser event and the camera.
this.myInCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.red   = 0;
    this.button.fillColor.blue  = 1;
    this.button.fillColor.green = 0;
}
this.myOutCallback = function( event, camera, callbackArgs0, callbackArgs1, callbackArgs2 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1, callbackArgs2);
    this.button.fillColor.red   = 1;
    this.button.fillColor.blue  = 0;
    this.button.fillColor.green = 0;
}





Button.removeCursorOutCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when the cursor is moved out of this Button's bounds.

Button.removeCursorOutCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removeCursorOutCallback parameter: callbackName
[type: string] 
The name of the callback function.





Button.simulateCursorOutCallback(simulatedEvent, simulatedCamera)
[type: function] 
Manually triggers the 'cursorOut' callback for this Button.

Button.simulateCursorOutCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulateCursorOutCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.





Button.addDragCallback(callbackOwner, callbackName, callbackArgs, allowInOutAndMove, requireDragInitiationThreshold)
[type: function] 
Adds a callback for when this Button is dragged.

Button.addDragCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addDragCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addDragCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, and the viewing Camera will automatically be prepended to this list of arguments, so the callback implementation must be written to receive those as its first two parameters.

Button.addDragCallback parameter: allowInOutAndMove
[type: boolean] [default: false] [optional] 
Boolean determining if other buttons will receive cursorIn, cursorOut, and cursorMove events while this Button is being dragged.

Button.addDragCallback parameter: requireDragInitiationThreshold
[type: boolean] [default: true] [optional] 
Boolean determining if the cursor must be dragged by a minimum threshold before 'drag' callbacks start to happen. See 'Camera.mouseDragInitiationThreshold' and 'Camera.touchDragInitiationThreshold' for more information.

example:
// Objective: Add a DragCallback and a DropCallback to a Button.
// Action: Drag the box.
// Expected Result: As you are dragging the box it will be white. When you drop it, it will turn red.
 
// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Add callbacks, passing the owner of the function and the function name.
this.button.addDragCallback( this, "myDragCallback", ["myArgs0", "myArgs1"] );
this.button.addDropCallback( this, "myDropCallback", ["myArgs0", "myArgs1"] );

// Add both callback functions. Your first 2 parameters will always be the browser event and the camera.
this.myDragCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('drag callback:', event.type, camera.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.green = 1;
    this.button.fillColor.blue = 1;
    this.button.position.x = nc.mainCamera.getCursorPosition().x;
    this.button.position.y = nc.mainCamera.getCursorPosition().y;
}
// Your first 2 parameters will always be the browser event and the camera. For a DropCallback you will receive 2 additional arguments, the dragged button and the button being dropped onto. 
this.myDropCallback = function( event, camera, draggedButton, dropTargetButton, callbackArgs0, callbackArgs1 ) {
    console.log('drop callback:', event.type, camera.name, draggedButton.name, dropTargetButton.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.green = 0;
    this.button.fillColor.blue = 0;
}





Button.removeDragCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when this Button is dragged.

Button.removeDragCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removeDragCallback parameter: callbackName
[type: string] 
The name of the callback function.





Button.simulateDragCallback(simulatedEvent, simulatedCamera)
[type: function] 
Manually triggers the 'drag' callback for this Button.

Button.simulateDragCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulateDragCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.





Button.addDropCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback for when this Button is dropped (after being dragged). Please note that the Button must have a drag callback in order for any drop callbacks to occur.

Button.addDropCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addDropCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addDropCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, the viewing Camera, the dragged Button, and the Button being dropped onto (if any) will automatically be prepended to this list of arguments, so the callback implementation must plan to receive those as its first four parameters.

example:
// Objective: Add a DragCallback and a DropCallback to a Button.
// Action: Drag the box.
// Expected Result: As you are dragging the box it will be white. When you drop it, it will turn red.
 
// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Add callbacks, passing the owner of the function and the function name.
this.button.addDragCallback( this, "myDragCallback", ["myArgs0", "myArgs1"] );
this.button.addDropCallback( this, "myDropCallback", ["myArgs0", "myArgs1"] );

// Add both callback functions. Your first 2 parameters will always be the browser event and the camera.
this.myDragCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('drag callback:', event.type, camera.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.green = 1;
    this.button.fillColor.blue = 1;
    this.button.position.x = nc.mainCamera.getCursorPosition().x;
    this.button.position.y = nc.mainCamera.getCursorPosition().y;
}
// Your first 2 parameters will always be the browser event and the camera. For a DropCallback you will receive 2 additional arguments, the dragged button and the button being dropped onto. 
this.myDropCallback = function( event, camera, draggedButton, dropTargetButton, callbackArgs0, callbackArgs1 ) {
    console.log('drop callback:', event.type, camera.name, draggedButton.name, dropTargetButton.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.green = 0;
    this.button.fillColor.blue = 0;
}





Button.removeDropCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when this Button is dropped (after being dragged).

Button.removeDropCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removeDropCallback parameter: callbackName
[type: string] 
The name of the callback function.





Button.simulateDropCallback(simulatedEvent, simulatedCamera, simulatedDropRecipient)
[type: function] 
Manually triggers the 'drop' callback for this Button.

Button.simulateDropCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulateDropCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.

Button.simulateDropCallback parameter: simulatedDropRecipient
[type: Button] [optional] 
Button acting as the Button that is being dropped onto.





Button.addPressCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback for when this Button is pressed down.

Button.addPressCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addPressCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addPressCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, and the viewing Camera will automatically be prepended to this list of arguments, so the callback implementation must be written to receive those as its first two parameters.

example:
// Objective: Add a PressCallback and a ReleaseCallback to a Button.
// Action: Press and release the button to change its color.
// Expected Result: Each time you are pressing the button it will be red. When you release it, it will turn back to green.

// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Initially, make the button green.
this.button.fillColor.red = 0;
this.button.fillColor.blue = 0;
// Add callbacks, passing the owner of the function and the function name.
this.button.addPressCallback( this, "myPressCallback", ["myArgs0", "myArgs1"] );
this.button.addReleaseCallback( this, "myReleaseCallback", ["myArgs0", "myArgs1"] );

// Add callback functions. Your first 2 parameters will always be the browser event and the camera.
this.myPressCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.red   = 1;
    this.button.fillColor.green = 0;
}
this.myReleaseCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.red   = 0;
    this.button.fillColor.green = 1;
}





Button.removePressCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when this Button is pressed down.

Button.removePressCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removePressCallback parameter: callbackName
[type: string] 
The name of the callback function.





Button.simulatePressCallback(simulatedEvent, simulatedCamera)
[type: function] 
Manually triggers the 'press' callback for this Button.

Button.simulatePressCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulatePressCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.





Button.addReleaseCallback(callbackOwner, callbackName, callbackArgs, releaseRequiresInitialPress)
[type: function] 
Adds a callback for when this Button is released.

Button.addReleaseCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addReleaseCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addReleaseCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, and the viewing Camera will automatically be prepended to this list of arguments, so the callback implementation must be written to receive those as its first two parameters.

Button.addReleaseCallback parameter: releaseRequiresInitialPress
[type: boolean] [default: true] [optional] 
If true, the Button must be pressed before being released in order for the callback to occur.

example:
// Objective: Add a PressCallback and a ReleaseCallback to a Button.
// Action: Press and release the button to change its color.
// Expected Result: Each time you are pressing the button it will be red. When you release it, it will turn back to green.

// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Initially, make the button green.
this.button.fillColor.red = 0;
this.button.fillColor.blue = 0;
// Add callbacks, passing the owner of the function and the function name.
this.button.addPressCallback( this, "myPressCallback", ["myArgs0", "myArgs1"] );
this.button.addReleaseCallback( this, "myReleaseCallback", ["myArgs0", "myArgs1"] );

// Add callback functions. Your first 2 parameters will always be the browser event and the camera.
this.myPressCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.red   = 1;
    this.button.fillColor.green = 0;
}
this.myReleaseCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1);
    this.button.fillColor.red   = 0;
    this.button.fillColor.green = 1;
}





Button.removeReleaseCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when this Button is released.

Button.removeReleaseCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removeReleaseCallback parameter: callbackName
[type: string] 
The name of the callback function.





Button.simulateReleaseCallback(simulatedEvent, simulatedCamera)
[type: function] 
Manually triggers the 'release' callback for this Button.

Button.simulateReleaseCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulateReleaseCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.





Button.addDoubleTapCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback for when this Button is tapped twice in fast succession. See 'nc.multiTapInterval' to adjust the multi-tap speed.

Button.addDoubleTapCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addDoubleTapCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addDoubleTapCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, and the viewing Camera will automatically be prepended to this list of arguments, so the callback implementation must be written to receive those as its first two parameters.

example:
// Objective: Add a DoubleTapCallback to a Button.
// Action: Double tap the box.
// Expected Result: Each time you double tap the box it expands to 4 times its original size or contracts back to its original size.
 
// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Add a callback, passing the owner of the function and the function name.
this.button.addDoubleTapCallback( this, "myCallback", ["myArgs0", "myArgs1"] );
  
// Add a callback function. Your first 2 parameters will always be the browser event and the camera.
this.myCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1);

    if ( this.button.scale.x == 1 ) {
        this.button.scale.x = 4;
        this.button.scale.y = 4;
    } else {
        this.button.scale.x = 1;
        this.button.scale.y = 1;
    }
 }





Button.removeDoubleTapCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when this Button is tapped twice in fast succession.

Button.removeDoubleTapCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removeDoubleTapCallback parameter: callbackName
[type: string] 
The name of the callback function.





Button.simulateDoubleTapCallback(simulatedEvent, simulatedCamera)
[type: function] 
Manually triggers the 'doubleTap' callback for this Button.

Button.simulateDoubleTapCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulateDoubleTapCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.





Button.addTripleTapCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback for when this Button is tapped three times in fast succession. See 'nc.multiTapInterval' to adjust the multi-tap speed.

Button.addTripleTapCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addTripleTapCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addTripleTapCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, and the viewing Camera will automatically be prepended to this list of arguments, so the callback implementation must be written to receive those as its first two parameters.

example:
// Objective: Add a TripleTapCallback to a Button.
// Action: Triple tap the box.
// Expected Result: Each time you triple tap the box it expands to 4 times its original size or contracts back to its original size.
 
// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Add a callback, passing the owner of the function and the function name.
this.button.addTripleTapCallback( this, "myCallback", ["myArgs0", "myArgs1"] );
  
// Add a callback function. Your first 2 parameters will always be the browser event and the camera.
this.myCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1);

    if ( this.button.scale.x == 1 ) {
        this.button.scale.x = 4;
        this.button.scale.y = 4;
    } else {
        this.button.scale.x = 1;
        this.button.scale.y = 1;
    }
 }





Button.removeTripleTapCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when this Button is tapped three times in fast succession.

Button.removeTripleTapCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removeTripleTapCallback parameter: callbackName
[type: string] 
The name of the callback function.





Button.simulateTripleTapCallback(simulatedEvent, simulatedCamera)
[type: function] 
Manually triggers the 'tripleTap' callback for this Button.

Button.simulateTripleTapCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulateTripleTapCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.





Button.addScrollCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback for when the cursor 'scroll' occurs over this Button. Invoke the 'preventDefault' method on the event sent to the callback to prevent browser-level scrolling functionality.

Button.addScrollCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addScrollCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addScrollCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, and the viewing Camera will automatically be prepended to this list of arguments, so the callback implementation must be written to receive those as its first two parameters.

example:
// Objective: Add a ScrollCallback to a Button.
// Action: Mouse wheel up and down over the white box.
// Expected Result: As you mouse wheel up, the box expands. As you wheel down, it contacts.

// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Add a callback, passing the owner of the function and the function name.
this.button.addScrollCallback( this, "myCallback", ["myArgs0", "myArgs1"] );

// Add a callback function. Your first 2 parameters will always be the browser event and the camera.
this.myCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
    console.log('callback:', event.name, camera.name, callbackArgs0, callbackArgs1);
    
    // Use the event to get the delta of the mouse wheel
    if ( event.wheelDelta > 0 ) {
        // "zoom in" no greater than 5 x original size
        if ( this.button.scale.x <= 5 ) {
           this.button.scale.x = this.button.scale.x + .1;
           this.button.scale.y = this.button.scale.y + .1;
        }    
    } else {
        // zoom out no smaller than .05 original size
        if ( this.button.scale.x >= 0.5 ) {
            this.button.scale.x = this.button.scale.x - .1;
            this.button.scale.y = this.button.scale.y - .1;
        }    
    }
}





Button.removeScrollCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when the cursor 'scroll' occurs over this Button.

Button.removeScrollCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removeScrollCallback parameter: callbackName
[type: string] 
The name of the callback function.





Button.simulateScrollCallback(simulatedEvent, simulatedCamera)
[type: function] 
Manually triggers the 'scroll' callback for this Button.

Button.simulateScrollCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulateScrollCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.





Button.addContextMenuCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback for when the in-browser context menu is activated over this Button. Invoke the 'preventDefault' method on the event sent to the callback to prevent built-in browser context menu from appearing.

Button.addContextMenuCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.addContextMenuCallback parameter: callbackName
[type: string] 
The name of the callback function.

Button.addContextMenuCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the callback-triggering browser-generated event, and the viewing Camera will automatically be prepended to this list of arguments, so the callback implementation must be written to receive those as its first two parameters.

example:
// Objective: Add a ContextMenuCallback to a Button.
// Action: Bring the mouse into the white box and right click your mouse.
// Expected Result: The console should read "callback: contextmenu MainCamera myArgs0 myArgs1".

// Create a button using the Button constructor.
this.button = new Button( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
// Add a reference to a callback function passing the owner of the function and the function name.
this.button.addContextMenuCallback( this, "myCallback", ["myArgs0", "myArgs1"] );

// Add a callback function. Your first 2 parameters will always be the browser event and the camera.
this.myCallback = function( event, camera, callbackArgs0, callbackArgs1 ) {
   console.log('callback:', event.type, camera.name, callbackArgs0, callbackArgs1);
}





Button.removeContextMenuCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when the in-browser context menu is activated over this Button.

Button.removeContextMenuCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Button.removeContextMenuCallback parameter: callbackName
[type: string] 
The name of the callback function.





Button.simulateContextMenuCallback(simulatedEvent, simulatedCamera)
[type: function] 
Manually triggers the 'contextMenu' callback for this Button.

Button.simulateContextMenuCallback parameter: simulatedEvent
[type: object] [optional] 
Event object that can be supplied in place of the authentic browser-generated event that occurs when the callback is triggered naturally.

Button.simulateContextMenuCallback parameter: simulatedCamera
[type: object] [optional] 
The Camera that will be supplied to the callback as the 'triggering' Camera.






































































































































































































































































































































































































----------------------------------------------------------
Section 77: ProjectSettings
----------------------------------------------------------


ProjectSettings
[type: class] [NON-INSTANTIABLE] 
Represents the persistent per-project settings stored in the project's "ProjectSettings.json" file. Unlike most documented Incisor® classes, this is not a standard runtime object that you instantiate or access directly from normal project code. This class exists for documentation consistency and describes the JSON object edited through the "Project Settings..." popup in the Project menu while a project is open. These settings are stored in the root directory of each project and apply only to that project. This documentation describes the serialized ProjectSettings.json object itself, not the live runtime object at "nc.projectConfiguration". Several serialized members documented here also determine matching or closely related runtime members on "nc.projectConfiguration", and those shared cases are called out below. 





ProjectSettings.docFormatVersion
[type: number] 
Numeric version of the serialized ProjectSettings document format.





ProjectSettings.publicProjectName
[type: string] 
The public display name of the project. This serialized value is the source for the runtime "nc.projectConfiguration.projectName" value, where it represents the name of the current Incisor® project as determined in the "ProjectSettings".





ProjectSettings.projectCodeName
[type: string] 
The code-safe name of the project as used within JavaScript / TypeScript. Generally this name should avoid spaces and special characters.





ProjectSettings.latestIncisorVersionSetUsed
[type: string] 
The Incisor® version set most recently used to save these project settings.

example:
// Example:
// "Red"





ProjectSettings.latestIncisorVersionUsed
[type: string] 
The full Incisor® version string most recently used to save these project settings.

example:
// Example:
// "2026.04.10.12.11.41"





ProjectSettings.requiredPermissions
[type: string] 
String used to store any required permissions metadata for this project. This field exists in ProjectSettings.json even if no permissions are currently required.





ProjectSettings.usingTypescript
[type: boolean] 
Read-only flag denoting if this is a TypeScript project, or a standard JavaScript project.





ProjectSettings.assetConfigurationDefinitions
[type: dictionary] 
Definitions for the values used by this project's supported asset configurations. The default project template defines "assetPackageScale", "soundQuality", and "language", but additional user-defined dimensions may also be present. These serialized definitions determine the valid value space for the runtime "nc.projectConfiguration.assetConfiguration" object.


ProjectSettings.assetConfigurationDefinitions.assetPackageScale
[type: [string]] 
A list of scale values that determine an automatic scale applied to graphic assets within each supported asset configuration.

example:
// Example values:
// ["100","50"]


ProjectSettings.assetConfigurationDefinitions.soundQuality
[type: [string]] 
A list of sound quality definitions in the format "AAA_BBB", where AAA is "mono" or "stereo" and BBB is the bitrate in kilobits.

example:
// Example values:
// ["stereo_115","mono_55"]


ProjectSettings.assetConfigurationDefinitions.language
[type: [string]] 
A list of language codes supported by the project.

example:
// Example values:
// ["en","es"]





ProjectSettings.assetConfigurationDataOrder
[type: [string]] 
The order in which asset configuration dimensions are displayed and interpreted.

example:
// Example:
// ["assetPackageScale","soundQuality","language"]





ProjectSettings.conditionalCodeTagDefinitions
[type: [string]] 
User-defined conditional code tags available to the project's configurations. These are the tags that can later be included or excluded per configuration. During runtime such tags are available in auto-complete via the CODE object.

example:
// Example:
CODE.includeIf___WebPublish;
   console.log("This only occurs in configurations that include the 'WebPublish' conditional code tag.")
CODE.includeEnd___WebPublish;





ProjectSettings.coreCanvasResolutionX
[type: number] [default: 1920] 
The core canvas pixel width. This represents the pixel width of the canvas RenderTarget at it's native scale. This serialized value is the source for the runtime "nc.projectConfiguration.coreCanvasResolutionX" value.





ProjectSettings.coreCanvasResolutionY
[type: number] [default: 1080] 
The core canvas pixel height. This represents the pixel height of the canvas RenderTarget at it's native scale. This serialized value is the source for the runtime "nc.projectConfiguration.coreCanvasResolutionY" value.





ProjectSettings.canvasTransparency
[type: boolean] [default: false] 
Boolean determining if any portion of the canvas will be transparent, enabling the html page to be partially viewed "through" the canvas. This serialized value is the source for the runtime "nc.projectConfiguration.canvasTransparency" value.





ProjectSettings.mainCameraType
[type: string] [default: "orthographic"] 
String value denoting the default camera type used for the "mainCamera" in the "mainScene". This serialized value is the source for the runtime "nc.projectConfiguration.mainCameraType" value. Runtime changes to the runtime value must be made in PreloadConfiguration code, which is located in the "ProjectCode/PreloadConfiguration" local directory. Possible values for this property are "orthographic" or "perspective".





ProjectSettings.maskingMode
[type: string] [default: "overlapping"] 
String value denoting the masking mode for this project. This serialized value is the source for the runtime "nc.projectConfiguration.maskingMode" value. The masking mode determines how different MaskGroups interact with eachother. Possible values for this property are "overlapping" or "disjoint". When the maskingMode is "overlapping", up to 8 MaskGroups can be defined and GraphicObjects can subscribe to any combination of those MaskGroups. When the maskingMode is "disjoint", up to 255 MaskGroups can be defined, but GraphicObjects can only subscribe to one mask at a time.





ProjectSettings.defaultTimelineTimeSnap
[type: number] [default: 0.02] 
Number value denoting the default keyframe-time snap grid (in time units) for new Timelines in this project. This serialized value is the source for the runtime "nc.defaultTimelineTimeSnap" value. A brand-new Timeline adopts this as its timeSnap; existing Timelines keep their own stored value, and a Timeline saved before this setting existed falls back to the legacy 1/60 grid so older Constructs do not change.





ProjectSettings.preserveDrawingBuffer
[type: boolean] [default: true] 
Boolean value determining if the drawing buffer is preserved for reading. This serialized value is the source for the runtime "nc.projectConfiguration.preserveDrawingBuffer" value. Preserving the drawing buffer enables several useful development features, but may cause performance issues in published software on some devices. It is therefore recommended that this flag be set to true for when the project is unpublished, and false for when the project is published.





ProjectSettings.defaultGraphicAssetEffectNodes
[type: [string]] 
List of Nodes added to the presets for all GraphicAssets. This serialized value determines the runtime value of "nc.projectConfiguration.defaultGraphicAssetEffectNodes".

example:
// Example:
// ["ColorMultiply"]





ProjectSettings.devModeConfiguration
[type: string] 
The name of the configuration used while actively developing in Incisor®.

example:
// Example:
// "LocalDev"





ProjectSettings.configurations
[type: object] 
Dictionary of named project configurations. Configurations are interchangeable sets of project settings used to develop and publish the same project in different modes.





ProjectSettings.auxiliaryPublishingPackageDefinitions
[type: dictionary] 
Definitions for auxiliary publishing packages. These package definitions can be enabled or disabled within individual configurations to activate additional publishing targets such as Electron.


ProjectSettings.auxiliaryPublishingPackageDefinitions.electron
[type: object] 
Dictionary of named Electron auxiliary publishing package definitions.





ProjectSettings.autoClearMetaFiles
[type: boolean] [default: true] 
Setting determining if Incisor® automatically clears generated meta files when appropriate.





ProjectSettings.limitPublishedBuildsKept
[type: number] [default: 0] 
The maximum number of older published builds that Incisor® keeps. A value of 0 indicates that no historical build limit is being enforced.





ProjectSettings.enableDynamicDocumentation
[type: boolean] [default: true] 
Setting determining if dynamic documentation is enabled for this project.





ProjectSettings.generateSourceMaps
[type: boolean] [default: true] 
Setting determining if the browser tools can show and step through your original project files while developing.





ProjectSettings.screenShotDestination
[type: string] [default: "ScreenShots"] 
Project-relative path for where screenshots will be saved.





ProjectSettings.additionalLiveViewModes
[type: [string]] 
Additional view modes available to the Live View panel. Items are generally of the format "AAAxBBB" or "AAAxBBB_maximize".

example:
// Example values:
// ["16x9_maximize","9x16_maximize","1920x1080","1080x1920"]





ProjectSettings.fontDefinitions
[type: [ProjectSettingsFontDefinition]] 
Definitions for the fonts used by this project. These serialized definitions are the source for the runtime dictionary at "nc.projectConfiguration.fontDefinitions".





ProjectSettings.loadingTierDefinitions
[type: [ProjectSettingsLoadingTierDefinition]] 
Definitions for the project's lazy-loading tiers. These serialized definitions are the source for the runtime dictionary at "nc.projectConfiguration.loadingTierDefinitions".





ProjectSettings.fontReduction
[type: dictionary] 
Settings controlling how Incisor® determines which characters are included for fonts.


ProjectSettings.fontReduction.includeStandardCharactersWhenUnPublished
[type: boolean] [default: true] 
Setting that determines if Incisor® automatically includes all characters from "standardFontCharacters" in all fonts while the project is unpublished / in development.


ProjectSettings.fontReduction.includeStandardCharactersWhenPublished
[type: boolean] [default: true] 
Setting that determines if Incisor® automatically includes all characters from "standardFontCharacters" in all fonts when the project is published.


ProjectSettings.fontReduction.includeTranscriptCharacters
[type: boolean] [default: true] 
Setting that determines if Incisor® automatically includes characters that appear in the ProjectTranscript.json file.


ProjectSettings.fontReduction.limitTranscriptCharactersByLanguage
[type: boolean] [default: true] 
Setting that determines if transcript characters are limited by the current language.


ProjectSettings.fontReduction.limitTranscriptCharactersByPhrase
[type: boolean] [default: false] 
Setting that determines if transcript characters are limited to only the phrases explicitly associated with each font definition.


ProjectSettings.fontReduction.standardFontCharacters
[type: [number]] 
A list of unicode character codes included for all fonts, as long as the associated "includeStandardCharacters" setting indicates inclusion.










----------------------------------------------------------
Section 78: ProjectSettingsConfiguration
----------------------------------------------------------


ProjectSettingsConfiguration
[type: class] [NON-INSTANTIABLE] 
A named project configuration from ProjectSettings.json. Configurations define how a project behaves in a particular development or publishing mode. 





ProjectSettingsConfiguration.publishIndexFile
[type: boolean] [default: true] 
Flag determining if the project is published as a complete web-ready package including the index file. Reasons to disable this include environments that use the associated JavaScript directly, negating the need for html.





ProjectSettingsConfiguration.supportedAssetConfigurations
[type: [object]] 
List of supported asset configuration combinations for this project configuration. Each entry is a small object whose members correspond to the names defined in "assetConfigurationDefinitions" such as "assetPackageScale", "soundQuality", and "language".

example:
// Example values:
// [
//   {"assetPackageScale":"100","soundQuality":"mono_115","language":"en"},
//   {"assetPackageScale":"100","soundQuality":"mono_115","language":"es"},
//   {"assetPackageScale":"50","soundQuality":"mono_55","language":"en"},
//   {"assetPackageScale":"50","soundQuality":"mono_55","language":"es"}
// ]





ProjectSettingsConfiguration.conditionalCodeTagsIncluded
[type: [string]] 
The conditional code tags enabled for this configuration. Code included between these tags will be included when this configuration is used.





ProjectSettingsConfiguration.optionalCodeModulesExcluded
[type: [string]] 
Optional Incisor® code modules excluded for this configuration. Optional code modules are groups of functionality that can be left out of projects in order to optimize their overall published download size. Optional code modules can be marked for exclusion in ProjectSettings.





ProjectSettingsConfiguration.minification
[type: ProjectSettingsMinification] 
Settings for if/how Incisor® minifies project and API code for this configuration.





ProjectSettingsConfiguration.removeComments
[type: boolean] [default: false] 
Setting determining if comments are removed from user code when publishing this configuration.





ProjectSettingsConfiguration.removeWhiteSpace
[type: boolean] [default: false] 
Setting determining if whitespace is removed from user code when publishing this configuration. It should be noted that in order to use whitespace removal, user code MUST contain semicolons.





ProjectSettingsConfiguration.spriteSheetDimensionLimit
[type: number] [default: 4096] 
Dimension limit used when generating sprite sheets for this configuration.





ProjectSettingsConfiguration.auxiliaryPublishingPackages
[type: [string]] 
The auxiliary publishing packages enabled for this configuration. Entries reference named package definitions from "auxiliaryPublishingPackageDefinitions".










----------------------------------------------------------
Section 79: ProjectSettingsMinification
----------------------------------------------------------


ProjectSettingsMinification
[type: class] [NON-INSTANTIABLE] 
Settings for how a project configuration minifies code. 





ProjectSettingsMinification.enableMinification
[type: boolean] [default: false] 
Setting determining if Incisor® applies minification when publishing.





ProjectSettingsMinification.automaticallyMinifyAllKeywords
[type: boolean] [default: true] 
Setting determining if minification is automatically applied to all project code tokens that are not explicitly marked as excluded from minification. If this value is false, only words/tokens explicitly included in a 'MinifyList' will be minified. To list tokens explicitly for inclusion or exclusion in minificaiton add them to the files in the Utilities/MinificationLists directory.





ProjectSettingsMinification.minifyPrefix
[type: string] [default: "minify_"] 
Prefix that indicates a code token should be minified.





ProjectSettingsMinification.minifySuffix
[type: string] [default: "_minify"] 
Suffix that indicates a code token should be minified.





ProjectSettingsMinification.doNotMinifyPrefix
[type: string] [default: "doNotMinify_"] 
Prefix that indicates a code token should not be minified.





ProjectSettingsMinification.doNotMinifySuffix
[type: string] [default: "_doNotMinify"] 
Suffix that indicates a code token should not be minified.





ProjectSettingsMinification.minifyIncisorApiKeywords
[type: boolean] [default: false] 
Setting determining if Incisor® applies minification to keywords from the Incisor API.





ProjectSettingsMinification.minifyAssetNames
[type: boolean] [default: false] 
Setting determining if Incisor® applies minification to project asset names.





ProjectSettingsMinification.substitutionAssignment
[type: string] [default: "deterministicRandom"] 
Method used to assign substitution tokens during minification. Acceptable values are "ordered", "random", or "deterministicRandom".





ProjectSettingsMinification.keywordAndStringPairTreatment
[type: string] [default: "minifyBoth"] 
Setting that determines how minification behaves when a keyword / string pair is encountered. Acceptable values are "minifyBoth", "minifyNeither", or "minifyKeywordOnly".










----------------------------------------------------------
Section 80: ProjectSettingsFontDefinition
----------------------------------------------------------


ProjectSettingsFontDefinition
[type: class] [NON-INSTANTIABLE] 
A font definition entry from ProjectSettings.json. At runtime these serialized entries are used to populate "nc.projectConfiguration.fontDefinitions". 





ProjectSettingsFontDefinition.fontName
[type: string] 
The name of the font definition.





ProjectSettingsFontDefinition.kerningAdjustment
[type: number] [default: 0] 
Kerning adjustment applied to the font.





ProjectSettingsFontDefinition.lineHeight
[type: number] 
The line height used by the font.





ProjectSettingsFontDefinition.characterWidth
[type: number] 
The character width used by the font. This value is initially taken from the width of the null character (_Char0).





ProjectSettingsFontDefinition.alwaysIncludeTheseCharacters
[type: [(number|string)]] 
Unicode characters or character codes that will always be included with this font, regardless of the current language.





ProjectSettingsFontDefinition.phrasesUsingThisFont
[type: [string]] 
Phrase IDs that explicitly use this font. These entries can be used in conjunction with font reduction settings.










----------------------------------------------------------
Section 81: ProjectSettingsLoadingTierDefinition
----------------------------------------------------------


ProjectSettingsLoadingTierDefinition
[type: class] [NON-INSTANTIABLE] 
A loading tier definition entry from ProjectSettings.json. Loading tiers are a means to organize AssetComponents into separately downloadable groups. At runtime these serialized entries are used to populate "nc.projectConfiguration.loadingTierDefinitions". 





ProjectSettingsLoadingTierDefinition.loadingTier
[type: number] 
The numeric designation of this loading tier. Loading tiers are a means to organize AssetComponents into separately downloadable groups.





ProjectSettingsLoadingTierDefinition.isAutoLoaded
[type: boolean] [default: true] 
Flag determining if the content associated with this tier is automatically loaded. Automatically loaded tiers are loaded in ascending order (numerically).





ProjectSettingsLoadingTierDefinition.incrementalContentProcessing
[type: boolean] [default: false] 
Flag determining if the content associated with this loading tier will be processed This setting can be used to minimize performance hits caused when asset data is 'lazy-loaded' during the end-user experience; When true, the processing of assets within a tier is spread out over multiple screen updates. incrementally after loading.





ProjectSettingsLoadingTierDefinition.assetDataFileSizeLimitKB
[type: number] [default: 800] 
A soft limit on the size of asset data files within this tier.





ProjectSettingsLoadingTierDefinition.performDuplicateRemoval
[type: boolean] [default: true] 
Flag determining if the content associated with this tier is eligible for duplicate removal. Duplicate removal ensure that if two asset componets have the same exact data, the data is only downloaded once.










----------------------------------------------------------
Section 82: ProjectSettingsElectronPackageDefinition
----------------------------------------------------------


ProjectSettingsElectronPackageDefinition
[type: class] [NON-INSTANTIABLE] 
A named Electron auxiliary publishing package definition from ProjectSettings.json. These definitions are referenced by project configurations to enable Electron publishing. 





ProjectSettingsElectronPackageDefinition.packaging
[type: ProjectSettingsElectronPackaging] 
Settings for how the Electron application is packaged.





ProjectSettingsElectronPackageDefinition.width
[type: number] [default: 800] 
Initial width of the Electron window.





ProjectSettingsElectronPackageDefinition.height
[type: number] [default: 800] 
Initial height of the Electron window.





ProjectSettingsElectronPackageDefinition.x
[type: number] [default: 0] 
X position of the Electron window.





ProjectSettingsElectronPackageDefinition.y
[type: number] [default: 0] 
Y position of the Electron window.





ProjectSettingsElectronPackageDefinition.windowPositionDelay
[type: number] [default: 0] 
Delay in milliseconds before positioning and scaling the Electron window.





ProjectSettingsElectronPackageDefinition.center
[type: boolean] [default: false] 
Determines if the Electron window is centered on screen.





ProjectSettingsElectronPackageDefinition.minWidth
[type: number] [default: 0] 
Minimum width of the Electron window.





ProjectSettingsElectronPackageDefinition.minHeight
[type: number] [default: 0] 
Minimum height of the Electron window.





ProjectSettingsElectronPackageDefinition.maxWidth
[type: number] [default: 0] 
Maximum width of the Electron window.





ProjectSettingsElectronPackageDefinition.maxHeight
[type: number] [default: 0] 
Maximum height of the Electron window.





ProjectSettingsElectronPackageDefinition.resizable
[type: boolean] [default: true] 
Determines if the Electron window is resizable.





ProjectSettingsElectronPackageDefinition.movable
[type: boolean] [default: true] 
Determines if the Electron window is movable.





ProjectSettingsElectronPackageDefinition.minimizable
[type: boolean] [default: true] 
Determines if the Electron window is minimizable.





ProjectSettingsElectronPackageDefinition.maximizable
[type: boolean] [default: true] 
Determines if the Electron window is maximizable.





ProjectSettingsElectronPackageDefinition.closable
[type: boolean] [default: true] 
Determines if the Electron window is closable.





ProjectSettingsElectronPackageDefinition.focusable
[type: boolean] [default: true] 
Determines if the Electron window is focusable.





ProjectSettingsElectronPackageDefinition.level
[type: string] [default: "normal"] 
Sets the window's stacking level relative to other windows on the system.





ProjectSettingsElectronPackageDefinition.fullscreen
[type: boolean] [default: false] 
Determines if the Electron window launches in native fullscreen mode.





ProjectSettingsElectronPackageDefinition.fullscreenable
[type: boolean] [default: true] 
Determines if the Electron window is allowed to enter fullscreen mode.





ProjectSettingsElectronPackageDefinition.simpleFullscreen
[type: boolean] [default: false] 
Enables a non-Space-creating fullscreen mode on macOS.





ProjectSettingsElectronPackageDefinition.skipTaskbar
[type: boolean] [default: false] 
Determines if the application is hidden from the taskbar.





ProjectSettingsElectronPackageDefinition.kiosk
[type: boolean] [default: false] 
Determines if the application runs in kiosk mode.





ProjectSettingsElectronPackageDefinition.icon
[type: string] [default: ""] 
Path to an icon png used by the OS to represent the Electron window or app.





ProjectSettingsElectronPackageDefinition.frame
[type: boolean] [default: true] 
Determines if the Electron window has a standard frame.





ProjectSettingsElectronPackageDefinition.menuBarVisible
[type: boolean] [default: true] 
Determines if the Electron window menu bar is visible.





ProjectSettingsElectronPackageDefinition.autoHideMenuBar
[type: boolean] [default: false] 
Determines if the Electron window menu bar is automatically hidden.





ProjectSettingsElectronPackageDefinition.transparent
[type: boolean] [default: false] 
Determines if the Electron window is transparent.





ProjectSettingsElectronPackageDefinition.type
[type: string] [default: "normal"] 
Determines the type of window created by this app. The effect of this property is OS-dependent.





ProjectSettingsElectronPackageDefinition.backgroundColor
[type: string] [default: "#FFF"] 
Background color of the Electron window.





ProjectSettingsElectronPackageDefinition.hasShadow
[type: boolean] [default: true] 
Determines if the Electron window has a shadow.





ProjectSettingsElectronPackageDefinition.opacity
[type: number] [default: 1] 
Opacity of the Electron window on a scale from 0 to 1.





ProjectSettingsElectronPackageDefinition.visualEffectState
[type: string] [default: "followWindow"] 
Can be used in conjunction with "vibrancy" and controls whether the effect stays visible when the app is inactive.





ProjectSettingsElectronPackageDefinition.darkTheme
[type: boolean] [default: false] 
Determines if the Electron window uses a dark theme where supported.





ProjectSettingsElectronPackageDefinition.vibrancy
[type: string] [default: "default"] 
The Electron vibrancy option. This enables a translucent, blurred background effect on macOS where supported.





ProjectSettingsElectronPackageDefinition.zoomToPageWidth
[type: boolean] [default: false] 
Determines if the Electron window should zoom to page width.





ProjectSettingsElectronPackageDefinition.enableContextMenu
[type: boolean] [default: false] 
Enables the context menu in the Electron window.





ProjectSettingsElectronPackageDefinition.incisorFileIoLayer
[type: boolean] [default: true] 
Determines whether this published Electron build exposes the native fileIO layer, allowing nc.fileIO requests to be serviced by the Electron runtime (reading and writing within the application's own data directory). Only has an effect when the 'fileIO' and 'fileIoElectron' optional code modules are included (see "optionalCodeModulesExcluded"). The scope of file access is further governed by "allowUniversalFileIO".





ProjectSettingsElectronPackageDefinition.allowUniversalFileIO
[type: boolean] [default: false] 
Determines whether this published Electron build may read and write files outside its own application data directory (only applies when the fileIO layer is active - see "incisorFileIoLayer"). When false, fileIO is confined to relative paths within the app's data directory and non-relative paths are refused. When true, the published application can access any file on the user's machine. This is the Electron-build equivalent of the application-level "allowUniversalFileIO" setting that governs fileIO while developing in Incisor.





ProjectSettingsElectronPackageDefinition.webPreferences
[type: ProjectSettingsElectronWebPreferences] 
Web preference settings passed to Electron for the generated window.










----------------------------------------------------------
Section 83: ProjectSettingsElectronPackaging
----------------------------------------------------------


ProjectSettingsElectronPackaging
[type: class] [NON-INSTANTIABLE] 
Packaging settings for an Electron auxiliary publishing package. 





ProjectSettingsElectronPackaging.targets
[type: [string]] [default: []] 
The runtimes to build an application for, from "win32-x64", "win32-arm64", "darwin-arm64", "darwin-x64", "linux-x64" and "linux-arm64". Each one gets its own application when the package is published. When the list is empty, the platform Incisor is running on is built. Files in a folder of the package's 'ElectronExtras' folder that is named for a runtime are added to that runtime's application only.





ProjectSettingsElectronPackaging.reproducibleBinary
[type: boolean] [default: false] 
Determines whether publishing this package from the same project always gives the same application. When true, a copy of the Electron runtime is kept in the project, so the project can be rebuilt later without downloading it again.





ProjectSettingsElectronPackaging.asar
[type: boolean] [default: false] 
Determines whether the application's files are packed into a single app.asar archive instead of being left as separate files. Files that must stay loose, such as native modules (.node), are kept beside the archive.





ProjectSettingsElectronPackaging.asarIntegrity
[type: boolean] [default: false] 
Determines whether the application refuses to run if its app.asar archive has been changed, and refuses to load its code from anywhere else. Only applies when asar is true. The change check is available for Windows and Mac applications.





ProjectSettingsElectronPackaging.productName
[type: string] [default: ""] 
The name of the application, used for its file name and in the operating system's menus. When blank the project's public name is used.





ProjectSettingsElectronPackaging.appId
[type: string] [default: ""] 
The identifier the operating system uses for the application, in reverse domain form such as "com.mycompany.mygame". When blank "com.example" followed by the project's code name is used.





ProjectSettingsElectronPackaging.version
[type: string] [default: ""] 
The version number of the application. When blank "1.0.0" is used.





ProjectSettingsElectronPackaging.copyright
[type: string] [default: ""] 
The copyright line stored in the application.





ProjectSettingsElectronPackaging.appIcon
[type: string] [default: ""] 
The path to the icon of the application file, relative to the project or absolute. It can be one square PNG (1024 by 1024 is best), a folder of square PNGs of different sizes (the names do not matter), an .icns file for Mac applications, or an .ico file for Windows applications. Mac and Windows applications use it. Linux applications do not.










----------------------------------------------------------
Section 84: ProjectSettingsElectronWebPreferences
----------------------------------------------------------


ProjectSettingsElectronWebPreferences
[type: class] [NON-INSTANTIABLE] 
Web preference settings for an Electron auxiliary publishing package. 





ProjectSettingsElectronWebPreferences.nodeIntegration
[type: boolean] [default: false] 
Determines if Node integration is enabled in the Electron window.





ProjectSettingsElectronWebPreferences.contextIsolation
[type: boolean] [default: true] 
Determines if Electron context isolation is enabled.





ProjectSettingsElectronWebPreferences.enableRemoteModule
[type: boolean] [default: false] 
Determines if Electron's remote module is enabled.





ProjectSettingsElectronWebPreferences.preload
[type: string] [default: ""] 
Optional preload script path.





ProjectSettingsElectronWebPreferences.sandbox
[type: boolean] [default: false] 
Determines if sandbox mode is enabled.





ProjectSettingsElectronWebPreferences.devTools
[type: boolean] [default: true] 
Determines if Electron developer tools are enabled.





ProjectSettingsElectronWebPreferences.zoomFactor
[type: number] [default: 1] 
Zoom factor applied to the Electron page.





ProjectSettingsElectronWebPreferences.javascript
[type: boolean] [default: true] 
Determines if JavaScript execution is enabled.





ProjectSettingsElectronWebPreferences.webSecurity
[type: boolean] [default: true] 
Determines if Electron web security is enabled.





ProjectSettingsElectronWebPreferences.allowRunningInsecureContent
[type: boolean] [default: false] 
Determines if insecure content is allowed to run.





ProjectSettingsElectronWebPreferences.experimentalFeatures
[type: boolean] [default: false] 
Determines if experimental browser features are enabled.





ProjectSettingsElectronWebPreferences.backgroundThrottling
[type: boolean] [default: true] 
Determines if rendering and timers are throttled while the window is in the background.





ProjectSettingsElectronWebPreferences.webviewTag
[type: boolean] [default: false] 
Determines if the <webview> tag is enabled.





ProjectSettingsElectronWebPreferences.nativeWindowOpen
[type: boolean] [default: false] 
Determines if native window open behavior is used.





ProjectSettingsElectronWebPreferences.scrollBounce
[type: boolean] [default: false] 
Determines if scroll bounce is enabled where supported.





ProjectSettingsElectronWebPreferences.offscreen
[type: boolean] [default: false] 
Determines if offscreen rendering is enabled.





ProjectSettingsElectronWebPreferences.plugins
[type: boolean] [default: false] 
Determines if browser plugins are enabled.





ProjectSettingsElectronWebPreferences.webaudio
[type: boolean] [default: false] 
Determines if web audio is enabled.





ProjectSettingsElectronWebPreferences.disableDialogs
[type: boolean] [default: false] 
Determines if JavaScript dialogs are disabled.










----------------------------------------------------------
Section 85: GraphicObject
----------------------------------------------------------


GraphicObject
[type: class] [extends: SceneObject] 
GraphicObjects are SceneObjects with visible components such as Geometry, Materials, and Textures. Anything that you can see in an Incisor® Scene is some form of GraphicObject. GraphicObjects can easily be set to different GraphicAssets such as source Images, OBJs, or other customizable visuals.





GraphicObject.visible
[type: boolean] [default: true] 
Boolean determining if this GraphicObject is visible. Unlike the 'enabled' property of SceneObjects, 'GraphicObject.visible' does not affect any descendants of this GraphicObject. It should be noted that 'turning off' objects using 'GraphicObject.visible=false' is often less performant than 'SceneObject.enabled=false', because while the 'visible' property does prevent the object from rendering, the 'enabled' property also prevents several additional hierarchical calculations from occuring for the effected SceneObjects.

example:
// Objective: Make a GraphicObject not visible.
// Expected Result: Only the "WhiteTriangle" is visible. The "WhiteBox" is not.

// Add a "WhiteBox" GraphicObject to the main scene using the GraphicObject constructor.
let whiteBox = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "WhiteBox" );
// move the "WhiteBox" 100 world units to the left
whiteBox.position.x = -100;

// Add a "WhiteTriangle" GraphicObject to the main scene using the GraphicObject constructor.
let whiteTriangle = new GraphicObject( nc.graphicAssets.WhiteTriangle, nc.mainScene, "WhiteTriangle" );
// move the "WhiteTriangle" 100 world units to the right
whiteTriangle.position.x = 100;

// Set "WhiteBox" to visible = false.
whiteBox.visible = false;





GraphicObject.layer
[type: Layer] [default: nc.layers.DefaultLayer] 
The GraphicObject's render-order Layer within the Scene. For a list of available layers per Scene, see 'nc.layersByScene'





GraphicObject.subLayer
[type: number] [default: 0] 
The GraphicObject's render-order within it's assigned Layer as represented by a number between -1 and 1.





GraphicObject.graphicAsset
[type: GraphicAsset] [default: nc.graphicAssets.WhiteBox] 
Use this to set or get the current GraphicAsset for this GraphicObject. Also see 'setGraphicAsset', which can set the GraphicAsset with options to forego the EffectNode and EffectController presets. When 'getting' this value, keep in mind that it will only reflect the GraphicAsset that this GraphicObject was previously set to; the value returned does not reflect customizations made to the Geometry, Materials, EffectNodes or EffectControllers that occurred since it was previously set.

example:
// Objective: Set the GraphicAsset of a GraphicObject
// Expected Result: You will see a WhiteTriangle on the screen and the console should have 2 log messages as follows:
// 'MyGraphicObject' GraphicAsset name: WhiteBox
// 'MyGraphicObject' GraphicAsset name: WhiteTriangle 

// Add a GraphicObject to the main scene using the GraphicObject constructor and the WhiteBox GraphicAsset.
let myGraphicObject = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "MyGraphicObject" );
// Console log the name of the GraphicAsset
console.log("'MyGraphicObject' GraphicAsset name:", myGraphicObject.graphicAsset.name);
// Update 'MyGraphicObject' to the WhiteTriangle GraphicObject.
myGraphicObject.graphicAsset = nc.graphicAssets.WhiteTriangle;
// Console log the name of the GraphicAsset again.
console.log("'MyGraphicObject' GraphicAsset name:", myGraphicObject.graphicAsset.name);





GraphicObject.materialMaster
[type: MaterialMaster] 
The MaterialMaster is a convenience-based object that allows quick manipulation of all of the Materials on a given GraphicObject. To manipulate all of the Materials on a GraphicObject at the same time, you can simply manipulate its MaterialMaster. It should be noted that querying values from the MaterialMaster can be misleading, as the returned values only refer to the last values set on the MaterialMaster itself, and would not reflect individual changes made to the Materials themselves.

example:
// Objective: Use a GraphicObject's MaterialMaster to change its color.
// Expected Result: You will see a red box.

// Add a GraphicObject to the main scene using the GraphicObject constructor and the WhiteBox GraphicAsset.
let myGraphicObject = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "MyGraphicObject" ) ;
// Get the instance of this GraphicObject's MaterialMaster
let materialMaster = myGraphicObject.materialMaster;
// By default, the RGB values of fillColor are set to 1. Set the green and blue values to zero to leave only red.
materialMaster.fillColor.green = 0;
materialMaster.fillColor.blue  = 0;





GraphicObject.geometry
[type: Geometry] [default: nc.geometries.WhiteBox] 
The current Geometry of this GraphicObject. Setting this GraphicObject's GraphicAsset will update its Geometry automatically, but the Geometry can be set directly for further customization.

example:
// Objective: Get the current Geometry of a GraphicObject
// Expected Result: The console should have 2 log messages as follows:
// 'MyGraphicObject' (Box) sourceWidth, sourceHeight 100 100
// 'MyGraphicObject' (Triangle) sourceWidth, sourceHeight 50 100
 
// Create a GraphicObject using the white box GraphicAsset.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "MyGraphicObject" );
// Console log the Geometry sourceWidth and sourceHeight.
console.log("'MyGraphicObject' (Box) sourceWidth, sourceHeight", myGraphicObject.geometry.sourceWidth, myGraphicObject.geometry.sourceHeight);
// Update the Geometry of myGraphicObject with the white triangle.
myGraphicObject.geometry = nc.geometries.WhiteTriangle;
// Console log the Geometry sourceWidth and sourceHeight again.
console.log("'MyGraphicObject' (Triangle) sourceWidth, sourceHeight", myGraphicObject.geometry.sourceWidth, myGraphicObject.geometry.sourceHeight);





GraphicObject.graphicExpander
[type: GraphicExpander] 
A GraphicExpander allows a region of a GraphicObject to be specified as expandable to a new size. When a new size is specified, this region of the GraphicObject will change size, but the area outside the expandable region will move and stretch to keep aligned to the expanded region. This property defaults to undefined, but can be enabled by calling 'GraphicObject.configureGraphicExpander()'.

example:
[ReferenceSnippet: GraphicObject_ConfigureGraphicExpander]





GraphicObject.spriteSetter
[type: SpriteSetter] 
A SpriteSetter is a PlaybackController that switches a GraphicObject's graphicAsset between numerically sequential GraphicAssets. This property defaults to undefined, but can be enabled by calling 'GraphicObject.configureSpriteSetter()'.

example:
// Objective: Configure a SpriteSetter





GraphicObject.masking
[type: Masking] 
Object controlling the masking of a GraphicObject. Masking functionality enables selective rendering of portions of GraphicObjects. MaskGroups can be defined, and then GraphicObjects can be configured as 'mask', which add their shape to the area of the newly defined MaskGroup. Then, when other GraphicObjects are configured as 'masked', their rendering only occures within areas defined by the MaskGroup.





GraphicObject.frustumCulling
[type: boolean] [default: true] 
Boolean determining if the GraphicObject is automatically omitted from rendering when it is entirely outside of the Camera's viewing area (its frustum). While the value defaults to true, reasons to set it false include situations where the Geometry of a given GraphicObject is being adjusted via EffectNode (on the GPU), and so while an object's postion may indicate that it should be culled due to being out of view, its Geometry may be distorted into a position that is actually in view of the camera, and should therefore be rendered after all.





GraphicObject.setGraphicAsset(graphicAsset, maintainEffectNodes, maintainEffectControllerValues)
[type: function] 
Changes this GraphicObject's GraphicAsset, updating its Geometry and Materials.

GraphicObject.setGraphicAsset parameter: graphicAsset
[type: GraphicAsset] 
The GraphicAsset that this GraphicObject will become. For a list of available GraphicAssets, see 'nc.graphicAssets'.

GraphicObject.setGraphicAsset parameter: maintainEffectNodes
[type: boolean] [default: false] [optional] 
When a GraphicObject's GraphicAsset is changed, its EffectNodes are also changed to the EffectNode 'presets' for that GraphicAsset. To ignore the presets and maintain the current EffectNodes, set this parameter to true.

GraphicObject.setGraphicAsset parameter: maintainEffectControllerValues
[type: boolean] [default: false] [optional] 
When a GraphicObject's GraphicAsset is changed, its EffectController values may also be changed to the EffectController 'presets' for that GraphicAsset. To ignore the presets and maintain the current EffectController values, set this parameter to true.

example:
// Objective: Set a GraphicAsset on a GraphicObject.
// Expected Result: You will see a white triangle. 

// Add a GraphicObject to the main scene using the GraphicObject constructor and the WhiteBox GraphicAsset.
let myGraphicObject = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "MyGraphicObject") ;
// Call setGraphicAsset() to change the White Box to a White Triangle
myGraphicObject.setGraphicAsset( nc.graphicAssets.WhiteTriangle );





GraphicObject.setMaterials(materials)
[type: function] 
Sets this GraphicObject's Materials directly. This is used for specialized customization of GraphicObjects, and is not needed when working with standard GraphicAssets.

GraphicObject.setMaterials parameter: materials
[type: [Material], Material] 
The new list of Materials for this GraphicObject.





GraphicObject.getMaterials()
[type: function] [returns: [Material]] 
Returns the list of this GraphicObject's Materials.





GraphicObject.configureGraphicExpander()
[type: function] 
Adds a GraphicExpander instance to this GraphicObject, which allows the GraphicObject to be expanded to a new size from the middle out.





GraphicObject.configureSpriteSetter(keyGraphicAsset, frameRate, pauseImmunity, speedControl)
[type: function] 
Adds a SpriteSetter instance to this GraphicObject, which allows the GraphicObject's graphicAsset to be switched to numerically sequential GraphicAssets.

GraphicObject.configureSpriteSetter parameter: keyGraphicAsset
[type: GraphicAsset] 
Specifies the key GraphicAsset. This GraphicAsset's name should end in a number. All GraphicAssets whose name matches the key GraphicAsset's name with a different trailing number will be used to set the SpriteSetter's associated GraphicAssets list. For example, if the key GraphicAsset is named "MyAnimation001", all GraphicAssets with the name "MyAnimation" followed by any sequence of the digits 0-9 will be gathered into this SpriteSetter's associated GraphicAssets.

GraphicObject.configureSpriteSetter parameter: frameRate
[type: number] [default: nc.targetFixedUpdateRate] [optional] 
Specifies the frames per second at which the SpriteSetter should play. Note that this is reflected in the SpriteSetter's playbackRate value.

GraphicObject.configureSpriteSetter parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this ParticleSystem will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

GraphicObject.configureSpriteSetter parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this ParticleSystem is affected by.

example:
// Objective: Configure a SpriteSetter



























































































































































































































































































































----------------------------------------------------------
Section 86: Masking
----------------------------------------------------------


Masking
[type: class] 
Object controlling the masking of a GraphicObject. Masking functionality enables selective rendering of portions of GraphicObjects. MaskGroups can be defined, and then GraphicObjects can be configured as 'mask', which add their shape to the area of the newly defined MaskGroup. Then, when other GraphicObjects are configured as 'masked', their rendering only occures within areas defined by the MaskGroup.





Masking.inheritedTypes
[type: object] 
Dictionary of type that this object inherits from.





Masking.enabled
[type: boolean] [default: false] 
Flag determining if masking functionality is enabled (for both 'mask' and 'masked').





Masking.type
[type: string] [default: "masked"] 
String property that determines if this GraphicObject is a 'mask' or 'masked'. When masking functionality is enabled, a 'mask' contributes to the MaskGroup(s) it is associated with. When a GraphicObject is 'masked' it is only rendered in the areas determined by the MaskGroup(s) it is associated with. This setting does nothing when 'GraphicObject.masking.enabled' is false;





Masking.invert
[type: boolean] [default: false] 
Boolean determining if the affect of masking on a 'masked' GraphicObject is inverted, meaning that the areas where it is masked and the areas where it is not masked are switched. When this value is false, the masked GraphicObject in question is only rendered in areas that 'mask' GraphicObjects also occupy. When this value is true, the masked GraphicObject in question is only rendered in areas that 'mask' GraphicObjects do not occupy. This setting only applies to GraphicObjects with the 'masked' type, 'mask' GraphicObjects are unaffected by this setting. This setting does nothing when 'GraphicObject.masking.enabled' is false.





Masking.makeMask(maskGroups)
[type: function] 
Causes this GraphicObject to contribute to the given MaskGroup(s), adding its fully filled Geometry to the MaskGroups' areas. A mask only clips the cursor input of masked Buttons if the mask is itself a Button. Masks that are plain GraphicObjects clip rendering only.

Masking.makeMask parameter: maskGroups
[type: MaskGroup, [MaskGroup]] 
The MaskGroup(s) that this GraphicObject's shape will be added to. For a list of available MaskGroups, see 'nc.maskGroups'.

example:
// Objective: Use a mask to reveal only a portion of the phrase "Hello World."
// Expected Result: You will see the word "World." on screen.

// create a TextBox
let textBox = nc.addTextBox( nc.mainScene );
textBox.string = "Hello World."
textBox.makeMasked( nc.maskGroups.MainMaskGroup ); // mask it with "MainMaskGroup"

// create a GraphicObject rectangle and position it to cover the word "World."
this.masker = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Masker" );
this.masker.scale.x = 2; // rectangle
this.masker.position.x = 75; // position
this.masker.masking.makeMask( nc.maskGroups.MainMaskGroup ); // make it a masker for "MainMaskGroup"





Masking.makeMasked(maskGroups, invert)
[type: function] 
Causes this GraphicObject to only be rendered in the areas defined by the given MaskGroup(s). When this GraphicObject is a Button, it also only receives cursor input within those areas, but only where a mask that is itself a Button is under the cursor. A Button masked by plain GraphicObject masks never receives input.

Masking.makeMasked parameter: maskGroups
[type: MaskGroup, [MaskGroup]] 
The MaskGroup(s) that the rendering of this GraphicObject will be limited to. For a list of available MaskGroups, see 'nc.maskGroups'.

Masking.makeMasked parameter: invert
[type: boolean] [default: false] [optional] 
Inverts the effect of the masking, swapping the areas where this GraphicObject will and won't be rendered.

example:
// Objective: Use a mask to reveal only a portion of the phrase "Hello World."
// Expected Result: You will see the word "World." on screen.

// create a TextBox
let textBox = nc.addTextBox( nc.mainScene );
textBox.string = "Hello World."
textBox.makeMasked( nc.maskGroups.MainMaskGroup ); // mask it with "MainMaskGroup"

// create a GraphicObject rectangle and position it to cover the word "World."
this.masker = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Masker" );
this.masker.scale.x = 2; // rectangle
this.masker.position.x = 75; // position
this.masker.masking.makeMask( nc.maskGroups.MainMaskGroup ); // make it a masker for "MainMaskGroup"





Masking.setMaskGroups(maskGroups)
[type: function] 
Sets the MaskGroup or list of MaskGroups that this GraphicObject is associated with.

Masking.setMaskGroups parameter: maskGroups
[type: MaskGroup, [MaskGroup]] 
The MaskGroup or list of MaskGroups to set.





Masking.getMaskGroups()
[type: function] [returns: [MaskGroup]] 
Gets the list of MaskGroups that this GraphicObject is associated with.










----------------------------------------------------------
Section 87: MaskGroup
----------------------------------------------------------


MaskGroup
[type: class] 
Masking functionality enables selective rendering of portions of GraphicObjects. MaskGroups can be defined, and then GraphicObjects can be configured as 'mask', which add their shape to the area of the newly defined MaskGroup. Then, when other GraphicObjects are configured as 'masked', their rendering only occures within areas defined by the MaskGroup.





MaskGroup.type
[type: string] 
Type identifier.





MaskGroup.inheritedTypes
[type: object] 
Dictionary of type that this object inherits from.





MaskGroup.name
[type: string] 
The name of the MaskGroup





MaskGroup.maskGroupNumber
[type: number] 
The numeric value representing this MaskGroup.










----------------------------------------------------------
Section 88: SpriteSetter
----------------------------------------------------------


SpriteSetter
[type: class] [extends: ValuePlaybackController] [NON-INSTANTIABLE] 
A SpriteSetter is a PlaybackController that switches a GraphicObject's graphicAsset between numerically sequential GraphicAssets. It is typically used to create a sprite animation. 





SpriteSetter.type
[type: string] 
Type identifier.





SpriteSetter.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





SpriteSetter.keyGraphicAsset
[type: GraphicAsset] 
The key GraphicAsset for this SpriteSetter. Setting this property automatically gathers all numerically similar GraphicAssets into the associated GraphicAssets list (equivalent to calling setKeyGraphicAsset).





SpriteSetter.getAssociatedGraphicAssets()
[type: function] [returns: [GraphicAsset]] 
Returns a copy of the array of GraphicAssets that are iterated through during playback.





SpriteSetter.setAssociatedGraphicAssets(graphicAsset)
[type: function] 
Manually populates the array of GraphicAssets that will be iterated through during playback.

SpriteSetter.setAssociatedGraphicAssets parameter: graphicAsset
[type: [GraphicAsset], GraphicAsset] 
GraphicAsset or Array of Graphic Assets that will be iterated through during playback.





SpriteSetter.setKeyGraphicAsset(graphicAsset)
[type: function] 
Sets the key GraphicAsset. This GraphicAsset's name should end in a number. All GraphicAssets whose name matches the key GraphicAsset's name with a different trailing number will be used to set the SpriteSetter's associated GraphicAssets list. For example, if the key GraphicAsset is named "MyAnimation001", all GraphicAssets with the name "MyAnimation" followed by any sequence of the digits 0-9 will be gathered into this SpriteSetter's associated GraphicAssets.

SpriteSetter.setKeyGraphicAsset parameter: graphicAsset
[type: GraphicAsset] 
The GraphicAssets used for automatical detection all all numerically similar GraphicAssets.


































































































































----------------------------------------------------------
Section 89: UxTable
----------------------------------------------------------


UxTable
[type: class] [extends: LayoutStack] [requires: unpublished only, extensions scope] 
A specialized user interface object for use within the Incisor Inspector and Inspector extensions. This is a specialized vertical LayoutStack that displays data as a grid of editable UxTableCell cells. All cells default to editingMode='editable', horizontalJustification='center', wrapToFit=true, and scaleToFit=false. Use 'nce.addUxTable' to create a UxTable from within an extensions scope.





UxTable.numRows
[type: number] [default: 3] 
The total number of rows in the table. Setting this value dynamically adds or removes rows from the bottom of the table.





UxTable.numColumns
[type: number] [default: 3] 
The total number of columns in the table. Setting this value dynamically adds or removes columns from the right side of the table.





UxTable.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body] 
The TextFormat applied to all cells in the table. Setting this clones the value and applies it to all existing cells. New cells created by adding rows or columns also inherit this format.





UxTable.setRowHeight(rowIdx, height)
[type: function] 
Sets the height of all cells in the given row by assigning their boxHeight. A height of 0 clears the boxHeight constraint, allowing cells to size to their content.

UxTable.setRowHeight parameter: rowIdx
[type: number] 
The zero-based index of the row to resize.

UxTable.setRowHeight parameter: height
[type: number] 
A non-negative number. Use 0 to clear any existing height constraint.





UxTable.getRowHeight(rowIdx)
[type: function] [returns: number] 
Returns the current height value stored for the given row.

UxTable.getRowHeight parameter: rowIdx
[type: number] 
The zero-based index of the row.





UxTable.setColumnWidth(colIdx, width)
[type: function] 
Sets the boxWidth of all cells in the given column. A width of 0 is not permitted - all cells must have a positive boxWidth.

UxTable.setColumnWidth parameter: colIdx
[type: number] 
The zero-based index of the column to resize.

UxTable.setColumnWidth parameter: width
[type: number] 
A positive non-zero number.





UxTable.getColumnWidth(colIdx)
[type: function] [returns: number] 
Returns the current width value stored for the given column.

UxTable.getColumnWidth parameter: colIdx
[type: number] 
The zero-based index of the column.





UxTable.addColumnWidthChangeCallback(owner, name, args)
[type: function] 
Registers a callback to be fired whenever a column width is changed via setColumnWidth. The callback receives (colIdx, width) where colIdx is the zero-based column index and width is the new width value.

UxTable.addColumnWidthChangeCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.addColumnWidthChangeCallback parameter: name
[type: string] 
The name of the callback function on the owner.

UxTable.addColumnWidthChangeCallback parameter: args
[type: Array, any] [optional] 
Optional additional argument or arguments passed to the callback after the standard parameters.





UxTable.removeColumnWidthChangeCallback(owner, name)
[type: function] 
Removes a previously registered column width change callback.

UxTable.removeColumnWidthChangeCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.removeColumnWidthChangeCallback parameter: name
[type: string] 
The name of the callback function on the owner.





UxTable.addContextMenuCallback(owner, name, args)
[type: function] 
Registers a callback to be fired when any cell in the table is right-clicked. The callback receives (event, camera, menu, cell) where menu is the newly created UxMenu (not yet open) and cell is the UxTableCell that was right-clicked. The menu is only created and shown if at least one context menu callback is registered. It is automatically disposed when closed.

UxTable.addContextMenuCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.addContextMenuCallback parameter: name
[type: string] 
The name of the callback function on the owner.

UxTable.addContextMenuCallback parameter: args
[type: Array, any] [optional] 
Optional additional argument or arguments passed to the callback after the standard parameters.





UxTable.removeContextMenuCallback(owner, name)
[type: function] 
Removes a previously registered context menu callback.

UxTable.removeContextMenuCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.removeContextMenuCallback parameter: name
[type: string] 
The name of the callback function on the owner.





UxTable.addStartEditingCallback(owner, name, args)
[type: function] 
Registers a callback to be fired whenever any cell in the table begins editing. The callback receives (cell) where cell is the UxTableCell that started editing.

UxTable.addStartEditingCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.addStartEditingCallback parameter: name
[type: string] 
The name of the callback function on the owner.

UxTable.addStartEditingCallback parameter: args
[type: Array, any] [optional] 
Optional additional argument or arguments passed to the callback after the standard parameters.





UxTable.removeStartEditingCallback(owner, name)
[type: function] 
Removes a previously registered start-editing callback.

UxTable.removeStartEditingCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.removeStartEditingCallback parameter: name
[type: string] 
The name of the callback function on the owner.





UxTable.addEditCommitCallback(owner, name, args)
[type: function] 
Registers a callback to be fired whenever any cell in the table commits an edit. The callback receives (newString, originalString, cell) where cell is the UxTableCell that was edited.

UxTable.addEditCommitCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.addEditCommitCallback parameter: name
[type: string] 
The name of the callback function on the owner.

UxTable.addEditCommitCallback parameter: args
[type: Array, any] [optional] 
Optional additional argument or arguments passed to the callback after the standard parameters.





UxTable.removeEditCommitCallback(owner, name)
[type: function] 
Removes a previously registered edit commit callback.

UxTable.removeEditCommitCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.removeEditCommitCallback parameter: name
[type: string] 
The name of the callback function on the owner.





UxTable.addDimensionChangeCallback(owner, name, args)
[type: function] 
Registers a callback to be fired whenever the table's numRows or numColumns changes.

UxTable.addDimensionChangeCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.addDimensionChangeCallback parameter: name
[type: string] 
The name of the callback function on the owner.

UxTable.addDimensionChangeCallback parameter: args
[type: Array, any] [optional] 
Optional additional argument or arguments passed to the callback.





UxTable.removeDimensionChangeCallback(owner, name)
[type: function] 
Removes a previously registered dimension change callback.

UxTable.removeDimensionChangeCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.removeDimensionChangeCallback parameter: name
[type: string] 
The name of the callback function on the owner.





UxTable.getCells()
[type: function] [returns: [[UxTableCell]]] 
Returns a 2D array of all cells in the table, organized as getCells()[row][column].





UxTable.addCursorInCallback(owner, name, args)
[type: function] 
Registers a callback to be fired whenever the cursor enters any cell in the table. The callback receives (event, camera, cell) where cell is the UxTableCell the cursor entered.

UxTable.addCursorInCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.addCursorInCallback parameter: name
[type: string] 
The name of the callback function on the owner.

UxTable.addCursorInCallback parameter: args
[type: Array, any] [optional] 
Optional additional argument or arguments passed to the callback after the standard parameters.





UxTable.removeCursorInCallback(owner, name)
[type: function] 
Removes a previously registered cursor-in callback.

UxTable.removeCursorInCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.removeCursorInCallback parameter: name
[type: string] 
The name of the callback function on the owner.





UxTable.addCursorOutCallback(owner, name, args)
[type: function] 
Registers a callback to be fired whenever the cursor leaves any cell in the table. The callback receives (event, camera, cell) where cell is the UxTableCell the cursor left.

UxTable.addCursorOutCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.addCursorOutCallback parameter: name
[type: string] 
The name of the callback function on the owner.

UxTable.addCursorOutCallback parameter: args
[type: Array, any] [optional] 
Optional additional argument or arguments passed to the callback after the standard parameters.





UxTable.removeCursorOutCallback(owner, name)
[type: function] 
Removes a previously registered cursor-out callback.

UxTable.removeCursorOutCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.removeCursorOutCallback parameter: name
[type: string] 
The name of the callback function on the owner.





UxTable.addDragCallback(owner, name, args)
[type: function] 
Registers a callback to be fired whenever any cell in the table is dragged. The callback receives (event, camera, cell) where cell is the UxTableCell being dragged.

UxTable.addDragCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.addDragCallback parameter: name
[type: string] 
The name of the callback function on the owner.

UxTable.addDragCallback parameter: args
[type: Array, any] [optional] 
Optional additional argument or arguments passed to the callback after the standard parameters.





UxTable.removeDragCallback(owner, name)
[type: function] 
Removes a previously registered drag callback.

UxTable.removeDragCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.removeDragCallback parameter: name
[type: string] 
The name of the callback function on the owner.





UxTable.addDropCallback(owner, name, args)
[type: function] 
Registers a callback to be fired whenever a cell is dropped onto any cell in the table. The callback receives (event, camera, draggedCell, droppedCell).

UxTable.addDropCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.addDropCallback parameter: name
[type: string] 
The name of the callback function on the owner.

UxTable.addDropCallback parameter: args
[type: Array, any] [optional] 
Optional additional argument or arguments passed to the callback after the standard parameters.





UxTable.removeDropCallback(owner, name)
[type: function] 
Removes a previously registered drop callback.

UxTable.removeDropCallback parameter: owner
[type: object] 
The object that owns the callback function.

UxTable.removeDropCallback parameter: name
[type: string] 
The name of the callback function on the owner.





















































































































































































































































































































































































































----------------------------------------------------------
Section 90: Camera
----------------------------------------------------------


Camera
[type: class] [extends: SceneObject] [NON-INSTANTIABLE] 
A Camera is a specialized SceneObject with the ability to render the Scene that contains it to a RenderTarget. 





Camera.autoRender
[type: boolean] [default: true] 
Boolean determining if this Camera is automatically rendered with every screen update.





Camera.autoRenderOrder
[type: number] [default: 0] 
Number determining this Camera's order in the list of automatically rendered Cameras. Higher numbers correspond to earlier render order.





Camera.backgroundColor
[type: Color] [default: Color(0,0,0,0)] 
Color determining the background color (aka the 'clear color') of this Camera. Please note that the 'MainCamera' defaults to [0.1,0.08,0.08,1], while all other cameras default to [0,0,0,0]. These values can be changed at any time.





Camera.cursorInteractive
[type: boolean] [default: false] 
Boolean determining if this camera will be used in conjunction with a cursor for Buttons or other cursor activity. Cameras are responsible for relating the cursor's screen position to a position within the Scene and this flag informs the Camera of that requirement. To optimize your project, ensure that this property is only set to true when cursor interactivity (Buttons etc...) in the Scene that this Camera is rendering.





Camera.adaptiveCameraMode
[type: string] 
Property determining the 'adaptive camera mode' of this Camera. Adaptive camera modes can put a Camera into a state where it reacts to the shape it's RenderTarget, extending or contracting the view area of the Camera as the shape if it's RenderTarget changes. The available values can be found in 'constants.adaptiveCameraModes'.





Camera.clearsColor
[type: boolean] 
Boolean determining if the color buffer is cleared in this Camera's RenderTarget prior to rendering.





Camera.clearsDepth
[type: boolean] 
Boolean determining if the depth buffer is cleared in this Camera's RenderTarget prior to rendering.





Camera.clearsStencil
[type: boolean] 
Boolean determining if the stencil buffer is cleared in this Camera's RenderTarget prior to rendering.





Camera.renderTarget
[type: RenderTarget] 
The RenderTarget this Camera will render to when Camera.render is invoked.





Camera.cursorInputOverride()
[type: function, CursorInputOverrideButton] 
This property provides means to override the automated setting of this Camera's cursorViewPosition. This is most commonly deployed when a RenderTarget used within a primary Scene serves as a 'window' into a secondary Scene that requires cursor interaction - this property would be used to map the cursor interaction through the window into the secondary screen. This property can be used two ways: 1. Define a CursorInputOverrideButton and set this property to that object. When you do this, the button serves as a 'cursor mapping surface', where the edges of the CursorInputOverrideButton correspond to the edges of the secondary Camera's view area. 2. Set this property to a function that remaps the cursorViewPosition manually. This method can be used to further customize the setting of this Camera's cursorViewPosition. If implemented, the first parameter of the function should take the triggering browser-generated cursor event, and the second parameter will be a Vector2 holding the default-calculated cursorViewPosition. The function should use those parameters as input, generate the desired remapped values, and call 'setCursorViewPosition' on the camera accordingly.





Camera.touchDragInitiationThreshold
[type: number] [default: 0.05] 
Proportion of the Camera's view area that a touch-based cursor drag must travel in order to initiate a Button 'drag'. While using a touch-based device, tapping the screen often produces a tiny unintentional cursor drag. This value creates a threshold; if the cursor moves less than this portion of the Camera's view area during a screen touch, no Button 'drag' occurs.





Camera.mouseDragInitiationThreshold
[type: number] [default: 0.005] 
Proportion of the Camera's view area that a mouse-based cursor drag must travel in order to initiate a Button 'drag'. While using a mouse, clicking sometimes produces a tiny un-intentional cursor drag. This value creates a threshold; if the cursor moves less than this portion of the Camera's view area during a click, no Button 'drag' occurs.





Camera.isCurrentlyRendering
[type: boolean] 
Boolean denoting if the Camera is currently in the process of rendering. This property can be queried prior to any potentially recursive 'Camera.render' calls to prevent an infinite self-invocation scenario.





Camera.timelineRenderDriver
[type: Timeline] [default: undefined] 
Optional TimelineManager that can drive this camera's rendering. This property defaults to undefined, but when it is set to a given TimelineManager the Camera will render continuously as long as one or more Timeline with non-zero influence is playing. If the 'generatesPrecomp' setting for a given Construct is true, and if that Construct has one or more Timelines, then the associate Precomp Camera's 'timelineRenderDriver' value is automatically set to the Construct instance's TimelineManager. This enables Construct-generated Precomps to render while timelines are playing, and rest while timelines are not playing.





Camera.viewNear
[type: number] 
The distance from the Camera to the near side of the view area (frustum). For OrthographicCameras this value defaults to 0, for PerspectiveCameras this value defaults to 10.





Camera.viewFar
[type: number] [default: 2000] 
The distance from the Camera to the far side of the view area (frustum). For OrthographicCameras this value defaults to 2000, for PerspectiveCameras this value defaults to 2500.





Camera.viewDepth
[type: number] 
The depth of the camera view area (frustum) in 'world units' as measured from the 'viewNear' value.





Camera.render(skipRenderPreparations)
[type: function] 
Renders the contents of the Scene within the Camera's view area to the RenderTarget.

Camera.render parameter: skipRenderPreparations
[type: boolean] [default: false] [optional] 
Boolean that, if true, tells the rendering process to skip render preparations for efficiency. This flag is best used with secondary Cameras that render Scenes that have already been rendered once in their current state (as the preparations would have already been completed).





Camera.setCursorViewPosition(x, y, z, simulateCursorMoveEvent)
[type: function] 
Updates the Camera's cursor view position to the given x and y coordinates. Camera view coordinates operate with bounds from -.5 to .5, where -.5 is the left/bottom edge of the view plane, and .5 is the right/top edge. The cursor view position is used to calculate cursor interaction with Buttons etc.

Camera.setCursorViewPosition parameter: x
[type: number] 
The x position for the cursor in terms of Camera view coordinates [-.5,.5]

Camera.setCursorViewPosition parameter: y
[type: number] 
The y position for the cursor in terms of Camera view coordinates [-.5,.5]

Camera.setCursorViewPosition parameter: z
[type: number] 
The z position for the cursor in terms of Camera view coordinates [-.5,.5] (where .5 is the near side of the frustum)

Camera.setCursorViewPosition parameter: simulateCursorMoveEvent
[type: boolean] [default: false] 
Boolean indicating if the "simulateCursorMoveEvent" will automatically be called. If true it should be noted that the associated call to 'simulateCursorMoveEvent' will use the default param 'updateScene=true', which could result in an extra performance cost per invocation.





Camera.getCursorViewPosition(returnVector3)
[type: function] [returns: Vector3] 
Returns a Vector3 with the cursor position in terms of Camera view coordinates. Camera view coordinates operate with bounds from -.5 to .5, where -.5 is the left/bottom/far edge of the frustum, and .5 is the right/top/near edge.

Camera.getCursorViewPosition parameter: returnVector3
[type: Vector3] [optional] 
Optional Vector3 that can be supplied to avoid the generation of a new Vector3 object for efficiency.





Camera.setCursorPosition(x, y, z, simulateCursorMoveEvent)
[type: function] 
Updates the Camera's cursor position from a given world position. The cursor position is used to calculate cursor interaction with Buttons etc.

Camera.setCursorPosition parameter: x
[type: number] 
The x position for the cursor in terms of world coordinates

Camera.setCursorPosition parameter: y
[type: number] 
The y position for the cursor in terms of world coordinates

Camera.setCursorPosition parameter: z
[type: number] 
The z position for the cursor in terms of world coordinates

Camera.setCursorPosition parameter: simulateCursorMoveEvent
[type: boolean] [default: false] 
Boolean indicating if the 'simulateCursorMoveEvent' will automatically be called. If true it should be noted that the associated call to 'simulateCursorMoveEvent' will use the default param 'updateScene=true', which could result in an extra performance cost per invocation.





Camera.getCursorPosition(returnVector3)
[type: function] [returns: Vector3] 
Returns a Vector3 with the cursor position in terms of world coordinates. The cursor position is used to calculate cursor interaction with Buttons etc.

Camera.getCursorPosition parameter: returnVector3
[type: Vector3] [optional] 
Optional Vector3 that can be supplied to avoid the generation of a new Vector3 object for efficiency.





Camera.performManualCursorRolloverCheck()
[type: function] 
Manually checks this Camera's cursor position, triggering any appropriate 'cursorIn' or 'cursorOut' callbacks for the appropriate Buttons. This function can be used to ensure that 'cursorIn' or 'cursorOut' callbacks are triggered even when there is no originating cursor event; for example, if Buttons are moving themselves, and a new Button moves under the cursor, invoking this function would evaluate the cursor and button positions and ultimately trigger the 'cursorIn' callback for the new Button.





Camera.simulateCursorMoveEvent(updateScene)
[type: function] 
Simulates a 'cursorMove' AppEvent at the current cursor position. Please note that either setCursorViewPosition or setCursorPosition will need to called to actually change the position of the cursor, as this method is only responsible for triggering the cursorMove-related Button callbacks. You can reposition the cursor AND get cursorMove-related Button callbacks by calling setCursorViewPosition or setCursorPosition with paramater simulateCursorMoveEvent=true. Also, please note this Camera must render once before the cursorPosition will intersect with any Buttons.

Camera.simulateCursorMoveEvent parameter: updateScene
[type: boolean] [default: true] [optional] 
Boolean determining if the Scene will be manually updated prior to the simulated AppEvent; this ensures that the most recent Scene changes (changes within the current screenUpdate) affecting Button detection are accounted for, but can result in an extra cost to performance per invocation, so should not be overly used.





Camera.simulateCursorPressEvent(updateScene)
[type: function] 
Simulates a 'cursorPress' AppEvent at the current cursor position. Call setCursorViewPosition or setCursorPosition prior to calling this function to change the cursor position if needed. Please note this Camera must render once before the cursorPosition will intersect with any Buttons.

Camera.simulateCursorPressEvent parameter: updateScene
[type: boolean] [default: true] [optional] 
Boolean determining if the Scene will be manually updated prior to the simulated AppEvent; this ensures that the most recent Scene changes (changes within the current screenUpdate) affecting Button detection are accounted for, but can result in an extra cost to performance per invocation, so should not be overly used.





Camera.simulateCursorReleaseEvent(updateScene)
[type: function] 
Simulates a 'cursorRelease' AppEvent at the current cursor position. Call setCursorViewPosition or setCursorPosition prior to calling this function to change the cursor position if needed. Please note this Camera must render once before the cursorPosition will intersect with any Buttons.

Camera.simulateCursorReleaseEvent parameter: updateScene
[type: boolean] [default: true] [optional] 
Boolean determining if the Scene will be manually updated prior to the simulated AppEvent; this ensures that the most recent Scene changes (changes within the current screenUpdate) affecting Button detection are accounted for, but can result in an extra cost to performance per invocation, so should not be overly used.





Camera.simulateCursorScrollEvent(updateScene)
[type: function] 
Simulates a 'cursorScroll' AppEvent at the current cursor position. Call setCursorViewPosition or setCursorPosition prior to calling this function to change the cursor position if needed. Please note this Camera must render once before the cursorPosition will intersect with any Buttons.

Camera.simulateCursorScrollEvent parameter: updateScene
[type: boolean] [default: true] [optional] 
Boolean determining if the Scene will be manually updated prior to the simulated AppEvent; this ensures that the most recent Scene changes (changes within the current screenUpdate) affecting Button detection are accounted for, but can result in an extra cost to performance per invocation, so should not be overly used.





Camera.simulateContextMenuEvent(updateScene)
[type: function] 
Simulates a 'contextMenu' AppEvent at the current cursor position. Call setCursorViewPosition or setCursorPosition prior to calling this function to change the cursor position if needed. Please note this Camera must render once before the cursorPosition will intersect with any Buttons. Also, it should be noted that this method is not capable of producing the browser's actual context menu, it is only a means to trigger the Incisor®-level AppEvents and callbacks that such an event would produce.

Camera.simulateContextMenuEvent parameter: updateScene
[type: boolean] [default: true] [optional] 
Boolean determining if the Scene will be manually updated prior to the simulated AppEvent; this ensures that the most recent Scene changes (changes within the current screenUpdate) affecting Button detection are accounted for, but can result in an extra cost to performance per invocation, so should not be overly used.





Camera.getIntersections(viewPosition, sceneObjects, intersectionsArray)
[type: function] [returns: [Intersection]] 
The means to determine which SceneObject (if any) intersect with a given position within the Camera's view.

Camera.getIntersections parameter: viewPosition
[type: Vector2] [default: Camera.getViewPosition()] [optional] 
The position within the Camera's view space [-.5,.5]x[-.5,.5] to use when determining if any SceneObjects intersect.

Camera.getIntersections parameter: sceneObjects
[type: [SceneObject]] [default: Scene.getDescendants()] [optional] 
The list of SceneObjects to test for intersection.

Camera.getIntersections parameter: intersectionsArray
[type: Array] [optional] 
Optional array that can be provided as an optimization to avoid the creation of a new array.





Camera.clear(clearColor, clearDepth, clearStencil)
[type: function] 
Clears the connected RenderTarget's buffers as specified.

Camera.clear parameter: clearColor
[type: boolean] [default: true] [optional] 
Boolean indicating if the color buffer should be cleared from the attached RenderTarget.

Camera.clear parameter: clearDepth
[type: boolean] [default: true] [optional] 
Boolean indicating if the depth buffer should be cleared from the attached RenderTarget.

Camera.clear parameter: clearStencil
[type: boolean] [default: true] [optional] 
Boolean indicating if the clearStencil buffer should be cleared from the attached RenderTarget.



























































































































































































































































































































----------------------------------------------------------
Section 91: OrthographicCamera
----------------------------------------------------------


OrthographicCamera
[type: class] [extends: Camera] 
An OrthographicCamera is a camera that renders orthographically, with no perspective.





OrthographicCamera.coreViewWidth
[type: number] [default: 500] 
The base width of the camera view area (frustum) in 'world units'. This number may not match the actual view width for certain settings of the 'adaptiveCameraMode' property.





OrthographicCamera.coreViewHeight
[type: number] [default: 500] 
The base height of the camera view area (frustum) in 'world units'. This number may not match the actual view height for certain settings of the 'adaptiveCameraMode' property.





OrthographicCamera.getCurrentViewDimensions()
[type: function] [returns: Vector3] 
Returns a Vector3 containing current dimensions of this Camera's current view area, inclusive of any changes brought about by its adaptiveCameraMode.

















































































































































































































































































































































































































































































----------------------------------------------------------
Section 92: PerspectiveCamera
----------------------------------------------------------


PerspectiveCamera
[type: class] [extends: Camera] 
A PerspectiveCamera is a Camera that renders with a perspective view, defined by its 'coreViewAngleVertical' and 'coreViewAngleHorizontal' values.





PerspectiveCamera.coreViewAngleVertical
[type: number] [default: 60] 
The core angle between the bottom and top of the visible area for this PerspectiveCamera. This number may not match the actual view angle for certain settings of the 'adaptiveCameraMode' property.





PerspectiveCamera.coreViewAngleHorizontal
[type: number] [default: 60] 
The core angle between the left and right of the visible area for this PerspectiveCamera. This number may not match the actual view angle for certain settings of the 'adaptiveCameraMode' property.





PerspectiveCamera.getCurrentViewAngles()
[type: function] [returns: Vector2] 
Returns a Vector2 containing current horizontal and vertical view angles for this Camera's view area, inclusive of any changes brought about by its adaptiveCameraMode.

















































































































































































































































































































































































































































































----------------------------------------------------------
Section 93: Intersection
----------------------------------------------------------


Intersection
[type: class] [NON-INSTANTIABLE] 
Class holding the information about an intersection between a point in a Camera's view and a SceneObject in the Scene. Objects of this type are returned from the Camera.getIntersections method. 





Intersection.sceneObject
[type: SceneObject] 
The SceneObject that is intersected.





Intersection.intersectionPosition
[type: Vector3] 
The global position of the intersection within the given Scene.










----------------------------------------------------------
Section 94: LoadingTierDefinition
----------------------------------------------------------


LoadingTierDefinition
[type: class] [NON-INSTANTIABLE] 
Object with information about a loading tier. Loading tiers are a means to organize AssetComponents into separately downloadable groups. 





LoadingTierDefinition.type
[type: string] 
Type identifier.





LoadingTierDefinition.loadingTier
[type: number] 
The loading tier number.





LoadingTierDefinition.isAutoLoaded
[type: boolean] 
Bool determining if this loading tier is automatically loaded on startup.





LoadingTierDefinition.incrementalContentProcessing
[type: boolean] 
Bool determining if the processing of the data in this loading tier is processed incrementally. This setting can be used to minimize performance hits caused when asset data is 'lazy-loaded' during the end-user experience. When true, the processing of assets within a tier is spread out over multiple screen updates. This can be changed while the tier is loading, for example set to false to finish processing a tier that is suddenly needed.





LoadingTierDefinition.assetDataFileSizeLimitKB
[type: number] 
A limit on the size of the published asset data files within this loading tier. This setting can be used to break up the loading of asset data in order to help minimize performance hits caused when asset data is 'lazy-loaded' during the end-user experience. It should be noted that this is a soft-limit; individual assetComponents whose data is larger than this limit will result in oversized asset data files.





LoadingTierDefinition.spriteSheetDimensionLimit
[type: number] 
A limit on the dimensions of sprite sheets within this loading tier. It should be noted that this is a soft-limit; individual GraphicAssets whose dimensions are larger than this limit will result in oversized sprite sheet files.





LoadingTierDefinition.isLoaded
[type: boolean] 
Bool indicating if all of the assets in this loading tier have been loaded.





LoadingTierDefinition.isLoading
[type: boolean] 
Bool indicating if this LoadingTier is in the process of loading or is queued to load.





LoadingTierDefinition.loadingProgress
[type: number] 
Number from 0 to 1 indicating the loading progress of this LoadingTier.










----------------------------------------------------------
Section 95: IncisorExtensions
----------------------------------------------------------


IncisorExtensions
[type: class] [extends: INCISOR] [NON-INSTANTIABLE] [requires: unpublished only, extensions scope] 
Object housing all of the Incisor Extensions functionality. In general, this object has much of the same functionality as nc/INCISOR and is therefore documented as extending that object but not all of the same functionality is available through this object, so auto-complete may show some non-existent members. This object is accessible in the 'CODE.runBeforeInit' block of the extensions scope by the instance name 'nce'. 





IncisorExtensions.incisorExtensions_global
[type: object] 
The global incisor extensions object. This corresponds to the scope of the javascript code placed in the "Global Extensions" folder in the "Application Support" directory (which can be accessed from the Incisor menu). It should be noted that the global extensions scope is initialized before the project extensions scope, and as such 'nce.incisorExtensions_project' member will likely be undefined from within the global scope on init. Once project extensions are loaded the 'nce.incisorExtensions_project' member is initialized.





IncisorExtensions.incisorExtensions_project
[type: object] 
The project extensions object. This corresponds to the scope of the javascript code placed in the "ProjectExtensions" folder in the "Utilities" directory of the given project. It should be noted that the global extensions scope is initialized before the project extensions scope, and as such 'nce.incisorExtensions_project' member will likely be undefined from within the global scope on init. Once project extensions are loaded the 'nce.incisorExtensions_project' member is initialized.





IncisorExtensions.projectNC
[type: INCISOR] 
A reference to the 'nc' object (INCISOR) inside of the target project. Please note that this value can be undefined, when the project is loading or if the project code has a runtime or syntax error. See also 'nce.addProjectConnectionCallback' and 'nce.addProjectDisconnectionCallback' for the associated callbacks.





IncisorExtensions.projectAutoRefreshIsPaused
[type: boolean] 
True while the project's automatic refresh on code changes is paused by 'nce.pauseProjectAutoRefresh'.





IncisorExtensions.projectPR
[type: ProjectMain] 
A reference to the 'pr' object (ProjectMain) inside of the target project. Please note that this value can be undefined, when the project is loading or if the project code has a runtime or syntax error. See also 'nce.addProjectConnectionCallback' and 'nce.addProjectDisconnectionCallback' for the associated callbacks.





IncisorExtensions.addInspectorMenuItem(menuPath, callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds menu item to the menus along the top of the Incisor inspector, and registers a callback function (from within the Incisor extensions scope) that will be triggered whenever that menu item is selected. It should be noted that custom inspector menu items cannot be added to built-in Incisor menus.

IncisorExtensions.addInspectorMenuItem parameter: menuPath
[type: [string]] 
An array of menu item names, where the first name is the name of the root custom menu. For example ["MyMenu","MySubMenu","MyTargetMenuItem"], would create a 'MyMenu' menu in the inspector, with sub-menu 'SubMenu', which would hold the 'MyTargetMenuItem' option that triggers the desired callback.

IncisorExtensions.addInspectorMenuItem parameter: callbackOwner
[type: object] 
The object (from within the given IncisorExtensions context) that owns the callback function.

IncisorExtensions.addInspectorMenuItem parameter: callbackName
[type: string] 
The name of the callback function.

IncisorExtensions.addInspectorMenuItem parameter: callbackArgs
[type: Array] [optional] 
A list of parameters that will be sent to the callback function.





IncisorExtensions.registerInspectorPanelDefinition(name, classDefinition)
[type: function] 
Registers a custom InspectorPanel type with the Incisor GUI, enabling users to select this newly defined panel as an option from within the Inspector.

IncisorExtensions.registerInspectorPanelDefinition parameter: name
[type: string] 
The name of the InspectorPanel - this name should match (exactly) the name given to the InspectorPanel constructor 'panelTypeName' param. This is the name that will appear in the panel type selection drop down in the GUI.

IncisorExtensions.registerInspectorPanelDefinition parameter: classDefinition
[type: object] 
The class Definition for the new InspectorPanel type. The class definition provided for this parameter should extend 'InspectorPanel'





IncisorExtensions.saveProjectScreenShot(path, isPathRelative)
[type: function] [returns: string] 
Saves a screen shot of the project and returns the path of the screenshot.

IncisorExtensions.saveProjectScreenShot parameter: path
[type: string] 
The path to the screenshot. If left undefined, the 'screenShotDestination' value in the ProjectSettings is used.

IncisorExtensions.saveProjectScreenShot parameter: isPathRelative
[type: boolean] 
Boolean determining if the screen shot's path is relative to the project.





IncisorExtensions.saveInspectorScreenShot(path, isPathRelative)
[type: function] [returns: string] 
Saves a screen shot of the entire inspector and returns the path of the screenshot.

IncisorExtensions.saveInspectorScreenShot parameter: path
[type: string] 
The path to the screenshot. If left undefined, the 'screenShotDestination' value in the ProjectSettings is used.

IncisorExtensions.saveInspectorScreenShot parameter: isPathRelative
[type: boolean] 
Boolean determining if the screen shot's path is relative to the project.





IncisorExtensions.alert(popupTitleText, popupBodyText)
[type: function] 
Displays a standardized UiPopupWindow with the given title and body text populated. This method is asyncronously awaitable in the event the given alert needs to be shown before code excution continues.

IncisorExtensions.alert parameter: popupTitleText
[type: string] 
The text displayed in the title bar of the UiPopupWindow.

IncisorExtensions.alert parameter: popupBodyText
[type: string] 
The text displayed in the body of the UiPopupWindow.





IncisorExtensions.showYesNoQueryPopup(popupTitleText, popupBodyText)
[type: function] [returns: string] 
Displays a standardized UiPopupWindow that will return a Yes/No string based on which decision button the user presses. This method is asyncronously awaitable in the event the given popup to be shown before code excution continues.

IncisorExtensions.showYesNoQueryPopup parameter: popupTitleText
[type: string] 
The text displayed in the title bar of the UiPopupWindow.

IncisorExtensions.showYesNoQueryPopup parameter: popupBodyText
[type: string] 
The text displayed in the body of the UiPopupWindow.





IncisorExtensions.showTextQueryPopup(popupTitleText, popupBodyText, textFieldLabel, defaultResponse)
[type: function] [returns: string] 
Displays a standardized UiPopupWindow that will return a user-populated string based on what the user enters in a UiTextField. This method is asyncronously awaitable in the event the given popup to be shown before code excution continues.

IncisorExtensions.showTextQueryPopup parameter: popupTitleText
[type: string] 
The text displayed in the title bar of the UiPopupWindow.

IncisorExtensions.showTextQueryPopup parameter: popupBodyText
[type: string] 
The text displayed in the body of the UiPopupWindow.

IncisorExtensions.showTextQueryPopup parameter: textFieldLabel
[type: string] 
The label text for the UiTextField user-prompt.

IncisorExtensions.showTextQueryPopup parameter: defaultResponse
[type: string] 
The text value pre-populated in the UiTextField user-prompt.





IncisorExtensions.showPathQueryPopup(popupTitleText, popupBodyText, root, showFiles, selectableFiles, allowMultiSelect, rootSelectorActive)
[type: function] [returns: string] 
Displays a standardized UiPopupWindow that displays a FileBrowser and returns the user's selection. This method is asyncronously awaitable in the event the given popup to be shown before code excution continues.

IncisorExtensions.showPathQueryPopup parameter: popupTitleText
[type: string] 
The text displayed in the title bar of the UiPopupWindow.

IncisorExtensions.showPathQueryPopup parameter: popupBodyText
[type: string] 
The text displayed in the body of the UiPopupWindow.

IncisorExtensions.showPathQueryPopup parameter: root
[type: string] 
The root directory to show in the FileBrowser.

IncisorExtensions.showPathQueryPopup parameter: showFiles
[type: boolean] 
Flag determining if files are shown in the FileBrowser.

IncisorExtensions.showPathQueryPopup parameter: selectableFiles
[type: boolean] 
Flag determining if files are able to be selected in the FileBrowser.

IncisorExtensions.showPathQueryPopup parameter: allowMultiSelect
[type: boolean] 
Flag determining if multiple items can be selected at once in the FileBrowser.

IncisorExtensions.showPathQueryPopup parameter: rootSelectorActive
[type: boolean] 
Flag determining if the user can change the root directory of the FileBrowser.





IncisorExtensions.addProjectConnectionCallback(callbackOwner, callbackName)
[type: function] 
Adds a callback for when the Inspector connects to the project.

IncisorExtensions.addProjectConnectionCallback parameter: callbackOwner
[type: object] 
The object that owns the callback function.

IncisorExtensions.addProjectConnectionCallback parameter: callbackName
[type: string] 
The name of the callback function.





IncisorExtensions.removeProjectConnectionCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

IncisorExtensions.removeProjectConnectionCallback parameter: callbackOwner
[type: object] 
The object that owns the callback function.

IncisorExtensions.removeProjectConnectionCallback parameter: callbackName
[type: string] 
The name of the callback function.





IncisorExtensions.addProjectDisconnectionCallback(callbackOwner, callbackName)
[type: function] 
Adds a callback for when the Inspector disconnects from the project.

IncisorExtensions.addProjectDisconnectionCallback parameter: callbackOwner
[type: object] 
The object that owns the callback function.

IncisorExtensions.addProjectDisconnectionCallback parameter: callbackName
[type: string] 
The name of the callback function.





IncisorExtensions.removeProjectDisconnectionCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

IncisorExtensions.removeProjectDisconnectionCallback parameter: callbackOwner
[type: object] 
The object that owns the callback function.

IncisorExtensions.removeProjectDisconnectionCallback parameter: callbackName
[type: string] 
The name of the callback function.





IncisorExtensions.showProgressBar(name, progress, note)
[type: function] 
Displays a progress bar in the Incisor inspector.

IncisorExtensions.showProgressBar parameter: name
[type: string] 
The name of the task associated with this progress bar.

IncisorExtensions.showProgressBar parameter: progress
[type: number] 
Progress, as indicated by a number from 0 to 1. Call this function with a value of 1 to clear the progress bar.

IncisorExtensions.showProgressBar parameter: note
[type: string] 
An optional secondary note that can change as the progress us update.





IncisorExtensions.addPrePublishCallback(callbackOwner, callbackName)
[type: function] 
Adds a callback that occurs directly before the publishing of the project. A PrePublishInfoObject is passed to the callbacks as the first parameter.

IncisorExtensions.addPrePublishCallback parameter: callbackOwner
[type: object] 
The object that owns the callback function.

IncisorExtensions.addPrePublishCallback parameter: callbackName
[type: string] 
The name of the callback function.





IncisorExtensions.removePrePublishCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

IncisorExtensions.removePrePublishCallback parameter: callbackOwner
[type: object] 
The object that owns the callback function.

IncisorExtensions.removePrePublishCallback parameter: callbackName
[type: string] 
The name of the callback function.





IncisorExtensions.addPostPublishCallback(callbackOwner, callbackName)
[type: function] 
Adds a callback that occurs directly after the publishing of the project. A PostPublishInfoObject with name of the configuration, the publishing timestamp, the destination directory, and the hosted port (if applicable) is passed to the callbacks as the first parameter.

IncisorExtensions.addPostPublishCallback parameter: callbackOwner
[type: object] 
The object that owns the callback function.

IncisorExtensions.addPostPublishCallback parameter: callbackName
[type: string] 
The name of the callback function.





IncisorExtensions.removePostPublishCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

IncisorExtensions.removePostPublishCallback parameter: callbackOwner
[type: object] 
The object that owns the callback function.

IncisorExtensions.removePostPublishCallback parameter: callbackName
[type: string] 
The name of the callback function.





IncisorExtensions.addFileBrowser(parent, name, root, useRelativePaths, singularFocusTarget)
[type: function] [returns: FileBrowser] 
Adds a FileBrowser to the specified parent. A FileBrowser is a specialized LayoutStack with functionality which makes it an ineractive inspector for the OS file system. This class is meant for use in tool development within extensions, and provides a visual means for developers locate and manipulate directories and files. FileBrowsers can only be added to descendants of the 'bodyStack' of a ScrollingPanel.

IncisorExtensions.addFileBrowser parameter: parent
[type: SceneObject] 
The parent to add the FileBrowser to.

IncisorExtensions.addFileBrowser parameter: name
[type: string] 
The name of the new FileBrowser.

IncisorExtensions.addFileBrowser parameter: root
[type: string] [default: nce.paths.desktopPath] [optional] 
The root directory for the FileBrowser.

IncisorExtensions.addFileBrowser parameter: useRelativePaths
[type: boolean] [default: false] [optional] 
Boolean indicating if the paths displayed in the FileBrowser will be relative to the Project.

IncisorExtensions.addFileBrowser parameter: singularFocusTarget
[type: SceneObject] [default: undefined] [optional] 
The SceneObject that must be focused in order for this FileBrowser's keyboard functionality to be active.





IncisorExtensions.addColorSupervisor(parent, name)
[type: function] [returns: ColorSupervisorButton] 
Creates and returns a new ColorSupervisorButton within the specified parent. A ColorSupervisorButton is a UiGraphicButton that displays a color swatch representing the supervised color property. When multiple diverging color values are supervised, a minus icon is shown instead. Pressing the button opens a ColorPicker popup allowing the user to edit the color live. Configure the resulting object's 'propertyOwners' and 'propertyPath', or 'propertyGetterOwner'/'propertyGetterName' and 'propertySetterOwner'/'propertySetterName', to connect it to the desired color property.

IncisorExtensions.addColorSupervisor parameter: parent
[type: SceneObject] 
The parent to add the ColorSupervisorButton to.

IncisorExtensions.addColorSupervisor parameter: name
[type: string] 
The name of the new ColorSupervisorButton.





IncisorExtensions.addUxTable(parent, name)
[type: function] [returns: UxTable] 
Creates and returns a new UxTable within the specified parent. A UxTable is a specialized vertical LayoutStack that displays data as a grid of editable UxTableCell cells. Columns are resizable by dragging the dividers between them. Double-clicking a divider auto-sizes the column to fit its content. Right-clicking any cell fires context menu callbacks, allowing custom menus to be populated.

IncisorExtensions.addUxTable parameter: parent
[type: SceneObject] 
The parent to add the UxTable to.

IncisorExtensions.addUxTable parameter: name
[type: string] 
The name of the new UxTable.





IncisorExtensions.addUxKeyframedValueSupervisor(parent, name)
[type: function] [returns: UxKeyframedValueSupervisor] 
Creates and returns a new UxKeyframedValueSupervisor within the specified parent. A UxKeyframedValueSupervisor displays a single KeyframedValue as an editable row of keyframes, either as a one line dope sheet or as a curve graph. Keyframes can be selected, dragged, stepped, and shaped by their handles, and right-clicking either a keyframe or the background fires context menu callbacks, allowing custom menus to be populated.

IncisorExtensions.addUxKeyframedValueSupervisor parameter: parent
[type: SceneObject] 
The parent to add the UxKeyframedValueSupervisor to.

IncisorExtensions.addUxKeyframedValueSupervisor parameter: name
[type: string] 
The name of the new UxKeyframedValueSupervisor.





IncisorExtensions.runProcess(processExecutable, args, directory)
[type: function] [returns: ProcessResult] 
Runs a provided external executable with the given arguments, returning a ProcessResult object with any ouput from the executable. This functionality is meant to run a given process in a 'one-shot' manner, performing a single setup and sending a single set of arguments to the executable, immediately closing the standard-in stream, and reading both the standard-out and standard-error streams. It should be noted that the "allowExternalExecutableProcesses" setting in ApplicationSettings must be set to true to use this method. Be aware of the risks you are assuming by using this functionality.

IncisorExtensions.runProcess parameter: processExecutable
[type: string] 
The absolute path to the external executable to be run.

IncisorExtensions.runProcess parameter: args
[type: string] [default: ""] [optional] 
The arguments to send to the given executable process.

IncisorExtensions.runProcess parameter: directory
[type: string] [default: ""] [optional] 
The 'working directory' for the executable process.





IncisorExtensions.reloadProject()
[type: function] 
Reloads the project, keeping the current instance of the inspector running. Calling this function is the equivalent of pressing the refresh button in the upper left corner of the 'Live View' panel.





IncisorExtensions.pauseProjectAutoRefresh()
[type: function] 
Pauses the project's automatic refresh on code changes, regardless of the 'refreshOnCodeChange' application setting. Each call must be matched by a call to 'nce.resumeProjectAutoRefresh', and the pause also ends when the connection closes. Calling 'nce.reloadProject' still refreshes the project while paused.





IncisorExtensions.resumeProjectAutoRefresh()
[type: function] 
Ends one 'nce.pauseProjectAutoRefresh' call. Automatic refresh resumes once every pause has been ended.





IncisorExtensions.runCmd(command, directory, processConfigs)
[type: function] [returns: ProcessResult] 
Runs the given command within the Windows command prompt, returning a ProcessResult object with the related output. This functionality is meant to run a given command in a 'one-shot' manner, performing a single command, immediately closing the standard-in stream, and reading both the standard-out and standard-error streams. It should be noted that the "allowExternalExecutableProcesses" setting in ApplicationSettings must be set to true to use this method. Be aware of the risks you are assuming by using this functionality.

IncisorExtensions.runCmd parameter: command
[type: string] [default: ""] [optional] 
The command to send to the Windows command prompt.

IncisorExtensions.runCmd parameter: directory
[type: string] [default: ""] [optional] 
The 'working directory' for the executable process.

IncisorExtensions.runCmd parameter: processConfigs
[type: ProcessConfiguration] [default: undefined] [optional] 
Object containing configurations for how the process will be run.





IncisorExtensions.runBash(command, directory, processConfigs)
[type: function] [returns: ProcessResult] 
Runs the given bash command, returning a ProcessResult object with the related output. This functionality is meant to run a given command in a 'one-shot' manner, performing a single command, immediately closing the standard-in stream, and reading both the standard-out and standard-error streams. It should be noted that the "allowExternalExecutableProcesses" setting in ApplicationSettings must be set to true to use this method. Be aware of the risks you are assuming by using this functionality.

IncisorExtensions.runBash parameter: command
[type: string] [default: ""] [optional] 
The command to send to 'bash'.

IncisorExtensions.runBash parameter: directory
[type: string] [default: ""] [optional] 
The 'working directory' for the executable process.

IncisorExtensions.runBash parameter: processConfigs
[type: ProcessConfiguration] [default: undefined] [optional] 
Object containing configurations for how the process will be run.





IncisorExtensions.clearProjectDetritus(projectPath, clearPublishing, clearAutoSave, clearAuxiliarySupport, clearAssetCache)
[type: function] [returns: ProcessResult] 
Method that clears a project of excess and unnecessary directories and files for the purpose of streamlining.

IncisorExtensions.clearProjectDetritus parameter: projectPath
[type: string] [default: nce.projectPath] [optional] 
The path of the project to clear the detritus from.

IncisorExtensions.clearProjectDetritus parameter: clearPublishing
[type: boolean] [default: false] [optional] 
Boolean determining if the project's Publishing directory will be deleted.

IncisorExtensions.clearProjectDetritus parameter: clearAutoSave
[type: boolean] [default: false] [optional] 
Boolean determining if the project's AutoSave directory will be deleted.

IncisorExtensions.clearProjectDetritus parameter: clearAuxiliarySupport
[type: boolean] [default: false] [optional] 
Boolean determining if any excess workspace folders project's auxiliaryPublishingSupport directory will be deleted.

IncisorExtensions.clearProjectDetritus parameter: clearAssetCache
[type: boolean] [default: false] [optional] 
Boolean determining if the project's AssetCache directory will be deleted.





IncisorExtensions.compileTypescript(projectPath, checkOnly)
[type: function] [returns: [string]] 
Compiles a TypeScript project into JavaScript, the same way Incisor does when the project is opened, or only checks it for errors.

IncisorExtensions.compileTypescript parameter: projectPath
[type: string] [default: nce.projectPath] [optional] 
The path of the project.

IncisorExtensions.compileTypescript parameter: checkOnly
[type: boolean] [default: false] [optional] 
If true, nothing is compiled and the project's type and syntax errors are returned. If false, the project is compiled and only the errors that stop the compile are returned.





IncisorExtensions.addToolTip(targetObject, tipTitle, tip, underlineOffset)
[type: function] 
Adds a tool tip to the given object. Target the label of an element that has one, and the 'mainButton' of a UiButton or UiGraphicButton that does not.

IncisorExtensions.addToolTip parameter: targetObject
[type: object] 
The object the tool tip is added to.

IncisorExtensions.addToolTip parameter: tipTitle
[type: string] 
The title of the tool tip, in the form "owning element→target element".

IncisorExtensions.addToolTip parameter: tip
[type: string] 
The body text of the tool tip.

IncisorExtensions.addToolTip parameter: underlineOffset
[type: number] [default: 0] [optional] 
Shifts the underline drawn beneath the target. Pass '-nce.uiStyle.spacer_tiny' for any target that has a background panel.





IncisorExtensions.openProject(projectPath)
[type: function] [returns: IncrCommsResponseObject] 
Opens the project at the given path.

IncisorExtensions.openProject parameter: projectPath
[type: string] 
The path of the project to open.





IncisorExtensions.getRecentProjects()
[type: function] [returns: IncrCommsResponseObject] 
Retrieves the list of recently opened projects, where the payload is a JSON string of that list, oldest first. Each entry is an array of the project's path, its public name, the file name of its thumbnail, and whether it uses TypeScript.





IncisorExtensions.saveProject()
[type: function] [returns: IncrCommsResponseObject] 
Saves the project this extensions context is attached to.











































































































































































































































































































































































































































































































































































































































































































































































































































































































----------------------------------------------------------
Section 96: ProcessResult
----------------------------------------------------------


ProcessResult
[type: class] [NON-INSTANTIABLE] [requires: unpublished only, extensions scope] 
Object containing information about the running of an executable via 'nce.runProcess'. 





ProcessResult.stdOut
[type: string] 
The standard output from the given executable process.





ProcessResult.stdErr
[type: string] 
The standard error from the given executable process.





ProcessResult.exception
[type: string] 
If there is an exception while attempting to run the given executable process, it will be populated in this value.










----------------------------------------------------------
Section 97: InspectorPanel
----------------------------------------------------------


InspectorPanel
[type: class] [requires: unpublished only, extensions scope] 
Object defining an inspector panel within the Incisor GUI. Custom panels can be defined and registered in Incisor extensions code placed in the 'Utilities/ProjectExtensions' directory within the project, or within the 'Global Extensions' directory in the application support directory (available from within the Incisor menu). To make a custom panel, define a class that extends this class, populating the 'headerScrollingPanel' and 'bodyScrollingPanel' members with the desired custom content. Then call 'nce.registerInspectorPanelDefinition' with the newly defined class as a parameter and the new panel should appear in the panel options menu.





InspectorPanel.type
[type: string] 
The type indicator for this object.





InspectorPanel.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





InspectorPanel.headerScrollingPanel
[type: ScrollingPanel] 
The ScrollingPanel that contains the header content for this InspectorPanel. This, and 'bodyScrollingPanel' are where the majority of the customization for user-defined panels take place. This will be undefined if the InspectorPanel is instantiated with 'includeBodyScrollingPanel=false'





InspectorPanel.bodyScrollingPanel
[type: ScrollingPanel] 
The ScrollingPanel that contains the body content for this InspectorPanel. This, and 'headerScrollingPanel' are where the majority of the customization for user-defined panels take place. This will be undefined if the InspectorPanel is instantiated with 'includeHeaderScrollingPanel=false'





InspectorPanel.panelWidth
[type: number] 
The current width of the InspectorPanel.





InspectorPanel.panelHeight
[type: number] 
The current height of the InspectorPanel.





InspectorPanel.headerScrollingPanelCoreHeight
[type: number] 
The core height of the headerScrollingPanel (before uiZoom is applied).





InspectorPanel.headerScrollingPanelHeight
[type: number] 
The current height of this InspectorPanel's headerScrollingPanel, with uiZoom factored in.





InspectorPanel.inspectorPanelUid
[type: number] 
The unique identifier for this InspectorPanel.





InspectorPanel.menubarHeight
[type: number] 
The current height of this InspectorPanel's menu bar.





InspectorPanel.panelType
[type: string] 
The name of the panel type. This is the name that will appear within the panel options drop down menu.





InspectorPanel.subPanels
[type: Array] 
Array containing the subPanels of this InspectorPanel. For standard 'content' panels, this array will be be empty, as subpanels are only present in InspectorPanels that are strictly 'container' panels.





InspectorPanel.divisionLocation
[type: number] [default: 0.5] 
Value used by 'container' panels to determine the proportion of its area that each subPanel will occupy. For standard 'content' panels this value is unused.





InspectorPanel.isColumns
[type: boolean] [default: {true}] 
Boolean value used by 'container' panels to determine if its subPanels are side-by-side or top-and-bottom. For standard 'content' panels this value is unused.





InspectorPanel.dividerButton
[type: Button] 
Button used by 'container' panels that allow the user to change the 'divisionLocation' value. For standard 'content' panels this member is undefined.





InspectorPanel.borderLeft
[type: GraphicObject] 
The GraphicObject that serves as the left border of this InspectorPanel.





InspectorPanel.borderRight
[type: GraphicObject] 
The GraphicObject that serves as the right border of this InspectorPanel.





InspectorPanel.borderTop
[type: GraphicObject] 
The GraphicObject that serves as the top border of this InspectorPanel.





InspectorPanel.borderBottom
[type: GraphicObject] 
The GraphicObject that serves as the bottom border of this InspectorPanel.





InspectorPanel.leftMenuStack
[type: LayoutStack] 
The horizontal LayoutStack on the left side of the InspectorPanel's menu bar. This LayoutStack contains the panel type selection UiDropDownMenu.





InspectorPanel.panelTypeMenu
[type: UiDropDownMenu] 
The drop down mene containing all of the panel type options. This menu is what is used by the users to select different panels.





InspectorPanel.rightMenuStack
[type: LayoutStack] 
The horizontal LayoutStack on the right side of the InspectorPanel's menu bar. This LayoutStack contains the '+' button and the 'x' button.





InspectorPanel.plusButton
[type: UiGraphicButton] 
The UiGraphicButton serving as the '+' button on the righthand side of the InspectorPanel's menu bar. Users use this button to add subPanels to this InspectorPanel.





InspectorPanel.exButton
[type: UiGraphicButton] 
The UiGraphicButton serving as the 'x' button on the righthand side of the InspectorPanel's menu bar. Users use this button to close this InspectorPanel.





InspectorPanel.menuBarBackground
[type: UiPanel, Button] 
The UiPanel/Button that serves as the background for this InspectorPanel's menu bar.





InspectorPanel.panelMaskGraphic
[type: Button] 
This Button serves as a mask for the 'panelTypeMenu', 'plusButton', and 'exButton', ensuring that those items don't extend outside of the menu bar  regardless of the uiZoom and size/aspect-ratio of the InspectorPanel.





InspectorPanel.rolloverButton
[type: Button] 
The Button responsible for setting the 'nc.singularFocusObject' to each InspectorPanel as the user's cursor moves over it (via 'addCursorInCallback').





InspectorPanel.quadrantButtonContainer
[type: SceneObject] 
SceneObject containing the 'quadrantButtons', which are the Buttons that enable the user to select the top, bottom, left, or right portionm of the InspectorPanel.





InspectorPanel.quadrantButtonLeft
[type: UiPanel, Button] 
The 'quadrantButton' that enables the user to select the left portion of this InspectorPanel.





InspectorPanel.quadrantButtonRight
[type: UiPanel, Button] 
The 'quadrantButton' that enables the user to select the right portion of this InspectorPanel.





InspectorPanel.quadrantButtonTop
[type: UiPanel, Button] 
The 'quadrantButton' that enables the user to select the top portion of this InspectorPanel.





InspectorPanel.quadrantButtonBottom
[type: UiPanel, Button] 
The 'quadrantButton' that enables the user to select the bottom portion of this InspectorPanel.





InspectorPanel.headerDivider
[type: GraphicObject] 
A thin line between the headerScrollingPanel and bodyScrollingPanel





InspectorPanel.addResizeCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever the InspectorPanel is resized.

InspectorPanel.addResizeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

InspectorPanel.addResizeCallback parameter: callbackName
[type: string] 
The name of the callback function.

InspectorPanel.addResizeCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function.





InspectorPanel.removeResizeCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback for when the InspectorPanel is resized.

InspectorPanel.removeResizeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

InspectorPanel.removeResizeCallback parameter: callbackName
[type: string] 
The name of the callback function.










----------------------------------------------------------
Section 98: FileBrowser
----------------------------------------------------------


FileBrowser
[type: class] [extends: LayoutStack] [NON-INSTANTIABLE] [requires: unpublished only, extensions scope] 
A FileBrowser is a specialized LayoutStack with functionality which makes it an ineractive inspector for the OS file system. This class is meant for use in tool development within extensions, and provides a visual means for developers locate and manipulate directories and files. FileBrowsers must be located within the 'bodyStack' of a ScrollingPanel. Call nce.addFileBrowser to make a new FileBrowser.





FileBrowser.root
[type: string] [default: nc.paths.desktopPath] 
The path of the root directory of of the FileBrowser. The contents of the root directory are the 'topmost' items shown in this FileBrowser.





FileBrowser.showHiddenItems
[type: boolean] [default: true] 
Flag determining if hidden items are shown in the FileBrowser.





FileBrowser.selectableHiddenItems
[type: boolean] [default: true] 
Flag determining if hidden items are selectable within the FileBrowser.





FileBrowser.showFiles
[type: boolean] [default: true] 
Flag determining if files are shown in the FileBrowser. If false, the FileBrowser will only display directories.





FileBrowser.selectableFiles
[type: boolean] [default: true] 
Flag determining if files are selectable within the FileBrowser. If false, only directories will be selectable in the FileBrowser.





FileBrowser.allowRearrange
[type: boolean] [default: true] 
Flag determining if files and directories can be rearranged via dragging and dropping.





FileBrowser.allowMultiSelect
[type: boolean] [default: true] 
Flag determining if more than one path can be selected at once.





FileBrowser.overrideList
[type: [PathInfo]] [default: udefined] 
An array of PathInfos can be provided to have the FileBrowser show a specific group of files in a flat list. This can be used in conjunction with a UiTextField to provide a search field for the FileBrowser. Set this property to undefined to return to normal





FileBrowser.addFilterCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback function that is invoked when directory contents are displayed. An array of PathInfos are sent to each callback as the first parameter, and this list can be edited by the receiving callback as a means to apply specific filtering rules for what is displayed in this FileBrowser.

FileBrowser.addFilterCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

FileBrowser.addFilterCallback parameter: callbackName
[type: number] 
The name of the callback function.

FileBrowser.addFilterCallback parameter: callbackArgs
[type: number] [optional] 
Arguments for the callback function.





FileBrowser.removeFilterCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

FileBrowser.removeFilterCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

FileBrowser.removeFilterCallback parameter: callbackName
[type: number] 
The name of the callback function.





FileBrowser.addFileSystemChangeCallback(callbackOwner, callbackName, callbackArgs, callbackBeforeChange)
[type: function] 
Adds a callback function that is invoked when the FileBrowser initiates a file system change. For example if 'allowRearrange' is true, and a file is dragged to a new directory, then these callbacks will be invoked. The type of the file system change, and an array of the associated paramters are sent to the callbacks as the first two parameters.

FileBrowser.addFileSystemChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

FileBrowser.addFileSystemChangeCallback parameter: callbackName
[type: number] 
The name of the callback function.

FileBrowser.addFileSystemChangeCallback parameter: callbackArgs
[type: number] [optional] 
Arguments for the callback function.

FileBrowser.addFileSystemChangeCallback parameter: callbackBeforeChange
[type: boolean] [default: true] [optional] 
Boolean determining if the given callback will be called before or after the change event.





FileBrowser.removeFileSystemChangeCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

FileBrowser.removeFileSystemChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

FileBrowser.removeFileSystemChangeCallback parameter: callbackName
[type: number] 
The name of the callback function.





FileBrowser.addSelectionChangeCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback function that is invoked when there is a change to the files/directories that are currently selected in this FileBrowser.

FileBrowser.addSelectionChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

FileBrowser.addSelectionChangeCallback parameter: callbackName
[type: number] 
The name of the callback function.

FileBrowser.addSelectionChangeCallback parameter: callbackArgs
[type: number] [optional] 
Arguments for the callback function.





FileBrowser.removeSelectionChangeCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

FileBrowser.removeSelectionChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

FileBrowser.removeSelectionChangeCallback parameter: callbackName
[type: number] 
The name of the callback function.





FileBrowser.getCurrentSelection()
[type: function] [returns: [PathInfo]] 
Returns a list of the currently selected items for this FileBrowser.





FileBrowser.openToPath(path, openPathProvided)
[type: function] 
Instructs the FileBrowser to open all of the containing directories of the given path so that it is visible.

FileBrowser.openToPath parameter: path
[type: string] 
The path to open to.

FileBrowser.openToPath parameter: openPathProvided
[type: boolean] [default: false] [optional] 
Boolean determining if the given path itself should also be open (assumning it is a directory)





FileBrowser.refresh()
[type: function] 
Refreshes the FileBrowser, causing it to reflect any changes made since it was last refreshed.





















































































































































































































































































































































































































----------------------------------------------------------
Section 99: PrePublishInfoObject
----------------------------------------------------------


PrePublishInfoObject
[type: class] [NON-INSTANTIABLE] [requires: unpublished only, extensions scope] 
Object containing pre-publish information. 





PrePublishInfoObject.configurationName
[type: string] 
The name of the configuration to use when publishing.





PrePublishInfoObject.proceedWithPublishing
[type: boolean] [default: true] 
Boolean indicating whether or not to proceed with publishing. To cancel the publishing process, set this value to false.





PrePublishInfoObject.hostPublishedProject
[type: boolean] 
Boolean indicating whether the published project will be automatically hosted.










----------------------------------------------------------
Section 100: PostPublishInfoObject
----------------------------------------------------------


PostPublishInfoObject
[type: class] [NON-INSTANTIABLE] [requires: unpublished only, extensions scope] 
Object containing post-publish information. 





PostPublishInfoObject.configurationName
[type: string] 
The name of the configuration to use when publishing.





PostPublishInfoObject.publishTimeStamp
[type: string] 
The time stamp of the published project.





PostPublishInfoObject.hostedPort
[type: string] 
The port that the newly published project is being hosted on (if applicable).





PostPublishInfoObject.destinationDirectory
[type: string] 
The relative path for the directory of the newly published project.










----------------------------------------------------------
Section 101: ProcessConfiguration
----------------------------------------------------------


ProcessConfiguration
[type: class] [requires: unpublished only, extensions scope] 
Object containing configurations for how a process will run during nce.runProcess, nce.runCmd, or nce.runBash.





ProcessConfiguration.createNoWindow
[type: boolean] [default: true] 
Determines if the new process will create a new window.





ProcessConfiguration.redirectStandardInput
[type: boolean] [default: true] 
Determines if 'StandardInput' will be redirected for the given process.





ProcessConfiguration.redirectStandardOutput
[type: boolean] [default: true] 
Determines if 'StandardOutput' will be redirected for the given process. If true, the standard out contents will be returned as part of the ProcessResult object returned.





ProcessConfiguration.redirectStandardError
[type: boolean] [default: true] 
Determines if 'StandardError' will be redirected for the given process. If true, the standard error contents will be returned as part of the ProcessResult object returned.





ProcessConfiguration.closeStandardInputImmediately
[type: boolean] [default: true] 
Determines if the 'StandardInput' stream for the given process will be immediately closed. This is sometimes necessary in order to prevent the process from locking up Incisor due to it waiting for input that's never coming. If true, the standard error contents will be returned as part of the ProcessResult object returned.





ProcessConfiguration.useShellExecute
[type: boolean] [default: false] 
Determines if the given process will use ShellExecute.





ProcessConfiguration.waitForExit
[type: boolean] [default: false] 
Determines if Incisor will wait for the process to exit before moving on.










----------------------------------------------------------
Section 102: ColorSupervisorButton
----------------------------------------------------------


ColorSupervisorButton
[type: class] [extends: UiGraphicButton] [NON-INSTANTIABLE] [requires: unpublished only, extensions scope] 
A UiGraphicButton that supervises one or more color properties, displaying a live color swatch. When all supervised items share the same color value, the swatch reflects that color. When supervised items have diverging values, a minus icon is shown in place of the swatch. Pressing the button opens a ColorPicker popup that allows the user to edit the color live across all supervised items. Use 'propertyOwners' paired with 'propertyPath' for simple dot-notation property access, or 'propertyGetterOwner'/'propertyGetterName' paired with 'propertySetterOwner'/'propertySetterName' for custom getter/setter control. Call nce.addColorSupervisor to create a new ColorSupervisorButton.





ColorSupervisorButton.propertyOwners
[type: [object]] 
An array of objects whose color property will be supervised by this button. Use in conjunction with 'propertyPath' to specify a dot-notation path to the color property on each object.





ColorSupervisorButton.propertyPath
[type: string] 
A dot-notation string path to the color property on each object in 'propertyOwners'. For example, a value of "colorMultiply" would supervise the 'colorMultiply' property directly on each owner.





ColorSupervisorButton.propertyGetterOwner
[type: object] 
The owner of a custom getter function that returns an array of color values, one per supervised item. Use in conjunction with 'propertyGetterName' as an alternative to 'propertyOwners'/'propertyPath'.





ColorSupervisorButton.propertyGetterName
[type: string] 
The name of the custom getter function on 'propertyGetterOwner'. The function must return an array of color values, one per supervised item.





ColorSupervisorButton.propertyGetterArgs
[type: Array, any] 
Optional arguments to pass to the custom getter function.





ColorSupervisorButton.propertySetterOwner
[type: object] 
The owner of a custom setter function that applies a chosen color to all supervised items. Use in conjunction with 'propertySetterName' as an alternative to 'propertyOwners'/'propertyPath'.





ColorSupervisorButton.propertySetterName
[type: string] 
The name of the custom setter function on 'propertySetterOwner'. The function receives the newly chosen color as its first argument.





ColorSupervisorButton.propertySetterArgs
[type: Array, any] 
Optional additional arguments to pass to the custom setter function, appended after the color argument.





ColorSupervisorButton.showAlpha
[type: boolean] [default: true] 
Boolean determining whether the alpha channel is shown and editable in the ColorPicker popup.





ColorSupervisorButton.closeCallbackOwner
[type: object] 
The owner of a callback that is invoked when the ColorPicker popup closes.





ColorSupervisorButton.closeCallbackName
[type: string] 
The name of the callback function on 'closeCallbackOwner' that is invoked when the ColorPicker popup closes.



























































































































































































































































































































































































































































































----------------------------------------------------------
Section 103: PixelsObject
----------------------------------------------------------


PixelsObject
[type: class] [NON-INSTANTIABLE] 
A PixelsObject is an RGBA bitmap image in a simple, 'data-only' format, used for basic image access and manipulation. 





PixelsObject.type
[type: string] 
Type identifier.





PixelsObject.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PixelsObject.width
[type: number] 
The width of the PixelsObject.





PixelsObject.height
[type: number] 
The height of the PixelsObject.





PixelsObject.writePngFile(filePath, isPathRelative, writeRawBase64)
[type: function] [returns: IncrCommsResponseObject] 
Writes the bitmap from this PixelsObject to a ".png" file at the given path.

PixelsObject.writePngFile parameter: filePath
[type: string] 
The relative or absolute path to the file in question.

PixelsObject.writePngFile parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

PixelsObject.writePngFile parameter: writeRawBase64
[type: boolean] [default: false] [optional] 
Bool stating if the file written will be in Base64 text format.





PixelsObject.getPixel(x, y)
[type: function] [returns: Vector4] 
Returns a Vector4 containing the RGBA color of the pixel at the given coordinates.

PixelsObject.getPixel parameter: x
[type: number] 
The horizontal index of the pixel to get the color of.

PixelsObject.getPixel parameter: y
[type: number] 
The vertical index of the pixel to get the color of. The vertical position of pixels in PixelObjects map from bottom to top.





PixelsObject.setPixel(x, y, color)
[type: function] 
Sets the RGBA color Value of the pixel at the given coordinates

PixelsObject.setPixel parameter: x
[type: number] 
The horizontal index of the pixel to set the color of.

PixelsObject.setPixel parameter: y
[type: number] 
The vertical index of the pixel to get set color of. The vertical position of pixels in PixelObjects map from bottom to top.

PixelsObject.setPixel parameter: color
[type: Vector4] 
Vector with the RGBA color value for the desired pixel.





PixelsObject.unMultiply()
[type: function] 
Performs a transformation on the bitmap data stored in this PixelsObject that approximates the reversal of "premultiplication" of images with transparency. Depending on the source of the content within this PixelsObject, you may want to invoke 'unMultiply' before writing it to an image on disk. This is because Incisor® primarily works with normal 'unmultiplied' source images and premultiplies images during runtime, so PixelsObjects created from composites of those premultiplied images will likely need to be unmultiplied prior to being written to disk to ensure that the resulting image is saved in the original 'unmultiplied' color space.










----------------------------------------------------------
Section 104: PixelsObjects
----------------------------------------------------------


PixelsObjects
[type: class] 
Object housing functionality for PixelsObjects, which are RGBA bitmap images in a simple, 'data-only' format, used for basic image access and manipulation.





PixelsObjects.getNewBlankPixelsObject(width, height, color)
[type: function] [returns: PixelsObject] 
Returns a uniformly colored PixelsObject of the width, height, and color provided.

PixelsObjects.getNewBlankPixelsObject parameter: width
[type: number] 
The width of the desired PixelsObject.

PixelsObjects.getNewBlankPixelsObject parameter: height
[type: number] 
The height of the desired PixelsObject.

PixelsObjects.getNewBlankPixelsObject parameter: color
[type: Vector4] 
Vector with the RGBA color values for the new PixelsObject.





PixelsObjects.getPixelsObject(source)
[type: function] [returns: PixelsObject] 
Returns a PixelsObject generated from the given RenderTarget or Texture. It should be noted that the texture will need to be loaded before invoking this function - see nc.addTierLoadedCallback and nc.awaitLoadedTiers for more information.

PixelsObjects.getPixelsObject parameter: source
[type: RenderTarget, Texture] 
The RenderTarget or Texture to generate the PixelsObject from. It should be noted that Textures that were originally created from PixelsObjects cannot be used to create a PixelsObject.










----------------------------------------------------------
Section 105: UiGraphicButton
----------------------------------------------------------


UiGraphicButton
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A ui-specialized horizontal LayoutStack housing an image-based Button (including a UiPanel background) with various UI functionalities and defaults applied. UI functionality includes:  • pre-configured with LayoutObject functionality.  • uiStyle TextFormats and Colors applied.  • pre-configured with 'UiKeyboardNavigable' functionality.  • uiZoom-enabled.  • nearestPixelRendering-enabled.





UiGraphicButton.isActive
[type: boolean] [default: true] 
Boolean determining if the UiGraphicButton is available for end-user-internaction, or if it is unavailable and 'grayed out'.





UiGraphicButton.graphicObject
[type: GraphicObject] 
The GraphicObject for this UiGraphicButton.





UiGraphicButton.graphicScaleFactor
[type: number] 
A scale multiplier for the graphic object. Use this property instead of directly scaling the GraphicObject to preserve UiZoom and LayoutObject functionality. Please note that this facter does not affect the size of the Button, just the GraphicObject displayed on it.





UiGraphicButton.width
[type: number] 
The core width of the UiGraphicButton.





UiGraphicButton.height
[type: number] 
The core height of the UiGraphicButton.





UiGraphicButton.displayLabel
[type: boolean] [default: false] 
Boolean determining if a label TextBox is displayed to the left of the UiGraphicButton.





UiGraphicButton.label
[type: UiText] [default: undefined] 
A UiText that acts as a label for the UiGraphicButton. Please note that this item is undefined until the 'displayLabel' property is set to true.





UiGraphicButton.mainButton
[type: Button] 
The main Button for the UiGraphicButton, this object is a UiPanel which also implements Button.





UiGraphicButton.outline
[type: UiOutline] 
The outline of the button, which is used to indicate when the end-user outlines this UiGraphicButton using keyboard navigation (tab, arrows, etc...).





UiGraphicButton.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body.clone()] 
The TextFormat applied to this UiGraphicButton. Setting this property updates the graphic's scale factor and button dimensions to match the TextFormat's character scale, and also applies the TextFormat to the label (when displayLabel is true).





UiGraphicButton.buttonBackgroundColor
[type: Color] [default: nc.uiStyle.color_buttonPanel] 
The Color of the Button background.





UiGraphicButton.highlightedButtonBackgroundColor
[type: Color] [default: nc.uiStyle.color_highlightedButtonPanel] 
The Color of the Button background when it's highlighted.





UiGraphicButton.addTriggerCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever this UiGraphicButton is triggered via the cursor or keyboard navigation. The triggering browser-created event, and the UiGraphicButton itself are sent to the callback as its first two parameters.

UiGraphicButton.addTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this UiGraphicButton is triggered via the cursor or keyboard navigation.

UiGraphicButton.addTriggerCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this UiGraphicButton is triggered via the cursor or keyboard navigation.

UiGraphicButton.addTriggerCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever this UiGraphicButton is triggered via the cursor or keyboard navigation.





UiGraphicButton.removeTriggerCallback(callbackOwner, callbackName)
[type: function] 
Removes the given trigger callback.

UiGraphicButton.removeTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UiGraphicButton.removeTriggerCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





















































































































































































































































































































































































































----------------------------------------------------------
Section 106: Scene
----------------------------------------------------------


Scene
[type: class] [extends: SceneObject] 
A Scene is a root SceneObject in the hierarchy. All SceneObjects are either Scenes or descendants of Scenes.





Scene.layerOrderLedger
[type: [string]] 
A read-only list of this Scene's layer names in order from back to front.





Scene.defineLayer(name, placeBehindThisLayer)
[type: function] [returns: Layer] 
Defines a new Layer within this Scene. For a list of all Layers within all Scenes, see 'nc.layers'. For a list of all Layers within specific Scenes, see 'nc.layersByScene'.

Scene.defineLayer parameter: name
[type: string] 
The name of the new Layer.

Scene.defineLayer parameter: placeBehindThisLayer
[type: Layer] [default: nc.layers.DefaultLayer] [optional] 
Supply this optional Layer, and the newly defined Layer will be populated behind the provided Layer.



























































































































































































































































































































----------------------------------------------------------
Section 107: Layer
----------------------------------------------------------


Layer
[type: class] [NON-INSTANTIABLE] 
Object representing a rendering order group. The 'GraphicObject.layer' property can assigned to specific Layers to manipulate the render order of the given GraphicObject. Use 'Scene.defineLayer' to add a new Layer to a Scene. To manipulate the render order of GraphicObjects within the same Layer, see the 'GraphicObject.subLayer' property. 





Layer.type
[type: string] 
The type identifier.





Layer.name
[type: string] 
The name of the Layer










----------------------------------------------------------
Section 108: LayersByScene
----------------------------------------------------------


LayersByScene
[type: class] [NON-INSTANTIABLE] 
Dictionary of Dictionaries of Layers per Scene. 





LayersByScene."MainScene"
[type: LayersInScene0] 
Dictionary of Layers in the 'MainScene' Scene.










----------------------------------------------------------
Section 109: TimeStamp
----------------------------------------------------------


TimeStamp
[type: class] [NON-INSTANTIABLE] 
Object housing functionality for time stamps, the Incisor® standardized format for date and time. 





TimeStamp.getTimeStamp(includeMilliseconds)
[type: function] [returns: string] 
Produces the current time in the Incisor® standardized time stamp format: YYYY.MM.DD.hh.mm.ss(.mmmm)

TimeStamp.getTimeStamp parameter: includeMilliseconds
[type: boolean] 
A boolean indicating if the timestamp will include milliseconds.





TimeStamp.compareTimeStamps(firstTimestamp, secondTimestamp)
[type: function] [returns: string] 
Compares two TimeStamps and returns a string describing their relationship ("lessThan","equal", or "greaterThan").

TimeStamp.compareTimeStamps parameter: firstTimestamp
[type: string] 
The first timestamp to compare.

TimeStamp.compareTimeStamps parameter: secondTimestamp
[type: string] 
The second timestamp to compare.





TimeStamp.convertDateToTimeStamp(date, includeMilliseconds)
[type: function] [returns: string] 
Converts a JavaScript Date to a TimeStamp string.

TimeStamp.convertDateToTimeStamp parameter: date
[type: string] 
The Date value to convert.

TimeStamp.convertDateToTimeStamp parameter: includeMilliseconds
[type: boolean] [optional] 
Flag determining if the TimeStamp should include milliseconds.





TimeStamp.convertTimeStampToDate(timeStamp)
[type: function] [returns: Date] 
Converts a TimeStamp string to a JavaScript Date

TimeStamp.convertTimeStampToDate parameter: timeStamp
[type: string] 
The first timestamp to convert to a Date.





TimeStamp.compareIncisorVersionSets(firstVersionSetName, secondVersionSetName)
[type: function] [returns: string] 
Compares the names of two Incisor® version sets and returns a string describing their relationship ("lessThan","equal", or "greaterThan").

TimeStamp.compareIncisorVersionSets parameter: firstVersionSetName
[type: string] 
The first Incisor® version set name to compare.

TimeStamp.compareIncisorVersionSets parameter: secondVersionSetName
[type: string] 
The second Incisor® version set name to compare.










----------------------------------------------------------
Section 110: UxStringSupervisorTextField
----------------------------------------------------------


UxStringSupervisorTextField
[type: class] [extends: UiTextField] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. Supervisors provide the means for users to both monitor and manipulate properties within the project during runtime. This particular object is meant to supervise a string property, with the user able to adjust the value directly by entering a new value in this UiTextField. When multiple diverging values are supervised, a '-' is shown. 'Ux' supervisors operate exclusively on arrays of values, ensuring support for supervising multiple values at once. 





UxStringSupervisorTextField.propertyOwners
[type: Array] [default: undefined] 
Array of objects owning the properties being supervised. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorTextField.propertyPath
[type: string] [default: ""] 
A period-separated string representing the 'dot path' or 'dereference chain' from each owner object to the property being supervised. For example if you are supervising the fontName of the TextFormat on a TextBox this value would be 'textFormat.fontName'. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorTextField.propertyGetterOwner
[type: object] [default: undefined] 
The object owning the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorTextField.propertyGetterName
[type: string] [default: undefined] 
The name of the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorTextField.propertyGetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorTextField.propertySetterOwner
[type: object] [default: undefined] 
The object owning the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorTextField.propertySetterName
[type: string] [default: undefined] 
The name of the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorTextField.propertySetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter, these parameters will be appended. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorTextField.valueValidationOwner
[type: object] [default: undefined] 
The owner of the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the format of strings entered into the supervisor textField, you can write a validation function that takes a value as a parameter and returns the adjusted value.





UxStringSupervisorTextField.valueValidationName
[type: string] [default: undefined] 
The name of the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the format of strings entered into the supervisor textField, you can write a validation function that takes a value as a parameter and returns the adjusted value.





UxStringSupervisorTextField.valueValidationArgs
[type: Array, any] [default: undefined] 
Parameters for the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the format of strings entered into the supervisor textField, you can write a validation function that takes a value as a parameter and returns the adjusted value.





UxStringSupervisorTextField.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body.clone()] 
the TextFormat of all of the text items within the supervisor, which is also used to scale graphical components.





UxStringSupervisorTextField.sync()
[type: function] 
Method brings this UxStringSupervisorTextField up to date with the values it supervises, without waiting for the next fixedUpdate. This method is automatically called every fixedUpdate.

















































































































































































































































































































































































































































































----------------------------------------------------------
Section 111: UxNumberSupervisorTextField
----------------------------------------------------------


UxNumberSupervisorTextField
[type: class] [extends: UiTextField] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. Supervisors provide the means for users to both monitor and manipulate properties within the project during runtime. This particular object is meant to supervise a number property, with the user able to adjust the value directly by entering a new value in the 'textField' member. When multiple diverging values are supervised, a '-' is shown. 'Ux' supervisors operate exclusively on arrays of values, ensuring support for supervising multiple values at once. 





UxNumberSupervisorTextField.displayPrecision
[type: number] [default: 3] 
The number of digits shown to the right of the decimal within the UiTextField for this UxNumberSupervisorTextField.





UxNumberSupervisorTextField.dragMultiplier
[type: number] [default: 1] 
A numeric factor multiplying the effect that dragging the label has on the supervised value. A rule of thumb used within the Incisor Inspector is that the user should be able to drag across the entire expected range of the value by moving the cursor 500 world units. For example, a good drag multiplier for a value that ranges from 0 to 1 would be 1/500.





UxNumberSupervisorTextField.propertyOwners
[type: Array] [default: undefined] 
Array of objects owning the properties being supervised. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorTextField.propertyPath
[type: string] [default: ""] 
A period-separated string representing the 'dot path' or 'dereference chain' from each owner object to the property being supervised. For example if you are supervising the x position of a SceneObject this value would be 'position.x'. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorTextField.propertyGetterOwner
[type: object] [default: undefined] 
The object owning the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorTextField.propertyGetterName
[type: string] [default: undefined] 
The name of the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorTextField.propertyGetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorTextField.propertySetterOwner
[type: object] [default: undefined] 
The object owning the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorTextField.propertySetterName
[type: string] [default: undefined] 
The name of the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorTextField.propertySetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter, these parameters will be appended. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxNumberSupervisorTextField.valueValidationOwner
[type: object] [default: undefined] 
The owner of the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the values to integers, you can write a validation function that takes a value as a parameter and returns the rounded value.





UxNumberSupervisorTextField.valueValidationName
[type: string] [default: undefined] 
The name of the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the values to integers, you can write a validation function that takes a value as a parameter and returns the rounded value.





UxNumberSupervisorTextField.valueValidationArgs
[type: Array, any] [default: undefined] 
Parameters for the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the values to integers, you can write a validation function that takes a value as a parameter and returns the rounded value.





UxNumberSupervisorTextField.deltaTriangle
[type: UiText] 
The UiText containing the triangle that indicates when the supervisor is in 'deltaMode', which is an altered state of functionality in which the user interface adjustments are made in terms of the amount of change to the values as opposed to the standard state in which the values are set in absolute terms.





UxNumberSupervisorTextField.dragArrows
[type: UiText] 
A UiText containing a small arrows icon that helps to indicate to users that they can click and drag the labels to adjust the values.





UxNumberSupervisorTextField.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body.clone()] 
the TextFormat of all of the text items within the supervisor, which is also used to scale graphical components.





UxNumberSupervisorTextField.dragPointer
[type: GraphicObject] 
A GraphicObject that serves as a 'visual teather' between the cursor and the label while the value is being dragged. This member will remain undefined until dragging occurs, at which point the object is created on the fly if needed.





UxNumberSupervisorTextField.singularFocusTarget
[type: SceneObject] [default: this] 
The SceneObject used as the singular focus requirement when the drag escape keydown callback is registered. The default value is this UxNumberSupervisorTextField itself, but another SceneObject can be supplied when it would be a better singular-focus recipient.





UxNumberSupervisorTextField.sync()
[type: function] 
Method brings this UxNumberSupervisorTextField up to date with the values it supervises, without waiting for the next fixedUpdate. This method is automatically called every fixedUpdate.

















































































































































































































































































































































































































































































----------------------------------------------------------
Section 112: UxBooleanSupervisorCheckbox
----------------------------------------------------------


UxBooleanSupervisorCheckbox
[type: class] [extends: UiGraphicButton] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. Supervisors provide the means for users to both monitor and manipulate properties within the project during runtime. This particular object is meant to supervise a boolean property, with the user able to adjust the value directly checking or unchecking a checkbox button. When multiple diverging values are supervised, a '-' is shown. 'Ux' supervisors operate exclusively on arrays of values, ensuring support for supervising multiple values at once. 





UxBooleanSupervisorCheckbox.propertyOwners
[type: Array] [default: undefined] 
Array of objects owning the properties being supervised. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxBooleanSupervisorCheckbox.propertyPath
[type: string] [default: ""] 
A period-separated string representing the 'dot path' or 'dereference chain' from each owner object to the property being supervised. For example if you are supervising the enabled state of a SceneObject's parent this value would be 'parent.enabled'. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxBooleanSupervisorCheckbox.propertyGetterOwner
[type: object] [default: undefined] 
The object owning the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxBooleanSupervisorCheckbox.propertyGetterName
[type: string] [default: undefined] 
The name of the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxBooleanSupervisorCheckbox.propertyGetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxBooleanSupervisorCheckbox.propertySetterOwner
[type: object] [default: undefined] 
The object owning the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxBooleanSupervisorCheckbox.propertySetterName
[type: string] [default: undefined] 
The name of the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxBooleanSupervisorCheckbox.propertySetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter, these parameters will be appended. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxBooleanSupervisorCheckbox.valueValidationOwner
[type: object] [default: undefined] 
The owner of the function (optional) that will be used to validate/adjust values before they are set by this supervisor.





UxBooleanSupervisorCheckbox.valueValidationName
[type: string] [default: undefined] 
The name of the function (optional) that will be used to validate/adjust values before they are set by this supervisor.





UxBooleanSupervisorCheckbox.valueValidationArgs
[type: Array, any] [default: undefined] 
Parameters for the function (optional) that will be used to validate/adjust values before they are set by this supervisor.





UxBooleanSupervisorCheckbox.textFormat
[type: TextFormat] [default: undefined] 
the TextFormat of all of the text items within the supervisor, which is also used to scale graphical components.





UxBooleanSupervisorCheckbox.sync()
[type: function] 
Method brings this UxBooleanSupervisorCheckbox up to date with the values it supervises, without waiting for the next fixedUpdate. This method is automatically called every fixedUpdate.






















































































































































































































































































































































































































































































----------------------------------------------------------
Section 113: AncillaryDevInfo
----------------------------------------------------------


AncillaryDevInfo
[type: class] [NON-INSTANTIABLE] [requires: unpublished only] 
Object housing ancillary development-environment information automatically populated by Incisor at load time. Accessible via 'nc.projectConfiguration.ancillaryDevInfo'. Undefined in published builds — always guard access with a check against 'nc.projectConfiguration.isProjectPublished'. 





AncillaryDevInfo.projectPath
[type: string] 
Absolute path to the current Incisor project directory on the host machine.





AncillaryDevInfo.applicationSupportPath
[type: string] 
Absolute path to the application support directory on the host machine.





AncillaryDevInfo.desktopPath
[type: string] 
Absolute path to the desktop directory of the current user on the host machine.





AncillaryDevInfo.userDirectoryPath
[type: string] 
Absolute path to the home/user directory of the current user on the host machine.





AncillaryDevInfo.deviceID
[type: string] 
Unique identifier for the host device.





AncillaryDevInfo.permissions
[type: string] 
String representation of the current permissions granted to this Incisor installation.





AncillaryDevInfo.useTestServer
[type: boolean] 
Boolean indicating whether the project is currently connecting to the test server rather than the production server.





AncillaryDevInfo.screenShotDestination
[type: string] 
Path to the directory where screenshots taken during development will be saved.





AncillaryDevInfo.platform
[type: string] 
String identifying the operating system of the host machine. Possible values: 'osx', 'windows', 'linux'.





AncillaryDevInfo.drives
[type: [string]] 
Array of root drive paths available on the host machine.










----------------------------------------------------------
Section 114: ScrollingPanel
----------------------------------------------------------


ScrollingPanel
[type: class] [extends: CursorInputOverrideButton] 
A ScrollingPanel is a specialized GraphicObject with a Scene that it renders to its RenderTarget/Texture. The Cameara that renders the Scene is the 'view window' into the Scene in question, and if the content from the Scene is larger than the Camera's bounds, then scroll pills appear, and the end-user can navigate around the Scene by scrolling. Within the Scene, a LayoutStack manages the layout of the contained content an informs the ScrollingPanel of the contents' size.





ScrollingPanel.scene
[type: Scene] 
The Scene where the content in this ScrollingPanel resides.





ScrollingPanel.bodyStack
[type: LayoutStack] 
The LayoutStack that manages the content in this ScrollingPanel. In order for any content to be properly recognized by this ScrollingPanel, it must be added to the LayoutStack using 'ScrollingPanel.layoutStack.addElements'





ScrollingPanel.camera
[type: OrthographicCamera] 
The Camera that renders the 'view window' of this ScrollingPanel to it's RenderTarget/Texture.





ScrollingPanel.renderTarget
[type: RenderTarget] 
The RenderTarget that this ScrollingPanel is rendered to.





ScrollingPanel.width
[type: number] [default: 500] 
The width of the ScrollingPanel. This also informs the width of the Camera's view area within the Scene.





ScrollingPanel.height
[type: number] [default: 500] 
The height of the ScrollingPanel. This also informs the height of the Camera's view area within the Scene.





ScrollingPanel.dragPanelToScroll
[type: boolean] [default: true] 
Flag determining if the end-user can scroll by dragging anywhere within the ScrollingPanel. If false, the user can still Scroll using the standard mouse/trackpad methods, or by dragging the scroll pills.





ScrollingPanel.dragPanelMomentum
[type: boolean] [default: true] 
Flag determining if the scrolling motion maintains momentum when the end-user 'flings' their finger across the ScrollPanel (if 'dragPanelToScrol=true').





ScrollingPanel.panelDragMomentumDecay
[type: number] [default: 0.9] 
Value that multiplies the momentum speed of the ScrollingPanel (if applicable) each fixedUpdate, causing the 'flung' scrolling to slow down eventually.





ScrollingPanel.scrollPillVertical
[type: UiPanel] 
A UiPanel/Button that can be dragged up and down to control the vertical scroll of this ScrollingPanel. The scroll pills are children of the ScrollingPanel, and are not within the ScrollingPanel's Scene.





ScrollingPanel.scrollPillHorizontal
[type: UiPanel] 
A UiPanel/Button that can be dragged left and right to control the horizontal scroll of this ScrollingPanel. The scroll pills are children of the ScrollingPanel, and are not within the ScrollingPanel's Scene.





ScrollingPanel.scrollPillThickness
[type: number] [default: nc.uiStyle.spacer_medium] 
Width of the verticalScrollPill and height of the horizontalScrollPill. This value will be automatically adjusted down if it is more than 25% of the width or height of this ScrollingPanel.





ScrollingPanel.scrollPillShapeRatio
[type: number] [default: 3] 
Number determining the length to width ratio of the scroll pills. This value will be automatically adjusted down if it results in a scroll pill that is longer than 50% of its range of motion.





ScrollingPanel.scrollPillColor
[type: Color] 
The Color of the scroll pills.





ScrollingPanel.scrollPillHighlightColor
[type: Color] 
The Color of the scroll pills when highlighted. The 'alpha' value from this color is disregarded.





ScrollingPanel.scrollPillOpacity
[type: number] 
The baseline opacity of the scroll pills.





ScrollingPanel.scrollAmountVertical
[type: number] 
The current vertical scroll amount ranging from 0 to 1.





ScrollingPanel.scrollAmountHorizontal
[type: number] 
The current horizontal scroll amount ranging from 0 to 1.





ScrollingPanel.scrollPillFadeDelay
[type: number] [default: 1.2] 
The number of seconds (since the latest scrolling activity) before the scroll pills will fade away. The pills will re-appear upon new scroll activity. Set this value to 0 to make the scroll pills never fade away.





ScrollingPanel.pivotPoint
[type: Vector2] [default: new Vector2(-.5,.5)] 
The pivot point of the ScrollingPanel.





ScrollingPanel.useNearestPixelRendering
[type: boolean] [default: false] 
A ScrollingPanel is ultimately a 'pre-rendered' Scene that is positioned in the outer Scene and then rendered again. Because of this, certain canvas sizes or TextBox positioning can lead to slightly blurrier rendering that can be noticable for finer detail. Calling this function can mitigate such fine-detail-blurriness, as it sets the downscalingMode and upscalingMode to 'nearest', and sets the 'snapToNearestWorldPosition' to true. These settings help to ensure that the ScrollingPanel texture pixels are always aligned with the canvas pixels, preserving the original crispy edges. The tradeoff with using this mode is that the position of text will appear to always snap to the nearest pixel, which can lead to jerky-looking movement at slow speeds, and also rotation and other transformations will tear badly.





ScrollingPanel.uiZoomAffectsPanelSize
[type: boolean] [default: true] 
Boolean determining if uiZoom affects the affective view size of the ScrollingPanel.





ScrollingPanel.popToOuterSceneAndMaintainPosition(sceneObject)
[type: function] 
Re-parents a descendant of the ScrollingPanel Scene to the SceneContaining the ScrollingPanel itself while maintaining visual global position.

ScrollingPanel.popToOuterSceneAndMaintainPosition parameter: sceneObject
[type: SceneObject] 
The SceneObject to move from the ScrollingPanel Scene to the Scene that contains the ScrollingPanel.





ScrollingPanel.getOuterScenePosition(sceneObject)
[type: function] 
Returns a Vector3 corresponding to the global position of a SceneObject residing in the ScrollingPanel Scene, but from the context of the 'outer' Scene which contains the ScrollingPanel itself. This can be used to align something in the 'outer' Scene with something inside the ScrollingPanel Scene.

ScrollingPanel.getOuterScenePosition parameter: sceneObject
[type: SceneObject] 
The SceneObject within the ScrollingPanel Scene to get the position of.





ScrollingPanel.scrollToObject(sceneObject, width, height, widthBuffer, heightBuffer)
[type: function] [returns: boolean] 
Scrolls the ScrollingPanel so that the given SceneObject is visible within its Camera's viewing area. Dimensions, and buffer values can be supplied to ensure that the entire SceneObject is made visible upon calling this function. A true value is returned if the object is found otherwise false is returned.

ScrollingPanel.scrollToObject parameter: sceneObject
[type: SceneObject] 
The SceneObject to scroll to.

ScrollingPanel.scrollToObject parameter: width
[type: number] [default: 0] [optional] 
The width of the SceneObject can be supplied here to help ensure that the entire object is visible within the Camera's viewing area. If the SceneObject has a configured LayoutObject, then this parameter can be left undefined, and the LayourObject's width will automatically be applied.

ScrollingPanel.scrollToObject parameter: height
[type: number] [default: 0] [optional] 
The height of the SceneObject can be supplied here to help ensure that the entire object is visible within the Camera's viewing area. If the SceneObject has a configured LayoutObject, then this parameter can be left undefined, and the LayourObject's height will automatically be applied.

ScrollingPanel.scrollToObject parameter: widthBuffer
[type: number] [default: 0] [optional] 
A buffer can be supplied here to ensure that the scrolling results in the SceneObject being visible with X amount of room to spare.

ScrollingPanel.scrollToObject parameter: heightBuffer
[type: number] [default: 0] [optional] 
A buffer can be supplied here to ensure that the scrolling results in the SceneObject being visible with Y amount of room to spare.




































































































































































































































































































































































































































































































































































































----------------------------------------------------------
Section 115: Material
----------------------------------------------------------


Material
[type: class] 
Materials are objects that control how the visual 'surfaces' defined in a Geometry are configured and ultimately rendered by WebGL. This visual configuration is managed through the EffectNodes and EffectControllers on each Material.





Material.type
[type: string] 
Type identifier.





Material.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





Material.blendingMode
[type: string] [default: nc.blendingModes.standard] 
Determines how this Material composites with what is drawn behind it. Accepts a blending mode name string (from nc.blendingModes, which includes all built-in and custom modes), or a direct CustomBlendingMode object reference — both forms are equivalent. The value is always stored and returned as a name string. Built-in modes: "standard" (normal alpha blending), "add" (adds color on top — useful for glow/fire), "subtract" (subtracts color), "multiply" (multiplies color with what's behind), "none" (no blending). Custom blend modes are defined via nc.defineCustomBlendingMode, which automatically registers the mode's name in nc.blendingModes.





Material.auxShaderSegment_vertexSupport
[type: string] [default: ""] 
An auxiliary shader support string that enables for the insertion of GLSL shader code before the vertex shader main. This can be used to add custom functionality to this Material's vertex shader beyond the built-in EffectNode functionality.





Material.shaderSegment_matrixMath
[type: string] [default: "gl_Position=projectionMatrix*(modelViewMatrix*vec4(vertex,1.0));"] 
A shader segment string, determining the GLSL code used in the 'matrix math' segment at the end of the vertex shader. This can be used to customize the vertex shader matrix math.





Material.auxShaderSegment_postMatrixMath
[type: string] [default: ""] 
An auxiliary shader support string that enables for the insertion of GLSL shader code after the 'matrix math' segment of the vertex shader. This can be used to add custom functionality to this Material's vertex shader beyond the standard built-in functionality.





Material.effectNodesLedger
[type: [string]] 
A list of the names of this Material's EffectNodes for quick-reference while debugging or inspecting. To access and manipulate the actual EffectNodes, use Material.getEffectNodes, Material.setEffectNodes, or Material.addEffectNodes.





Material.compiledVertexShader
[type: string] 
The the compiled GLSL vertex shader string for this Material, resulting from combining this Material's EffectNodes. This property is generally only meant for troubleshooting, and is read-only.





Material.compiledFragmentShader
[type: string] 
The the compiled GLSL fragment shader string for this Material, resulting from combining this Material's EffectNodes. This property is generally only meant for troubleshooting, and is read-only.





Material.faceCulling
[type: string] [default: 'none'] 
Determines which side of each triangle in the geometry is drawn - 'none' draws both sides, 'back' drops the triangles facing away from the camera, and 'front' drops the ones facing it. Please note that though the default value for this property is 'none', many GraphicAssets come with Material presets that can override the default.





Material.depthTest
[type: boolean] [default: nc.defaultDepthTesting] 
Flag determining if fragments (pixels) drawn with this Material are tested against other fragment depths (as stored in the depth buffer), ensuring that only the closest fragment is drawn. This flag is useful with geometries that have a full 3D shape such as those from OBJs etc... Please note that though the default value for this property is determined by the current value of nc.defaultDepthTesting, many GraphicAssets come with Material presets that can override the default.





Material.depthWrite
[type: boolean] [default: nc.defaultDepthWriting] 
Flag determining if the depths of fragments (pixels) drawn with this Material are written to the depth buffer, and can therefore be used to occlude other fragments. Please note that though the default value for this property is determined by the current value of nc.defaultDepthWriting, many GraphicAssets come with Material presets that can override the default.





Material.transparent
[type: boolean] [default: nc.defaultTransparency] 
Flag determining if fragments (pixels) drawn with this Material are blended with what is already in the frame buffer rather than replacing it. Transparent Materials are also drawn after opaque ones, in back-to-front order. This is independent of 'depthWrite' and 'depthTest', so a transparent Material can still take part in the depth buffer. Please note that though the default value for this property is determined by the current value of nc.defaultTransparency, many GraphicAssets come with Material presets that can override the default.





Material.fillColor
[type: Color] 
The EffectController for the 'FillColor' EffectNode, which entirely fills the associated Geometry with the red, green, blue, and alpha color values provided. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





Material.mainTexture
[type: Texture] 
The EffectController for the 'SampleMainTexture' EffectNode that tells it which Texture to render.





Material.colorMultiply
[type: Color] 
The EffectController for the 'ColorMultiply' EffectNode, which multiplies the red, green, blue, and alpha color values of the Material it is applied to. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





Material.shapify
[type: shapify] 
The EffectController for the 'Shapify' EffectNode. The Shapify EffectNode converts edge data stored in a 'shapified' Texture into a presentable image with edges that stay sharp regardless of the scale of the associated GraphicObject. This is an instance of the dynamically defined EffectController 'shapify' (base type: 'Vector2'). To get a new instance, use "nc.effectControllers['shapify'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





Material.incr_TwoColorGradient
[type: incr_TwoColorGradient] 
The incr_TwoColorGradient EffectController. This is an instance of the dynamically defined EffectController 'incr_TwoColorGradient' (base type: 'Vector4'). To get a new instance, use "nc.effectControllers['incr_TwoColorGradient'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





Material.incr_TwoColorGradient_color0
[type: Color] 
The incr_TwoColorGradient_color0 EffectController. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





Material.incr_TwoColorGradient_color1
[type: Color] 
The incr_TwoColorGradient_color1 EffectController. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





Material.shear
[type: shear] 
EffectController for the Shear EffectNode, which distorts the shape to appear slanted or skewed. This is an instance of the dynamically defined EffectController 'shear' (base type: 'Vector3'). To get a new instance, use "nc.effectControllers['shear'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





Material.shear_center
[type: Vector2] 
EffectController for the Shear EffectNode, which distorts the shape to appear slanted or skewed. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





Material.getEffectNodes()
[type: function] [returns: [EffectNode]] 
Returns this Material's current EffectNodes. EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. Each EffectNode can be manipulated dynamically by one or more EffectControllers, which are accessable as direct members of the given SceneObject or Material. When a GraphicObject is set to a particular GraphicAsset, it's Materials adopt the GraphicAsset's EffectNode and EffectController presets by default, but they can be customized at any time.





Material.setEffectNodes(effectNodes)
[type: function] 
Sets the EffectNodes for this Material. EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. Each EffectNode can be manipulated dynamically by one or more EffectControllers, which are accessable as direct members of the given SceneObject or Material. When a GraphicObject is set to a particular GraphicAsset, it's Materials adopt the GraphicAsset's EffectNode and EffectController presets by default, but they can be customized at any time.

Material.setEffectNodes parameter: effectNodes
[type: [EffectNode], EffectNode] 
The new list of EffectNodes that will apply to this SceneObject and all of its Materials.





Material.addEffectNodes(effectNodes)
[type: function] 
Adds the given EffectNodes to this Material. EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. Each EffectNode can be manipulated dynamically by one or more EffectControllers, which are accessable as direct members of the given SceneObject or Material. When a GraphicObject is set to a particular GraphicAsset, it's Materials adopt the GraphicAsset's EffectNode and EffectController presets by default, but they can be customized at any time.

Material.addEffectNodes parameter: effectNodes
[type: [EffectNode], EffectNode] 
The EffectNodes to add to this Material.





Material.setShaderDefinitions(definitionsDictionary)
[type: function] 
Sets the shader definitions for this Material. Shader definitions serve as a means to dynamically change the composition of the GLSL shader code in any/all of the EffectNodes on this Material. Definitions consist of key-value pairs where for each pair, the value will be substitute in for each instance of the key found in the shader code. Definitions can also be used as preprocessor directives when '#ifdef' and '#endif' statements are used in the shader code.

Material.setShaderDefinitions parameter: definitionsDictionary
[type: object] 
The dictionary of shader definitions to set for this Material.





Material.getShaderDefinitions()
[type: function] [returns: object] 
Returns the dictionary of shader definitions for this Material. Shader definitions serve as a means to dynamically change the composition of the GLSL shader code in any/all of the EffectNodes on this Material. Definitions consist of key-value pairs where for each pair, the value will be substitute in for each instance of the key found in the shader code. Definitions can also be used as preprocessor directives when '#ifdef' and '#endif' statements are used in the shader code.





Material.dispose()
[type: function] 
Disposes this Material, and removes internal Incisor® references to it to aid memory management.










----------------------------------------------------------
Section 116: ConstructDefinition
----------------------------------------------------------


ConstructDefinition
[type: class] [NON-INSTANTIABLE] 
ConstructDefinitions house the defining attributes of Constructs. To create an instance of a given Construct, use 'nc.myConstruct.add()'. 





ConstructDefinition.type
[type: string] 
Type identifier.





ConstructDefinition.name
[type: string] 
The name of the ConstructDefinition.





ConstructDefinition.blueprint
[type: Blueprint] 
Object defining the Construct's composition and layout.





ConstructDefinition.unitsPerPixel
[type: [number]] 
Array of numbers that multiply all of the positions and scales related to this Construct.





ConstructDefinition.add(parent, name)
[type: function] 
Adds an instance of this Construct to the given parent.

ConstructDefinition.add parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The SceneObject that will be the parent of the newly added Construct instance.

ConstructDefinition.add parameter: name
[type: string] [optional] 
The name of the newly added Construct instance. If left undefined, this propery will default to the name of the Construct.





ConstructDefinition.getPortableObject()
[type: function] 
Returns an object version of the ConstructDefinition equivalent to the '.construct' file that defines this Construct.










----------------------------------------------------------
Section 117: Blueprint
----------------------------------------------------------


Blueprint
[type: class] 
Object that stores information about a collection of SceneObjects that can be recreated later. This object is the foundation for Incisor® Constructs.










----------------------------------------------------------
Section 118: Construct
----------------------------------------------------------


Construct
[type: class] [extends: SceneObject] [NON-INSTANTIABLE] 
Constructs are collections of different types of SceneObjects that can be built, arranged, and animated from within the Incisor® GUI. For a list of available ConstructDefinitions, see 'nc.constructDefs'. 





Construct.constructDefinition
[type: ConstructDefinition] 
The ConstructDefinition associated with this Construct. Once a Construct is instantiated, this value cannot change.



























































































































































































































































































































----------------------------------------------------------
Section 119: UrlParameterIterator
----------------------------------------------------------


UrlParameterIterator
[type: class] [NON-INSTANTIABLE] [requires: module - urlParameterIterator] 
Object housing testing functionality that enables a project to refresh itself repeatedly with different url parameters. Such functionality can help with batch testing of a project's configurations or settings. To use this functionality, first call the 'UrlParameterIteration.setup' method, passing it an array of objects where each object represents the url parameters you would like the browser to refresh with. When ready to start the iteration, call 'UrlParameterIteration.start'. Then add the desired functionality per url parameter - be sure to implement what you want conditionally based on the url params (otherwise everything will happen on every refresh). When the desired tasks (testing, screen shots, etc...) have completed for each set of url parameters, call 'UrlParameterIteration.next', this will proceed to refresh with the next set of url parameters.





UrlParameterIterator.setup(urlParametersList, postIterationCallbackOwner, postIterationCallackName)
[type: function] 
Function that informs the UrlParameterIterator of the set of url parameters that it will iterate over. This function must be called un-conditionally upon every refresh in order for the UrlPerameterIterator to function properly.

UrlParameterIterator.setup parameter: urlParametersList
[type: [object]] 
Array of objects where each object represents the active url parameters for a particular iteration.

UrlParameterIterator.setup parameter: postIterationCallbackOwner
[type: object] 
The object owning the callback function to be called when the iteration completes.

UrlParameterIterator.setup parameter: postIterationCallackName
[type: string] 
The name of the callback function to be called when the iteration completes.





UrlParameterIterator.start(startingIndex)
[type: function] 
Starts the process of refreshing the browser, iterating through the list of url parameters provided in 'UrlParameterIterator.setup'.

UrlParameterIterator.start parameter: startingIndex
[type: number] [default: 0] [optional] 
Optional starting index, enabling iteration to start at a non-zero value.





UrlParameterIterator.next()
[type: function] 
Proceeds to the next item in the list of url parameters, refreshing the browser with the coorespoinging url.










----------------------------------------------------------
Section 120: UiLinkButton
----------------------------------------------------------


UiLinkButton
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A ui-specialized horizontal LayoutStack housing a text-based Button with various UI functionalities and defaults applied. The UiLinkButton is similar to the UiButton, but has no visible background, and instead the text itself is the interactive component. UI functionality includes:  • pre-configured with LayoutObject functionality.  • uiStyle TextFormats and Colors applied.  • pre-configured with 'UiKeyboardNavigable' functionality.  • uiZoom-enabled.  • nearestPixelRendering-enabled.





UiLinkButton.isActive
[type: boolean] [default: true] 
Boolean determining if the UiLinkButton is available for end-user-internaction, or if it is unavailable and 'grayed out'.





UiLinkButton.mainText
[type: TextBox] 
The TextBox with main text for this UiLinkButton. The size of the text informs the button's size and layout.





UiLinkButton.displayLabel
[type: boolean] [default: false] 
Boolean determining if a label TextBox is displayed to the left of the UiLinkButton.





UiLinkButton.label
[type: UiText] [default: undefined] 
A UiText that acts as a label for the UiLinkButton. Please note that this item is undefined until the 'displayLabel' property is set to true.





UiLinkButton.mainButton
[type: Button] 
The main Button for the UiLinkButton, this object is a UiPanel which also implements Button. This item defaults to 'visible=false'.





UiLinkButton.outline
[type: UiOutline] 
The outline of the button, which is used to indicate when the end-user outlines this UiLinkButton using keyboard navigation (tab, arrows, etc...).





UiLinkButton.buttonTextColor
[type: Color] [default: nc.uiStyle.color_interactiveText] 
The base Color of the TextBox for this UiLinkButton.





UiLinkButton.highlightedButtonTextColor
[type: Color] [default: nc.uiStyle.color_highlightedInteractiveText] 
The highlighted Color of the TextBox for this UiLinkButton.





UiLinkButton.addTriggerCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever this UiLinkButton is triggered via the cursor or keyboard navigation. The triggering browser-created event, and the UiLinkButton itself are sent to the callback as its first two parameters.

UiLinkButton.addTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this UiLinkButton is triggered via the cursor or keyboard navigation.

UiLinkButton.addTriggerCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this UiLinkButton is triggered via the cursor or keyboard navigation.

UiLinkButton.addTriggerCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever this UiLinkButton is triggered via the cursor or keyboard navigation.





UiLinkButton.removeTriggerCallback(callbackOwner, callbackName)
[type: function] 
Removes the given trigger callback.

UiLinkButton.removeTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UiLinkButton.removeTriggerCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





















































































































































































































































































































































































































----------------------------------------------------------
Section 121: TimePlaybackController
----------------------------------------------------------


TimePlaybackController
[type: class] [extends: PlaybackController] 
A time-based PlaybackController with "startTime", "time", and "endTime" properties.





TimePlaybackController.time
[type: number] 
The current time (in seconds) of the PlaybackController. While playing, this value is automatically updated every fixedUpdate, or it can also be set manually at any time.





TimePlaybackController.startTime
[type: number] 
The starting time of the PlaybackController.





TimePlaybackController.endTime
[type: number] 
The end time of the PlaybackController.





TimePlaybackController.initialTime
[type: number] 
The initial time for this TimePlaybackController when it is included in a newly instantiated Construct. This property will be set to the TimePlaybackController's 'startTime' as a default.
























































































































----------------------------------------------------------
Section 122: ValuePlaybackController
----------------------------------------------------------


ValuePlaybackController
[type: class] [extends: PlaybackController] 
A value-based PlaybackController with "startValue", "value", and "endValue" properties.





ValuePlaybackController.value
[type: number] 
The current value (in seconds) of the PlaybackController. While playing, this value is automatically updated every fixedUpdate, or it can also be set manually at any time.





ValuePlaybackController.startValue
[type: number] 
The starting value of the PlaybackController.





ValuePlaybackController.endValue
[type: number] 
The end value of the PlaybackController.





ValuePlaybackController.initialValue
[type: number] 
The initial value for this ValuePlaybackController when it is included in a newly instantiated Construct. This property will be set to the ValuePlaybackController's 'startValue' as a default.
























































































































----------------------------------------------------------
Section 123: PlaybackController
----------------------------------------------------------


PlaybackController
[type: class] [NON-INSTANTIABLE] 
Object managing the playing, pausing, and stopping of items that change over time such as Timelines, Sounds, or ParticleSystems. 





PlaybackController.type
[type: string] 
Type identifier.





PlaybackController.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PlaybackController.lazyStop
[type: boolean] [default: false] 
Boolean flag determining if the PlaybackController will hault the next time the time reachs the endTime (or startTime if playback is a negative value). If this flag is false, the PlaybackController loops and continues playing indefinitely.





PlaybackController.duration
[type: number] 
The read-only length of this PlaybackController in seconds. To change the duration, adjust the 'startTime' or 'endTime' properties.





PlaybackController.playbackState
[type: string] [default: nc.constants.playbackStates.stopped] 
Read-only string denoting the current playback state: 'stopped', 'paused', or 'playing'. State values are available in 'nc.constants.playbackStates'.





PlaybackController.playbackRate
[type: number] [default: 1] 
Value multiplying the progression of the 'time' value. To play twice as fast use 2, for items that can play backwards, use negative values.





PlaybackController.netPlaybackRate
[type: number] 
Read-only value denoting the net playbackRate, including the effects of this PlaybackController's SpeedControls.





PlaybackController.pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] 
The PauseEvent or Array of PauseEvents that this PlaybackController will be immune to. Set this parameter to [] for this PlaybackController to have no pause immunity.





PlaybackController.speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] 
The SpeedControl or Array of SpeedControls that this PlaybackController is affected by.





PlaybackController.autoplayMode
[type: string] [default: "none"] 
Determines how the PlaybackController behaves when included in a newly instantiated Construct. "loop" — automatically starts playing (loops continuously). "once" — automatically starts playing once and stops at the end (sets lazyStop to true). "none" — does not automatically play.





PlaybackController.autoplayWhenInConstruct
[type: boolean] [default: true] 
DEPRECATION ID 2026.05.04.00 — use autoplayMode instead. Boolean determining if the PlaybackController automatically starts playing when included in a newly instantiated Construct. Setting true converts to autoplayMode "loop"; setting false converts to autoplayMode "none".





PlaybackController.play()
[type: function] 
Changes the playbackState to "playing", and begins the progression of the 'time' value. While playing, the PlaybackController automatically updates the 'time' value once every fixedUpdate.





PlaybackController.playOnce(lazyStopCallbackOwner, lazyStopCallbackName, lazyStopCallbackArgs)
[type: function] 
Starts playing with 'time=startTime' (or if playbackRate is negative, 'time=endTime') and sets the 'lazyStop' value to true. An optional callback function can be provided for when playbackController stops - this callback is consumed upon stopping.

PlaybackController.playOnce parameter: lazyStopCallbackOwner
[type: object] [optional] 
The object owning the optional callback function that is triggered when a lazy stop occurs.

PlaybackController.playOnce parameter: lazyStopCallbackName
[type: string] [optional] 
The name of the optional callback function that is triggered when a lazy stop occurs.

PlaybackController.playOnce parameter: lazyStopCallbackArgs
[type: Array, any] [optional] 
Parameters for the optional callback function that is triggered when a lazy stop occurs.





PlaybackController.pause()
[type: function] 
Changes the playbackState to "paused", and pauses the progression of the 'time' value.





PlaybackController.stop()
[type: function] 
Changes the playbackState to "stopped" and sets the 'time' value to 'startTime'.





PlaybackController.addTimeUpdateCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs any time the 'time' property is updated, which happens while this PlaybackController is playing, but also when time is set directly. The time value will be sent to this callback as its first parameter, with any user-defined args following.

PlaybackController.addTimeUpdateCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that is triggered when time is updated.

PlaybackController.addTimeUpdateCallback parameter: callbackName
[type: string] 
The name of the callback function that is triggered when time is updated.

PlaybackController.addTimeUpdateCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered when time is updated.





PlaybackController.removeTimeUpdateCallback(callbackOwner, callbackName)
[type: function] 
Removes the given timeUpdate callback.

PlaybackController.removeTimeUpdateCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

PlaybackController.removeTimeUpdateCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





PlaybackController.addLazyStopCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs upon the next 'lazyStop', which occurs any time the time reaches the startTime or endTime while the 'lazyStop' flag is true. It should be noted that all lazyStop callbacks are consumed upon encountering a lazyStop, and would need to be-added to be triggered upon subsequent lazyStops.

PlaybackController.addLazyStopCallback parameter: callbackOwner
[type: object] 
The object owning the optional callback function that is triggered when a lazy stop occurs.

PlaybackController.addLazyStopCallback parameter: callbackName
[type: string] 
The name of the optional callback function that is triggered when a lazy stop occurs.

PlaybackController.addLazyStopCallback parameter: callbackArgs
[type: Array, any] [optional] 
Parameters for the optional callback function that is triggered when a lazy stop occurs.





PlaybackController.removeLazyStopCallback(callbackOwner, callbackName)
[type: function] 
Removes the given lazyStop callback.

PlaybackController.removeLazyStopCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

PlaybackController.removeLazyStopCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





PlaybackController.addStateChangeCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs if/when any component of this PlaybackController has changed. This can be used to manage processes that run entirely outside of the Incisor® system by providing a callback to update said processes upon any change. A string denoting the triggering change will be passed in as the callback function's first parameter, and user-defined parameters will follow.

PlaybackController.addStateChangeCallback parameter: callbackOwner
[type: object] 
The object owning the optional callback function that is triggered when any component of this PlaybackController has changed.

PlaybackController.addStateChangeCallback parameter: callbackName
[type: string] 
The name of the optional callback function that is triggered when any component of this PlaybackController has changed.

PlaybackController.addStateChangeCallback parameter: callbackArgs
[type: Array, any] [optional] 
Parameters for the optional callback function that is triggered when any component of this PlaybackController has changed.





PlaybackController.removeStateChangeCallback(callbackOwner, callbackName)
[type: function] 
Removes the given stateChange callback.

PlaybackController.removeStateChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

PlaybackController.removeStateChangeCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





PlaybackController.dispose()
[type: function] 
Removes internal Incisor® references to this PlaybackController in order to aid memory management.










----------------------------------------------------------
Section 124: UiBooleanSupervisor_checkbox
----------------------------------------------------------


UiBooleanSupervisor_checkbox
[type: class] [extends: UiGraphicButton] [requires: module - extendedUi] 
A specialized UiGraphicButton that includes a Supervisor member, enabling it to monitor and adjust a boolean property's value during runtime. To use this class, configure the 'supervisedPropertyGetter' and 'supervisedPropertySetter' callbacks on the Supervisor. Once configured, the visibility of the 'graphicObject' member will be updated every fixed update to reflect the most current value of the supervised property, and the value of the supervised property will also be 'adjustable' via cursor interaction.





UiBooleanSupervisor_checkbox.supervisor
[type: Supervisor] 
Supervisor with callbacks that enable this UiBooleanSupervisor_checkbox to monitor and adjust a boolean property's value during runtime.



























































































































































































































































































































































































































































































----------------------------------------------------------
Section 125: Publishing
----------------------------------------------------------


Publishing
[type: class] [NON-INSTANTIABLE] [requires: unpublished only] 
Object housing functionality for publishing projects. 





Publishing.publishProject(configurationName, hostPublishedProject)
[type: function] [returns: IncrCommsResponseObject] 
Compiles the user code from the current project together with the Incisor® code to produce a complete, optimized, and ready-to-host web package. Publishing configuration options such as asset packaging settings, code formatting settings, and more are defined in ProjectSettings. By default, newly published projects will be placed in the 'Publishing' directory in the project.

Publishing.publishProject parameter: configurationName
[type: string] [optional] 
The name of the configuration to be used in publishing this project.

Publishing.publishProject parameter: hostPublishedProject
[type: boolean] [optional] 
Flag determining if the published project should be automatically hosted. [Default: false]










----------------------------------------------------------
Section 126: Precomp
----------------------------------------------------------


Precomp
[type: class] 
A Precomp (short for 'precomposition'), is an object with its own Scene, Camera, RenderTarget, and GraphicAsset. When the Precomp's Camera renders, it informs the associated GraphicAsset, which can be instantiated by making new GraphicObject. Precomps can be used for optimization in many ways, including precomposing several ScenenObjects together, rendering the Scene, and using the resulting GraphicAsset to recreate the collection in a single GraphicObject.





Precomp.type
[type: string] 
Type identifier.





Precomp.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





Precomp.name
[type: string] 
The name of the Precomp. This name will also be used for the GraphicAsset, Texture, and Geometry that are created as part of this Precomp.





Precomp.scene
[type: Scene] 
The Scene holding the this Precomp's content. This is the Scene that is rendered to inform the associated GraphicAsset.





Precomp.camera
[type: OrthographicCamera, PerspectiveCamera] 
The Camera that resides in, and renders, this Precomp's Scene.





Precomp.renderTarget
[type: RenderTarget] 
The RenderTarget that this Precomp's Camera renders to.





Precomp.graphicAsset
[type: GraphicAsset] 
The GraphicAsset using this Precomp's RenderTarget (using its Texture)





Precomp.automaticallyManageLoadingTierDelayedContentRendering
[type: boolean] [default: true] 
Boolean determining if this Precomp attempts to manage its own delayed rendering. With this value set to true and 'autorender=true', this Precomp will change the 'autoRenderOrder' of its own Camera to account for any Precomp nesting that migth occur. With this value set to true and 'autorender=false', this Precomp will set up an internal callback to render its Scene content once it all loads. If this value is set to false, no delayed rendering management actions occur unless manually triggered. The Precomp can be rendered at any time by calling 'Precomp.camera.render'.





Precomp.writePngFile(filePath, isPathRelative, postLoadCallbackOwner, postLoadCallbackName, postLoadCallbackArgs, unMultiply, writeRawBase64)
[type: function] [requires: unpublished only, module - fileIO] 
An awaitable method that writes the rendered content from this Precomp's RenderTarget to disk as a '.png' file once it has all loaded. A callback function can be provided to manipulate the contents of this Precomp once it has loaded before it is rendered and write to file.

Precomp.writePngFile parameter: filePath
[type: string] 
The relative or absolute path to the png file to be written to disk.

Precomp.writePngFile parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

Precomp.writePngFile parameter: postLoadCallbackOwner
[type: object] [optional] 
The owner of the optional callback function that is called once the Precomp Scene's content is loaded before it is rendered.

Precomp.writePngFile parameter: postLoadCallbackName
[type: string] [optional] 
The name of the optional callback function that is called once the Precomp Scene's content is loaded before it is rendered.

Precomp.writePngFile parameter: postLoadCallbackArgs
[type: Array, any] [optional] 
Parameters for the optional callback function that is called once the Precomp Scene's content is loaded before it is rendered.

Precomp.writePngFile parameter: unMultiply
[type: boolean] [default: true] [optional] 
Boolean determining if the contents of the RenderTarget are 'un-multiplied' before the '.png' is written. Since textures loaded in Incisor® use premultiplied alpha, un-multiplication would need to happen to get a file with transparency that was equivalent to the original asset files.

Precomp.writePngFile parameter: writeRawBase64
[type: boolean] [default: false] [optional] 
Boolean Bool stating if the file written will be in Base64 text format.










----------------------------------------------------------
Section 127: AnimatedProperty
----------------------------------------------------------


AnimatedProperty
[type: class] [extends: KeyframedValue] [NON-INSTANTIABLE] 
An AnimatedProperty is a KeyframedValue bound to a property so that a Timeline can animate it over time. On top of all of the keyframing behavior it inherits from KeyframedValue, it adds the binding (propertyPath / propertyOwner) that connects the keyframed value to the thing being animated. Create an AnimatedProperty with Timeline.addAnimatedProperty. 





AnimatedProperty.type
[type: string] 
Type identifier.





AnimatedProperty.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





AnimatedProperty.propertyPath
[type: [string]] 
The path to the animated property, as an array of member names (for example ['scale','x'] or ['material','0','arch','strength']). This is the property's identity and is serialized verbatim. A path whose first member is 'nc' addresses something global rather than anything on a SceneObject - a Sound or a custom AppEvent, for instance - and has no propertyOwner.





AnimatedProperty.propertyOwner
[type: SceneObject] 
The SceneObject that propertyPath is relative to. Undefined for owner-less properties (such as a timeline-driven sound).





AnimatedProperty.bindingKind
[type: string] 
How this property reads and writes its value: 'path' (a direct property-path assignment) or 'callback' (a built-in handler, used for special cases such as materials, graphicAsset, and invoke).





















































































----------------------------------------------------------
Section 128: CustomBlendingMode
----------------------------------------------------------


CustomBlendingMode
[type: class] [NON-INSTANTIABLE] 
A CustomBlendingMode defines a fully configurable WebGL blending operation that can be assigned to a Material's 'blending' property. It exposes independent control over the blend equation and source/destination factors for both RGB and alpha channels. Use 'nc.defineCustomBlendingMode' to create a CustomBlendingMode. Its name is automatically added to 'nc.blendingModes' alongside the built-in modes. Defined CustomBlendingModes are stored in 'nc.customBlendingModes'. 





CustomBlendingMode.type
[type: string] 
Type identifier.





CustomBlendingMode.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





CustomBlendingMode.name
[type: string] 
The name of this CustomBlendingMode, as provided to 'nc.defineCustomBlendingMode'.





CustomBlendingMode.equation
[type: string] [default: nc.constants.customBlendingModeEquations.add] 
The blending equation applied to the RGB channels. Determines how the weighted source and destination RGB values are combined into the final output. For available values, see 'nc.constants.customBlendingModeEquations'.





CustomBlendingMode.alphaEquation
[type: string] [default: undefined] 
An optional separate blending equation applied to the alpha channel. When undefined, the value of 'equation' is used for both RGB and alpha. For available values, see 'nc.constants.customBlendingModeEquations'.





CustomBlendingMode.srcFactor
[type: string] [default: nc.constants.customBlendingModeFactors.srcAlpha] 
The blending factor applied to the source RGB color before the blend equation is evaluated. For available values, see 'nc.constants.customBlendingModeFactors'.





CustomBlendingMode.srcAlphaFactor
[type: string] [default: undefined] 
An optional separate blending factor applied to the source alpha before the blend equation is evaluated. When undefined, the value of 'srcFactor' is used for both RGB and alpha. For available values, see 'nc.constants.customBlendingModeFactors'.





CustomBlendingMode.dstFactor
[type: string] [default: nc.constants.customBlendingModeFactors.oneMinusSrcAlpha] 
The blending factor applied to the destination RGB color before the blend equation is evaluated. For available values, see 'nc.constants.customBlendingModeFactors'.





CustomBlendingMode.dstAlphaFactor
[type: string] [default: undefined] 
An optional separate blending factor applied to the destination alpha before the blend equation is evaluated. When undefined, the value of 'dstFactor' is used for both RGB and alpha. For available values, see 'nc.constants.customBlendingModeFactors'.










----------------------------------------------------------
Section 129: UiTextField
----------------------------------------------------------


UiTextField
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A ui-specialized horizontal LayoutStack housing an editable TextBox with various UI functionalities and defaults applied. UI functionality includes:  • pre-configured with LayoutObject functionality.  • uiStyle TextFormats and Colors applied.  • pre-configured with 'UiKeyboardNavigable' functionality.  • uiZoom-enabled.  • pre-configured with 'UiVisualFocus' functionality.  • nearestPixelRendering-enabled.





UiTextField.isActive
[type: boolean] [default: true] 
Boolean determining if the UiTextField is available for end-user-internaction, or if it is unavailable and 'grayed out'.





UiTextField.mainText
[type: TextBox] 
The main editable TextBox for this UiTextField.





UiTextField.displayLabel
[type: boolean] [default: false] 
Boolean determining if a label UiText is displayed to the left of the UiTextField.





UiTextField.label
[type: UiText] [default: undefined] 
A UiText that acts as a label for the UiTextField. Please note that this item is undefined until the 'displayLabel' property is set to true.





UiTextField.mainButton
[type: Button] 
The main Button for the UiTextField, this object is a UiPanel which also implements Button.





UiTextField.outline
[type: UiOutline] 
The outline of the button, which is used to indicate when the end-user outlines this UiTextField using keyboard navigation (tab, arrows, etc...).





UiTextField.buttonBackgroundColor
[type: Color] [default: nc.uiStyle.color_buttonPanel] 
The Color of the Button background.





UiTextField.highlightedButtonBackgroundColor
[type: Color] [default: nc.uiStyle.color_highlightedButtonPanel] 
The Color of the Button background when it's highlighted.





UiTextField.displayExButton
[type: boolean] [default: false] 
Boolean determining if a clear ('ex') button is displayed at the right side of the UiTextField. When true, the button appears only when the text field is non-empty and clears the text when pressed. The exButton is lazily created the first time this is set to true.





UiTextField.exButton
[type: UiGraphicButton] [default: undefined] 
A UiGraphicButton displaying the ex icon, positioned at the right edge of the UiTextField's text area. Visible only when the text field is non-empty. Please note that this item is undefined until the 'displayExButton' property is set to true.





UiTextField.addTriggerCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever this UiTextField is triggered via the cursor or keyboard navigation. The triggering browser-created event, and the UiTextField itself are sent to the callback as its first two parameters.

UiTextField.addTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this UiTextField is triggered via the cursor or keyboard navigation.

UiTextField.addTriggerCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this UiTextField is triggered via the cursor or keyboard navigation.

UiTextField.addTriggerCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever this UiTextField is triggered via the cursor or keyboard navigation.





UiTextField.removeTriggerCallback(callbackOwner, callbackName)
[type: function] 
Removes the given trigger callback.

UiTextField.removeTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UiTextField.removeTriggerCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





















































































































































































































































































































































































































----------------------------------------------------------
Section 130: WaitThen
----------------------------------------------------------


WaitThen
[type: class] 
A WaitThen is an object that provides a means to schedule a delayed callback. This differs from standard javascript 'setTimeout' in that it is compatable with Incisor®'s pausing system, as well its SpeedControls, and 'nc.softwareSpeed'. WaitThen instances can be constructed normally using 'new', or you can just call 'nc.waitThen' which makes use of an internally pooled group of WaitThens. It is recommended that 'nc.waitThen' be used where possible to avoid needlessly instantiating new objects, and also avoid the potential for memory leaks.





WaitThen.type
[type: string] 
Type identifier.





WaitThen.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





WaitThen.name
[type: string] [default: "WaitThen"] 
The name of the WaitThen.





WaitThen.progress
[type: number] [default: 0] 
The progress of the WaitThen on the scale from [0,1].





WaitThen.isActive
[type: boolean] [default: false] 
Boolean reporting if this WaitThen is currently 'counting down'. Pausing is not factored into this property; a WaitThen that is activated and then subjected to a PauseEvent would still report 'true'.





WaitThen.callbackOwner
[type: object] 
The object owning the callback function invoked when this WaitThen completes.





WaitThen.callbackName
[type: string] 
The name of the callback function invoked when this WaitThen completes.





WaitThen.callbackArgs
[type: any] 
Arguments for the callback function invoked when this WaitThen completes.





WaitThen.pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] 
The PauseEvent or Array of PauseEvents that this WaitThen will be immune to. Set this parameter to [] for this WaitThen to have no pause immunity.





WaitThen.speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] 
The SpeedControl or Array of SpeedControls that this WaitThen is affected by.





WaitThen.duration
[type: number] 
Read-only property indicating the current duration of the WaitThen.





WaitThen.activate(duration, callbackOwner, callbackName, callbackArgs, pauseImmunity, speedControl)
[type: function] 
Activates this WaitThen, starting the 'count-down' to this WaitThen's callback.

WaitThen.activate parameter: duration
[type: number] 
Seconds before the callback will occur.

WaitThen.activate parameter: callbackOwner
[type: object] 
The object owning the callback function that is called when the WaitThen completes.

WaitThen.activate parameter: callbackName
[type: string] 
The name of the function that is called when the WaitThen completes.

WaitThen.activate parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the WaitThen completes.

WaitThen.activate parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this WaitThen will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

WaitThen.activate parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this WaitThen is affected by.





WaitThen.stop(performCallback)
[type: function] 
Stops this WaitThen.

WaitThen.stop parameter: performCallback
[type: boolean] [default: false] [optional] 
Boolean determining if the callback function will be called immediately, or if it will be skipped entirely.










----------------------------------------------------------
Section 131: UiStringSupervisor_menu
----------------------------------------------------------


UiStringSupervisor_menu
[type: class] [extends: UiDropDownMenu] [requires: module - extendedUi] 
A specialized UiDropDownMenu that includes a Superivor member, enabling it to monitor and adjust a string property's value during runtime. To use this class, configure the 'supervisedPropertyGetter' and 'supervisedPropertySetter' callbacks on the Supervisor. Once configured, the 'mainText' member will be updated every fixed update to reflect the most current value of the supervised string property, and the value of the supervised property will also be 'adjustable' via cursor interaction with the UiMenu.





UiStringSupervisor_menu.supervisor
[type: Supervisor] 
Supervisor with callbacks that enable this UiStringSupervisor_menu to monitor and adjust a boolean property's value during runtime.





UiStringSupervisor_menu.updateStringOptionsCallbackOwner
[type: object] 
The owner of the optional callback function that will be called whenever the UiMenu is opened in order to update the list of options. The provided callback function should return an Array of strings meant to be the options presented by this UiStringSupervisor_menu.





UiStringSupervisor_menu.updateStringOptionsCallbackName
[type: string] 
The name of the optional callback function that will be called whenever the UiMenu is opened in order to update the list of options. The provided callback function should return an Array of strings meant to be the options presented by this UiStringSupervisor_menu.





UiStringSupervisor_menu.updateStringOptionsCallbackArgs
[type: any] 
Parameters for the optional callback function that will be called whenever the UiMenu is opened in order to update the list of options. The provided callback function should return an Array of strings meant to be the options presented by this UiStringSupervisor_menu.





UiStringSupervisor_menu.setStringOptions(stringOptions)
[type: function] 
Method to update the list of string options available within the UiMenu. This method can be used once during setup in situations where the list of options is static. In such a case, the 'updateStringOptionsCallback' callback could be left undefined.

UiStringSupervisor_menu.setStringOptions parameter: stringOptions
[type: [string]] 
The list of strings that will appear as options in the drop down menu.












































































































































































































































































































































































































































































----------------------------------------------------------
Section 132: GraphicAsset
----------------------------------------------------------


GraphicAsset
[type: class] [NON-INSTANTIABLE] 
A GraphicAsset is an object that represents a piece of visual content such as an image file or an 'OBJ'. GraphicAssets contain a Geometry, and a set of MaterialPresets that, when applied via 'GraphicObject.graphicAsset' or 'GraphicObject.setGraphicAsset', change the appearance of a GraphicObject to that of the GraphicAsset. 





GraphicAsset.type
[type: string] 
Type identifier





GraphicAsset.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





GraphicAsset.name
[type: string] 
The GraphicAsset's name.

example:
// Objective: Set and Get the name of a GraphicAsset.
// Expected Result: The console should read "name is WhiteBox"

// Create a GraphicObject using the WhiteBox GraphicAsset.
let myGraphicObject = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "MyGraphicObject" );
// Get an instance of the GraphicAsset from its GraphicObject.
let myGraphicAsset = myGraphicObject.graphicAsset;
// Console log the name of the GraphicAsset.
console.log("name is", myGraphicAsset.name );





GraphicAsset.geometry
[type: Geometry] 
This GraphicAsset's geometry.

example:
// Objective: Get the current Geometry of a GraphicAsset
// Expected Result: The console should have 2 log messages as follows:
//     myGraphicAsset (Box) sourceWidth, sourceHeight 100 100
//     myGraphicAsset (Triangle) sourceWidth, sourceHeight 50 100

// Create a GraphicObject using the white box GraphicAsset.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "MyGraphicObject" );
// Get the GraphicAsset from the GraphicObject
let myGraphicAsset = myGraphicObject.graphicAsset;
// Console log the Geometry sourceWidth and sourceHeight of the GraphicAsset.
console.log("myGraphicAsset (Box) sourceWidth, sourceHeight", myGraphicAsset.geometry.sourceWidth, myGraphicAsset.geometry.sourceHeight);
// Update the Geometry of myGraphicAsset with the white triangle.
myGraphicAsset.geometry = nc.geometries.WhiteTriangle;
// Console log the Geometry sourceWidth and sourceHeight again.
console.log("myGraphicAsset (Triangle) sourceWidth, sourceHeight", myGraphicAsset.geometry.sourceWidth, myGraphicAsset.geometry.sourceHeight);





GraphicAsset.materialPresets
[type: [MaterialPreset]] 
List of MaterialPresets associated with this GraphicAsset.










----------------------------------------------------------
Section 133: MaterialPreset
----------------------------------------------------------


MaterialPreset
[type: class] [NON-INSTANTIABLE] 
A MaterialPreset is an object with the instructions for configuring a Material. A list of MaterialPresets is included with every GraphicAsset, so that when a GraphicObject is set to a given GraphicAsset, that GraphicObject's Materials can be configured accordingly. For example, for a standard image-file GraphicAsset, the typical MaterialPreset would list the "SampleMainTexture" EffectNode, and would also have the name of the Texture to set for the 'mainTexture' EffectController. 





MaterialPreset.type
[type: string] 
Type identifier





MaterialPreset.effectNodeNames
[type: [string]] 
List of the names of the EffectNodes to be applied to the Material.





MaterialPreset.materialValues
[type: object] 
Dictionary of EffectController values to be applied to the Material. Please note that the EffectController values stored in this object will be listed in a more primative form than elsewhere: EffectControllers that have a Vector base type will be stored as a simple array of numeric values within this object. Also Texture EffectController values are simply referenced by including the name of the Texture in question.










----------------------------------------------------------
Section 134: CustomAddOnDefinition
----------------------------------------------------------


CustomAddOnDefinition
[type: class] [NON-INSTANTIABLE] 
Object housing information about the CustomAddOns currently registered in this project. 





CustomAddOnDefinition.name
[type: string] 
The name of the CustomAddOn.





CustomAddOnDefinition.baseType
[type: string] 
The the name base type of the given CustomAddOn definition. Every registered CustomAddOn must extend one of the CustomAddOn types (i.e. CustomAddOn_SceneObject, CustomAddOn_GraphicObject, etc...), and this value denotes which of those types were extended to to create this particular CustomAddOn.





CustomAddOnDefinition.acceptableOwner
[type: string] 
The name of the type that is required as an owner. For example, if the CustomAddOn extended CustomAddOn_Button, then the 'acceptableOnwer' value would be 'Button' and this CustomAddOn can only be added to objects that extend the Button type.





CustomAddOnDefinition.properties
[type: [object]] 
Array of objects that containing information about the registered properties for this CustomAddOn. Registered properties are accessible for monitoring and manipulating within the inspector. Registered properties can also be flagged as 'persistent', which enables their values to be stored in containing Constructs. To register a property for a CustomAddOn call 'nc.registerCustomAddOnProperty'. If this CustomAddOn has no registered properties, then this member will be undefined.





CustomAddOnDefinition.classDefinition
[type: object] 
The class definition for this CustomAddOn.





CustomAddOnDefinition.description
[type: string] 
An optional description of this CustomAddOn.










----------------------------------------------------------
Section 135: RegisteredProperty
----------------------------------------------------------


RegisteredProperty
[type: class] [NON-INSTANTIABLE] 
Object housing information about the CustomAddOns currently registered in this project. 





RegisteredProperty.type
[type: string] 
The type of the RegisteredProperty.





RegisteredProperty.propertyPath
[type: [string]] 
The path from the given CustomAddOn or CustomObject instance to the property.





RegisteredProperty.isPersistent
[type: boolean] [default: true] 
Flag determining if the registered property's value should be stored in an owning Construct. To make the values of this property persistent within Constructs, set this flag to true.





RegisteredProperty.validationList
[type: [any]] [default: undefined] 
If this property is of type 'number' or 'string', then an Array of the given type can be provided so that the values appear in a drop-down list in the inspector, thus ensuring that only the given values are available to be selected within the GUI.





RegisteredProperty.validationCallbackOwner
[type: object] [default: undefined] 
If this property is of type 'number' or 'string', and a validation list has not been provided, then a function callback can be provided for a method which accepts the property value and returns a sanitized version of the value. This property is the owner of that callback.





RegisteredProperty.validationCallbackName
[type: string] [default: undefined] 
If this property is of type 'number' or 'string', and a validation list has not been provided, then a function callback can be provided for a method which accepts the property value and returns a sanitized version of the value. This property is the name of that callback.





RegisteredProperty.validationCallbackArgs
[type: string] [default: undefined] 
If this property is of type 'number' or 'string', and a validation list has not been provided, then a function callback can be provided for a method which accepts the property value and returns a sanitized version of the value. This property represents the parameters for that callback.





RegisteredProperty.dragMultiplier
[type: number] [default: 1] 
If this property is of type 'number', then this number can control how sensative the property's supervisor is with regards to the cursor-drag interactivity.





RegisteredProperty.displayInGui
[type: boolean] [default: true] 
Flag determining if this RegisteredProperty will appear as a Supervisor in the GUI.





RegisteredProperty.description
[type: string] [default: undefined] 
An optional description of this registered property, used as a tooltip in the inspector GUI.










----------------------------------------------------------
Section 136: CustomAddOnBase
----------------------------------------------------------


CustomAddOnBase
[type: class] [NON-INSTANTIABLE] 
CustomAddOns are objects containing modular user-defined functionality that can be added to different types of SceneObjects in the GUI. The type of the particular CustomAddOn determines what type of SceneObject it can be added to. For example, a CustomAddOn_SceneObject can be added to all objects that inherit from SceneObject, while a CustomAddOn_Button can only be added to objects that inherit from Button. To add a CustomAddOn in code, simply create a new instance of the CustomAddOn, passing the owning object as the parameter. To make a CustomAddOn available in the Incisor inspector build a class that extends one of the CustomAddOn types within a 'codeAsset' file, then call 'nc.registerCustomAddOn' in a 'runBeforeInit' block to register the new CustomAddOn type with the GUI. Once a CustomAddOn is added to another object, it can be found in that object's 'customAddOns' member, which is a dictionary of CustomAddOns. 





CustomAddOnBase.type
[type: string] 
Type identifier.





CustomAddOnBase.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





CustomAddOnBase.name
[type: string] 
The name of the CustomAddOn - this will automatically be set to match the name of the class definition.





CustomAddOnBase.addDisposalCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback for when this CustomAddOn is disposed. It should be noted that this CustomAddOn will be automatically disposed if the owning object is disposed.

CustomAddOnBase.addDisposalCallback parameter: callbackOwner
[type: object] 
The object owning the callback that occurs when this CustomAddOn is disposed.

CustomAddOnBase.addDisposalCallback parameter: callbackName
[type: string] 
The name of the callback that occurs when this CustomAddOn is disposed.

CustomAddOnBase.addDisposalCallback parameter: callbackArgs
[type: Array, any] [optional] 
Parameters for this callback.





CustomAddOnBase.removeDisposalCallback(callbackOwner, callbackName)
[type: function] 
Removes a callback for when this CustomAddOn is disposed.

CustomAddOnBase.removeDisposalCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

CustomAddOnBase.removeDisposalCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





CustomAddOnBase.dispose()
[type: function] 
Removes this CustomAddOn from its owner and performs any registered disposal callbacks. It should be noted that this CustomAddOn will be automatically disposed if the owning object is disposed.










----------------------------------------------------------
Section 137: CustomAddOn_SceneObject
----------------------------------------------------------


CustomAddOn_SceneObject
[type: class] [extends: CustomAddOnBase] [NON-INSTANTIABLE] 
CustomAddOns are objects containing modular user-defined functionality that can be added to different types of SceneObjects in the GUI. The type of the particular CustomAddOn determines what type of SceneObject it can be added to. For example, a CustomAddOn_SceneObject can be added to all objects that inherit from SceneObject, while a CustomAddOn_Button can only be added to objects that inherit from Button. To add a CustomAddOn in code, simply create a new instance of the CustomAddOn, passing the owning object as the parameter. To make a CustomAddOn available in the Incisor inspector build a class that extends one of the CustomAddOn types within a 'codeAsset' file, then call 'nc.registerCustomAddOn' in a 'runBeforeInit' block to register the new CustomAddOn type with the GUI. Once a CustomAddOn is added to another object, it can be found in that object's 'customAddOns' member, which is a dictionary of CustomAddOns. 





CustomAddOn_SceneObject.owner
[type: SceneObject] 
The owner of this CustomAddOn. This is the object that this CustomAddOn is meant to add its functionality to.








































----------------------------------------------------------
Section 138: CustomAddOn_GraphicObject
----------------------------------------------------------


CustomAddOn_GraphicObject
[type: class] [extends: CustomAddOnBase] [NON-INSTANTIABLE] 
CustomAddOns are objects containing modular user-defined functionality that can be added to different types of SceneObjects in the GUI. The type of the particular CustomAddOn determines what type of SceneObject it can be added to. For example, a CustomAddOn_SceneObject can be added to all objects that inherit from SceneObject, while a CustomAddOn_Button can only be added to objects that inherit from Button. To add a CustomAddOn in code, simply create a new instance of the CustomAddOn, passing the owning object as the parameter. To make a CustomAddOn available in the Incisor inspector build a class that extends one of the CustomAddOn types within a 'codeAsset' file, then call 'nc.registerCustomAddOn' in a 'runBeforeInit' block to register the new CustomAddOn type with the GUI. Once a CustomAddOn is added to another object, it can be found in that object's 'customAddOns' member, which is a dictionary of CustomAddOns. 





CustomAddOn_GraphicObject.owner
[type: GraphicObject] 
The owner of this CustomAddOn. This is the object that this CustomAddOn is meant to add its functionality to.








































----------------------------------------------------------
Section 139: CustomAddOn_Button
----------------------------------------------------------


CustomAddOn_Button
[type: class] [extends: CustomAddOnBase] [NON-INSTANTIABLE] 
CustomAddOns are objects containing modular user-defined functionality that can be added to different types of SceneObjects in the GUI. The type of the particular CustomAddOn determines what type of SceneObject it can be added to. For example, a CustomAddOn_SceneObject can be added to all objects that inherit from SceneObject, while a CustomAddOn_Button can only be added to objects that inherit from Button. To add a CustomAddOn in code, simply create a new instance of the CustomAddOn, passing the owning object as the parameter. To make a CustomAddOn available in the Incisor inspector build a class that extends one of the CustomAddOn types within a 'codeAsset' file, then call 'nc.registerCustomAddOn' in a 'runBeforeInit' block to register the new CustomAddOn type with the GUI. Once a CustomAddOn is added to another object, it can be found in that object's 'customAddOns' member, which is a dictionary of CustomAddOns. 





CustomAddOn_Button.owner
[type: Button] 
The owner of this CustomAddOn. This is the object that this CustomAddOn is meant to add its functionality to.








































----------------------------------------------------------
Section 140: CustomAddOn_TextBox
----------------------------------------------------------


CustomAddOn_TextBox
[type: class] [extends: CustomAddOnBase] [NON-INSTANTIABLE] 
CustomAddOns are objects containing modular user-defined functionality that can be added to different types of SceneObjects in the GUI. The type of the particular CustomAddOn determines what type of SceneObject it can be added to. For example, a CustomAddOn_SceneObject can be added to all objects that inherit from SceneObject, while a CustomAddOn_Button can only be added to objects that inherit from Button. To add a CustomAddOn in code, simply create a new instance of the CustomAddOn, passing the owning object as the parameter. To make a CustomAddOn available in the Incisor inspector build a class that extends one of the CustomAddOn types within a 'codeAsset' file, then call 'nc.registerCustomAddOn' in a 'runBeforeInit' block to register the new CustomAddOn type with the GUI. Once a CustomAddOn is added to another object, it can be found in that object's 'customAddOns' member, which is a dictionary of CustomAddOns. 





CustomAddOn_TextBox.owner
[type: TextBox] 
The owner of this CustomAddOn. This is the object that this CustomAddOn is meant to add its functionality to.








































----------------------------------------------------------
Section 141: CustomAddOn_TextAssembly
----------------------------------------------------------


CustomAddOn_TextAssembly
[type: class] [extends: CustomAddOnBase] [NON-INSTANTIABLE] 
CustomAddOns are objects containing modular user-defined functionality that can be added to different types of SceneObjects in the GUI. The type of the particular CustomAddOn determines what type of SceneObject it can be added to. For example, a CustomAddOn_SceneObject can be added to all objects that inherit from SceneObject, while a CustomAddOn_Button can only be added to objects that inherit from Button. To add a CustomAddOn in code, simply create a new instance of the CustomAddOn, passing the owning object as the parameter. To make a CustomAddOn available in the Incisor inspector build a class that extends one of the CustomAddOn types within a 'codeAsset' file, then call 'nc.registerCustomAddOn' in a 'runBeforeInit' block to register the new CustomAddOn type with the GUI. Once a CustomAddOn is added to another object, it can be found in that object's 'customAddOns' member, which is a dictionary of CustomAddOns. 





CustomAddOn_TextAssembly.owner
[type: TextAssembly] 
The owner of this CustomAddOn. This is the object that this CustomAddOn is meant to add its functionality to.








































----------------------------------------------------------
Section 142: CustomAddOn_ParticleSystem
----------------------------------------------------------


CustomAddOn_ParticleSystem
[type: class] [extends: CustomAddOnBase] [NON-INSTANTIABLE] 
CustomAddOns are objects containing modular user-defined functionality that can be added to different types of SceneObjects in the GUI. The type of the particular CustomAddOn determines what type of SceneObject it can be added to. For example, a CustomAddOn_SceneObject can be added to all objects that inherit from SceneObject, while a CustomAddOn_Button can only be added to objects that inherit from Button. To add a CustomAddOn in code, simply create a new instance of the CustomAddOn, passing the owning object as the parameter. To make a CustomAddOn available in the Incisor inspector build a class that extends one of the CustomAddOn types within a 'codeAsset' file, then call 'nc.registerCustomAddOn' in a 'runBeforeInit' block to register the new CustomAddOn type with the GUI. Once a CustomAddOn is added to another object, it can be found in that object's 'customAddOns' member, which is a dictionary of CustomAddOns. 





CustomAddOn_ParticleSystem.owner
[type: ParticleSystem] 
The owner of this CustomAddOn. This is the object that this CustomAddOn is meant to add its functionality to.








































----------------------------------------------------------
Section 143: CustomAddOn_Construct
----------------------------------------------------------


CustomAddOn_Construct
[type: class] [extends: CustomAddOnBase] [NON-INSTANTIABLE] 
CustomAddOns are objects containing modular user-defined functionality that can be added to different types of SceneObjects in the GUI. The type of the particular CustomAddOn determines what type of SceneObject it can be added to. For example, a CustomAddOn_SceneObject can be added to all objects that inherit from SceneObject, while a CustomAddOn_Button can only be added to objects that inherit from Button. To add a CustomAddOn in code, simply create a new instance of the CustomAddOn, passing the owning object as the parameter. To make a CustomAddOn available in the Incisor inspector build a class that extends one of the CustomAddOn types within a 'codeAsset' file, then call 'nc.registerCustomAddOn' in a 'runBeforeInit' block to register the new CustomAddOn type with the GUI. Once a CustomAddOn is added to another object, it can be found in that object's 'customAddOns' member, which is a dictionary of CustomAddOns. 





CustomAddOn_Construct.owner
[type: Construct] 
The owner of this CustomAddOn. This is the object that this CustomAddOn is meant to add its functionality to.








































----------------------------------------------------------
Section 144: RenderTarget
----------------------------------------------------------


RenderTarget
[type: class] 
RenderTargets are objects that contain Textures to render to, as well as settings for how those textures may be resized automatically based on environmental factors such as canvas size, canvas aspect ratio, and the current asset package scale.





RenderTarget.type
[type: string] 
Type identifier.





RenderTarget.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





RenderTarget.name
[type: string] 
The name of the RenderTarget. This name must be unique.





RenderTarget.coreWidth
[type: number] [default: 500] 
The base width value of this RenderTarget. To get the final horizontal render resolution of this RenderTarget's Texture, start with this value, then apply all of the enabled automatic adjustments (such as canvasAspectMatching and assetPackageScaleResolutionScaling).





RenderTarget.coreHeight
[type: number] [default: 500] 
The base height value of this RenderTarget. To get the final vertical render resolution of this RenderTarget's Texture, start with this value, then apply all of the enabled automatic adjustments (such as canvasAspectMatching and assetPackageScaleResolutionScaling).





RenderTarget.canvasAspectMatching
[type: boolean] [default: false] 
Flag determining whether or not this RenderTarget automatically matches the aspect ratio of the canvas.





RenderTarget.canvasSizeResolutionScaling
[type: boolean] [default: false] 
Flag determining whether or not this RenderTarget automatically scales its resolution based on the size of the canvas.





RenderTarget.capCanvasSizeResolutionScaling
[type: boolean] [default: false] 
Flag determining whether or not the canvasSizeResolutionScaling factor for this RenderTarget is capped to 1. This only applies if canvasSizeResolutionScaling is true.





RenderTarget.assetPackageScaleResolutionScaling
[type: boolean] [default: false] 
Flag determining whether or not this RenderTarget automatically scales its resolution based on the current assetPackageScale. The current assetPackageScale can be found at nc.projectConfiguration.assetConfiguration.assetPackageScale.





RenderTarget.auxiliaryResolutionScaleFactor
[type: number] [default: 1] 
Additional factor that multiplies this RenderTarget's resolution scale.





RenderTarget.globalRenderTargetResolutionScaling
[type: boolean] [default: true] 
Flag determining whether or not this RenderTarget automatically scales its resolution based on the current nc.globalRenderTargetResolutionScaler value.





RenderTarget.resizeLazyUpdater
[type: LazyUpdater] 
The LazyUpdater in charge of updating the size of this RenderTarget's Texture. The 'updateIfNeeded' call for this LazyUpdater is called whenever this RenderTarget is rendered to, but you can call it directly if you need to ensure that changes to the RenderTarget size are applied immediately for any reason.





RenderTarget.texture
[type: Texture] 
The Texture associated with this RenderTarget.





RenderTarget.renderResolutionLedger
[type: object] [requires: unpublished only] 
Aan object containing a complete record of all of the factors that contribute to the final render resolution of this RenderTarget.





RenderTarget.getCurrentRenderResolution()
[type: function] 
Returns a vector containing the current render resolution for this RenderTarget.





RenderTarget.dispose()
[type: function] 
Removes internal Incisor® references to this RenderTargert.










----------------------------------------------------------
Section 145: ApplicationSettings
----------------------------------------------------------


ApplicationSettings
[type: class] [NON-INSTANTIABLE] 
Represents the persistent application-wide settings stored in Incisor's "ApplicationSettings.json" file. Unlike most documented Incisor® classes, this is not a standard runtime object that you instantiate or access directly from normal project code. This reference class exists for documentation consistency and describes the JSON object edited through the "Application Settings..." popup in the Incisor menu. These settings are stored in the Incisor Application Support directory and persist regardless of whether a project is open, and regardless of which project is currently open. 





ApplicationSettings.docFormatVersion
[type: number] 
Numeric version of the serialized ApplicationSettings document format.





ApplicationSettings.incisorVersion
[type: string] 
Version string for the Incisor® application that last wrote this settings object.





ApplicationSettings.language
[type: string] 
Language code used by the Incisor® application.





ApplicationSettings.logs
[type: dictionary] 
Settings for how Incisor® log files are written. Incisor® log files are written to the Application Support directory.


ApplicationSettings.logs.verbosity
[type: string] [default: "high"] 
The amount of information included in the logs.

example:
// Example values:
// "high"
// "full"


ApplicationSettings.logs.entryCharLimit
[type: number] [default: 500] 
When logging verbosity is set to anything but "full", each log entry is limited to this number of characters.





ApplicationSettings.maxUndoStates
[type: number] [default: 500] 
The maximum number of Undo/Redo steps stored in Incisor® memory during runtime.





ApplicationSettings.runHiddenTabsUnthrottled
[type: boolean] [default: false] 
When true, projects in tabs that are not showing keep running at full speed. When false, hidden tabs are throttled.





ApplicationSettings.connectionPorts
[type: [number]] 
A list of ports that Incisor® can use when hosting projects locally. Incisor® does its best to determine when ports are in use by other processes, but in some cases different ports must be used.





ApplicationSettings.colorTheme
[type: string] [default: "Default"] 
The name of the currently selected built-in or custom color theme.





ApplicationSettings.inspectorLayoutPresets
[type: [object]] [default: []] 
Saved inspector layout preset data. This field stores persistent layout preset objects for the Incisor® inspector. User-defined presets can be defined from within the 'View' menu.





ApplicationSettings.customColorThemes
[type: [ApplicationColorTheme]] 
User-defined custom color themes available in the Application Settings popup.





ApplicationSettings.maxThreads
[type: number] [default: 8] 
The maximum number of threads Incisor® can use in its operations.





ApplicationSettings.refreshOnCodeChange
[type: boolean] [default: true] 
Setting determining if changing code on disk causes the current project to automatically refresh.





ApplicationSettings.runProjectOnOpen
[type: boolean] [default: false] 
When true, a project's code runs as soon as the project opens. When false, the project opens stopped, with its code switched off, until the Run button in the Live View is pressed.





ApplicationSettings.stopProjectOnException
[type: boolean] [default: true] 
When true, an exception thrown by project code stops the project, reloading it with its code switched off so that the inspector stays usable. When false, the project keeps running after an exception.





ApplicationSettings.security
[type: dictionary] 
Security-related application settings and options associated with risk.


ApplicationSettings.security.allowUniversalFileIO
[type: boolean] [default: false] 
Setting determining if Incisor® is allowed universal FileIO from within projects. Be advised that, when true, project and extension code can affect any file on your computer. Note that this governs fileIO while developing in Incisor® - published Electron builds have their own separate "allowUniversalFileIO" option on the Electron auxiliaryPublishingPackage.


ApplicationSettings.security.allowExternalExecutableProcesses
[type: boolean] [default: false] 
Setting determining if Incisor® is allowed to run external executable processes on behalf of extension code. Be advised that, when true, extension code can be used to run virtually any command on your system.


ApplicationSettings.security.allowEditorDebugging
[type: boolean] [default: false] 
Setting determining if Incisor® opens a debugging port that code editors such as Visual Studio Code can attach to. Takes effect the next time Incisor® starts. Be advised that, when true, any program on your computer can connect to the port and run code inside your projects.


ApplicationSettings.security.editorDebuggingPort
[type: number] [default: 9222] 
The port Incisor® opens for code editors to attach to when allowEditorDebugging is true. Change it if another program on your computer already uses the default port. Takes effect the next time Incisor® starts.


ApplicationSettings.security.enableCLI
[type: boolean] [default: false] 
Setting determining if Incisor® accepts commands from the command line, such as publishing a project or taking a screenshot of an open project tab. Be advised that, when true, any program on your computer can issue these commands, and a script can do anything the open project can do.


ApplicationSettings.security.allowRemoteHosting
[type: boolean] [default: false] 
Setting determining if Incisor® is allowed to host files remotely. This is primarily used to host published projects for testing on external devices. Be advised that remote hosting may expose your system to significant risk of unauthorized access.





ApplicationSettings.clearConsoleOnProjectRefresh
[type: boolean] [default: true] 
Setting determining if refreshing the project clears the browser console.





ApplicationSettings.showToolTips
[type: boolean] [default: true] 
Setting determining if tool tips are shown when hovering over controls.





ApplicationSettings.toolTipDisplayDelay
[type: number] [default: 1.5] 
The number of seconds the cursor must hover over a control before a tool tip appears.





ApplicationSettings.testString
[type: string] [default: ""] 
Generic string field currently present in the default ApplicationSettings.json template. This field may be used for testing or other internal application purposes depending on the Incisor® version.










----------------------------------------------------------
Section 146: ApplicationColorTheme
----------------------------------------------------------


ApplicationColorTheme
[type: class] [NON-INSTANTIABLE] 
A user-defined custom color theme available within Incisor® Application Settings. 





ApplicationColorTheme.name
[type: string] 
The display name of this custom color theme.

example:
// Examples from the default template:
// "Classic Incisor Red"
// "Reverse Haircut"
// "Globo Gym"





ApplicationColorTheme.colors
[type: dictionary] 
The collection of UI color slots that define this custom theme. Each color value is stored as a serialized object with normalized "red", "green", and "blue" members in the range of 0 to 1.


ApplicationColorTheme.colors.color_appHeader
[type: object] 
Color used for the app header region.


ApplicationColorTheme.colors.color_headerTitle
[type: object] 
Color used for the header title text.


ApplicationColorTheme.colors.color_mainText
[type: object] 
Main text color used throughout the UI.


ApplicationColorTheme.colors.color_inactiveText
[type: object] 
Color used for inactive text.


ApplicationColorTheme.colors.color_interactiveText
[type: object] 
Color used for interactive text.


ApplicationColorTheme.colors.color_semiInteractiveText
[type: object] 
Color used for semi-interactive text.


ApplicationColorTheme.colors.color_editorBackgroundDark
[type: object] 
Dark editor background color.


ApplicationColorTheme.colors.color_editorBackgroundLight
[type: object] 
Light editor background color.


ApplicationColorTheme.colors.color_highlightedInteractiveText
[type: object] 
Highlighted interactive text color.


ApplicationColorTheme.colors.color_mainPanelBackground
[type: object] 
Main panel background color.


ApplicationColorTheme.colors.color_lightPanelBackground
[type: object] 
Light panel background color.


ApplicationColorTheme.colors.color_darkPanelBackground
[type: object] 
Dark panel background color.


ApplicationColorTheme.colors.color_dimmerBackground
[type: object] 
Dimmer background color.


ApplicationColorTheme.colors.color_panelHeader
[type: object] 
Panel header color.


ApplicationColorTheme.colors.color_panelBorder
[type: object] 
Panel border color.


ApplicationColorTheme.colors.color_panelHeaderHighlight
[type: object] 
Panel header highlight color.


ApplicationColorTheme.colors.color_buttonPanel
[type: object] 
Button panel color.


ApplicationColorTheme.colors.color_highlightedButtonPanel
[type: object] 
Highlighted button panel color.


ApplicationColorTheme.colors.color_builtInHeaderMenu
[type: object] 
Built-in header menu color.


ApplicationColorTheme.colors.color_popupWindowHeader
[type: object] 
Popup window header color.


ApplicationColorTheme.colors.color_brightHighlightedButtonPanel
[type: object] 
Bright highlighted button panel color.


ApplicationColorTheme.colors.color_navigationOutline
[type: object] 
Navigation outline color.


ApplicationColorTheme.colors.color_selection
[type: object] 
Selection color.


ApplicationColorTheme.colors.color_selectionOutlineBase
[type: object] 
Base color used for selection outlines.










----------------------------------------------------------
Section 147: LayoutStack
----------------------------------------------------------


LayoutStack
[type: class] [extends: SceneObject] 
Specialized SceneObject that organizes visual content (TextBoxes, Graphics, Buttons, etc...) into dynamic vertical or horizontal stacks. LayoutStacks automatically adjust their layout based on their elements. For example if a TextBox element gets larger, the other elements are shifted so that the TextBox doesn't overlap its neighboring elements. LayoutStacks manage this choreography using the "LayoutObject" member of each of its elements, which can be configured by calling SceneObject.configureLayoutObject. LayoutStacks are also automatically configured as LayoutObjects, so they can also be added to LayoutStacks for nesting.





LayoutStack.isVertical
[type: boolean] [default: true] 
Flag that determines if this LayoutStack is a vertical stack organized from top to bottom or a horizontal stack organzied from left to right.





LayoutStack.pivotPoint
[type: Vector2] [default: new Vector2(-.5,.5)] 
The pivot point for the LayoutStack, with [0,0] meaning center pivot, and [.5,.5] meaning right-top pivot. LayoutStacks are center-based by default like to most GraphicObjects. It should be noted that pivotPoint and justification seperate concepts and do not affect eachother. Justification affects the alignment of the content within the bounds of the LayoutStack, and pivotPoint affects where the 'origin' of the LayoutStack is relative to those bounds.





LayoutStack.elementSpacer
[type: number] [default: 0] 
Number corresponding to the amount of space between each element in the LayoutStack. For LayoutStacks with standardUiZoomFunctionality enabled, this these spaces will be scaled by nc.uiZoom.totalZoom.





LayoutStack.minWidth
[type: number] [default: 0] 
Optional minimum width for this LayoutStack.





LayoutStack.minHeight
[type: number] [default: 0] 
Optional minimum height for this LayoutStack.





LayoutStack.displayBorder
[type: boolean] [default: false] 
Boolean determining if a border (consisting of a UiOutline) is displayed. The border automatically changes shape based on the layoutObject.width and layoutObject.height properties. It should be noted that the associated LayoutStack.border member will be undefined until this flag is set to true.





LayoutStack.border
[type: UiOutline] [default: undefined] 
UiOutline that (when displayed) automatically adjusts to the layoutObject.width and layoutObject.height properties of this LayoutStack. It should be noted that this property is undefined unless LayoutStack.displayBorder is set to true.





LayoutStack.displayBackgroundPanel
[type: boolean] [default: false] 
Boolean determining if a background panel (consisting of a UiPanel) is displayed. The panel automatically changes shape based on the layoutObject.width and layoutObject.height properties. It should be noted that the associated LayoutStack.backgroundPanel member will be undefined until this flag is set to true.





LayoutStack.backgroundPanel
[type: UiPanel] [default: undefined] 
UiPanel that (when displayed) automatically adjusts to the layoutObject.width and layoutObject.height properties of this LayoutStack. It should be noted that this property is undefined unless LayoutStack.displayBackgroundPanel is set to true.





LayoutStack.backgroundPanelExpansion
[type: number] [default: 0] 
An offset applied to the size of the backgroundPanel in all directions, expanding or contracting it relative to the LayoutStack's content bounds. The value is pre-uiZoom and will be scaled by nc.uiZoom.totalZoom before being applied. A positive value expands the panel beyond the content bounds; a negative value contracts it. Has no effect unless displayBackgroundPanel is true.





LayoutStack.borderExpansion
[type: number] [default: 0] 
An offset applied to the size of the border in all directions, expanding or contracting it relative to the LayoutStack's content bounds. The value is pre-uiZoom and will be scaled by nc.uiZoom.totalZoom before being applied. A positive value expands the border beyond the content bounds; a negative value contracts it. Has no effect unless displayBorder is true.





LayoutStack.addElements(elements, index)
[type: function] 
Adds the specified SceneObject(s) as elements to the LayoutStack. Please note that SceneObjects added to LayoutStacks are re-assigned to be children of that LayoutStack. If an added SceneObject has not yet been configured with LayoutObject functionality, the standard LayoutObject configuration will be applied. The LayoutObject configuration of any SceneObject can be customized by calling 'SceneObject.configureLayoutObject' before adding it to a LayoutStack. The LayoutObject configuration is a means by which a LayoutStack can determine the layout dimensions of its elements, inform the elements to refresh their layouts, and be informed by elements to update its layout due to a change in dimensions of the elements.

LayoutStack.addElements parameter: elements
[type: SceneObject, [SceneObject]] 
The SceneObject(s) to add as elements to the LayoutStack.

LayoutStack.addElements parameter: index
[type: number] [default: (pushed to end)] [optional] 
Optional index enabling inserting elements in locations other than at the end of the elements list.





LayoutStack.addSpacerElement(spacerWidth, spacerHeight, index)
[type: function] [returns: object] 
Adds a blank element as a spacer between other elements. For LayoutStacks with standardUiZoomFunctionality enabled, this these spacers will be scaled by nc.uiZoom.totalZoom. Returns a spacer object.

LayoutStack.addSpacerElement parameter: spacerWidth
[type: number] 
The width (in world units) of the spacer to add.

LayoutStack.addSpacerElement parameter: spacerHeight
[type: number] 
The height (in world units) of the spacer to add.

LayoutStack.addSpacerElement parameter: index
[type: number] [default: (pushed to end)] [optional] 
Optional index enabling inserting spacers in locations other than at the end of the elements list.





LayoutStack.removeElementAt(index, dispose)
[type: function] 
Removes the element at the given index.

LayoutStack.removeElementAt parameter: index
[type: number] 
The index of the element to remove.

LayoutStack.removeElementAt parameter: dispose
[type: boolean] [default: true] [optional] 
Boolean determining of the item is disposed.





LayoutStack.getElements()
[type: function] [returns: [SceneObject]] 
Returns a shallow copy of the current array of elements.





LayoutStack.removeElement(element, dispose)
[type: function] 
Removes the given element from the LayoutStack.

LayoutStack.removeElement parameter: element
[type: object] 
The element to remove.

LayoutStack.removeElement parameter: dispose
[type: boolean] [default: true] [optional] 
Boolean determining if the item is disposed.





LayoutStack.clear(dispose)
[type: function] 
Clears all of the elements from the LayoutStack

LayoutStack.clear parameter: dispose
[type: boolean] [default: true] [optional] 
Boolean determining if cleared elements are also disposed.





LayoutStack.justifyAll(justification)
[type: function] 
Applies the given justification to all of the LayoutStack's elements. Calling this method also sets an internal default, so that when new SceneObjects that have never been configured as LayoutObjects are added as elements, the given justification will be applied.

LayoutStack.justifyAll parameter: justification
[type: string] 
The justification to apply to all of the LayoutStack's elements. For a list of justifications see 'nc.constants.justifications'.



























































































































































































































































































































----------------------------------------------------------
Section 148: UxStringSupervisorMenu
----------------------------------------------------------


UxStringSupervisorMenu
[type: class] [extends: UiDropDownMenu] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. Supervisors provide the means for users to both monitor and manipulate properties within the project during runtime. This particular object is meant to supervise a string property, with the user able to adjust the value by choosing from a selection of values within this UiDropDownMenu. When multiple diverging values are supervised, a '-' is shown. 'Ux' supervisors operate exclusively on arrays of values, ensuring support for supervising multiple values at once. 





UxStringSupervisorMenu.propertyOwners
[type: Array] [default: undefined] 
Array of objects owning the properties being supervised. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorMenu.propertyPath
[type: string] [default: ""] 
A period-separated string representing the 'dot path' or 'dereference chain' from each owner object to the property being supervised. For example if you are supervising the fontName of the TextFormat on a TextBox this value would be 'textFormat.fontName'. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorMenu.propertyGetterOwner
[type: object] [default: undefined] 
The object owning the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorMenu.propertyGetterName
[type: string] [default: undefined] 
The name of the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorMenu.propertyGetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to get the array of supervised values. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorMenu.propertySetterOwner
[type: object] [default: undefined] 
The object owning the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorMenu.propertySetterName
[type: string] [default: undefined] 
The name of the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorMenu.propertySetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to set the array of supervised values. The function will be sent an array of values as it's first parameter, these parameters will be appended. 'Ux' supervisors can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string,  or by using a propertyGetter function and propertySetter function. To use a particular method, leave the members associated with the other method undefined. Both methods always operate on Arrays, ensuring support for supervising multiple values.





UxStringSupervisorMenu.valueValidationOwner
[type: object] [default: undefined] 
The owner of the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to alter the strings selected via the drow down based on some circumstance, you can write a validation function that takes a value as a parameter and returns the adjusted value.





UxStringSupervisorMenu.valueValidationName
[type: string] [default: undefined] 
The name of the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the format of strings entered into the supervisor textField, you can write a validation function that takes a value as a parameter and returns the adjusted value.





UxStringSupervisorMenu.valueValidationArgs
[type: Array, any] [default: undefined] 
Parameters for the function (optional) that will be used to validate/adjust values before they are set by this supervisor. For example if you want to restrict the format of strings entered into the supervisor textField, you can write a validation function that takes a value as a parameter and returns the adjusted value.





UxStringSupervisorMenu.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body.clone()] 
the TextFormat of all of the text items within the supervisor, which is also used to scale graphical components.





UxStringSupervisorMenu.dashWidth
[type: number] [default: 65] 
The boxWidth applied to mainText when the supervisor is displaying '-' (no supervised value or diverging values). Set to 0 automatically when a real value is displayed. Prevents the control from appearing too narrow.





UxStringSupervisorMenu.overrideWidth
[type: number] [default: undefined] 
When defined, overrides the boxWidth applied to mainText when a real (non-dash) value is displayed. By default the boxWidth is set to 0 when a value is shown, allowing the text to size naturally. Set overrideWidth to a fixed pixel value when you need the control to maintain a consistent width regardless of value content.





UxStringSupervisorMenu.sync()
[type: function] 
Method brings this UxStringSupervisorMenu up to date with the values it supervises, without waiting for the next fixedUpdate. This method is automatically called every fixedUpdate.












































































































































































































































































































































































































































































----------------------------------------------------------
Section 149: UiStringSupervisor_textField
----------------------------------------------------------


UiStringSupervisor_textField
[type: class] [extends: UiTextField] [requires: module - extendedUi] 
A specialized UiTextField that includes a Superivor member, enabling it to monitor and adjust a string property's value during runtime. To use this class, configure the 'supervisedPropertyGetter' and 'supervisedPropertySetter' callbacks on the Supervisor. Once configured, the 'mainText' TextBox will be updated every fixed update to reflect the most current value of the supervised property, and the value of the supervised property will also be 'adjustable' via direct editing of the 'mainText' TextBox.





UiStringSupervisor_textField.supervisor
[type: Supervisor] 
Supervisor with callbacks that enable this UiStringSupervisor_textField to monitor and adjust a string property's value during runtime.

















































































































































































































































































































































































































































































----------------------------------------------------------
Section 150: UiNumberSupervisor_textField
----------------------------------------------------------


UiNumberSupervisor_textField
[type: class] [extends: UiButton] [requires: module - extendedUi] 
A specialized UiTextField that includes a Supervisor member, enabling it to monitor and adjust a number property's value during runtime. To use this class, configure the 'supervisedPropertyGetter' and 'supervisedPropertySetter' callbacks on the Supervisor. Once configured, the 'mainText' TextBox will be updated every fixed update to reflect the most current value of the supervised property, and the value of the supervised property will also be 'adjustable' via keyboard and cursor interaction.





UiNumberSupervisor_textField.supervisor
[type: Supervisor] 
Supervisor with callbacks that enable this UiNumberSupervisor_textField to monitor and adjust a number property's value during runtime.





UiNumberSupervisor_textField.dragMultiplier
[type: number] [default: 1] 
Number that multiplies the affect of dragging with this UiNumberSupervisor_textField. For reference, a value of 1 is fitting for a numeric property whose range is roughly 500;





UiNumberSupervisor_textField.sliderArrowsIcon
[type: GraphicObject] 
GraphicObject on the leftmost side of this UiNumberSupervisor_textField indicating that it can be dragged and scrolled.





UiNumberSupervisor_textField.sliderArrowsIconScaleFactor
[type: number] 
Number multiplying the scale of the 'sliderArrowsIcon' GraphicObject. Use this property instead of directly scaling the sliderArrowsIcon GraphicObject to preserve UiZoom and LayoutObject functionality.





UiNumberSupervisor_textField.displayPrecision
[type: number] [default: 3] 
The number of digits shown to the right of the decimal within the UiTextField for this UiNumberSupervisor_textField.







































































































































































































































































































































































































































































----------------------------------------------------------
Section 151: LazyUpdater
----------------------------------------------------------


LazyUpdater
[type: class] 
Object that manages the calling of a given callback, ensuring that it is only called when necessary. This is often used to ensure that calls to methods that are performance-expensive are as limited as possible. First connect the performance-heavy task via the constructor callback parameters, then later call the 'updateIfNeeded' method; if the 'needsUpdate' flag has been set to true since the last 'updateIfNeeded' call, then callback will occur, otherwise it is skipped. An example of how you can use this is in situation where you are doing manual rendering; you only want to render once per ScreenUpdate, and you don't want to render if nothing substantive has changed in the scene. In this case, you would set the 'needsUpdate' flag to true every time something in the scene is adjusted, and ensure that a call to 'updateIfNeeded' is placed in a ScreenUpdater-driven function.





LazyUpdater.type
[type: string] 
Type identifier.





LazyUpdater.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





LazyUpdater.needsUpdate
[type: boolean] [default: false] 
Flag indicating whether the target method is in need of an update.





LazyUpdater.updateIfNeeded()
[type: function] 
Calls the target method if the 'needsUpdate' flag is true, and sets it to false either way.










----------------------------------------------------------
Section 152: KeyframedValue
----------------------------------------------------------


KeyframedValue
[type: class] 
A KeyframedValue defines a value over time using Keyframes, returning the interpolated (or stepped) value at any requested time via getValue. It is owner-agnostic — it holds no reference to any object or property; it simply maps a time to a value. (AnimatedProperty extends KeyframedValue to bind it to a property within a Timeline.)





KeyframedValue.type
[type: string] 
Type identifier.





KeyframedValue.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





KeyframedValue.valueType
[type: string] 
The kind of value this holds, which determines how it is evaluated. The available values can be found in constants.keyframedValueTypes.





KeyframedValue.interpolation
[type: string] 
The interpolation used between numeric Keyframes. The available values can be found in constants.keyframedValueInterpolationTypes.





KeyframedValue.timeSnap
[type: number] [default: 0.02] 
The grid, in time units, that Keyframe times are snapped onto whenever the Keyframes are rebuilt. This is never undefined; setting it to undefined or a value less than or equal to zero coerces it back to the default. An AnimatedProperty added to a Timeline instead adopts (and is kept in sync with) that Timeline's timeSnap.





KeyframedValue.valueSnap
[type: number] [default: undefined] 
The grid, in value units, that numeric (floatingPoint) Keyframe values (and secondaryValues) are snapped onto whenever the Keyframes are rebuilt. Optional: undefined (or a value less than or equal to zero) turns value snapping off. Only floatingPoint KeyframedValues snap; boolean/string/invoke ignore it. AnimatedProperties created with Timeline.addAnimatedProperty default to 0.01.





KeyframedValue.continueLeft
[type: string] [default: "constant"] 
How this value continues before its first Keyframe. One of constants.continueModes ('constant', 'extrapolate', 'loop', 'pingPong'). 'constant' holds the first Keyframe's value; 'extrapolate' continues the opening tangent linearly (numeric values only); 'loop' and 'pingPong' repeat or bounce the keyframe range. Has no effect while there is only one Keyframe.





KeyframedValue.continueRight
[type: string] [default: "constant"] 
How this value continues after its last Keyframe. One of constants.continueModes ('constant', 'extrapolate', 'loop', 'pingPong'). 'constant' holds the last Keyframe's value; 'extrapolate' continues the closing tangent linearly (numeric values only); 'loop' and 'pingPong' repeat or bounce the keyframe range. Has no effect while there is only one Keyframe.





KeyframedValue.keyframes
[type: [ValueKeyframe]] 
The live array of Keyframes defining this value. Add Keyframes with addKeyframe; the array is kept sorted and de-duplicated internally.





KeyframedValue.playbackDirection
[type: number] [default: 1] 
The direction of travel used when evaluating 'invoke' crossings: +1 for forward, -1 for reverse. Typically set by the driving object (e.g. a Timeline). Not used for value properties.





KeyframedValue.startTime
[type: number] 
The start of the loop range used for 'invoke' rollover handling. Undefined means no looping.





KeyframedValue.endTime
[type: number] 
The end of the loop range used for 'invoke' rollover handling. Undefined means no looping.





KeyframedValue.invocationsIncludePreviousTime
[type: boolean] [default: false] 
A one-time flag for 'invoke' evaluation. When true, the next getValue includes the previous time in its crossing span (so a Keyframe exactly on the current time can fire), then it is automatically reset to false. Typically set true by a driver as it goes from not-playing to playing, so a Keyframe on the start time fires on first play.





KeyframedValue.isDisposed
[type: boolean] [default: undefined] 
Flag indicating if this KeyframedValue has been disposed. If the KeyframedValue has not been disposed, this property will be undefined.





KeyframedValue.addKeyframe(time, value, keyframeType, invocationParameters)
[type: function] [returns: ValueKeyframe] 
Adds a Keyframe to this KeyframedValue.

KeyframedValue.addKeyframe parameter: time
[type: number] 
The time of the Keyframe.

KeyframedValue.addKeyframe parameter: value
[type: number, boolean, string] 
The value at the Keyframe (a number, boolean, or string depending on valueType). Not used for 'invoke' properties.

KeyframedValue.addKeyframe parameter: keyframeType
[type: string] [default: 'standard'] [optional] 
The type of the Keyframe; the available values can be found in constants.keyframeTypes. A 'left' or 'right' Keyframe is a single stepped Keyframe carrying two values: its primary 'value' governs one side and its 'secondaryValue' governs the other (see ValueKeyframe.keyframeType and ValueKeyframe.secondaryValue). No two Keyframes may share a time.

KeyframedValue.addKeyframe parameter: invocationParameters
[type: object] [optional] 
For 'invoke' properties, an arbitrary object carried by the Keyframe and handed back to the caller when the Keyframe is crossed.





KeyframedValue.getValue(time, triggerInvocations)
[type: function] [returns: number, boolean, string, [ValueKeyframe]] 
Returns this KeyframedValue's value at the given time. For numeric, boolean, and string properties this is the interpolated or stepped value. For 'invoke' properties there is no value; instead this returns the array of Keyframes crossed between the previous getValue call and this one (in travel order), or undefined if none were crossed.

KeyframedValue.getValue parameter: time
[type: number] 
The time to evaluate.

KeyframedValue.getValue parameter: triggerInvocations
[type: boolean] [default: true] [optional] 
For 'invoke' properties, whether this call should report crossed Keyframes. When false, the internal previous-time marker still advances but no Keyframes are returned (used, for example, when scrubbing or seeking). Not used for value properties.





KeyframedValue.dispose()
[type: function] 
Disposes of this KeyframedValue.










----------------------------------------------------------
Section 153: ValueKeyframe
----------------------------------------------------------


ValueKeyframe
[type: class] [NON-INSTANTIABLE] 
A ValueKeyframe holds a value (or invocation) at a specific time within a KeyframedValue. Create Keyframes with KeyframedValue.addKeyframe. 





ValueKeyframe.type
[type: string] 
Type identifier.





ValueKeyframe.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





ValueKeyframe.time
[type: number] 
The time of this ValueKeyframe.





ValueKeyframe.value
[type: number, boolean, string] 
The primary value at this ValueKeyframe (a number, boolean, or string depending on the owning KeyframedValue's valueType). Undefined for 'invoke' Keyframes. Sampling the KeyframedValue exactly at this ValueKeyframe's time always returns this value, for every keyframeType.





ValueKeyframe.secondaryValue
[type: number, boolean, string] 
The far-side value of a stepped ValueKeyframe. For a 'left' ValueKeyframe it is the value to the right of the ValueKeyframe's time; for a 'right' ValueKeyframe it is the value to the left. Ignored while keyframeType is 'standard'. Falls back to 'value' until explicitly set (so a fresh step is flat until this is moved). Same type as 'value'.





ValueKeyframe.keyframeType
[type: string] [default: "standard"] 
The type of this ValueKeyframe. The available values can be found in constants.keyframeTypes. 'standard' is a single continuous value. 'left' and 'right' are single stepped Keyframes that carry a discontinuity: 'value' governs the near side (left of a 'left', right of a 'right') and 'secondaryValue' governs the far side. No two Keyframes may share a time.





ValueKeyframe.leftHandleSpan
[type: number] 
The time-axis reach of the left interpolation handle, as a fraction (0-1) of the preceding segment's span. Undefined when there is no left handle.





ValueKeyframe.leftHandleValue
[type: number] 
The value-axis offset of the left interpolation handle, relative to the value this ValueKeyframe presents to its left (its 'value', or its 'secondaryValue' when keyframeType is 'right'). Undefined when there is no left handle.





ValueKeyframe.rightHandleSpan
[type: number] 
The time-axis reach of the right interpolation handle, as a fraction (0-1) of the following segment's span. Undefined when there is no right handle.





ValueKeyframe.rightHandleValue
[type: number] 
The value-axis offset of the right interpolation handle, relative to the value this ValueKeyframe presents to its right (its 'value', or its 'secondaryValue' when keyframeType is 'left'). Undefined when there is no right handle.





ValueKeyframe.invocationParameters
[type: object] 
For 'invoke' Keyframes, an object carried by the ValueKeyframe and used when it is crossed. On a Timeline property that declares invocation parameters - a custom AppEvent's 'trigger', for instance - these are the values that invocation is made with, and any declared parameter left out of the object falls back to its own default. On any other 'invoke' property the object is simply handed back to the caller.





ValueKeyframe.isDisposed
[type: boolean] [default: undefined] 
Flag indicating if this ValueKeyframe has been disposed. If the ValueKeyframe has not been disposed, this property will be undefined.





ValueKeyframe.dispose()
[type: function] 
Disposes of this ValueKeyframe, removing it from its KeyframedValue.










----------------------------------------------------------
Section 154: Code
----------------------------------------------------------


Code
[type: class] [NON-INSTANTIABLE] 
Object housing tools for pre-process manipulation of code such as including files and conditional code. An instance of this object can be refrenced globally by the name of 'CODE'. 





Code.includeIf___published
[type: object] 
Conditional code opener. Use this tag at the beginning of a section of code that will only be included when the project is published.





Code.includeEnd___published
[type: object] 
Conditional code closer. Use this tag at the end of a section of code that will only be included when the project is published.

example:
console.log('this is always happening');
CODE.includeIf___published;
  console.log('this is only happening when the project is published');
CODE.includeEnd___published;





Code.includeIf___unpublished
[type: object] 
Conditional code opener. Use this tag at the beginning of a section of code that will only be included when the project is not published.

example:
console.log('this is always happening');
CODE.includeIf___unpublished;
  console.log('this is only happening when the project is not published');
CODE.includeEnd___unpublished;





Code.includeEnd___unpublished
[type: object] 
Conditional code closer. Use this tag at the end of a section of code that will only be included when the project is not published.

example:
console.log('this is always happening');
CODE.includeIf___unpublished;
  console.log('this is only happening when the project is not published');
CODE.includeEnd___unpublished;





Code.preserve___begin
[type: object] 
Preservation opener. Use this tag at the beginning of a block of code to exempt it from all forms of code formatting including minification, whitespace removal, and comment removal.





Code.preserve___end
[type: object] 
Preservation closer. Use this tag at the end of a block of code to exempt it from all forms of code formatting including minification, whitespace removal, and comment removal.





Code.runBeforeInit___begin
[type: object] 
A code tag that denotes the beginning of a 'runBeforeInit' block. Generally, code written within Incisor® is completely object-oriented, and as such all code execution must originate from within class objects. In other words, if you open up a new javascript file, and type "nc.addGraphicObject();", you would get an error pointing out that 'nc' doesn't exist, since that code is running in a class-declaration scope. To get that code to execute properly, you would either need to included in a class function that is ultimately called as a result of the ProjectMain.init function, OR you can include that code in a 'runBeforeInit' block, which actually moves the code so that it will be executed right before the invocation of ProjectMain.init. It should be noted that 'runBeforeInit' blocks also exist for code assets, as well as Incisor® extensions, and have a similar effect - moving blocks of code to the same scope as the entry-points for those contexts.

example:
CODE.runBeforeInit___begin;
   // since this code is inside of a 'runBeforeInit' block, it will be run right before ProjectMain.init, and all standard classes will have access to the 'whiteBox' var.
   var whiteBox = nc.addGraphicObject();
CODE.runBeforeInit___end;





Code.runBeforeInit___end
[type: object] 
A code tag that denotes the end of a 'runBeforeInit' block. Generally, code written within Incisor® is completely object-oriented, and as such all code execution must originate from within class objects. In other words, if you open up a new javascript file, and type "nc.addGraphicObject();", you would get an error pointing out that 'nc' doesn't exist, since that code is running in a class-declaration scope. To get that code to execute properly, you would either need to included in a class function that is ultimately called as a result of the ProjectMain.init function, OR you can include that code in a 'runBeforeInit' block, which actually moves the code so that it will be executed right before the invocation of ProjectMain.init. It should be noted that 'runBeforeInit' blocks also exist for code assets, as well as Incisor® extensions, and have a similar effect - moving blocks of code to the same scope as the entry-points for those contexts.

example:
CODE.runBeforeInit___begin;
   // since this code is inside of a 'runBeforeInit' block, it will be run right before ProjectMain.init, and all standard classes will have access to the 'whiteBox' var.
   var whiteBox = nc.addGraphicObject();
CODE.runBeforeInit___end;





Code.includeIf___MyConditionalCodeTag
[type: object] 
Conditional code opener. Use this tag at the beginning of a section of code that will only be included when the associated conditional code tag is enabled in the given configuration.

example:
console.log('this is always happening');
this.includeIf___MyConditionalCodeTag;
  console.log('this is only happening when the MyConditionalCodeTag tag is included in the conditionalCodeTagsIncluded array for the current configuration.');
this.includeEnd___MyConditionalCodeTag;





Code.includeEnd___MyConditionalCodeTag
[type: object] 
Conditional code closer. Use this tag at the end of a section of code that will only be included when the associated conditional code tag is enabled in the given configuration.

example:
console.log('this is always happening');
this.includeIf___MyConditionalCodeTag;
  console.log('this is only happening when the MyConditionalCodeTag tag is included in the conditionalCodeTagsIncluded array for the current configuration.');
this.includeEnd___MyConditionalCodeTag;





Code.includeFile()
[type: function] 
Function that inserts Javascript code from another file at the location of the function call.










----------------------------------------------------------
Section 155: Timeline
----------------------------------------------------------


Timeline
[type: class] [extends: TimePlaybackController] [NON-INSTANTIABLE] 
Timelines are specialized PlaybackControllers that control animation of Constructs created in the Incisor® GUI. 





Timeline.type
[type: string] 
Type identifier.





Timeline.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





Timeline.name
[type: string] 
The name of the Timeline.





Timeline.weight
[type: number] 
This value determines the degree to which this particular timeline controls its Construct on a scale of 0 to 1 (the value is clamped to that range). If more than one Timeline has a non-zero weight, then control of the Construct is shared proportionally. If the total blendWeights of all of the Timelines is less than 1 then the NeutralState is given the remaining/complementary weight.





Timeline.influence
[type: number] 
The net contribution of this Timeline to its Construct's animated properties (0–1), derived from the weights of all Timelines. Use this to read back the final blended influence after all weights have been resolved.





Timeline.timeSnap
[type: number] [default: nc.defaultTimelineTimeSnap] 
The keyframe-time snap grid (in time units) for the whole Timeline. Setting it stores the Timeline's own value and pushes it onto every one of its AnimatedProperties' timeSnap, re-quantizing their Keyframes; a newly added AnimatedProperty adopts it too. A brand-new Timeline defaults to nc.defaultTimelineTimeSnap; a Timeline loaded from a Construct saved before this setting existed defaults to 1/60.





Timeline.swoopWeight(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs)
[type: function] [returns: Swooper] 
Swoops (interpolates) the Timeline's weight from its current value to the given end value over the duration. This function has no effect on the weights of other Timelines.

Timeline.swoopWeight parameter: endValue
[type: number] 
The ending value for the weight.

Timeline.swoopWeight parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

Timeline.swoopWeight parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

Timeline.swoopWeight parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

Timeline.swoopWeight parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

Timeline.swoopWeight parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.





Timeline.takeWeight(duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs)
[type: function] [returns: Swooper] 
A 'takeover helper' that swoops (interpolates) the Timeline's weight up to 1 and the other Timelines down to 0 over the duration.

Timeline.takeWeight parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

Timeline.takeWeight parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

Timeline.takeWeight parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

Timeline.takeWeight parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

Timeline.takeWeight parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.





Timeline.playOnceAndTakeWeight(fadeInTime, fadeOutTime, returnToTimeline, lazyStopCallbackOwner, lazyStopCallbackName, lazyStopCallbackArgs)
[type: function] 
Plays this Timeline once, swooping its weight up (and the other weights down) for its duration, and swooping back to restore the weights before the end of the timeline. The 'Ease' TweenType is used for both swoops.

Timeline.playOnceAndTakeWeight parameter: fadeInTime
[type: number] [optional] 
The amount of time to fade in this Timeline's weight. If left undefined, the value will default to either .25 seconds, or 10% of this Timeline's duration (whichever is smaller).

Timeline.playOnceAndTakeWeight parameter: fadeOutTime
[type: number] [optional] 
The amount of time to fade out this Timeline's weight before it ends. If left undefined, the value will default to either .25 seconds, or 10% of this Timeline's duration (whichever is smaller).

Timeline.playOnceAndTakeWeight parameter: returnToTimeline
[type: Timeline] [optional] 
The Timeline that will take full weight after the timeline completes. If this value is left undefined, then the Construct's Timelines will return to the weight configuration they had when this function was originally invoked.

Timeline.playOnceAndTakeWeight parameter: lazyStopCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Timeline is complete.

Timeline.playOnceAndTakeWeight parameter: lazyStopCallbackName
[type: string] [optional] 
The name of the function that is called when the Timeline is complete.

Timeline.playOnceAndTakeWeight parameter: lazyStopCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Timeline is complete.





Timeline.playAndTakeWeight(fadeInTime)
[type: function] 
Invokes 'play' on the Timeline while swooping it's weight up (and the other weights down).

Timeline.playAndTakeWeight parameter: fadeInTime
[type: number] [default: 0.25] [optional] 
The amount of time to fade in this Timeline's weight.





Timeline.addAnimatedProperty(sceneObject, propertyPath, valueType, interpolation, validateRecipientSupport)
[type: function] [returns: AnimatedProperty] 
Adds an AnimatedProperty to this Timeline, animating the given property of the given SceneObject with Keyframes. By default the property is screened against the set the given SceneObject actually supports animating; an unsupported property (or one already present on this Timeline) is refused and undefined is returned instead of an AnimatedProperty.

Timeline.addAnimatedProperty parameter: sceneObject
[type: SceneObject] 
The SceneObject that owns the property (propertyPath is relative to it). May be undefined for owner-less properties, and is disregarded entirely by a path rooted at 'nc'.

Timeline.addAnimatedProperty parameter: propertyPath
[type: [string]] 
The path to the property to animate, as an array of member names (for example ['scale','x']). A path whose first member is 'nc' addresses something global rather than anything on a SceneObject - ['nc','sounds','MySound','playOnce'] or ['nc','appEvents','MyEvent','trigger'] for instance - and is bound and stored with no owner at all.

Timeline.addAnimatedProperty parameter: valueType
[type: string] [default: 'floatingPoint'] [optional] 
The kind of value being animated. The available values can be found in constants.keyframedValueTypes.

Timeline.addAnimatedProperty parameter: interpolation
[type: string] [default: 'optimizedBezier'] [optional] 
The interpolation used between numeric Keyframes. The available values can be found in constants.keyframedValueInterpolationTypes.

Timeline.addAnimatedProperty parameter: validateRecipientSupport
[type: boolean] [default: true] [optional] 
When true, the property is screened against the set the given SceneObject supports animating, and an unsupported property is refused (returns undefined) rather than added. Pass false only when replaying trusted, already-valid data (such as deserialization) so a screening gap can never discard it.


































































































































----------------------------------------------------------
Section 156: CustomObjectDefinition
----------------------------------------------------------


CustomObjectDefinition
[type: class] [NON-INSTANTIABLE] 
Object housing information about the CustomObjects currently registered in this project. A 'CustomObject' is any object that inherits from one of the standard hierarchy objects (i.e. SceneObject, GraphicObject, Button, etc...), that is registered with the Incisor inspector using 'nc.registerCustomObject'. Once registered, CustomObjects can be added to Constructs from within the Incisor GUI. CustomObject properties can also be registered with Incisor, making them accessible for monitoring and manipulating from within the inspector. To create a CustomObject, build a class that extends one of the standard Incisor hierarchy object types within a 'codeAsset' file, then call 'nc.registerCustomObject' in a 'runBeforeInit' block to register the new CustomObject type with the GUI. 





CustomObjectDefinition.name
[type: string] 
The name of the CustomObject.





CustomObjectDefinition.baseType
[type: string] 
The the name base type of the given CustomObject definition. Every registered CustomObject must extend one of the allowable CustomObject types (i.e. SceneObject, GraphicObject, etc...), and this value denotes which of those types were extended to create this particular CustomObject.





CustomObjectDefinition.properties
[type: [object]] 
Array of objects that containing information about the registered properties for this CustomObject. Registered properties are accessible for monitoring and manipulating within the inspector. Registered properties can also be flagged as 'persistent', which enables their values to be stored in containing Constructs. To register a property for a CustomObject call 'nc.registerCustomObjectProperty'. If this CustomObject has no registered properties, then this member will be undefined.





CustomObjectDefinition.classDefinition
[type: object] 
The class definition for this CustomObject.





CustomObjectDefinition.description
[type: string] 
An optional description of this CustomObject, displayed as a tooltip in the inspector GUI.










----------------------------------------------------------
Section 157: TextFormat
----------------------------------------------------------


TextFormat
[type: class] 
Object containing text formatting information that can be applied the characters within TextAssembly or TextBox objects.





TextFormat.type
[type: string] 
Type identifier.





TextFormat.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





TextFormat.fontName
[type: string] [default: "MainFont"] 
The name of the font that characters with this TextFormat will use. See 'nc.fontNames' for the names of the fonts available in this project. Please note that changing the fontName will result in the entire 'characterMaterial' object being reset to the materialPresets of the "xxx_Char0" character of the new font.





TextFormat.characterScaleX
[type: number] [default: 1] 
The x-axis scale multiplier for characters that use this TextFormat.





TextFormat.characterScaleY
[type: number] [default: 1] 
The y-axis scale multiplier for characters that use this TextFormat.





TextFormat.kerning
[type: number] [default: 0] 
Number representing an added or reduced spacing between characters that use this TextFormat. This kerning number denotes the proportion of the 'characterWidth' (see ProjectConfiguration.fontDefitions) that will be added to or subtracted from the width of each character. The effects of kerning are also automatically multiplied by the given format's 'characterScaleX' value, UiZoom.totalZoom (if applicable), and the 'scaleToFitFactor' (if applicable).





TextFormat.verticalShift
[type: number] [default: 0] 
Number representing a veritcal offset that will be applied to the characters that use this TextFormat. This number denotes the proportion of the font's 'lineHeight' (see ProjectConfiguration.fontDefitions) that will be added to or subtracted from the vertical position of the characters using this TextFormat. The effects of verticalShift are also automatically multiplied by the given format's 'characterScaleY' value, UiZoom.totalZoom (if applicable), and the 'scaleToFitFactor' (if applicable).





TextFormat.lineHeightMultiplier
[type: number] [default: 1] 
Number that multiplies the effective layout height of characters the that use this TextFormat. As a default, the 'layout height' of any character within a font is the font's 'lineHeight' value (see ProjectConfiguration.fontDefitions). This number acts as a multiplier on that effective character height.





TextFormat.characterMaterial
[type: CharacterMaterial] 
Object defining EffectNodes amd EffectController values that will be applied to the characters that used this TextFormat.





TextFormat.clone()
[type: function] [returns: TextFormat] 
Returns a new TextFormat instance with the same values.





TextFormat.copy(source)
[type: function] 
Copies all property values from the source TextFormat into this TextFormat in-place, without allocating a new object. Prefer this over assigning a clone when 'this' already holds an initialized TextFormat and no new allocation is needed. All registered component-changed callbacks are fired once after all values have been written, rather than once per property as individual setter assignments would do. Note: changing the fontName will reset the characterMaterial EC values to the presets of the new font's character 0 before copying the source's EC values, matching the behavior of the fontName setter.

TextFormat.copy parameter: source
[type: TextFormat] 
The TextFormat whose values will be copied into this TextFormat.










----------------------------------------------------------
Section 158: CharacterMaterial
----------------------------------------------------------


CharacterMaterial
[type: class] [NON-INSTANTIABLE] 
Object representing the EffectNodes and EffectController values that will be applied to all of the TextBox or TextAssembly characters using the TextFormat that owns this CharacterMaterial. 





CharacterMaterial.type
[type: string] 
Type identifier.





CharacterMaterial.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





CharacterMaterial.fillColor
[type: Color] 
The EffectController for the 'FillColor' EffectNode, which entirely fills the associated Geometry with the red, green, blue, and alpha color values provided. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





CharacterMaterial.mainTexture
[type: Texture] 
The EffectController for the 'SampleMainTexture' EffectNode that tells it which Texture to render.





CharacterMaterial.colorMultiply
[type: Color] 
The EffectController for the 'ColorMultiply' EffectNode, which multiplies the red, green, blue, and alpha color values of the Material it is applied to. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





CharacterMaterial.shapify
[type: shapify] 
The EffectController for the 'Shapify' EffectNode. The Shapify EffectNode converts edge data stored in a 'shapified' Texture into a presentable image with edges that stay sharp regardless of the scale of the associated GraphicObject. This is an instance of the dynamically defined EffectController 'shapify' (base type: 'Vector2'). To get a new instance, use "nc.effectControllers['shapify'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





CharacterMaterial.incr_TwoColorGradient
[type: incr_TwoColorGradient] 
The incr_TwoColorGradient EffectController. This is an instance of the dynamically defined EffectController 'incr_TwoColorGradient' (base type: 'Vector4'). To get a new instance, use "nc.effectControllers['incr_TwoColorGradient'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





CharacterMaterial.incr_TwoColorGradient_color0
[type: Color] 
The incr_TwoColorGradient_color0 EffectController. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





CharacterMaterial.incr_TwoColorGradient_color1
[type: Color] 
The incr_TwoColorGradient_color1 EffectController. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





CharacterMaterial.shear
[type: shear] 
EffectController for the Shear EffectNode, which distorts the shape to appear slanted or skewed. This is an instance of the dynamically defined EffectController 'shear' (base type: 'Vector3'). To get a new instance, use "nc.effectControllers['shear'].new()". While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





CharacterMaterial.shear_center
[type: Vector2] 
EffectController for the Shear EffectNode, which distorts the shape to appear slanted or skewed. While some EffectNodes and EffectControllers are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





CharacterMaterial.getEffectNodes()
[type: function] [returns: [EffectNode]] 
Returns this CharacterMaterial's current EffectNodes. EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. Each EffectNode can be manipulated dynamically by one or more EffectControllers, which are accessable as direct members of this CharacterMaterial.





CharacterMaterial.setEffectNodes(effectNodes)
[type: function] 
Sets the EffectNodes for this CharacterMaterial, effectively setting them for all of the affected characters. EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. Each EffectNode can be manipulated dynamically by one or more EffectControllers, which are accessable as direct members of this CharacterMaterial.

CharacterMaterial.setEffectNodes parameter: effectNodes
[type: [EffectNode], EffectNode] 
The new list of EffectNodes that will apply this CharacterMaterial, which applies to all affected characters.





CharacterMaterial.addEffectNodes(effectNodes)
[type: function] 
Adds the given EffectNodes to this CharacterMaterial, effectively adding them to all of the affected characters. EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. Each EffectNode can be manipulated dynamically by one or more EffectControllers, which are accessable as direct members of this CharacterMaterial.

CharacterMaterial.addEffectNodes parameter: effectNodes
[type: [EffectNode], EffectNode] 
The EffectNodes to add to this CharacterMaterial, which applies to all affected characters.










----------------------------------------------------------
Section 159: IncisorApp
----------------------------------------------------------


IncisorApp
[type: class] [NON-INSTANTIABLE] [requires: unpublished only] 
Object housing functionality allowing for direct interactions with the Incisor® application from within the javascript runtime. Such functionality includes the ability to get/set project and application settings, initiate the hosting of files in local directories, script the opening of new browser tabs, and perform other transactions with the Incisor® application.





IncisorApp.getProjectSettings()
[type: function] [returns: IncrCommsResponseObject] 
Returns an IncrCommsResponseObject whose '.payload' member is copy of the current ProjectSettings of the currently open project in javascript object form. In order to update the ProjectSettings, pass 'IncisorApp.setProjectSettings' a version of this payload that contains the desired modifications.





IncisorApp.setProjectSettings(projectSettings)
[type: function] [returns: IncrCommsResponseObject] 
Updates the ProjectSettings of the currently open project in memory. The current ProjectSettings can be retrieved using 'IncisorApp.getProjectSettings', modified, and updated using this function. ProjectSettings updated using this method will be automatically validated against the internal Incisor® schema. Once updated, the current project must be saved in order for the changes to be reflected in the ProjectSettings.json file within the project directory.

IncisorApp.setProjectSettings parameter: projectSettings
[type: object] 
The desired ProjectSettings to update the project with.





IncisorApp.getApplicationSettings()
[type: function] [returns: IncrCommsResponseObject] 
Returns an IncrCommsResponseObject whose '.payload' member is copy of the Incisor ApplicationSettings in javascript object form. In order to update the ApplicationSettings, pass 'IncisorApp.setApplicationSettings' a version of this payload that contains the desired modifications.





IncisorApp.setApplicationSettings(applicationSettings, commitToDisk)
[type: function] [returns: IncrCommsResponseObject] 
Updates the Incisor® application settings in memory. The current ApplicationSettings can be retrieved using 'IncisorApp.getApplicationSettings', modified, and updated using this function. ApplicationSettings updated using this method will be automatically validated against the internal Incisor® schema.

IncisorApp.setApplicationSettings parameter: applicationSettings
[type: object] 
The desired ApplicationSettings to update Incisor® with.

IncisorApp.setApplicationSettings parameter: commitToDisk
[type: boolean] [default: false] [optional] 
Boolean determining if the new settings are immediately saved on disk, ensuring their persistence on subsequent application launches.





IncisorApp.hostLocalDirectory(directoryPath, isPathRelative, allowRemoteHosting, enableGzip)
[type: function] [returns: IncrCommsResponseObject] 
Begins hosting files in the given directory, and returns an IncrCommsResponseObject whose '.payload' member contains the port selected by Incisor® to host from.

IncisorApp.hostLocalDirectory parameter: directoryPath
[type: string] 
The relative or absolute path to the directory to host files from.

IncisorApp.hostLocalDirectory parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

IncisorApp.hostLocalDirectory parameter: allowRemoteHosting
[type: boolean] [default: false] [optional] 
Bool stating if external connections can make requests from this host. If true, the 'allowRemoteHosting' item in application settings must also be set to true.

IncisorApp.hostLocalDirectory parameter: enableGzip
[type: boolean] [default: true] [optional] 
Bool stating files hosted from this connection should be compressed using 'gzip'.





IncisorApp.stopHostingLocalDirectory(directoryPath, isPathRelative)
[type: function] [returns: IncrCommsResponseObject] 
Ends hosting files from the given directory, freeing up the associated port.

IncisorApp.stopHostingLocalDirectory parameter: directoryPath
[type: string] 
The relative or absolute path to the directory to stop hosting files from.

IncisorApp.stopHostingLocalDirectory parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path.





IncisorApp.openTabToUrl(url)
[type: function] [returns: IncrCommsResponseObject] 
Opens a new tab in the browser at the given url without requiring user interaction.

IncisorApp.openTabToUrl parameter: url
[type: string] 
The url to open the new browser tab to.





IncisorApp.pauseProjectDirectoryWatcher()
[type: function] 
Temporarily stops Incisor's file system watcher, allowing fileIO changes to the project without Incisor auto-refreshing the project in the inspector.





IncisorApp.resumeProjectDirectoryWatcher()
[type: function] 
Resumes Incisor's file system watcher, such that fileIO changes result in Incisor auto-refreshing the project in the inspector.










----------------------------------------------------------
Section 160: IncisorAppBasic
----------------------------------------------------------


IncisorAppBasic
[type: class] [NON-INSTANTIABLE] [requires: unpublished only] 
Object housing basic functionality allowing for direct interactions with the Incisor® application from within the javascript runtime. Such functionality includes the ability to get the list of optional code modules from the Incisor™ application. See 'nc.incisorApp' for many more application interaction options.





IncisorAppBasic.getOptionalCodeModuleNames()
[type: function] [returns: [string]] 
Returns a list of the names of all of the Incisor® 'optional code' modules. Optional code modules are groups of functionality that can be left out of projects in order to optimize their overall published download size. Optional code modules can be marked for exclusion in ProjectSettings.










----------------------------------------------------------
Section 161: Swooper
----------------------------------------------------------


Swooper
[type: class] [NON-INSTANTIABLE] 
Object controlling the 'swooping' (or interpolation) of a given numeric property or properties over a duration (using fixedUpdate). An object of this type is returned from all 'swoop' calls, providing a means to manage the given swooping process. 





Swooper.type
[type: string] 
Type identifier.





Swooper.name
[type: string] 
Name of the Swooper.





Swooper.numProperties
[type: number] 
The number of properties being interpolated by this Swooper.





Swooper.progress
[type: number] [default: 0] 
The number representing the progress of the interpolation of the value or values on where 0 corresponds to the startValues, and 1 corresponds to the endValues. This value is not meant to be manipulated as it is automatically changed over time via the internal fixedUpdate used by this Swooper.





Swooper.tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] 
The TweenType for this Swooper. A TweenType defines a method of interpolation between any two values or sets of values. The default TweenType is 'Linear', which defines a perfectly even interpolation between the startValues and endValues. TweenTypes can vary the timing of interpolation between two sets of values, as well as the path of the interpolation.





Swooper.controllers
[type: TweenControllers] [default: {}] 
Dictionary of dictionaries (per TweenType) of values that can be used to control this motion dynamically.





Swooper.startValues
[type: [number]] 
Array containing the starting value or values for the Swooper. The length of this array depends on this Swoop's 'numProperties'. Upon initiating a Swooper for a given numeric property/properties, their current values are stored in this array and used as the initial conditions for the interpolation.





Swooper.endValues
[type: [number]] 
Array containing the ending value or values for the Swooper. The length of this array depends on this Swoop's 'numProperties'. These values define the final target values for the swooped properties.





Swooper.currentValues
[type: [number]] 
Array containing the current value(s) for this Swooper. These are the values that the Tween function manipulates based its 'progress' property to create the desired movement.





Swooper.workspace
[type: object] 
An un-specified JS object of 'any' type to enable the user to stash persistant elements of their swooper within the tweenFunction.





Swooper.completionCallbackOwner
[type: object] [default: undefined] 
The object owning the optional callback function invoked when this Swooper completes.





Swooper.completionCallbackName
[type: string] [default: undefined] 
The name of the optional callback function invoked when this Swooper completes.





Swooper.completionCallbackArgs
[type: any] [default: undefined] 
Arguments for the optional callback function invoked when this Swooper completes.





Swooper.updaterCallbackOwner
[type: object] [default: undefined] 
The object owning the optional callback function invoked continuously (every fixedUpdate) during the interpolation process.





Swooper.updaterCallbackName
[type: string] [default: undefined] 
The name of the optional callback function invoked continuously (every fixedUpdate) during the interpolation process.





Swooper.pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] for this Swooper to have no pause immunity.





Swooper.speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.





Swooper.stop(setToEndValues, performCompletionCallback)
[type: function] 
Stops the Swooper if it is in progress.

Swooper.stop parameter: setToEndValues
[type: boolean] [default: false] [optional] 
Determines if the target properties are set to the endValues.

Swooper.stop parameter: performCompletionCallback
[type: boolean] [default: false] [optional] 
Determines if the pre-determined completionCallback (if defined) is performed.










----------------------------------------------------------
Section 162: TweenType
----------------------------------------------------------


TweenType
[type: class] 
Object defining a specific type of interpolation.





TweenType.type
[type: string] 
Type identifier.





TweenType.name
[type: string] 
Name of the Motion.





TweenType.tweenFunction()
[type: function] 
A reference to the function that defines the nature of the TweenType's motion.





TweenType.tweenControllerNames
[type: [string]] 
A list of optional tween controllers. These can be used to dynamically affect the nature of the TweenType's motion.





TweenType.tweenControllerDefaultValues
[type: [number]] 
A list of optional tween controller default values.





TweenType.description
[type: string] 
The description of the TweenType - this will appear in the autocomplete documentation.





TweenType.controllerDescriptions
[type: [string]] 
The description of the TweenType controllers - these descriptions will appear in the autocomplete documentation.










----------------------------------------------------------
Section 163: TweenControllers
----------------------------------------------------------


TweenControllers
[type: class] [NON-INSTANTIABLE] 
Dictionary of all registered TweenControllers. 










----------------------------------------------------------
Section 164: Curve
----------------------------------------------------------


Curve
[type: class] 
A Curve is a path defined by CurvePoints. The value of 'curveType' determines how the CurvePoints are interpreted to form the path.





Curve.curveType
[type: string] [default: "bezier"] 
The type of spline defining this Curve. See 'constants.curveTypes' for a list of available values.





Curve.cardinalTension
[type: number] [default: 0.5] 
When curveType is set to 'cardinal', this controls the curvature of the Curve. 0 produces straight lines between CurvePoints. 0.5 produces a Catmull-Rom spline.





Curve.points
[type: [CurvePoint]] 
The list of CurvePoints that define the curve shape. Each value of 'curveType' causes this list of CurvePoints to produce a different curve.





Curve.evaluateT(t, positionResult, tangentResult, normalResult, rotationResult, velocityResult)
[type: function] 
Evaluates the Curve at the given T value, which spans the entire curve in the range 0-1. Note that this typically does not progress with a constant speed, but is faster than evaluating a given distance with evaluateDistance.

Curve.evaluateT parameter: t
[type: number] 
The T value to evaluate, mapped to the range 0-1 along the length of the curve.

Curve.evaluateT parameter: positionResult
[type: Vector3] 
The resulting position expressed in the local space of the curve.

Curve.evaluateT parameter: tangentResult
[type: Vector3] [optional] 
The resulting tangent expressed in the local space of the curve. This corresponds to the velocity of a point following the curve via evaluateT, and is not normalized.

Curve.evaluateT parameter: normalResult
[type: Vector3] [optional] 
The resulting normal expressed in the local space of the curce. This vector is orthogonal to the tangent and is normalized.

Curve.evaluateT parameter: rotationResult
[type: Vector3] [optional] 
The resulting rotation that corresponds to the tangent and normal vectors.

Curve.evaluateT parameter: velocityResult
[type: Vector3] [optional] 
The resulting velocity expressed in the local space of the curve. If a point were to follow this curve via linearly increasing t values, this would be the velocity of the point at this position. Also known as the Curve's derivative.





Curve.evaluateDistance(distance, positionResult, tangentResult, normalResult, rotationResult, velocityResult)
[type: function] 
Evaluates the Curve at the given distance value, which spans the curve's length. Note that this allows progression at a constant speed, but is slower than evaluating a given T value with evaluateT.

Curve.evaluateDistance parameter: distance
[type: number] 
The distance to evaluate along the arc length of the curve.

Curve.evaluateDistance parameter: positionResult
[type: Vector3] 
The resulting position expressed in the local space of the curve.

Curve.evaluateDistance parameter: tangentResult
[type: Vector3] [optional] 
The resulting tangent expressed in the local space of the curve. This corresponds to the velocity of a point following the curve via evaluateT, and is not normalized.

Curve.evaluateDistance parameter: normalResult
[type: Vector3] [optional] 
The resulting normal expressed in the local space of the curce. This vector is orthogonal to the tangent and is normalized.

Curve.evaluateDistance parameter: rotationResult
[type: Vector3] [optional] 
The resulting rotation that corresponds to the tangent and normal vectors.

Curve.evaluateDistance parameter: velocityResult
[type: Vector3] [optional] 
The resulting velocity expressed in the local space of the curve. If a point were to follow this curve via linearly increasing t values, this would be the velocity of the point at this position. Also known as the Curve's derivative.





Curve.updatePoints()
[type: function] 
If ControlPoints are added to or removed from the points array, the curve will not be updated. This function foces the curve to reevaluate the points.





Curve.addCurveChangeCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that will be called when the curve shape changes. This includes changes to the CurvePoints, and changes to the curveType and cardinalTension.

Curve.addCurveChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Curve.addCurveChangeCallback parameter: callbackName
[type: string] 
The name of the callback function.

Curve.addCurveChangeCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function. Please note that the Curve object will be prepended to the list of callback parameters.





Curve.removeCurveChangeCallback(callbackOwner, callbackName)
[type: function] 
Removes the callback for when the curve shape changes.

Curve.removeCurveChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

Curve.removeCurveChangeCallback parameter: callbackName
[type: string] 
The name of the callback function.





Curve.addPoint()
[type: function] [returns: CurvePoint] 
Adds a new CurvePoint to the points array.





Curve.getLength()
[type: function] [returns: number] 
Returns the total arc of the curve.










----------------------------------------------------------
Section 165: CurvePoint
----------------------------------------------------------


CurvePoint
[type: class] [NON-INSTANTIABLE] 
A CurvePoint is a point used to define a Curve's shape. 





CurvePoint.position
[type: Vector3] [default: new Vector3(0,0,0)] 
The position of the CurvePoint in the local space of the Curve.





CurvePoint.leftHandle
[type: Vector3] [default: new Vector3(-100,0,0)] 
The left handle of the CurvePoint, expressed with respect to the CurvePoint's position. If the Curve's curveType is not 'bezier' or the CurvePoint is the first in the points array, this is undefined.





CurvePoint.rightHandle
[type: Vector3] [default: new Vector3(100,0,0)] 
The right handle of the CurvePoint, expressed with respect to the CurvePoint's position. If the Curve's curveType is not 'bezier' or 'hermite' or the CurvePoint is the last in the points array, this is undefined.





CurvePoint.bezierHandleType
[type: string] [default: "aligned"] 
The behavior of this CurvePoint when the Curve's curveType is "bezier" and one of the handles is moved. When a handle moves, "aligned" will ensure that the other handle remains colinear with the position and moved handle. "symmetric" will ensure that the other handle remains colinear with the position and moved handle, and matches the moved handles distance from the position.





CurvePoint.clone()
[type: function] [returns: number] 
Returns a unique copy of this CurvePoint.










----------------------------------------------------------
Section 166: Vector1Swoop
----------------------------------------------------------


Vector1Swoop
[type: class] [NON-INSTANTIABLE] 
Object housing the swoopers for this Vector's components 





Vector1Swoop.each(endValues, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) each of the Vector components from their current values to the given end values over the duration.

Vector1Swoop.each parameter: endValues
[type: [number]] 
The ending values for the Vector components being swooped. Any value left undefined leaves that component untouched by this Swooper.

Vector1Swoop.each parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

Vector1Swoop.each parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

Vector1Swoop.each parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

Vector1Swoop.each parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

Vector1Swoop.each parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

Vector1Swoop.each parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector1Swoop.each parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

Vector1Swoop.each parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

Vector1Swoop.each parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.





Vector1Swoop.all(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) all of the Vector components from their current values to the given end value over the duration.

Vector1Swoop.all parameter: endValue
[type: number] 
The ending value for the numeric properties being swooped.

Vector1Swoop.all parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

Vector1Swoop.all parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

Vector1Swoop.all parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

Vector1Swoop.all parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

Vector1Swoop.all parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

Vector1Swoop.all parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector1Swoop.all parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

Vector1Swoop.all parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

Vector1Swoop.all parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.





Vector1Swoop.x(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) given component from its current value to the given end value over the duration.

Vector1Swoop.x parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

Vector1Swoop.x parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

Vector1Swoop.x parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

Vector1Swoop.x parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

Vector1Swoop.x parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

Vector1Swoop.x parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

Vector1Swoop.x parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector1Swoop.x parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

Vector1Swoop.x parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

Vector1Swoop.x parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.










----------------------------------------------------------
Section 167: Vector2Swoop
----------------------------------------------------------


Vector2Swoop
[type: class] [extends: Vector1Swoop] [NON-INSTANTIABLE] 
Object housing the swoopers for this Vector's components 





Vector2Swoop.y(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) given component from its current value to the given end value over the duration.

Vector2Swoop.y parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

Vector2Swoop.y parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

Vector2Swoop.y parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

Vector2Swoop.y parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

Vector2Swoop.y parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

Vector2Swoop.y parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

Vector2Swoop.y parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector2Swoop.y parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

Vector2Swoop.y parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

Vector2Swoop.y parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.

























----------------------------------------------------------
Section 168: Vector3Swoop
----------------------------------------------------------


Vector3Swoop
[type: class] [extends: Vector2Swoop] [NON-INSTANTIABLE] 
Object housing the swoopers for this Vector's components 





Vector3Swoop.z(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) given component from its current value to the given end value over the duration.

Vector3Swoop.z parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

Vector3Swoop.z parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

Vector3Swoop.z parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

Vector3Swoop.z parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

Vector3Swoop.z parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

Vector3Swoop.z parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

Vector3Swoop.z parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector3Swoop.z parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

Vector3Swoop.z parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

Vector3Swoop.z parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.






























----------------------------------------------------------
Section 169: Vector4Swoop
----------------------------------------------------------


Vector4Swoop
[type: class] [extends: Vector3Swoop] [NON-INSTANTIABLE] 
Object housing the swoopers for this Vector's components 





Vector4Swoop.w(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) given component from its current value to the given end value over the duration.

Vector4Swoop.w parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

Vector4Swoop.w parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

Vector4Swoop.w parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

Vector4Swoop.w parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

Vector4Swoop.w parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

Vector4Swoop.w parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

Vector4Swoop.w parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector4Swoop.w parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

Vector4Swoop.w parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

Vector4Swoop.w parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.



































----------------------------------------------------------
Section 170: ColorSwoop
----------------------------------------------------------


ColorSwoop
[type: class] [extends: Vector4Swoop] [NON-INSTANTIABLE] 
Object housing the swoopers for this Vector's components 





ColorSwoop.red(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) given component from its current value to the given end value over the duration.

ColorSwoop.red parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

ColorSwoop.red parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

ColorSwoop.red parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

ColorSwoop.red parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

ColorSwoop.red parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

ColorSwoop.red parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

ColorSwoop.red parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

ColorSwoop.red parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

ColorSwoop.red parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

ColorSwoop.red parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.

example:
// Objective: Swoop the red Color of a GraphicObject.
// Expected Result: You will see a red box fade to black over a period of 10 seconds, then fade back to red over a period of 5 seconds.

// Create a Color using the Color constructor. Initially, make it red.
let color = new Color( 1, 0, 0, 1 );
// Create a GraphicObject using the GraphicObject constructor. Use the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "RedBox" );
// Set the GraphicObject's fillColor property to the new Color (initially red).
myGraphicObject.fillColor = color;
// Swoop the red color down to zero over 10 seconds then swoop it back to 1 over 5 seconds.
color.swoop.red( 0, 10, undefined, color.swoop, "red", [1,5] );





ColorSwoop.green(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) given component from its current value to the given end value over the duration.

ColorSwoop.green parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

ColorSwoop.green parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

ColorSwoop.green parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

ColorSwoop.green parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

ColorSwoop.green parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

ColorSwoop.green parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

ColorSwoop.green parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

ColorSwoop.green parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

ColorSwoop.green parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

ColorSwoop.green parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.

example:
// Objective: Swoop the green Color of a GraphicObject.
// Expected Result: You will see a green box fade to black over a period of 10 seconds, then fade back to green over a period of 5 seconds.

// Create a Color using the Color constructor. Initially, make it green.
let color = new Color( 0, 1, 0, 1 );
// Create a GraphicObject using the GraphicObject constructor. Use the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "GreenBox" );
// Set the GraphicObject's fillColor property to the new Color (initially green).
myGraphicObject.fillColor = color;
// Swoop the green color down to zero over 10 seconds then swoop it back to 1 over 5 seconds.
color.swoop.green( 0, 10, undefined, color.swoop, "green", [1,5] );





ColorSwoop.blue(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) given component from its current value to the given end value over the duration.

ColorSwoop.blue parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

ColorSwoop.blue parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

ColorSwoop.blue parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

ColorSwoop.blue parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

ColorSwoop.blue parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

ColorSwoop.blue parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

ColorSwoop.blue parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

ColorSwoop.blue parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

ColorSwoop.blue parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

ColorSwoop.blue parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.

example:
// Objective: Swoop the blue Color of a GraphicObject.
// Expected Result: You will see a blue box fade to black over a period of 10 seconds, then fade back to blue over a period of 5 seconds.

// Create a Color using the Color constructor. Initially, make it blue.
let color = new Color( 0, 0, 1, 1 );
// Create a GraphicObject using the GraphicObject constructor. Use the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "BlueBox" );
// Set the GraphicObject's fillColor property to the new Color (initially blue).
myGraphicObject.fillColor = color;
// Swoop the blue color down to zero over 10 seconds then swoop it back to 1 over 5 seconds.
color.swoop.blue( 0, 10, undefined, color.swoop, "blue", [1,5] );





ColorSwoop.alpha(endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) given component from its current value to the given end value over the duration.

ColorSwoop.alpha parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

ColorSwoop.alpha parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

ColorSwoop.alpha parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

ColorSwoop.alpha parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

ColorSwoop.alpha parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

ColorSwoop.alpha parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

ColorSwoop.alpha parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

ColorSwoop.alpha parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

ColorSwoop.alpha parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

ColorSwoop.alpha parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.

example:
// Objective: Swoop the alpha (transparency) of a GraphicObject.
// Expected Result: You will see a white box gradually disappear over a period of 10 seconds, then reappear back to white over a period of 5 seconds.

// Create a Color using the Color constructor. By default, it will be white.
let color = new Color();
// Create a GraphicObject using the GraphicObject constructor. Use the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject(nc.graphicAssets.whiteBox, nc.mainScene, "WhiteBox");
// Set the GraphicObject's fillColor property to the new Color (initially white).
myGraphicObject.fillColor = color;
// Swoop the alpha value down to zero over 10 seconds then swoop it back to 1 over 5 seconds.
color.swoop.alpha(0, 10, undefined, color.swoop, "alpha", [1, 5]);








































----------------------------------------------------------
Section 171: Vector1AddMotion
----------------------------------------------------------


Vector1AddMotion
[type: class] [NON-INSTANTIABLE] 
Object housing the 'addMotion' functions for this Vector's components 





Vector1AddMotion.each(lowerBounds, upperBounds, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to each of the components of this Vector (bounds to be supplied individually), and returns a Motion object, which can be used to control the motion dynamically.

Vector1AddMotion.each parameter: lowerBounds
[type: [number]] 
The lower bound(s) for the motion being added.

Vector1AddMotion.each parameter: upperBounds
[type: [number]] 
The upper bound(s) for the motion being added.

Vector1AddMotion.each parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

Vector1AddMotion.each parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

Vector1AddMotion.each parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector1AddMotion.each parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

Vector1AddMotion.each parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

Vector1AddMotion.each parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.

example:
// Objective: Use the each() function to add motion to the color of the box.
// Expected Result: You will see a box continuously fading in and out from bright white to a dark, semi-transparent blue.

// create a GraphicObject using the WhiteBox asset
let box = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Box" );
// set the lower and upper color bounds as arrays and slow the motion speed to .2
box.colorMultiply.addMotion.each( [0, .1, .6, .4], [.7, 1, .8, 2], .2 );





Vector1AddMotion.all(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds the a motion to all of the components of this Vector (using the same set of bounds), and returns a Motion object, which can be used to control the motion dynamically.

Vector1AddMotion.all parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

Vector1AddMotion.all parameter: upperBound
[type: number] 
The upper bound for the motion being added.

Vector1AddMotion.all parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

Vector1AddMotion.all parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

Vector1AddMotion.all parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector1AddMotion.all parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

Vector1AddMotion.all parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

Vector1AddMotion.all parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.

example:
// Objective: Use the all() function to add motion to the scale of a box.
// Expected Result: You will see a white box continuously expanding and contracting.

// create a GraphicObject using the WhiteBox asset
let box = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Box" );
// set the upper and lower bounds of the scale of the box and slow the motion speed to .2
box.scale.addMotion.all(  0, 3, .2 );





Vector1AddMotion.x(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the given component and returns a Motion object, which can be used to control the motion dynamically.

Vector1AddMotion.x parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

Vector1AddMotion.x parameter: upperBound
[type: number] 
The upper bound for the motion being added.

Vector1AddMotion.x parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

Vector1AddMotion.x parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

Vector1AddMotion.x parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector1AddMotion.x parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

Vector1AddMotion.x parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

Vector1AddMotion.x parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.

example:
// Objective: Use the x() function to add motion along the x axis.
// Expected Result: You will see a white box continuously moving back and forth along the x axis.

// create a GraphicObject using the WhiteBox asset
let box = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Box" );
// set the upper and lower bounds of the x position of the box and slow the motion speed to .2
box.position.addMotion.x(  -500, 500, .2 );










----------------------------------------------------------
Section 172: Vector2AddMotion
----------------------------------------------------------


Vector2AddMotion
[type: class] [extends: Vector1AddMotion] [NON-INSTANTIABLE] 
Object housing the 'addMotion' functions for this Vector's components 





Vector2AddMotion.y(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the given component and returns a Motion object, which can be used to control the motion dynamically.

Vector2AddMotion.y parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

Vector2AddMotion.y parameter: upperBound
[type: number] 
The upper bound for the motion being added.

Vector2AddMotion.y parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

Vector2AddMotion.y parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

Vector2AddMotion.y parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector2AddMotion.y parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

Vector2AddMotion.y parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

Vector2AddMotion.y parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.

example:
// Objective: Use the y() function to add motion along the y axis.
// Expected Result: You will see a white box continuously moving back and forth along the y axis.

// create a GraphicObject using the WhiteBox asset
let box = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Box" );
// set the upper and lower bounds of the y position of the box and slow the motion speed to .2
box.position.addMotion.y(  -500, 500, .2 );

























----------------------------------------------------------
Section 173: Vector3AddMotion
----------------------------------------------------------


Vector3AddMotion
[type: class] [extends: Vector2AddMotion] [NON-INSTANTIABLE] 
Object housing the 'addMotion' functions for this Vector's components 





Vector3AddMotion.z(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the given component and returns a Motion object, which can be used to control the motion dynamically.

Vector3AddMotion.z parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

Vector3AddMotion.z parameter: upperBound
[type: number] 
The upper bound for the motion being added.

Vector3AddMotion.z parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

Vector3AddMotion.z parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

Vector3AddMotion.z parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector3AddMotion.z parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

Vector3AddMotion.z parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

Vector3AddMotion.z parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.






























----------------------------------------------------------
Section 174: Vector4AddMotion
----------------------------------------------------------


Vector4AddMotion
[type: class] [extends: Vector3AddMotion] [NON-INSTANTIABLE] 
Object housing the 'addMotion' functions for this Vector's components 





Vector4AddMotion.w(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the given component and returns a Motion object, which can be used to control the motion dynamically.

Vector4AddMotion.w parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

Vector4AddMotion.w parameter: upperBound
[type: number] 
The upper bound for the motion being added.

Vector4AddMotion.w parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

Vector4AddMotion.w parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

Vector4AddMotion.w parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

Vector4AddMotion.w parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

Vector4AddMotion.w parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

Vector4AddMotion.w parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.



































----------------------------------------------------------
Section 175: ColorAddMotion
----------------------------------------------------------


ColorAddMotion
[type: class] [extends: Vector4AddMotion] [NON-INSTANTIABLE] 
Object housing the 'addMotion' functions for this Vector's components 





ColorAddMotion.red(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the given component and returns a Motion object, which can be used to control the motion dynamically.

ColorAddMotion.red parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

ColorAddMotion.red parameter: upperBound
[type: number] 
The upper bound for the motion being added.

ColorAddMotion.red parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

ColorAddMotion.red parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

ColorAddMotion.red parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

ColorAddMotion.red parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

ColorAddMotion.red parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

ColorAddMotion.red parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.

example:
// Objective: Create a blinking red box.
// Expected Result: You will see a box continuously blinking between red and black.

// Create a Color using the Color constructor. Initially, make it red.
let color = new Color( 1, 0, 0, 1 );
// Create a GraphicObject using the GraphicObject constructor. Use the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "RedBox" );
// Set the GraphicObject's fillColor property to the new Color.
myGraphicObject.fillColor = color;
// Add a blinking motion by setting the lower bound to black and the upper bound to red at a speed of 2.
color.addMotion.red( 0, 1, 2 );





ColorAddMotion.green(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the given component and returns a Motion object, which can be used to control the motion dynamically.

ColorAddMotion.green parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

ColorAddMotion.green parameter: upperBound
[type: number] 
The upper bound for the motion being added.

ColorAddMotion.green parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

ColorAddMotion.green parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

ColorAddMotion.green parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

ColorAddMotion.green parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

ColorAddMotion.green parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

ColorAddMotion.green parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.

example:
// Objective: Create a blinking green box.
// Expected Result: You will see a box continuously blinking between green and black.

// Create a Color using the Color constructor. Initially, make it green.
let color = new Color( 0, 1, 0, 1 );
// Create a GraphicObject using the GraphicObject constructor. Use the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "GreenBox" );
// Set the GraphicObject's fillColor property to the new Color.
myGraphicObject.fillColor = color;
// Add a blinking motion by setting the lower bound to black and the upper bound to green at a speed of 2.
color.addMotion.green( 0, 1, 2 );





ColorAddMotion.blue(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the given component and returns a Motion object, which can be used to control the motion dynamically.

ColorAddMotion.blue parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

ColorAddMotion.blue parameter: upperBound
[type: number] 
The upper bound for the motion being added.

ColorAddMotion.blue parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

ColorAddMotion.blue parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

ColorAddMotion.blue parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

ColorAddMotion.blue parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

ColorAddMotion.blue parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

ColorAddMotion.blue parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.

example:
// Objective: Create a blinking blue box.
// Expected Result: You will see a box continuously blinking between blue and black.

// Create a Color using the Color constructor. Initially, make it blue.
let color = new Color( 0, 0, 1, 1 );
// Create a GraphicObject using the GraphicObject constructor. Use the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "BlueBox" );
// Set the GraphicObject's fillColor property to the new Color.
myGraphicObject.fillColor = color;
// Add a blinking motion by setting the lower bound to black and the upper bound to blue at a speed of 2.
color.addMotion.blue( 0, 1, 2 );





ColorAddMotion.alpha(lowerBound, upperBound, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion to the given component and returns a Motion object, which can be used to control the motion dynamically.

ColorAddMotion.alpha parameter: lowerBound
[type: number] 
The lower bound for the motion being added.

ColorAddMotion.alpha parameter: upperBound
[type: number] 
The upper bound for the motion being added.

ColorAddMotion.alpha parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

ColorAddMotion.alpha parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

ColorAddMotion.alpha parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

ColorAddMotion.alpha parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

ColorAddMotion.alpha parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

ColorAddMotion.alpha parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.

example:
// Objective: Create a blinking box.
// Expected Result: You will see a box continuously blinking. It will gradually disappear and reappear back to white.

// Create a Color using the Color constructor. Initially, it will be white.
let color = new Color();
// Create a GraphicObject using the GraphicObject constructor. Use the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "WhiteBox" );
// Set the GraphicObject's fillColor property to the new Color.
myGraphicObject.fillColor = color;
// Add a blinking motion by setting the lower bound to transparent(0) and the upper bound to opaque(1) at a speed of 2.
color.addMotion.alpha( 0, 1, 2 );








































----------------------------------------------------------
Section 176: Vector4Base
----------------------------------------------------------


Vector4Base
[type: class] [NON-INSTANTIABLE] 
The 'base' object for the Vector4 type. This is not for general use - use Vector4 instead. 





Vector4Base.type
[type: string] 
Type identifier.





Vector4Base.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





Vector4Base.x
[type: number] 
The first component of this Vector.





Vector4Base.y
[type: number] 
The second component of this Vector.





Vector4Base.z
[type: number] 
The third component of this Vector.





Vector4Base.w
[type: number] 
The fourth component of this Vector.





Vector4Base.scaleByFactor(factor)
[type: function] 
Multiplies all Vector components by the given factor.

Vector4Base.scaleByFactor parameter: factor
[type: number] 
The value to multiply the Vector components by.

example:
// Objective: Use the scaleByFactor to change the color of the white box.
// Expected Result: You will see a half transparent gray box.

// create a GraphicObject using the WhiteBox asset
let box = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Box" );
// multiplying with the box's default color (1,1,1,1) results in a final color of (.5, .5, .5, .5) 
box.fillColor.scaleByFactor( .5 );





Vector4Base.multiply(vector)
[type: function] 
Multiplies all components of this Vector by the given Vector.

Vector4Base.multiply parameter: vector
[type: Vector4] 
The Vector to multiply this Vector by.

example:
// Objective: Use the multiply function to change the color of the white box.
// Expected Result: You will see a denim blue box.

// create a GraphicObject using the WhiteBox asset
let box = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Box" );
// create a color to multiply with the box's default color (1,1,1,1)
let colorMultiplier = new Color( 0, .5, 1, .8 );
// multiplying results in a final color of (0, .5, 1, .8) 
box.fillColor.multiply( colorMultiplier );





Vector4Base.multiplyByValues(x, y, z, w)
[type: function] 
Multiplies the components of this Vector by the values provided.

Vector4Base.multiplyByValues parameter: x
[type: number] [default: 1] [optional] 
The value to multiply the first component by.

Vector4Base.multiplyByValues parameter: y
[type: number] [default: 1] [optional] 
The value to multiply the second component by.

Vector4Base.multiplyByValues parameter: z
[type: number] [default: 1] [optional] 
The value to multiply the third component by.

Vector4Base.multiplyByValues parameter: w
[type: number] [default: 1] [optional] 
The value to multiply the fourth component by.

example:
// Objective: Use the multiplyByValues function to change the color of the white box.
// Expected Result: You will see a denim blue box.

// create a GraphicObject using the WhiteBox asset
let box = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Box" );
// multiplying with the box's default color (1,1,1,1) results in a final color of (0, .5, 1, .8) 
box.fillColor.multiplyByValues( 0, .5, 1, .8  );





Vector4Base.copy(vector)
[type: function] 
Sets all of this Vector's component values to the component values of the given Vector.

Vector4Base.copy parameter: vector
[type: Vector4] 
The Vector to copy component values from.





Vector4Base.isEqual(vector)
[type: function] [returns: boolean] 
Determines if all of the components of this Vector are equal to their counterparts in the given Vector.

Vector4Base.isEqual parameter: vector
[type: Vector4] 
The Vector to compare against.





Vector4Base.clone()
[type: function] [returns: Vector4] 
Returns a new Vector4 with the same component values as this Vector.










----------------------------------------------------------
Section 177: Vector4
----------------------------------------------------------


Vector4
[type: class] [extends: Vector4Base] 
An object with 4 numeric properties (x, y, z, w).





Vector4.swoop
[type: Vector4Swoop] 
Object housing the built-in swoopers for this Vector's components.





Vector4.addMotion
[type: Vector4AddMotion] 
Object housing the built-in 'addMotion' functions for this Vector's components.






































































----------------------------------------------------------
Section 178: Color
----------------------------------------------------------


Color
[type: class] [extends: Vector4Base] 
An object with 4 numeric properties (red, green, blue, alpha) representing a color with transparency.





Color.swoop
[type: ColorSwoop] 
Object housing the built-in swoopers for this Vector's components.

example:
// Objective: Swoop the Color of a GraphicObject.
// Expected Result: You will see a red box fade to black over a period of 10 seconds, then fade back to red over a period of 5 seconds.

// Create a Color using the Color constructor. Initially, make it red.
let color = new Color( 1, 0, 0, 1 );
// Create a GraphicObject using the GraphicObject constructor. Use the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "RedBox" );
// Set the GraphicObject's fillColor property to the new Color (initially red).
myGraphicObject.fillColor = color;
// Swoop the red color down to zero over 10 seconds then swoop it back to 1 over 5 seconds.
color.swoop.red( 0, 10, undefined, color.swoop, "red", [1,5] );





Color.addMotion
[type: ColorAddMotion] 
Object housing the built-in 'addMotion' functions for this Vector's components.

example:
// Objective: Add motion to the changing Colors of a box.
// Expected Result: You will see a box continuously changing colors as the red, green and blue values adjust up and down over different time intervals.

// Create a Color using the Color constructor. Initially, it will default to white.
let color = new Color();
// Create a GraphicObject using the GraphicObject constructor. Use the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "RedBox" );
// Set the GraphicObject's fillColor property to the new Color.
myGraphicObject.fillColor = color;
// Add motion to the red, green and blue values over different time intervals.
color.addMotion.red( 0, 1, .04 );
color.addMotion.green( 0, 1, .09 );
color.addMotion.blue( 0, 1, 1.5 );





Color.red
[type: number] 
The red value of this Color.

example:
// Objective: Get the red value of a Color.
// Expected Result: The console should read "The red value is 0.5".

// Create a color using the Color constructor. Set the red value to 0.5.
let color = new Color( 0.5, 0, 0, 1 );
console.log("The red value is", color.red);





Color.green
[type: number] 
The green value of this Color.

example:
// Objective: Get the green value of a Color.
// Expected Result: The console should read "The green value is 0.5".

// Create a color using the Color constructor. Set the green value to 0.5.
let color = new Color( 0, 0.5, 0, 1 );
console.log("The green value is", color.green);





Color.blue
[type: number] 
The blue value of this Color.

example:
// Objective: Get the blue value of a Color.
// Expected Result: The console should read "The blue value is 0.5".

// Create a color using the Color constructor. Set the blue value to 0.5.
let color = new Color( 0, 0, 0.5, 1 );
console.log("The blue value is", color.blue);





Color.alpha
[type: number] 
The alpha value of this Color.

example:
// Objective: Get the alpha value of a Color.
// Expected Result: The console should read "The alpha value is 0.5".

// Create a color using the Color constructor. Set the alpha value to 0.5.
let color = new Color( 0, 0, 0, 0.5 );
console.log("The alpha value is", color.alpha);






































































----------------------------------------------------------
Section 179: Vector3Base
----------------------------------------------------------


Vector3Base
[type: class] [NON-INSTANTIABLE] 
The 'base' object for the Vector3 type. This is not for general use - use Vector3 instead. 





Vector3Base.type
[type: string] 
Type identifier.





Vector3Base.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





Vector3Base.x
[type: number] 
The first component of this Vector.





Vector3Base.y
[type: number] 
The second component of this Vector.





Vector3Base.z
[type: number] 
The third component of this Vector.





Vector3Base.scaleByFactor(factor)
[type: function] 
Multiplies all Vector components by the given factor.

Vector3Base.scaleByFactor parameter: factor
[type: number] 
The value to multiply the Vector components by.





Vector3Base.multiply(vector)
[type: function] 
Multiplies all components of this Vector by the given Vector.

Vector3Base.multiply parameter: vector
[type: Vector3] 
The Vector to multiply this Vector by.





Vector3Base.multiplyByValues(x, y, z)
[type: function] 
Multiplies the components of this Vector by the values provided.

Vector3Base.multiplyByValues parameter: x
[type: number] [default: 1] [optional] 
The value to multiply the first component by.

Vector3Base.multiplyByValues parameter: y
[type: number] [default: 1] [optional] 
The value to multiply the second component by.

Vector3Base.multiplyByValues parameter: z
[type: number] [default: 1] [optional] 
The value to multiply the third component by.





Vector3Base.copy(vector)
[type: function] 
Sets all of this Vector's component values to the component values of the given Vector.

Vector3Base.copy parameter: vector
[type: Vector3] 
The Vector to copy component values from.





Vector3Base.isEqual(vector)
[type: function] [returns: boolean] 
Determines if all of the components of this Vector are equal to their counterparts in the given Vector.

Vector3Base.isEqual parameter: vector
[type: Vector3] 
The Vector to compare against.





Vector3Base.clone()
[type: function] [returns: Vector3] 
Returns a new Vector3 with the same component values as this Vector.










----------------------------------------------------------
Section 180: Vector3
----------------------------------------------------------


Vector3
[type: class] [extends: Vector3Base] 
An object with 3 numeric properties (x, y, z).





Vector3.swoop
[type: Vector3Swoop] 
Object housing the built-in swoopers for this Vector's components.





Vector3.addMotion
[type: Vector3AddMotion] 
Object housing the built-in 'addMotion' functions for this Vector's components.

































































----------------------------------------------------------
Section 181: Vector2Base
----------------------------------------------------------


Vector2Base
[type: class] [NON-INSTANTIABLE] 
The 'base' object for the Vector2 type. This is not for general use - use Vector2 instead. 





Vector2Base.type
[type: string] 
Type identifier.





Vector2Base.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





Vector2Base.x
[type: number] 
The first component of this Vector.





Vector2Base.y
[type: number] 
The second component of this Vector.





Vector2Base.scaleByFactor(factor)
[type: function] 
Multiplies all Vector components by the given factor.

Vector2Base.scaleByFactor parameter: factor
[type: number] 
The value to multiply the Vector components by.





Vector2Base.multiply(vector)
[type: function] 
Multiplies all components of this Vector by the given Vector.

Vector2Base.multiply parameter: vector
[type: Vector2] 
The Vector to multiply this Vector by.





Vector2Base.multiplyByValues(x, y)
[type: function] 
Multiplies the components of this Vector by the values provided.

Vector2Base.multiplyByValues parameter: x
[type: number] [default: 1] [optional] 
The value to multiply the first component by.

Vector2Base.multiplyByValues parameter: y
[type: number] [default: 1] [optional] 
The value to multiply the second component by.





Vector2Base.copy(vector)
[type: function] 
Sets all of this Vector's component values to the component values of the given Vector.

Vector2Base.copy parameter: vector
[type: Vector2] 
The Vector to copy component values from.





Vector2Base.isEqual(vector)
[type: function] [returns: boolean] 
Determines if all of the components of this Vector are equal to their counterparts in the given Vector.

Vector2Base.isEqual parameter: vector
[type: Vector2] 
The Vector to compare against.





Vector2Base.clone()
[type: function] [returns: Vector2] 
Returns a new Vector2 with the same component values as this Vector.










----------------------------------------------------------
Section 182: Vector2
----------------------------------------------------------


Vector2
[type: class] [extends: Vector2Base] 
An object with 2 numeric properties (x, y).





Vector2.swoop
[type: Vector2Swoop] 
Object housing the built-in swoopers for this Vector's components.





Vector2.addMotion
[type: Vector2AddMotion] 
Object housing the built-in 'addMotion' functions for this Vector's components.




























































----------------------------------------------------------
Section 183: VectorBase
----------------------------------------------------------


VectorBase
[type: class] [NON-INSTANTIABLE] 
The 'base' object for the Vector1 type. This is not for general use - use Vector1 instead. 





VectorBase.type
[type: string] 
Type identifier.





VectorBase.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





VectorBase.dimension
[type: number] 
The number of components this Vector has





VectorBase.x
[type: number] 
The first component of this Vector.





VectorBase.scaleByFactor(factor)
[type: function] 
Multiplies all Vector components by the given factor.

VectorBase.scaleByFactor parameter: factor
[type: number] 
The value to multiply the Vector components by.





VectorBase.multiply(vector)
[type: function] 
Multiplies all components of this Vector by the given Vector.

VectorBase.multiply parameter: vector
[type: Vector1] 
The Vector to multiply this Vector by.





VectorBase.multiplyByValues(x)
[type: function] 
Multiplies the components of this Vector by the values provided.

VectorBase.multiplyByValues parameter: x
[type: number] [default: 1] [optional] 
The value to multiply the first component by.





VectorBase.copy(vector)
[type: function] 
Sets all of this Vector's component values to the component values of the given Vector.

VectorBase.copy parameter: vector
[type: Vector1] 
The Vector to copy component values from.





VectorBase.isEqual(vector)
[type: function] [returns: boolean] 
Determines if all of the components of this Vector are equal to their counterparts in the given Vector.

VectorBase.isEqual parameter: vector
[type: Vector1] 
The Vector to compare against.





VectorBase.clone()
[type: function] [returns: Vector1] 
Returns a new Vector1 with the same component values as this Vector.










----------------------------------------------------------
Section 184: Vector1
----------------------------------------------------------


Vector1
[type: class] [extends: VectorBase] 
An object with 1 numeric property (x).





Vector1.swoop
[type: Vector1Swoop] 
Object housing the built-in swoopers for this Vector's components.





Vector1.addMotion
[type: Vector1AddMotion] 
Object housing the built-in 'addMotion' functions for this Vector's components.




























































----------------------------------------------------------
Section 185: Geometry
----------------------------------------------------------


Geometry
[type: class] [extends: AssetComponent] [NON-INSTANTIABLE] 
A Geometry is an object that defines a GraphicAsset's vertices, and the associated Materials and attributes. 





Geometry.sourceWidth
[type: number] 
The width of the source asset (with 'units per pixel' pre-applied).





Geometry.sourceHeight
[type: number] 
The height of the source asset (with 'units per pixel' pre-applied).





Geometry.unitsPerPixel
[type: [number]] 
The 'unitsPerPixel' scaler values for this Geometry.





Geometry.dispose()
[type: function] 
Removes internal Incisor® references to this Geometry.





Geometry._getPositionBounds()
[type: function] [returns: Object] 
Returns the left, right, bottom, and top bounds of the geometry's position attribute.








































----------------------------------------------------------
Section 186: SymbolReel
----------------------------------------------------------


SymbolReel
[type: class] [extends: SceneObject] [requires: module - symbolReels] 
A specialized SceneObject which owns a set of 'symbol' objects and moves them along a reel path to create a spinning reel, as used for slot games. The spinning effect is created by advancing each symbol's 'pathPosition' - a scalar measured in symbol slots, where whole numbers are the resting positions - and changing the symbol a given object represents whenever it crosses the wrap point at the end of the reel path. The symbol objects are created, owned, and disposed by this SymbolReel. They are never written into a Construct blueprint, and their class is supplied in code through 'symbolClassDefinition'. Until one is supplied, a built-in placeholder symbol is used, so that a reel laid out in the Construct editor is visible straight away. Symbol objects are built lazily, the first time the reel is laid out or the first time they are asked for, so project code can assign a 'symbolClassDefinition' and initial reel data first.





SymbolReel.symbolClassDefinition
[type: object] [default: undefined] 
The class definition used to construct each symbol object. The class must implement a 'setSymbol' function taking a single symbol string, which this SymbolReel calls whenever the symbol an object represents changes. Note that 'setSymbol' can be called with undefined, which happens whenever this SymbolReel has no data for a given position, so the class should handle that case. The class constructor receives two parameters - the parent SceneObject and the name - so a class extending GraphicObject should pass undefined as its own graphicAsset and set the graphic from within 'setSymbol' instead. This connection is made in code only. It is never selectable in the Incisor inspector, and it is never serialized into a Construct. Setting this disposes any existing symbol objects, and new ones are built lazily. Leave this undefined to use the built-in placeholder symbol chosen by 'defaultSymbolType'.





SymbolReel.defaultSymbolType
[type: string] [default: "TextBox"] 
Which built-in stand-in symbol this SymbolReel builds while no 'symbolClassDefinition' has been supplied. The available values can be found in constants.defaultSymbolTypes. 'TextBox' draws a grey card showing the symbol string itself, which reads clearly while a reel is being laid out in the Incisor inspector. 'GraphicObject' draws the GraphicAsset whose name matches the symbol, falling back to the WhiteBox for a symbol naming no GraphicAsset in the project, and takes on the EffectNode and EffectController presets of each GraphicAsset it is given. This has no effect once a 'symbolClassDefinition' is supplied, which is the normal arrangement for a finished game. Setting this disposes any existing symbol objects, and new ones are built lazily.





SymbolReel.numMainSymbols
[type: number] [default: 3] 
The number of symbol objects meant to be the main, visible symbols on this SymbolReel. Setting this disposes any existing symbol objects, and new ones are built lazily.





SymbolReel.numTopBufferSymbols
[type: number] [default: 1] 
The number of symbol objects populated 'above' the main visible symbols. Since the motion of the symbols on this SymbolReel is fully customizable, these buffer symbols will not necessarily be above the main symbols. Setting this disposes any existing symbol objects, and new ones are built lazily.





SymbolReel.numBottomBufferSymbols
[type: number] [default: 1] 
The number of symbol objects populated 'below' the main visible symbols. Since the motion of the symbols on this SymbolReel is fully customizable, these buffer symbols will not necessarily be below the main symbols. Setting this disposes any existing symbol objects, and new ones are built lazily.





SymbolReel.numSymbols
[type: number] 
The total number of symbol objects on this SymbolReel, being numMainSymbols plus numTopBufferSymbols plus numBottomBufferSymbols. This is derived from those three counts, so it reports the intended total even before the symbol objects have been built.





SymbolReel.spinSpeed
[type: number] [default: -0.25] 
The rate of motion for each symbol object during the reel spin, in symbol slots per sixtieth of a second. A value of 1 means each symbol travels one full symbol position every sixtieth of a second. The reel advances on real time, so this rate holds at any fixedUpdate rate.





SymbolReel.windupCurve
[type: KeyframedValue] 
The KeyframedValue describing this SymbolReel's motion during the 'windup' state. It is sampled over a progress range of 0 to 1, where 1 is the full 'windupDuration', and its value is a pathPosition offset applied to every symbol - so a curve peaking at 0.5 moves the symbols half a symbol position. Its output is multiplied by 'windupMagnitude'.





SymbolReel.windupDuration
[type: number] [default: 0.25] 
The amount of time that this SymbolReel spends in the 'windup' state.





SymbolReel.windupMagnitude
[type: number] [default: 1] 
A multiplier applied to the value returned by 'windupCurve', letting the windup motion be scaled at runtime without editing the curve.





SymbolReel.bounceCurve
[type: KeyframedValue] 
The KeyframedValue describing this SymbolReel's motion during the 'bounce' state. It is sampled over a progress range of 0 to 1, where 1 is the full 'bounceDuration', and its value is a pathPosition offset applied to every symbol. Its output is multiplied by 'bounceMagnitude'.





SymbolReel.bounceDuration
[type: number] [default: 0.25] 
The amount of time that this SymbolReel spends in the 'bounce' state.





SymbolReel.bounceMagnitude
[type: number] [default: 1] 
A multiplier applied to the value returned by 'bounceCurve', letting the bounce motion be scaled at runtime without editing the curve.





SymbolReel.assembleReelDataOnTheFly
[type: boolean] [default: true] 
Boolean indicating if this SymbolReel assembles its reel data as it spins. When true, the reel data starts as whatever was given to 'setInitialReelData' and each spin adds the symbols supplied to 'setTarget', growing until it reaches 'reelDataAssemblyMax', after which further symbols overwrite a random stretch of the existing data. When false, the full reel data must be supplied in code via 'setReelData', and calling 'beginSpin' before that has been done is an error. This is a code-only setting, never selectable in the Incisor inspector and never serialized into a Construct, so a reel always begins life assembling its data. Set it during 'ProjectMain.init'. Setting this changes nothing about the symbol objects and does not rebuild them.





SymbolReel.reelDataAssemblyMax
[type: number] [default: 200] 
When 'assembleReelDataOnTheFly' is true, this acts as a cap on the reel data length. Once the reel data reaches this length, symbols supplied to 'setTarget' are placed at a random position within the reel data, overwriting what was there, which keeps memory bounded over a long session. Like 'assembleReelDataOnTheFly' itself, this is a code-only setting - it is never selectable in the Incisor inspector and it is never serialized into a Construct.





SymbolReel.pathPositionSnap
[type: number] [default: 0.01] 
The grid, in pathPosition units, that the Keyframe times of every KeyframedValue owned by this SymbolReel are snapped onto. This SymbolReel holds the single snap value for all of them, in the same way that a Timeline holds one timeSnap for its AnimatedProperties. Setting it to undefined or to a value less than or equal to zero coerces it back to the default.





SymbolReel.reelState
[type: string] 
Read-only string indicating which state this SymbolReel is in. The available values can be found in constants.symbolReelStates. - The 'stopped' state is when the SymbolReel is at rest. - The 'windup' state is just before the main portion of the spin, when the SymbolReel is winding up. - The 'spinFree' state is when the SymbolReel is spinning freely, which continues indefinitely until 'beginStop' or 'slam' is called. - The 'stopping' state is the time after 'beginStop' has been called, during which the SymbolReel continues to spin until the final stopping symbols are found. - The 'stopImminent' state is when the final stopping symbols are visible on the SymbolReel and only need to travel into their final position. - The 'bounce' state is just before the spin ends, when the symbols recoil to simulate a physical reel coming to rest. Any change that would rebuild the symbol objects is refused while this is anything other than 'stopped'.





SymbolReel.symbolPathOverrideCallbackOwner
[type: object] 
The owner of a function that takes over positioning of the symbol objects entirely. When both this and 'symbolPathOverrideCallbackName' are set, the path value dictionary is not evaluated at all, and the given function is called once per symbol every time the reel lays out. The function receives the symbol object and its pathPosition as its first two parameters, followed by any 'symbolPathOverrideCallbackArgs'. This is a code-only facility for reel motion that needs to be algorithmic or dynamic, and it is not settable within the Incisor inspector.





SymbolReel.symbolPathOverrideCallbackName
[type: string] 
The name of a function that takes over positioning of the symbol objects entirely. When both this and 'symbolPathOverrideCallbackOwner' are set, the path value dictionary is not evaluated at all, and the given function is called once per symbol every time the reel lays out. The function receives the symbol object and its pathPosition as its first two parameters, followed by any 'symbolPathOverrideCallbackArgs'. This is a code-only facility for reel motion that needs to be algorithmic or dynamic, and it is not settable within the Incisor inspector.





SymbolReel.symbolPathOverrideCallbackArgs
[type: [any], any] 
Parameters for the symbol path override function. Parameters given here are supplied to the callback after the symbol object and its pathPosition.





SymbolReel.pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] 
The PauseEvent or Array of PauseEvents that this SymbolReel is immune to. Set this to [] for this SymbolReel to have no pause immunity.





SymbolReel.speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] 
The SpeedControl or Array of SpeedControls that this SymbolReel is affected by.





SymbolReel.symbolBuildLazyUpdater
[type: LazyUpdater] 
The LazyUpdater governing when this SymbolReel builds its symbol objects. Building is deferred so that project code has a window in which to assign a 'symbolClassDefinition' and initial reel data before anything is constructed. Calling 'updateIfNeeded' on it forces the build immediately, which the symbol accessors and the spin functions on this SymbolReel already do.





SymbolReel.layoutLazyUpdater
[type: LazyUpdater] 
The LazyUpdater governing when this SymbolReel places its symbol objects along the reel path again. Changing a symbol path value, or the pathPositionSnap, flags it, and it is serviced the next time the reel is traversed. Editing the Keyframes of a symbol path value directly does not go through this SymbolReel, so set 'needsUpdate' on this to have such an edit reflected while the reel is stopped.





SymbolReel.setInitialReelData(initialReelData)
[type: function] 
Sets the authored starting symbols for this SymbolReel. This data is serialized into a Construct, and its first 'numSymbols' entries determine what the symbol objects display when they are built - which is what makes a reel readable while it is being laid out in the Incisor inspector. When 'assembleReelDataOnTheFly' is true, this data additionally seeds the working reel data that each spin adds to. Any position without an entry here has undefined passed to its symbol object's 'setSymbol' function. A new SymbolReel is seeded with one entry per position, lettered so that 'A' falls on the first main visible position - a reel with one top buffer position reads 'Z', 'A', 'B' and so on. Calling this disposes any existing symbol objects, and new ones are built lazily.

SymbolReel.setInitialReelData parameter: initialReelData
[type: [string]] 
An array of strings representing the starting symbols.





SymbolReel.setReelData(reelData)
[type: function] 
Sets the full working reel strip for this SymbolReel. This is runtime data - it is never serialized into a Construct, and it does not rebuild the symbol objects, so it can be called at any point without disturbing what is on screen. This is how the reel data is supplied when 'assembleReelDataOnTheFly' is false, in which case calling 'beginSpin' before this has been called is an error.

SymbolReel.setReelData parameter: reelData
[type: [string]] 
The full set of reel data for this SymbolReel.





SymbolReel.setTarget(target)
[type: function] 
Sets where this SymbolReel comes to rest at the end of its next spin. When 'assembleReelDataOnTheFly' is false, provide an index into the reel data, and the symbol at that index appears in this SymbolReel's first main visible position when the spin ends, with the subsequent symbols below it. When 'assembleReelDataOnTheFly' is true, provide an array of the symbols to be displayed when the spin stops, containing exactly 'numSymbols' entries so that the top buffer symbols, the main symbols, and the bottom buffer symbols are all accounted for. An index may also be given in this mode.

SymbolReel.setTarget parameter: target
[type: number, [string]] 
The final stopping reel data index, or the final stopping set of symbols.





SymbolReel.beginSpin()
[type: function] 
Begins the spin sequence for this SymbolReel, changing the reelState from 'stopped' to 'windup'. Once the windup sequence completes the reelState becomes 'spinFree', and the SymbolReel spins until 'beginStop' or 'slam' is called. This has no effect unless the reelState is 'stopped', and it reports an error if no reel data has been defined.





SymbolReel.beginStop(performSplice)
[type: function] 
Starts the process of bringing this SymbolReel to rest, changing the reelState from 'spinFree' to 'stopping'. While stopping, the SymbolReel continues to spin until it encounters the symbols it needs for its final position. The 'performSplice' parameter tells the SymbolReel to jump to the place in the reel data where the very next symbols to become visible are the final ones, which shortens the stopping process. Provide false when the reel is meant to travel a specific short distance, such as a single position, since splicing would only lengthen the stop in that case. This has no effect, and reports a warning, unless the reelState is 'windup' or 'spinFree'.

SymbolReel.beginStop parameter: performSplice
[type: boolean] [default: true] [optional] 
Boolean indicating if the SymbolReel should jump to the place in the reel data where the next symbols made visible are the final stopping symbols.





SymbolReel.slam()
[type: function] 
Abruptly skips to the 'bounce' state, placing the final stopping symbols immediately. This has no effect if the reelState is already 'stopped' or 'bounce'.





SymbolReel.getSymbol(index)
[type: function] [returns: SceneObject] 
Returns the symbol object nearest the given position on the reel path. When the SymbolReel is stopped the symbols sit on whole pathPositions, so this is simply the symbol at that position. While the SymbolReel is moving the symbols sit between whole positions, so this answers which symbol object is currently nearest that spot. Exact ties resolve to the lower pathPosition. Any index in [-numTopBufferSymbols, numMainSymbols+numBottomBufferSymbols-1] can be given, as that is the range of resting pathPositions. The type of the returned object depends on the 'symbolClassDefinition' supplied to this SymbolReel. Calling this builds the symbol objects if they have not been built yet, and it returns undefined if the SymbolReel has no symbols.

SymbolReel.getSymbol parameter: index
[type: number] 
The position on the reel path to find the nearest symbol object to.





SymbolReel.getSymbols(presortByPathPosition)
[type: function] [returns: [SceneObject]] 
Returns an Array containing all of the symbol objects on this SymbolReel. The type of the objects in the returned array depends on the 'symbolClassDefinition' supplied to this SymbolReel. Calling this builds the symbol objects if they have not been built yet.

SymbolReel.getSymbols parameter: presortByPathPosition
[type: boolean] [optional] 
Boolean indicating if the returned symbols should be sorted by their pathPosition values.





SymbolReel.addPathValue(path)
[type: function] [returns: KeyframedValue] 
Adds a KeyframedValue that drives the given property of every symbol object as it travels along the reel path, and returns it. The property path is given relative to a symbol object using dot notation, such as 'position.y', 'scale.x', 'rotation.z', or 'colorMultiply.alpha'. The KeyframedValue is sampled at each symbol's pathPosition, so Keyframes are placed at symbol slots - a Keyframe at 0 describes the first main visible position, 1 the next, and -1 the top buffer position. If a KeyframedValue already exists for the given path, the existing one is returned rather than a new one being made. Paths that a plain property walk cannot reach are not supported. Where more is needed, expose a property with a getter and setter on the symbol class and drive that instead. A path that does not reach a settable property on the symbol objects is kept but left inert rather than written - see 'getPathValueIsValid'. These KeyframedValues are ignored entirely while a symbol path override callback is set. A new SymbolReel is seeded with defaults for 'position.y' and 'colorMultiply.alpha'.

SymbolReel.addPathValue parameter: path
[type: string] 
The property path, relative to a symbol object, given in dot notation.





SymbolReel.removePathValue(path)
[type: function] 
Removes and disposes the KeyframedValue driving the given property path, if there is one.

SymbolReel.removePathValue parameter: path
[type: string] 
The property path, relative to a symbol object, given in dot notation.





SymbolReel.renamePathValue(path, newPath)
[type: function] [returns: boolean] 
Moves the KeyframedValue driving one property path over to another, carrying it across intact so that a rename never costs it its Keyframes. Renaming a path to itself does nothing and returns true. Returns false, changing nothing, when this SymbolReel has no KeyframedValue for the given path, or when it already drives the new one.

SymbolReel.renamePathValue parameter: path
[type: string] 
The property path currently being driven, relative to a symbol object, given in dot notation.

SymbolReel.renamePathValue parameter: newPath
[type: string] 
The property path to drive instead, relative to a symbol object, given in dot notation.





SymbolReel.getPathValue(path)
[type: function] [returns: KeyframedValue] 
Returns the KeyframedValue driving the given property path, or undefined if there is none.

SymbolReel.getPathValue parameter: path
[type: string] 
The property path, relative to a symbol object, given in dot notation.





SymbolReel.getPathValuePaths()
[type: function] [returns: [string]] 
Returns an Array of every property path that currently has a KeyframedValue driving it on this SymbolReel.





SymbolReel.getPathValueIsValid(path)
[type: function] [returns: boolean] 
Returns whether the KeyframedValue driving the given property path is actually reaching the symbol objects. A path is only written when every step of the walk resolves on a symbol and the property at the end of it already holds the kind of value the KeyframedValue produces - a number for a 'floatingPoint' KeyframedValue, and so on. A path that fails either test is left inert, keeping its Keyframes and taking up no time, and it starts driving the symbols as soon as the path names a property the symbol class has. This is what stops a path naming a whole object, such as 'position' where 'position.y' was meant, from overwriting something a symbol needs to function. This is answered against the current symbol class, so supplying a different 'symbolClassDefinition' can change the answer for a given path. Returns false for a path this SymbolReel has no KeyframedValue for.

SymbolReel.getPathValueIsValid parameter: path
[type: string] 
The property path, relative to a symbol object, given in dot notation.





SymbolReel.addReelStateChangeCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever the 'reelState' of this SymbolReel changes. The new reelState and the previous reelState are sent to the callback as its first two parameters.

SymbolReel.addReelStateChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

SymbolReel.addReelStateChangeCallback parameter: callbackName
[type: string] 
The name of the callback function.

SymbolReel.addReelStateChangeCallback parameter: callbackArgs
[type: Array, any] [optional] 
Parameters for the callback function, supplied after the new and previous reelState.





SymbolReel.removeReelStateChangeCallback(callbackOwner, callbackName)
[type: function] 
Removes the given callback.

SymbolReel.removeReelStateChangeCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

SymbolReel.removeReelStateChangeCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.



























































































































































































































































































































----------------------------------------------------------
Section 187: UxVectorSupervisorTextField
----------------------------------------------------------


UxVectorSupervisorTextField
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. Supervisors provide the means for users to both monitor and manipulate properties within the project during runtime. This particular object is meant to supervise a Vector property, with the user able to adjust the value by adjusting the individual component UxNumberSupervisorTextFields. When multiple diverging component values are supervised, a '-' is shown. This supervisor edits the component values of the supervised Vector instances directly; it does not replace whole Vector references. 'Ux' supervisors operate exclusively on arrays of values, ensuring support for supervising multiple values at once. 





UxVectorSupervisorTextField.propertyOwners
[type: Array] [default: undefined] 
Array of objects owning the properties being supervised. UxVectorSupervisorTextField can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. Unlike supervisors for primitives, this class does not use a propertySetter function, because it is only meant to edit the component values of existing Vector objects, not replace whole Vector references. When using the getter method, the getter must return the actual Vector objects being supervised, not copies. Both methods always operate on Arrays, ensuring support for supervising multiple values. To use a particular method, leave the members associated with the other method undefined.





UxVectorSupervisorTextField.propertyPath
[type: string] [default: ""] 
A period-separated string representing the 'dot path' or 'dereference chain' from each owner object to the property being supervised. For example if you are supervising the scale of a SceneObject's parent this value would be 'parent.scale'. UxVectorSupervisorTextField can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. Unlike supervisors for primitives, this class does not use a propertySetter function, because it is only meant to edit the component values of existing Vector objects, not replace whole Vector references. When using the getter method, the getter must return the actual Vector objects being supervised, not copies. Both methods always operate on Arrays, ensuring support for supervising multiple values. To use a particular method, leave the members associated with the other method undefined.





UxVectorSupervisorTextField.propertyGetterOwner
[type: object] [default: undefined] 
The object owning the function used to get the array of supervised values. UxVectorSupervisorTextField can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. Unlike supervisors for primitives, this class does not use a propertySetter function, because it is only meant to edit the component values of existing Vector objects, not replace whole Vector references. When using the getter method, the getter must return the actual Vector objects being supervised, not copies. Both methods always operate on Arrays, ensuring support for supervising multiple values. To use a particular method, leave the members associated with the other method undefined.





UxVectorSupervisorTextField.propertyGetterName
[type: string] [default: undefined] 
The name of the function used to get the array of supervised values. UxVectorSupervisorTextField can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. Unlike supervisors for primitives, this class does not use a propertySetter function, because it is only meant to edit the component values of existing Vector objects, not replace whole Vector references. When using the getter method, the getter must return the actual Vector objects being supervised, not copies. Both methods always operate on Arrays, ensuring support for supervising multiple values. To use a particular method, leave the members associated with the other method undefined.





UxVectorSupervisorTextField.propertyGetterArgs
[type: Array, any] [default: undefined] 
Parameters for the function used to get the array of supervised values. UxVectorSupervisorTextField can be set up to supervise values using 2 methods: by using the propertyOwners Array and the propertyPath string, or by using a propertyGetter function. Unlike supervisors for primitives, this class does not use a propertySetter function, because it is only meant to edit the component values of existing Vector objects, not replace whole Vector references. When using the getter method, the getter must return the actual Vector objects being supervised, not copies. Both methods always operate on Arrays, ensuring support for supervising multiple values. To use a particular method, leave the members associated with the other method undefined.





UxVectorSupervisorTextField.componentSupervisors
[type: [UxNumberSupervisorTextField]] 
The array of UxNumberSupervisorTextField objects that represent the supervised Vector. It should be noted that the individual component supervisors are usually made on the fly as needed, and that though up to 4 may be created, only those needed given the supervised Vector's dimension will be enabled and displayed. If direct access to the component supervisors is needed immediately, you can call "prepopulateComponentSupervisors", which prepopulates as many component supervisors as needed.





UxVectorSupervisorTextField.textFormat
[type: TextFormat] [default: nc.uiStyle.textFormat_body.clone()] 
the TextFormat of all of the text items within the supervisor, which is also used to scale graphical components.





UxVectorSupervisorTextField.isActive
[type: boolean] [default: true] 
Boolean determining if the supervisor is interactive. When false, the supervisor has a dim appearance and all buttons are disabled.





UxVectorSupervisorTextField.singularFocusTarget
[type: SceneObject] [default: undefined] 
When set, restricts keyboard focus so that only one component text field can hold focus at a time within the specified target. Setting this property propagates the value to all current and future component UxNumberSupervisorTextFields automatically.





UxVectorSupervisorTextField.prepopulateComponentSupervisors(numComponents)
[type: function] 
Populates component supervisors (UxNumberSupervisorTextFields). Individual component supervisors are usually made on the fly as needed, but if immediate access is required this method can be invoked to populate the supervisors on-command.

UxVectorSupervisorTextField.prepopulateComponentSupervisors parameter: numComponents
[type: number] [optional] 
The number of component supervisors to prepopulate.





UxVectorSupervisorTextField.sync()
[type: function] 
Method brings this UxVectorSupervisorTextField and each of its component supervisors up to date with the values they supervise, without waiting for the next fixedUpdate. This method is automatically called every fixedUpdate.





















































































































































































































































































































































































































----------------------------------------------------------
Section 188: TextBox
----------------------------------------------------------


TextBox
[type: class] [extends: Button] 
A specialized Button that renders text to it's texture. All TextBoxes are connected to an internal text-rendering scene that renders directly to the given TextBox's RenderTarget. TextBoxes have 3 editing modes: none, selectable, and editable. Though TextBoxes inherit from Button, their default value for "buttonActive" value is false when the editing mode is set to 'none' TextBoxes tend to be more performant than TextAssemblies, since the resulting object is singular vs the many character-children of TextAssemblies.





TextBox.type
[type: string] 
Type identifier.





TextBox.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





TextBox.string
[type: string] [default: ""] 
The string value of the text to be displayed by this TextBox. Setting this value directly clears the 'phraseID' property of this TextBox (if applicable).

example:
// Objective: Set the text of a TextBox.
// Expected Result: You will see "My Text" on screen.

this.textBox = new TextBox();
this.textBox.string = "My Text";





TextBox.phraseID
[type: string] [default: undefined] 
Property to set this TextBox's string based on the associated phrase in the ProjectTranscript, which is updated based on the current language setting of the project. See 'nc.phraseIDs' for a list of available phrases.

example:
// Objective: Set the text of a TextBox based on a phrase defined in the ProjectTranscript.
// Expected Result: You will see "Hello World" on screen if the project language is 'en', or "Hola Mundo" if the language is 'es'.

this.textBox = new TextBox();
this.textBox.phraseID = nc.phraseIDs["Hello World"];





TextBox.boxWidth
[type: number] [default: 0] 
The maximum width that the laid out text will adhere to if 'wrapToFit' or 'scaleToFit' are true. When greater than 0, this value also determines the positioning of left or right justified text. A value of 0 corresponds to no limits on the width of the text.





TextBox.boxHeight
[type: number] [default: 0] 
The maximum height that the laid out text will adhere to if 'scaleToFit' is true. When greater than 0, this value also determines the positioning of top-justified or bottom-justified text. A value of 0 corresponds to no limits on the height of the text.





TextBox.wrapToFit
[type: boolean] [default: true] 
Bool determining if text will automatically flow onto new lines in order to fit the text within the designated 'boxWidth' value.





TextBox.scaleToFit
[type: boolean] [default: true] 
Bool determining if the text will automatically be scaled down to fit within the boxWidth and/or boxHeight.





TextBox.horizontalJustification
[type: string] [default: 'left'] 
The horizontalJustification of this TextBox. For acceptable values, see 'nc.constants.justfications'. Setting this value will change the horizontal justification for all of the text in this TextBox, but the value can be set for individual sections of the text using 'TextBox.setHorizontalJustification'.





TextBox.verticalJustification
[type: string] [default: 'top'] 
The verticalJustification of this TextBox. For acceptable values, see 'nc.constants.justfications'. Setting this value will change the vertical justification for all of the text in this TextBox.





TextBox.textWidth
[type: number] 
The read-only width of the text (once laid out). This number encapsulates the final width of the laid out text, including all of the TextFormats, the boxWidth and boxHeight, scaleToFit, wrapToFit etc...





TextBox.textHeight
[type: number] 
The read-only height of the text (once laid out). This number encapsulates the final height of the laid out text, including all of the TextFormats, the boxWidth and boxHeight, scaleToFit, wrapToFit etc...





TextBox.scaleToFitFactor
[type: number] 
For Texts or Textboxes with 'scaleToFit' set to true, this number denotes the multiplier that was applied in order for the given text to fit within the boxWidth, and boxHeight.





TextBox.baselinePosition
[type: number] [default: .22] 
Number representing the vertical placement of the baseline within each line of text in this TextBox. A value of 0 corresponds to the baseline of the text being positioned at the very bottom of each line, and a value of .5 corresponds to the baseline of the text being positioned in the middle of each line.





TextBox.textFormat
[type: TextFormat] [default: TextFormat()] 
Object housing information about the customization of the characters within this TextBox. This includes font, scale, baseline shift, kerning, line height, as well as information about EffectNodes and EffectController values used on the characters. Setting or adjusting this value will set the TextFormat for all of the characters in this TextBox. See 'TextBox.setTextFormat' to set the TextFormat for individual sections of this TextBox.





TextBox.layoutLazyUpdater
[type: LazyUpdater] 
The LazyUpdater is ultimately responsible for initiating the layout of the text. The setting of 'needsUpdate' and the calling of 'updateIfNeeded' is magaged as much as is possible internally by Incisor®, but if the need to force an update arises, set 'needsUpdate' to true, and call 'updateIfNeeded'.





TextBox.loadingTierRequirements
[type: [number]] 
A list of the loading tier requirements for this TextBox. These requirements tell the TextBox if/when the GraphicAssets used by the characters are loaded, and therefore inform when the text can first be rendered to the TextBox. If left undefined, this value will default to the loadingTierRequirements of the geometry of the first character's GraphicAssets.





TextBox.isTrimmed
[type: boolean] [default: 'false'] 
Flag determining if the Texture and Geometry of this TextBox are trimmed to fit the rendered text. If false, the Texture and Geometry will extend to the full bounds of this TextBox's boxWidth and boxHeight.





TextBox.editingMode
[type: string] [default: 'none'] 
Value determining the editing mode of this TextBox. See 'nc.constants.textBoxEditingModes' for a list of available options. When set to 'none' this TextBox is not interactive. When set to 'selectable' this TextBox is interactive via the keyboard and cursor: text in this TextBox can be selected but not edited. When set to 'editable' this TextBox is interactive via the keyboard and cursor: text in this TextBox can be selected and edited.

example:
// Objective: Edit the text of a TextBox.
// Expected Result: Click on "My Text" and edit it.

// Create a new TextBox.
this.textBox = new TextBox();
this.textBox.string = "My Text";
// Set the editingMode to editable.
this.textBox.editingMode = nc.constants.textBoxEditingModes.editable;





TextBox.highlightColor
[type: Vector4] [default: Vector4(.5,.6,1,.3)] 
The color value for the selection highlighter boxes.





TextBox.backgroundColor
[type: Vector4] [default: Vector4(0,0,0,0)] 
The background color for the TextBox.





TextBox.pivotPoint
[type: Vector2] [default: Vector2(0,0)] 
The pivot point for the TextBox, with [0,0] meaning center pivot, and [.5,.5] meaning right-top pivot. TextBoxes are center-based by default like to most GraphicObjects. It should be noted that pivotPoint and justification are seperate concepts and do not affect each other. Justification affects the alignment of the text within the bounds of the TextBox, and pivotPoint affects where the 'origin' of the TextBox is relative to those bounds.





TextBox.renderTarget
[type: RenderTarget] 
This TextBox's RenderTarget - the RenderTarget that its text gets rendered to.





TextBox.useNearestPixelRendering
[type: boolean] [default: false] 
A TextBox is ultimately 'pre-rendered' text that is positioned in the Scene and then rendered again. Because of this, certain canvas sizes or TextBox positioning can lead to slightly blurrier edges that can be noticable for small text. Calling this function can mitigate such small-text-blurriness, as it sets the downscalingMode and upscalingMode to 'nearest', and sets the 'snapToNearestWorldPosition' to true. These settings help to ensure that the TextBox texture pixels are always aligned with the canvas pixels, preserving the original crispy edges. The tradeoff with using this mode is that the position of text will appear to always snap to the nearest pixel, which can lead to jerky-looking movement at slow speeds, and also rotation and other transformations will tear badly. If these restrictions are un-workable, a "TextAssembly" is a good alternative.





TextBox.tabEndsEditing
[type: boolean] [default: true] 
Boolean determining if pressing the 'Tab' key ends the current editing session, relinquishing the focus. If this is true, and the newly focused object is a UiKeybaordNavigator, then the keyboard navigation would also be advanced. If this value is false, then pressing the 'Tab' key inserts 3 spaces.





TextBox.returnEndsEditing
[type: boolean] [default: true] 
Boolean determining if pressing the 'Return' key ends the current editing session, relinquishing the focus. If this value is false, then pressing the 'Return' key inserts a newline.





TextBox.upDownArrowEndsEditing
[type: boolean] [default: false] 
Boolean determining if pressing the ArrowUp or ArrowDown keys ends the current editing session. When true and a UiKeyboardNavigator is active, the corresponding directional navigation (goTowards) is also triggered.





TextBox.leftRightArrowEndsEditing
[type: boolean] [default: false] 
Boolean determining if pressing the ArrowLeft or ArrowRight keys ends the current editing session. When true and a UiKeyboardNavigator is active, the corresponding directional navigation (goTowards) is also triggered.





TextBox.singularFocusTarget
[type: SceneObject] 
The SceneObject that 'nc.singularFocusObject' will be set to when the end-user actively selects or edits this TextBox. The default value is set to this TextBox, but in the case where this TextBox is a descendant of a SceneObject that would be a better choice for singular focus (like when a TextBox is part of a TextField etc...), this option can be used to substitute a singular focus recipient.





TextBox.showWhiteSpace
[type: boolean] [default: false] 
Boolean indicating if whitespace characters will be visible in this TextBox.





TextBox.numHorizontalGridSegments
[type: number] [default: 1] 
The number of horizontal grid segments that will be used in this TextBox's Geometry.





TextBox.numVerticalGridSegments
[type: number] [default: 1] 
The number of vertical grid segments that will be used in this TextBox's Geometry.





TextBox.canvasSizeResolutionScaling
[type: number] 
A boolean determining if the resolution of this TextBox is affected by the scale of the canvas relative to it's core dimensions. In other words, if this flag is false, then the TextBox's RenderTarget is a static resolution, and if it is true then the RenderTarget will get bigger when the canvas is displayed bigger, and smaller as the canvas is shrunk. This flag effectively sets the 'canvasSizeResolutionScaling' value of this TextBox's RenderTarget, but in addition, it connects the TextBox to the 'canvasResize' appEvent, informing the TextBox to re-render whenever the canvas is resized.





TextBox.htmlBacking
[type: HtmlBacking] 
Object that allows this TextBox to be backed by a hidden HTML text input element. This allows mobile virtual keyboards to appear automatically when focusing on an Incisor TextBox.





TextBox.setSubstitutionCharacter(characterToSubstitute, graphicAsset, textFormat)
[type: function] 
Method used to swap all instances of the given character with a designated GraphicAsset. A TextFormat can also be supplied to help position and format the substituted GraphicAsset within the text.

TextBox.setSubstitutionCharacter parameter: characterToSubstitute
[type: string] 
The the character that will be replaced with the designated GraphicAsset.

TextBox.setSubstitutionCharacter parameter: graphicAsset
[type: GraphicAsset] 
The GraphicAsset that will substitute for the given characters.

TextBox.setSubstitutionCharacter parameter: textFormat
[type: TextFormat] [optional] 
Optional TextFromat to apply to the substituted GraphicAsset, which can be used to adjust its positioning and formating.

example:
// Objective: Substitute a character in a TextBox.
// Expected Result: The letter "A" in the word "PLAY" will be replaced by a white triangle.

// Create a new TextBox.
this.textBox = new TextBox();
this.textBox.string = "PRESS PLAY";

// Replace the letter A with a white triangle.
this.textBox.setSubstitutionCharacter( "A", nc.graphicAssets.WhiteTriangle );

// Create a TextFormat, update some of its properties and set it on the TextBox.
let textFormat = new TextFormat();
textFormat.kerning = 2;
textFormat.characterScaleY = .5;
textFormat.characterScaleX = .5;
textFormat.verticalShift = .50;
this.textBox.setTextFormat( textFormat, 8, 1 );





TextBox.setTextFormat(textFormat, startIdx, numChars)
[type: function] 
Sets the text format of the designated portion of text within a TextBox.

TextBox.setTextFormat parameter: textFormat
[type: TextFormat] 
The TextFormat that the specified characters will adopt.

TextBox.setTextFormat parameter: startIdx
[type: number] [optional] 
The index of the first character in the segment affected by this change. If left undefined, the given textFormat will be applied to all characters.

TextBox.setTextFormat parameter: numChars
[type: number] [default: infinity] [optional] 
The length of the segment affected by this change.

example:
// Objective: Use a TextFormat to manipulate characters in a TextBox.
// Expected Result: You will see the phrase "I Love Incisor". The word "Love" and the letter "I" in Incisor will be stretched and given extra space.

// Create a new TextBox.
this.textBox = new TextBox();
this.textBox.string = "I Love Incisor";
// Create a TextFormat and update some of its properties.
let textFormat = new TextFormat();
textFormat.kerning = 3;
textFormat.characterScaleY = 3;
textFormat.characterScaleX = 1.5;
// Set the TextFormat and provide the start index and number of characters affected.
this.textBox.setTextFormat( textFormat, 2, 6 );





TextBox.setHorizontalJustification(justification, startIdx, numChars)
[type: function] 
Sets the horizontal justification of the given range of characters. It should be noted that when characters are laid out into multiple lines, the horizontal justification for a given line is determined by the horizontal horizontalJustification value associated with the first character on that line.

TextBox.setHorizontalJustification parameter: justification
[type: string] 
The horizontal justification that the specified characters will adopt. See 'nc.constants.justifications' for justification values.

TextBox.setHorizontalJustification parameter: startIdx
[type: number] [optional] 
The index of the first character in the segment affected by this change. If left undefined, the given horizontalJustification will be applied to all characters.

TextBox.setHorizontalJustification parameter: numChars
[type: number] [default: infinity] [optional] 
The length of the segment affected by this change.





TextBox.insert(startIndex, stringToInsert)
[type: function] 
Inserts the given string at the given index.

TextBox.insert parameter: startIndex
[type: number] 
The index that the first character of the inserted string.

TextBox.insert parameter: stringToInsert
[type: string] 
The string to insert.





TextBox.delete(startIndex, count)
[type: function] 
Deletes the given range of characters.

TextBox.delete parameter: startIndex
[type: number] 
The index of the first character to delete.

TextBox.delete parameter: count
[type: number] 
The number of characters to delete.





TextBox.clearPools()
[type: function] 
Several object-pooling techniques are used internally within the TextAssembly and TextBox objects. Displaying/rendering text with large numbers of characters can leave a significant memory-footprint in these pools. This memory can be freed by calling this method - though the call itself may result in a one-time performance hit if large strings have been displayed/rednered previously.





TextBox.getSelectionRange()
[type: function] [returns: RangeInfo] 
Returns an object containing the start index, end index, and character count of the current selection. If the current selection is empty the values in the returned object will be -1.





TextBox.selectRange(startIndex, count)
[type: function] 
Selects the given range of characters.

TextBox.selectRange parameter: startIndex
[type: number] [default: 0] [optional] 
The first index of the desired range to select. If left undefined, the entire text will be selected.

TextBox.selectRange parameter: count
[type: number] [optional] 
The number of characters to be selected.





TextBox.addStringUpdateCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever this TextBox string changed (even during editing). The updated string is sent to the callback as its first parameter.

TextBox.addStringUpdateCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this TextBox string changed.

TextBox.addStringUpdateCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this TextBox string changed.

TextBox.addStringUpdateCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that occurs whenever this TextBox string changed.





TextBox.removeStringUpdateCallback(callbackOwner, callbackName)
[type: function] 
Removes the given stringUpdate callback.

TextBox.removeStringUpdateCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

TextBox.removeStringUpdateCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





TextBox.addStartEditCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs when this TextBox's 'editingMode' is changed to 'editing'. No parameters are sent to the callback.

TextBox.addStartEditCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs when this TextBox begins editing.

TextBox.addStartEditCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs when this TextBox begins editing.

TextBox.addStartEditCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that occurs when this TextBox begins editing.





TextBox.removeStartEditCallback(callbackOwner, callbackName)
[type: function] 
Removes the given startEdit callback.

TextBox.removeStartEditCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

TextBox.removeStartEditCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





TextBox.addEditCommitCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever this TextBox's 'editingMode' is changed from 'constants.textBoxEditingModes.editing' to any other value. The updated string is sent to the callback as its first parameter, and the original string is sent as the second parameter.

TextBox.addEditCommitCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever this TextBox string changed.

TextBox.addEditCommitCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever this TextBox string changed.

TextBox.addEditCommitCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that occurs whenever this TextBox string changed.





TextBox.removeEditCommitCallback(callbackOwner, callbackName)
[type: function] 
Removes the given editCommit callback.

TextBox.removeEditCommitCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

TextBox.removeEditCommitCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





















































































































































































































































































































































































































































































































































































----------------------------------------------------------
Section 189: HtmlBacking
----------------------------------------------------------


HtmlBacking
[type: class] [NON-INSTANTIABLE] 
Object that allows this TextBox to be backed by a hidden HTML text input element. This allows mobile virtual keyboards to appear automatically when focusing on an Incisor TextBox. 





HtmlBacking.enabled
[type: boolean] 
Boolean determining if HTML backing is enabled. When enabled, an HTML textbox is added to the parent of the canvas element, and text input is routed through this hidden input, which allows support for mobile virtual keyboards.





HtmlBacking.autoPosition
[type: boolean] 
Boolean determining whether the HTML textbox will be automatically places at the same coordinates as the canvas element when Incisor TextBox editing begins.










----------------------------------------------------------
Section 190: RangeInfo
----------------------------------------------------------


RangeInfo
[type: class] [NON-INSTANTIABLE] 
Object describing a range of indices, including a startIndex, endIndex, and count. 





RangeInfo.startIndex
[type: number] 
The first index included in the range of indices.





RangeInfo.endIndex
[type: number] 
The lase index included in the range of indices.





RangeInfo.count
[type: number] 
The number of indices included in the range.










----------------------------------------------------------
Section 191: Pdf
----------------------------------------------------------


Pdf
[type: class] [requires: unpublished only] 
Object that can be used to define a PDF file, which can then be written to disk.





Pdf.type
[type: string] 
Type identifier.





Pdf.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





Pdf.defaultFontSize
[type: number] [default: 40] 
The default font size for text within this Pdf.





Pdf.defaultFontName
[type: string] [default: "Noto Sans"] 
The default font for text within this Pdf. Please note that any fonts (ttf or otf files) used within Pdfs must reside within the 'Pdf Fonts' directory of the Incisor® application support directory, which can be accessed from the Incisor® menu.





Pdf.defineFont(name, regularFontFileName, boldFontFileName, italicFontFileName, boldItalicFontFileName)
[type: function] 
Defines a new font that can be used within this Pdf. Please note that any fonts (ttf or otf files) used within Pdfs must reside within the 'Pdf Fonts' directory of the Incisor® application support directory, which can be accessed from the Incisor® menu.

Pdf.defineFont parameter: name
[type: string] 
The name of the newly defined font to be made available to use within this Pdf.

Pdf.defineFont parameter: regularFontFileName
[type: string] 
The name of the font file (within the application support 'Pdf Fonts' directory) to be used for regular text.

Pdf.defineFont parameter: boldFontFileName
[type: string] [default: regularFontFileName] [optional] 
The name of the font file (within the application support 'Pdf Fonts' directory) to be used for bold text.

Pdf.defineFont parameter: italicFontFileName
[type: string] [default: regularFontFileName] [optional] 
The name of the font file (within the application support 'Pdf Fonts' directory) to be used for italic text.

Pdf.defineFont parameter: boldItalicFontFileName
[type: string] [default: regularFontFileName] [optional] 
The name of the font file (within the application support 'Pdf Fonts' directory) to be used for bold italic text.





Pdf.addSection()
[type: function] [returns: PdfSection] 
Adds a new PdfSection to this Pdf and returns it. A PdfSection is a group of pages with a shared style.





Pdf.writePdf(filePath, isPathRelative)
[type: function] 
Writes the Pdf file to the given path.

Pdf.writePdf parameter: filePath
[type: string] 
The relative or absolute path for the file to be written.

Pdf.writePdf parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.










----------------------------------------------------------
Section 192: PdfSection
----------------------------------------------------------


PdfSection
[type: class] [NON-INSTANTIABLE] 
A PdfSection is an object defining a group of pages within a Pdf that all share the same page style. To make a new PdfSection, call 'addSection' on the Pdf you wish to add the section to. 





PdfSection.type
[type: string] 
Type identifier.





PdfSection.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PdfSection.pageWidth
[type: number] [default: 2550] 
The width of the pages within this PdfSection.





PdfSection.pageHeight
[type: number] [default: 3300] 
The height of the pages within this PdfSection.





PdfSection.leftMargin
[type: number] [default: 150] 
The size of the left margin of the pages within this PdfSection.





PdfSection.rightMargin
[type: number] [default: 150] 
The size of the right margin of the pages within this PdfSection.





PdfSection.topMargin
[type: number] [default: 150] 
The size of the top margin of the pages within this PdfSection.





PdfSection.bottomMargin
[type: number] [default: 150] 
The size of the bottom margin of the pages within this PdfSection.





PdfSection.backgroundImage
[type: PdfImage] [default: undefined] 
The path of the backgroundImage within this PdfSection.





PdfSection.header
[type: PdfHeader] 
The header element for this PdfSection.





PdfSection.footer
[type: PdfFooter] 
The footer element for this PdfSection.





PdfSection.addParagraph()
[type: function] [returns: PdfParagraph] 
Adds a new PdfParagraph to this PdfSection and returns it. A PdfParagraph is simply a block of text.





PdfSection.addBackgroundImage(imagePath, isPathRelative, justificationH, justificationV)
[type: function] 
Adds a background image to this PdfSection.

PdfSection.addBackgroundImage parameter: imagePath
[type: string] 
The path of the background image being added within this PdfSection.

PdfSection.addBackgroundImage parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

PdfSection.addBackgroundImage parameter: justificationH
[type: string] [default: "center"] [optional] 
The horizontal justification of the background image being added to this PdfSection. For acceptable values, see 'nc.constants.justfications'.

PdfSection.addBackgroundImage parameter: justificationV
[type: string] [default: "center"] [optional] 
The vertical justification of the background image being added to this PdfSection. For acceptable values, see 'nc.constants.justfications'.





PdfSection.addImage(imagePath, isPathRelative, justificationH, justificationV)
[type: function] [returns: PdfImage] 
Adds a new Image to this PdfSection and returns it.

PdfSection.addImage parameter: imagePath
[type: string] 
The path of the image being added within this PdfSection.

PdfSection.addImage parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

PdfSection.addImage parameter: justificationH
[type: string] [default: "center"] [optional] 
The horizontal justification of the image being added to this PdfSection. For acceptable values, see 'nc.constants.justfications'.

PdfSection.addImage parameter: justificationV
[type: string] [default: "center"] [optional] 
The vertical justification of the image being added to this PdfSection. For acceptable values, see 'nc.constants.justfications'.





PdfSection.addTable(numRows, numCols, columnWidths)
[type: function] [returns: PdfTable] 
Adds a new PdfTable to this PdfSection and returns it.

PdfSection.addTable parameter: numRows
[type: number] 
The number of rows to add to this PdfTable.

PdfSection.addTable parameter: numCols
[type: number] 
The number of columns to add to each PdfRow in this PdfTable.

PdfSection.addTable parameter: columnWidths
[type: [number], number] 
An array containing the desired widths for each column in this PdfTable.





PdfSection.addTextFrame(width, height)
[type: function] [returns: PdfTextFrame] 
Adds a new PdfTextFrame to this PdfSection and returns it.

PdfSection.addTextFrame parameter: width
[type: number] 
The width of the PdfTextFrame being added.

PdfSection.addTextFrame parameter: height
[type: number] 
The height of the PdfTextFrame being added.





PdfSection.addPageBreak()
[type: function] 
Adds a page break after this PdfSection.





PdfSection.setMargins(margin)
[type: function] 
Sets all the margins of this PdfSection to a specified value.

PdfSection.setMargins parameter: margin
[type: number] 
Value to set all margins on this PdfSection to.










----------------------------------------------------------
Section 193: PdfParagraph
----------------------------------------------------------


PdfParagraph
[type: class] [NON-INSTANTIABLE] 
A PdfParagraph is an object defining a block of text and the associated formatting within a Pdf. To make a new PdfParagraph, call 'addParagraph' on the PdfSection, PdfCell, PdfHeader or PdfFooter, you wish to add the block of text to. 





PdfParagraph.type
[type: string] 
Type identifier.





PdfParagraph.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PdfParagraph.text
[type: string] [default: ""] 
The text to be displayed in this PdfParagraph.





PdfParagraph.justificationH
[type: string] [default: "center"] 
The justification of the text in this PdfParagraph. For acceptable values, see 'nc.constants.justfications'.





PdfParagraph.fontName
[type: string] [default: defaultFontName] 
The name of the font that will be used to render the text in this PdfParagraph. This value will default to the defualtFontName value of the containing Pdf. To use a new font, you must define it using "Pdf.defineFont", and also ensure that the associated font files are in the 'Pdf Fonts' directory of the Incisor® application support directory, which can be accessed from the Incisor® menu.





PdfParagraph.fontColor
[type: Color] [default: Color(0,0,0,1)] 
The color of the text in this PdfParagraph.





PdfParagraph.fontSize
[type: number] [default: defaultFontSize] 
The height of the pages within this PdfSection. This value will default to the defaultFontSize value of the containing Pdf.





PdfParagraph.spaceAfter
[type: number] [default: 0] 
The space size that will be added after this PdfParagraph.





PdfParagraph.spaceBefore
[type: number] [default: 0] 
The space size that will be added before this PdfParagraph.





PdfParagraph.leftIndent
[type: number] [default: 0] 
The left indentation amount of this PdfParagraph.





PdfParagraph.rightIndent
[type: number] [default: 0] 
The right indentation amount of this PdfParagraph.





PdfParagraph.bold
[type: boolean] [default: false] 
Boolean determining if the text in this PdfParagraph should be bold.





PdfParagraph.italic
[type: boolean] [default: false] 
Boolean determining if the text in this PdfParagraph should be italicized.





PdfParagraph.underline
[type: string] [default: ""] 
The underline type of the text in this PdfPagraph. For acceptable values, see 'nc.constants.pdfUnderlineTypes'.





PdfParagraph.addPageField()
[type: function] 
Adds a page number to the end of this PdfParagraph.










----------------------------------------------------------
Section 194: PdfHeader
----------------------------------------------------------


PdfHeader
[type: class] [NON-INSTANTIABLE] 
A PdfHeader is an object defining a heading element and the associated formatting within a PdfSection. Each section has exactly one PdfHeader. 





PdfHeader.type
[type: string] 
Type identifier.





PdfHeader.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PdfHeader.addParagraph()
[type: function] [returns: PdfParagraph] 
Adds a new PdfParagraph to this PdfHeader and returns it. A PdfParagraph is simply a block of text.





PdfHeader.addImage(imagePath, isPathRelative, justificationH, justificationV)
[type: function] [returns: PdfImage] 
Adds a new Image to this PdfHeader and returns it.

PdfHeader.addImage parameter: imagePath
[type: string] 
The path of the image being added to this PdfHeader.

PdfHeader.addImage parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

PdfHeader.addImage parameter: justificationH
[type: string] [optional] 
The horizontal justification of the image being added to this PdfHeader. For acceptable values, see 'nc.constants.justfications'.

PdfHeader.addImage parameter: justificationV
[type: string] [optional] 
The vertical justification of the image being added this PdfHeader. For acceptable values, see 'nc.constants.justfications'.





PdfHeader.addTable(numRows, numCols, columnWidths)
[type: function] [returns: PdfTable] 
Adds a new PdfTable to this PdfHeader and returns it.

PdfHeader.addTable parameter: numRows
[type: number] 
The number of rows to add to this PdfTable.

PdfHeader.addTable parameter: numCols
[type: number] 
The number of columns to add to each PdfRow in this PdfTable.

PdfHeader.addTable parameter: columnWidths
[type: [number], number] 
An array containing the desired widths for each column in this PdfTable.





PdfHeader.addTextFrame(width, height)
[type: function] [returns: PdfTextFrame] 
Adds a new PdfTextFrame to this PdfSection and returns it.

PdfHeader.addTextFrame parameter: width
[type: number] 
The width of the PdfTextFrame being added.

PdfHeader.addTextFrame parameter: height
[type: number] 
The height of the PdfTextFrame being added.










----------------------------------------------------------
Section 195: PdfFooter
----------------------------------------------------------


PdfFooter
[type: class] [NON-INSTANTIABLE] 
A PdfFooter is an object defining the footer element and associated formatting within a PdfSection. * Each section has exactly one PdfFooter. 





PdfFooter.type
[type: string] 
Type identifier.





PdfFooter.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PdfFooter.addParagraph()
[type: function] [returns: PdfParagraph] 
Adds a new PdfParagraph to this PdfHeader and returns it. A PdfParagraph is simply a block of text.





PdfFooter.addImage(imagePath, isPathRelative, justificationH, justificationV)
[type: function] [returns: PdfImage] 
Adds a new Image to this PdfFooter and returns it.

PdfFooter.addImage parameter: imagePath
[type: string] 
The path of the image being added to this PdfFooter.

PdfFooter.addImage parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

PdfFooter.addImage parameter: justificationH
[type: string] [default: "center"] [optional] 
The horizontal justification of the image being added to this PdfFooter. For acceptable values, see 'nc.constants.justfications'.

PdfFooter.addImage parameter: justificationV
[type: string] [default: "center"] [optional] 
The vertical justification of the image being added to this PdfFooter. For acceptable values, see 'nc.constants.justfications'.





PdfFooter.addTable(numRows, numCols, columnWidths)
[type: function] [returns: PdfTable] 
Adds a new PdfTable to this PdfFooter and returns it.

PdfFooter.addTable parameter: numRows
[type: number] 
The number of rows to add to this PdfTable.

PdfFooter.addTable parameter: numCols
[type: number] 
The number of columns to add to each PdfRow in this PdfTable.

PdfFooter.addTable parameter: columnWidths
[type: [number], number] 
An array containing the desired widths for each column in this PdfTable.





PdfFooter.addTextFrame(width, height)
[type: function] [returns: PdfTextFrame] 
Adds a new PdfTextFrame to this PdfSection and returns it.

PdfFooter.addTextFrame parameter: width
[type: number] 
The width of the PdfTextFrame being added.

PdfFooter.addTextFrame parameter: height
[type: number] 
The height of the PdfTextFrame being added.










----------------------------------------------------------
Section 196: PdfImage
----------------------------------------------------------


PdfImage
[type: class] 
A PdfImage is an object defining an image element within a Pdf. A PdfImage can reside within a PdfSection, PdfHeader, PdfFooter or PdfCell.





PdfImage.type
[type: string] 
Type identifier.





PdfImage.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PdfImage.isPathLocal
[type: boolean] [default: true] 






PdfImage.imagePath
[type: string] [default: ""] 






PdfImage.justificationH
[type: string] [default: "center"] 
The horizontal justification of this PdfImage. For acceptable values, see 'nc.constants.justfications'.





PdfImage.justificationV
[type: string] [default: "center"] 
The vertical justification of this PdfImage For acceptable values, see 'nc.constants.justfications'.





PdfImage.scaleWidth
[type: number] [default: 1.0] 
The horizontal scale of this PdfImage.





PdfImage.scaleHeight
[type: number] [default: 1.0] 
The vertical scale of this PdfImage.





PdfImage.scaleImage(scaleValue)
[type: function] 
Sets the horizontal and vertical scales of this PdfImage.

PdfImage.scaleImage parameter: scaleValue
[type: number] 
The factor to scale the image by.










----------------------------------------------------------
Section 197: PdfTable
----------------------------------------------------------


PdfTable
[type: class] [NON-INSTANTIABLE] 
A PdfTable is an object that represents a table element within a Pdf A PdfTable can reside within a PdfSection, PdfHeader or PdfFooter. 





PdfTable.type
[type: string] 
Type identifier.





PdfTable.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PdfTable.totalWidth
[type: number] [default: 0] 
The total width of this PdfTable. This value is derived by adding up each column width in the table.





PdfTable.leftBorderThickness
[type: number] [default: 10] 
The thickness of the left border in this PdfTable.





PdfTable.rightBorderThickness
[type: number] [default: 10] 
The thickness of the right border in this PdfTable.





PdfTable.bottomBorderThickness
[type: number] [default: 10] 
The thickness of the bottom border in this PdfTable.





PdfTable.topBorderThickness
[type: number] [default: 10] 
The thickness of the top border in this PdfTable.





PdfTable.diagonalDownThickness
[type: number] [default: 0] 
The thickness of the diagonalDown (top left to bottom right diagonal) in this PdfTable.





PdfTable.diagonalUpThickness
[type: number] [default: 0] 
The thickness of the diagonalUp (top right to bottom left diagonal) in this PdfTable.





PdfTable.leftBorderColor
[type: Color] [default: Color(0,0,0,1)] 
The color of the left border in this PdfTable.





PdfTable.rightBorderColor
[type: Color] [default: Color(0,0,0,1)] 
The color of the right border in this PdfTable.





PdfTable.bottomBorderColor
[type: Color] [default: Color(0,0,0,1)] 
The color of the bottom border in this PdfTable.





PdfTable.topBorderColor
[type: Color] [default: Color(0,0,0,1)] 
The color of the top border in this PdfTable.





PdfTable.diagonalDownColor
[type: Color] [default: Color(1,1,1,1)] 
The color of the diagonalDown (top left to bottom right diagonal) in this PdfTable.





PdfTable.diagonalUpColor
[type: Color] [default: Color(1,1,1,1)] 
The thickness of the diagonalUp (top right to bottom left diagonal) in this PdfTable.





PdfTable.rows
[type: [PdfRow]] [default: []] 
An array containing the PdfRows that reside in this PdfTable.





PdfTable.numColumns
[type: number] [default: 0] 
The number of columns for each row in this PdfTable.





PdfTable.setBorder(thickness, color)
[type: function] 
Sets the thickness and color for all borders in this PdfTable.

PdfTable.setBorder parameter: thickness
[type: number] [optional] 
The thickness to set all borders to.

PdfTable.setBorder parameter: color
[type: Color] [optional] 
The color to set all borders to.





PdfTable.addRow()
[type: function] 
Adds a PdfRow to this PdfTable.





PdfTable.getCell(row, column)
[type: function] [returns: PdfCell, undefined] 
Returns the PdfCell at the given row and column if it exists.

PdfTable.getCell parameter: row
[type: number] 
The row of the cell to get.

PdfTable.getCell parameter: column
[type: number] 
The column of the cell to get.










----------------------------------------------------------
Section 198: PdfRow
----------------------------------------------------------


PdfRow
[type: class] [NON-INSTANTIABLE] 
A PdfRow is an object that represents a row that resides within a PdfTable. 





PdfRow.type
[type: string] 
Type identifier.





PdfRow.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PdfRow.height
[type: number] [default: 50] 
The height of this PdfRow.





PdfRow.heightRule
[type: string] [default: "autoFit"] 
Setting that determines how the height of a row is calculated in this table. For acceptable values, see 'nc.constants.pdfHeightRuleTypes'.





PdfRow.cells
[type: [PdfCell]] [default: []] 
Array of PdfCells that reside within this PdfRow.










----------------------------------------------------------
Section 199: PdfCell
----------------------------------------------------------


PdfCell
[type: class] [NON-INSTANTIABLE] 
A PdfCell is an object that resides within a PdfRow and can contain PdfParagraphs, PdfImages and PdfTables within it. 





PdfCell.type
[type: string] 
Type identifier.





PdfCell.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PdfCell.backgroundColor
[type: Color] [default: Color(1,1,1,1)] 
The background color of this PdfCell.





PdfCell.justificationV
[type: string] [default: "center"] 
The verticialJustifcation of this PdfCell. For acceptable values, see 'nc.constants.justfications'.





PdfCell.justificationH
[type: string] [default: "center"] 
The horizontalJustifcation of this PdfCell. For acceptable values, see 'nc.constants.justfications'.





PdfCell.leftIndent
[type: number] [default: 0] 
The left indentation amount of this PdfCell.





PdfCell.rightIndent
[type: number] [default: 0] 
The right indentation amount of this PdfCell.





PdfCell.leftBorderThickness
[type: number] [default: 1] 
The thickness of the left border in this PdfCell.





PdfCell.rightBorderThickness
[type: number] [default: 1] 
The thickness of the right border in this PdfCell.





PdfCell.bottomBorderThickness
[type: number] [default: 1] 
The thickness of the bottom border in this PdfCell.





PdfCell.topBorderThickness
[type: number] [default: 1] 
The thickness of the top border in this PdfCell.





PdfCell.diagonalDownThickness
[type: number] [default: 0] 
The thickness of the diagonalDown (top left to bottom right diagonal) in this PdfCell.





PdfCell.diagonalUpThickness
[type: number] [default: 0] 
The thickness of the diagonalUp (top right to bottom left diagonal) in this PdfCell.





PdfCell.leftBorderColor
[type: Color] [default: Color(0,0,0,1)] 
The color of the left border in this PdfCell.





PdfCell.rightBorderColor
[type: Color] [default: Color(0,0,0,1)] 
The color of the right border in this PdfCell.





PdfCell.bottomBorderColor
[type: Color] [default: Color(0,0,0,1)] 
The color of the bottom border in this PdfCell.





PdfCell.topBorderColor
[type: Color] [default: Color(0,0,0,1)] 
The color of the top border in this PdfCell.





PdfCell.diagonalDownColor
[type: Color] [default: Color(1,1,1,1)] 
The color of the diagonalDown (top left to bottom right diagonal) in this PdfCell.





PdfCell.diagonalUpColor
[type: Color] [default: Color(1,1,1,1)] 
The thickness of the diagonalUp (top right to bottom left diagonal) in this PdfCell.





PdfCell.spaceAfter
[type: number] [default: 0] 
The space size that will be added after this PdfCell.





PdfCell.spaceBefore
[type: number] [default: 0] 
The space size that will be added before this PdfCell.





PdfCell.setBorder(thickness, color)
[type: function] 
Sets the thickness and color for all borders in this PdfCell.

PdfCell.setBorder parameter: thickness
[type: number] [optional] 
The thickness to set all borders to.

PdfCell.setBorder parameter: color
[type: Color] [optional] 
The color to set all borders to.





PdfCell.addParagraph()
[type: function] [returns: PdfParagraph] 
Adds a new PdfParagraph to this PdfCell and returns it. A PdfParagraph is simply a block of text.





PdfCell.addImage(imagePath, isPathRelative, justificationH)
[type: function] [returns: PdfImage] 
Adds a new Image to this PdfCell and returns it.

PdfCell.addImage parameter: imagePath
[type: string] 
The path of the image being added within this PdfCell.

PdfCell.addImage parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

PdfCell.addImage parameter: justificationH
[type: string] [default: "center"] [optional] 
The horizontal justification of the image being added to this PdfCell. For acceptable values, see 'nc.constants.justfications'.





PdfCell.addTable(numRows, numCols, columnWidths)
[type: function] [returns: PdfTable] 
Adds a new PdfTable to this PdfCell and returns it.

PdfCell.addTable parameter: numRows
[type: number] 
The number of rows to add to this PdfTable.

PdfCell.addTable parameter: numCols
[type: number] 
The number of columns to add to each PdfRow in this PdfTable.

PdfCell.addTable parameter: columnWidths
[type: [number], number] 
An array containing the desired widths for each column in this PdfTable.





PdfCell.mergeCellRight(numberOfCells)
[type: function] 
Merges this cell right by a specificed number of cells.

PdfCell.mergeCellRight parameter: numberOfCells
[type: number] 
The number of cells to merge.





PdfCell.addTextFrame(width, height)
[type: function] [returns: PdfTextFrame] 
Adds a new PdfTextFrame to this PdfSection and returns it.

PdfCell.addTextFrame parameter: width
[type: number] 
The width of the PdfTextFrame being added.

PdfCell.addTextFrame parameter: height
[type: number] 
The height of the PdfTextFrame being added.










----------------------------------------------------------
Section 200: PdfTextFrame
----------------------------------------------------------


PdfTextFrame
[type: class] [NON-INSTANTIABLE] 
A PdfTextFrame is an object that resides within a PdfSection, PdfHeader or PdfFooter and can contain PdfParagraphs, PdfImages and PdfTables within it. 





PdfTextFrame.type
[type: string] 
Type identifier.





PdfTextFrame.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





PdfTextFrame.leftMargin
[type: number] [default: 0] 
The size of the left margin of the pages within this PdfTextFrame.





PdfTextFrame.rightMargin
[type: number] [default: 0] 
The size of the right margin of the pages within this PdfTextFrame.





PdfTextFrame.topMargin
[type: number] [default: 0] 
The size of the top margin of the pages within this PdfTextFrame.





PdfTextFrame.bottomMargin
[type: number] [default: 0] 
The size of the bottom margin of the pages within this PdfTextFrame.





PdfTextFrame.height
[type: number] [default: 0] 
The height of this PdfTextFrame.





PdfTextFrame.width
[type: number] [default: 0] 
The width of this PdfTextFrame.





PdfTextFrame.addParagraph()
[type: function] [returns: PdfParagraph] 
Adds a new PdfParagraph to this PdfTextFrame and returns it. A PdfParagraph is simply a block of text.





PdfTextFrame.addImage(imagePath, isPathRelative, justificationH, justificationV)
[type: function] [returns: PdfImage] 
Adds a new Image to this PdfTextFrame and returns it.

PdfTextFrame.addImage parameter: imagePath
[type: string] 
The path of the image being added within this PdfTextFrame.

PdfTextFrame.addImage parameter: isPathRelative
[type: boolean] [default: true] [optional] 
Bool stating if the given path is relative to the project path or an absolute path. If an absolute path is used that is outside of the project directory, the 'allowUniversalFileIO' item in application settings must be set to true.

PdfTextFrame.addImage parameter: justificationH
[type: string] [default: "center"] [optional] 
The horizontal justification of the image being added to this PdfTextFrame. For acceptable values, see 'nc.constants.justfications'.

PdfTextFrame.addImage parameter: justificationV
[type: string] [default: "center"] [optional] 
The vertical justification of the image being added to this PdfTextFrame. For acceptable values, see 'nc.constants.justfications'.





PdfTextFrame.addTable(numRows, numCols, columnWidths)
[type: function] [returns: PdfTable] 
Adds a new PdfTable to this PdfTextFrame and returns it.

PdfTextFrame.addTable parameter: numRows
[type: number] 
The number of rows to add to this PdfTextFrame.

PdfTextFrame.addTable parameter: numCols
[type: number] 
The number of columns to add to each PdfRow in this PdfTextFrame.

PdfTextFrame.addTable parameter: columnWidths
[type: [number], number] 
An array containing the desired widths for each column in this PdfTextFrame.










----------------------------------------------------------
Section 201: CursorInputOverrideButton
----------------------------------------------------------


CursorInputOverrideButton
[type: class] [extends: Button] 
CursorInputOverrideButtons are specialized Buttons that serve as 'cursor input remapping surfaces'. These objects can be connected to Cameras (via Camera.cursorInputOverride), and serve as the means to map cursor input from an outer Scene into an inner Scene. When connected, the moving the cursor around the inside edge of the CursorInputOverrideButton will map the cursor to the inner edge of the Camera's viewing area within the Scene that the Camera is rendering. This only applies to Cameras whose 'cursorInteractive' property is set to true.





CursorInputOverrideButton.allowExtendedDrag
[type: boolean] [default: false] 
Flag determining if items within the inner scene can be dragged outside of the bounds of the viewing camera.































































































































































































































































































































































































































































































































































































----------------------------------------------------------
Section 202: UiMenu
----------------------------------------------------------


UiMenu
[type: class] [extends: SceneObject] [requires: module - extendedUi] 
A ui-specialized SceneObject that functions as a menu with menuItem options that can be selected with the cursor or with keyboard navigation. UI functionality includes:  • pre-configured with LayoutObject functionality.  • uiStyle TextFormats and Colors applied.  • pre-configured with 'UiKeyboardNavigable' functionality.  • uiZoom-enabled.  • pre-configured with 'UiVisualFocus' functionality.  • nearestPixelRendering-enabled.





UiMenu.isOpen
[type: boolean] [default: false] 
Boolean determining if the menu is open or closed.





UiMenu.menuBackground
[type: UiPanel] 
The UiPanel shown behind the UiMenuItem options in this UiMenu.





UiMenu.searchable
[type: boolean] 
Boolean determining if a search UiTextField appears at the top of the menu. When true, end-users can type in the field to filter the options shown in the UiMenu.





UiMenu.searchBarMenuItem
[type: UiMenuItem] 
The search bar UiMenuItem.





UiMenu.searchIconScaleFactor
[type: number] 
Scale multiplier for the search icon graphic.





UiMenu.minWidth
[type: number] 
The minimum width of the UiMenu.





UiMenu.textFormat
[type: TextFormat] 
The default TextFormat for the text within the UiMenu.





UiMenu.menuItemBackgroundColor
[type: Color] 
The default Color for the UiMenuItem backgrounds.





UiMenu.textColor
[type: Color] 
The default Color for the active text within the UiMenu.





UiMenu.inactiveTextColor
[type: Color] 
The default Color for the inactive text within the UiMenu.





UiMenu.textBuffer
[type: number] 
The size of the buffer spacer around and between text.





UiMenu.parentMenu
[type: UiMenu] 
If this UiMenu is a subMenu, then this property will be populated with the parent UiMenu, otherwise it will be undefined.





UiMenu.singularFocusTarget
[type: SceneObject] 
The SceneObject that 'nc.singularFocusObject' will be set to when this UiMenu opens. The default value is set to this UiMenu, but in the case where this UiMenu is a descendant of a SceneObject that would be a better choice for singular focus (like when a UiMenu is part of a UiDropDownMenu etc...), this option can be used to substitute a singular focus recipient.





UiMenu.addMenuItem(name, leftIconGraphicAsset, secondaryString, rightIconGraphicAsset, index)
[type: function] [returns: UiMenuItem] 
Adds a new UiMenuItem to the UiMenu.

UiMenu.addMenuItem parameter: name
[type: string] 
The string that will appear in the UiMenu.

UiMenu.addMenuItem parameter: leftIconGraphicAsset
[type: GraphicAsset] [optional] 
Optional GraphicAsset to include on the left side of the UiMenuItem.

UiMenu.addMenuItem parameter: secondaryString
[type: string] [optional] 
Optional secondary string to display on the right side of the UiMenuItem

UiMenu.addMenuItem parameter: rightIconGraphicAsset
[type: GraphicAsset] [optional] 
Optional GraphicAsset to include on the right side of the UiMenuItem.

UiMenu.addMenuItem parameter: index
[type: number] [optional] 
Index array location to insert the new UiMenuItem.





UiMenu.removeMenuItem(uiMenuItem)
[type: function] 
Removes a UiMenuItem.

UiMenu.removeMenuItem parameter: uiMenuItem
[type: UiMenuItem] 
The UiMenuItem to remove.





UiMenu.removeMenuItemByName(name)
[type: function] 
Removes the UiMenuItem with the given name.

UiMenu.removeMenuItemByName parameter: name
[type: string] 
The name of the UiMenuItem to remove.





UiMenu.addMenuItemTriggerCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever one of the UiMenuItems is selected via the cursor or keyboard navigation. The triggering UiMenuItem, and the UiMenu itself are sent to the callback as its first two parameters.

UiMenu.addMenuItemTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever one of the UiMenuItems is selected via the cursor or keyboard navigation.

UiMenu.addMenuItemTriggerCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever one of the UiMenuItems is selected via the cursor or keyboard navigation.

UiMenu.addMenuItemTriggerCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that occurs whenever one of the UiMenuItems is selected via the cursor or keyboard navigation.





UiMenu.removeMenuItemTriggerCallback(callbackOwner, callbackName)
[type: function] 
Removes the given trigger callback.

UiMenu.removeMenuItemTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UiMenu.removeMenuItemTriggerCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





UiMenu.addOpenCloseCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever the UiMenu is opened or closed via triggering or direct manipulation of the 'isOpen' flag. The UiMenu itself is sent to the callback as its first parameter.

UiMenu.addOpenCloseCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever the UiMenu is opened or closed.

UiMenu.addOpenCloseCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever the UiMenu is opened or closed.

UiMenu.addOpenCloseCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that occurs whenever the UiMenu is opened or closed.





UiMenu.removeOpenCloseCallback(callbackOwner, callbackName)
[type: function] 
Removes the given trigger callback.

UiMenu.removeOpenCloseCallback parameter: callbackOwner
[type: object] 
The object owning the callback to be removed.

UiMenu.removeOpenCloseCallback parameter: callbackName
[type: string] 
The name of the callback to be removed.





UiMenu.getMenuItems()
[type: function] [returns: [UiMenuItem]] 
Retuns an array of the current UiMenuItems in this UiMenu.





UiMenu.clearMenuItems()
[type: function] 
Clears all UiMenuItems.



























































































































































































































































































































----------------------------------------------------------
Section 203: UiMenuItem
----------------------------------------------------------


UiMenuItem
[type: class] [NON-INSTANTIABLE] [requires: module - extendedUi] 
A ui-specialized object with the components that comprise a menu item option within a UiMenu. UI functionality includes:  • pre-configured with LayoutObject functionality.  • uiStyle TextFormats and Colors applied.  • pre-configured with 'UiKeyboardNavigable' functionality.  • uiZoom-enabled. 





UiMenuItem.mainMenuItem
[type: TextBox, UiTextField] 
The main item showing in the UiMenu for each UiMenuItem. For all UiMenuItems except the searchBarMenuItem, this object is of type TextBox.





UiMenuItem.mainButton
[type: UiPanel] 
The main Button for the UiMenu for each UiMenuItem.





UiMenuItem.leftIconGraphicAsset
[type: GraphicAsset] 
The GraphicAsset for an optional icon to show on the left side of the UiMenuItem.





UiMenuItem.leftIconScaleFactor
[type: number] 
The scale factor for the optional icon to show on the left side of the UiMenuItem. Use this property instead of directly scaling the GraphicObject to preserve UiZoom and LayoutObject functionality.





UiMenuItem.leftIconGraphicObject
[type: GraphicObject] 
The read-only GraphicObject for the optional icon to show on the left side of the UiMenuItem.





UiMenuItem.rightIconGraphicAsset
[type: GraphicAsset] 
The GraphicAsset for an optional icon to show on the right side of the UiMenuItem.





UiMenuItem.rightIconScaleFactor
[type: number] 
The scale factor for the optional icon to show on the right side of the UiMenuItem. Use this property instead of directly scaling the GraphicObject to preserve UiZoom and LayoutObject functionality.





UiMenuItem.rightIconGraphicObject
[type: GraphicObject] 
The read-only GraphicObject for the optional icon to show on the right side of the UiMenuItem.





UiMenuItem.name
[type: string] 
The main string shown in the UiMenu for this UiMenuItem.





UiMenuItem.secondaryString
[type: string] 
The secondary string shown in the UiMenu on the right side of this UiMenuItem.





UiMenuItem.secondaryTextBox
[type: TextBox] 
The read-only TextBox for the optional secondary text to show on the right side of the UiMenuItem.





UiMenuItem.triggeringClosesMenu
[type: boolean] [default: true] 
Boolean determining if triggering this UiMenuItem automatically closes the menu.





UiMenuItem.subMenu
[type: UiMenu] 
If this UiMenuItem opens a sub-menu, then this property will be populated a reference to thed associated UiMenu, otherwise it will be undefined.





UiMenuItem.dispose()
[type: function] 
Disposes the UiMenuItem and all of its components










----------------------------------------------------------
Section 204: Constants
----------------------------------------------------------


Constants
[type: class] [NON-INSTANTIABLE] 
Object housing predefined constant values for various Incisor® options and modes. 





Constants.wrapModes
[type: dictionary] 
The available options for texture wrap modes.


Constants.wrapModes.clamp
[type: string] 
Clamps UV coordinates to the [0, 1] range so pixels outside the edge repeat the edge color.


Constants.wrapModes.repeat
[type: string] 
Tiles the texture by repeating it beyond the [0, 1] UV range.


Constants.wrapModes.mirroredRepeat
[type: string] 
Tiles the texture, mirroring it with each repeat.





Constants.textureDownscalingModes
[type: dictionary] 
The available options for texture down-scaling modes. These are the minification filters applied when a texture is displayed smaller than its native resolution.


Constants.textureDownscalingModes.linear
[type: string] 
Bilinear filtering. Interpolates between the four nearest texels for a smooth result.


Constants.textureDownscalingModes.nearest
[type: string] 
Nearest-neighbor filtering. Each pixel snaps to the closest texel, producing a sharp, pixelated result.


Constants.textureDownscalingModes.discreteMipmapNearest
[type: string] 
Selects the nearest mipmap level and applies nearest-neighbor filtering within it.


Constants.textureDownscalingModes.discreteMipmapLinear
[type: string] 
Selects the nearest mipmap level and applies bilinear filtering within it.


Constants.textureDownscalingModes.mipmapLinear
[type: string] 
Trilinear filtering. Bilinearly interpolates within each of the two nearest mipmap levels, then linearly interpolates between those results.





Constants.textureUpscalingModes
[type: dictionary] 
The available options for texture up-scaling modes. These are the magnification filters applied when a texture is displayed larger than its native resolution.


Constants.textureUpscalingModes.linear
[type: string] 
Bilinear filtering. Interpolates between the nearest texels for a smooth result.


Constants.textureUpscalingModes.nearest
[type: string] 
Nearest-neighbor filtering. Each pixel snaps to the closest texel, producing a sharp, pixelated result.





Constants.adaptiveCameraModes
[type: dictionary] 
The available options for adaptive camera modes.


Constants.adaptiveCameraModes.none
[type: string] 
No adaptive behavior. The camera uses its fixed projection settings regardless of viewport size.


Constants.adaptiveCameraModes.maximizeSafeZone
[type: string] 
The camera adjusts its projection to maximize the visible safe zone within the viewport as it resizes.


Constants.adaptiveCameraModes.unitsMatchPixels
[type: string] 
The camera scales so that one world unit equals one screen pixel at the current viewport resolution.


Constants.adaptiveCameraModes.preserveViewAngleVertical
[type: string] 
The camera maintains a consistent vertical field of view as the viewport resizes, allowing the horizontal extent to vary.


Constants.adaptiveCameraModes.preserveViewAngleHorizontal
[type: string] 
The camera maintains a consistent horizontal field of view as the viewport resizes, allowing the vertical extent to vary.





Constants.autoplayModes
[type: dictionary] 
The available options for PlaybackController autoplay modes.


Constants.autoplayModes.none
[type: string] 
The PlaybackController does not play automatically.


Constants.autoplayModes.loop
[type: string] 
The PlaybackController plays automatically and repeats indefinitely once it reaches the end.


Constants.autoplayModes.once
[type: string] 
The PlaybackController plays automatically and stops after completing a single pass.





Constants.effectControllerBaseTypes
[type: dictionary] 
The available options for EffectController base types.


Constants.effectControllerBaseTypes.Vector4
[type: string] 
A four-component (XYZW) vector value.


Constants.effectControllerBaseTypes.Vector3
[type: string] 
A three-component (XYZ) vector value.


Constants.effectControllerBaseTypes.Vector2
[type: string] 
A two-component (XY) vector value.


Constants.effectControllerBaseTypes.number
[type: string] 
A scalar numeric value.


Constants.effectControllerBaseTypes.Texture
[type: string] 
A Texture resource.


Constants.effectControllerBaseTypes.Matrix4
[type: string] 
A 4x4 matrix value.


Constants.effectControllerBaseTypes.Matrix4Array
[type: string] 
An array of 4x4 matrix values.





Constants.effectControllerMixModes
[type: dictionary] 
The available options for EffectController mix modes. Determines how an EffectController's value combines with values inherited from parent objects.


Constants.effectControllerMixModes.addition
[type: string] 
The EffectController's value is added to any inherited value.


Constants.effectControllerMixModes.multiplication
[type: string] 
The EffectController's value is multiplied by any inherited value.


Constants.effectControllerMixModes.materialOnly
[type: string] 
The EffectController's value is applied directly to the material, ignoring any inherited value.





Constants.blendingModes
[type: dictionary] 
The available options for material blending modes.


Constants.blendingModes.standard
[type: string] 
Standard alpha blending. The source color is composited over the destination based on its alpha value.


Constants.blendingModes.add
[type: string] 
Additive blending. The source color is added directly to the destination, brightening it.


Constants.blendingModes.multiply
[type: string] 
Multiplicative blending. The source color is multiplied by the destination color, darkening it.





Constants.customBlendingModeEquations
[type: dictionary] 
The available blending equations for use with a CustomBlendingMode. Determines how the source and destination color values are combined.


Constants.customBlendingModeEquations.add
[type: string] 
The source and destination values are added together.


Constants.customBlendingModeEquations.subtract
[type: string] 
The destination value is subtracted from the source value.


Constants.customBlendingModeEquations.reverseSubtract
[type: string] 
The source value is subtracted from the destination value.


Constants.customBlendingModeEquations.min
[type: string] 
The minimum of the source and destination values is used.


Constants.customBlendingModeEquations.max
[type: string] 
The maximum of the source and destination values is used.





Constants.customBlendingModeFactors
[type: dictionary] 
The available blending factors for use with a CustomBlendingMode. Determines the multiplier applied to the source or destination color components before the blending equation is applied.


Constants.customBlendingModeFactors.zero
[type: string] 
A factor of zero, contributing nothing.


Constants.customBlendingModeFactors.one
[type: string] 
A factor of one, contributing the full value.


Constants.customBlendingModeFactors.srcColor
[type: string] 
A factor equal to the source RGB color components.


Constants.customBlendingModeFactors.oneMinusSrcColor
[type: string] 
A factor equal to one minus the source RGB color components.


Constants.customBlendingModeFactors.srcAlpha
[type: string] 
A factor equal to the source alpha component.


Constants.customBlendingModeFactors.oneMinusSrcAlpha
[type: string] 
A factor equal to one minus the source alpha component.


Constants.customBlendingModeFactors.dstAlpha
[type: string] 
A factor equal to the destination alpha component.


Constants.customBlendingModeFactors.oneMinusDstAlpha
[type: string] 
A factor equal to one minus the destination alpha component.


Constants.customBlendingModeFactors.dstColor
[type: string] 
A factor equal to the destination RGB color components.


Constants.customBlendingModeFactors.oneMinusDstColor
[type: string] 
A factor equal to one minus the destination RGB color components.


Constants.customBlendingModeFactors.srcAlphaSaturate
[type: string] 
A factor equal to the minimum of the source alpha and one minus the destination alpha.





Constants.justifications
[type: dictionary] 
The available options for layout justifications.


Constants.justifications.left
[type: string] 
Aligns content to the left edge.


Constants.justifications.right
[type: string] 
Aligns content to the right edge.


Constants.justifications.center
[type: string] 
Centers content horizontally between the left and right edges.


Constants.justifications.top
[type: string] 
Aligns content to the top edge.


Constants.justifications.bottom
[type: string] 
Aligns content to the bottom edge.





Constants.geometryAttributeNumberTypes
[type: dictionary] 
The available options for Geometry attribute number types.


Constants.geometryAttributeNumberTypes.Int8
[type: string] 
Signed 8-bit integer. Values range from -128 to 127.


Constants.geometryAttributeNumberTypes.UInt8
[type: string] 
Unsigned 8-bit integer. Values range from 0 to 255.


Constants.geometryAttributeNumberTypes.Int16
[type: string] 
Signed 16-bit integer. Values range from -32768 to 32767.


Constants.geometryAttributeNumberTypes.UInt16
[type: string] 
Unsigned 16-bit integer. Values range from 0 to 65535.


Constants.geometryAttributeNumberTypes.Int32
[type: string] 
Signed 32-bit integer. Values range from -2147483648 to 2147483647.


Constants.geometryAttributeNumberTypes.UInt32
[type: string] 
Unsigned 32-bit integer. Values range from 0 to 4294967295.


Constants.geometryAttributeNumberTypes.Float32
[type: string] 
32-bit floating-point number. Standard GPU-native precision for most vertex attributes.


Constants.geometryAttributeNumberTypes.Float64
[type: string] 
64-bit floating-point number. Higher precision, but not natively supported on the GPU - values are typically converted to Float32 at runtime.





Constants.textBoxEditingModes
[type: dictionary] 
The available options for TextBox editing modes.


Constants.textBoxEditingModes.none
[type: string] 
The TextBox does not respond to user interaction. Text cannot be selected or edited.


Constants.textBoxEditingModes.selectable
[type: string] 
The TextBox text can be selected and copied, but not edited.


Constants.textBoxEditingModes.selecting
[type: string] 
The TextBox is actively in the process of being selected (a text selection drag is in progress).


Constants.textBoxEditingModes.editable
[type: string] 
The TextBox is ready to enter edit mode when the user interacts with it.


Constants.textBoxEditingModes.editing
[type: string] 
The TextBox is actively being edited and accepts keyboard input.





Constants.playbackStates
[type: dictionary] 
The available playback states for PlaybackControllers.


Constants.playbackStates.stopped
[type: string] 
The PlaybackController is stopped. Playback has not started or has ended.


Constants.playbackStates.paused
[type: string] 
The PlaybackController is paused. Playback can be resumed from the current position.


Constants.playbackStates.playing
[type: string] 
The PlaybackController is actively playing.





Constants.particleSystemEmitterShapes
[type: dictionary] 
The available types of ParticleSystemDefinition shapes.


Constants.particleSystemEmitterShapes.rectangle
[type: string] 
Particles are emitted from random positions within a rectangular area.


Constants.particleSystemEmitterShapes.circleUniform
[type: string] 
Particles are emitted from random positions distributed uniformly across a circular area.


Constants.particleSystemEmitterShapes.circleCenter
[type: string] 
Particles are emitted from random positions across a circular area with a bias towards the center.


Constants.particleSystemEmitterShapes.point
[type: string] 
Particles are emitted from a single point.


Constants.particleSystemEmitterShapes.custom
[type: string] 
Particles are emitted using a custom-defined callback function.





Constants.particleSystemRampInterpolationTypes
[type: dictionary] 
The available ParticleSystemDefinition ramp interpolation types.


Constants.particleSystemRampInterpolationTypes.linear
[type: string] 
Values between ramp keyframes are interpolated linearly.


Constants.particleSystemRampInterpolationTypes.smoothStep
[type: string] 
Values between ramp keyframes are interpolated using a smooth-step function, easing in and out at each keyframe.


Constants.particleSystemRampInterpolationTypes.catmullRom
[type: string] 
Values between ramp keyframes are interpolated using Catmull-Rom splines, producing smooth curves that pass through each keyframe.





Constants.particleSystemRampInputTypes
[type: dictionary] 
The available types of input for ParticleSystemDefinition ramps.


Constants.particleSystemRampInputTypes.emissionTime
[type: string] 
The ramp is driven by the time elapsed since the particle system began emitting, in seconds.


Constants.particleSystemRampInputTypes.ageRatio
[type: string] 
The ramp is driven by each particle's age as a normalized ratio of its total lifetime, from 0 at birth to 1 at death.





Constants.pdfUnderlineTypes
[type: dictionary] 
The styles of underlining available within the Pdf object.


Constants.pdfUnderlineTypes.single
[type: string] 
A single continuous underline.


Constants.pdfUnderlineTypes.dash
[type: string] 
A dashed underline.


Constants.pdfUnderlineTypes.dotDash
[type: string] 
An alternating dot-dash underline.


Constants.pdfUnderlineTypes.dotDotDash
[type: string] 
An alternating dot-dot-dash underline.


Constants.pdfUnderlineTypes.words
[type: string] 
Underlines are applied only beneath individual words, leaving spaces between words undecorated.





Constants.pdfHeightRuleTypes
[type: dictionary] 
The options available within the Pdf object for fitting items within a designated area height.


Constants.pdfHeightRuleTypes.autoFit
[type: string] 
The height automatically expands to fit the content.


Constants.pdfHeightRuleTypes.exactly
[type: string] 
The height is set to an exact fixed value. Content that exceeds this height is clipped.


Constants.pdfHeightRuleTypes.atLeast
[type: string] 
The height is at least the specified value, but expands further if the content requires more space.





Constants.maskingTypes
[type: dictionary] 
Options for masking - either being masked, or doing the masking.


Constants.maskingTypes.mask
[type: string] 
This object acts as a mask, defining the visible region for masked objects within the same mask group.


Constants.maskingTypes.masked
[type: string] 
This object is masked by the mask objects within the same mask group.





Constants.registeredPropertyTypes
[type: dictionary] 
The property types available to be registered within a CustomObject or CustomAddOn.


Constants.registeredPropertyTypes.number
[type: string] 
A numeric value.


Constants.registeredPropertyTypes.string
[type: string] 
A string value.


Constants.registeredPropertyTypes.boolean
[type: string] 
A boolean value.


Constants.registeredPropertyTypes.function
[type: string] 
A function reference.





Constants.curvePointBezierHandleTypes
[type: dictionary] 
The types of CurvePoint bezier handles that are available to be used within Curves.


Constants.curvePointBezierHandleTypes.independent
[type: string] 
The left and right handles can be moved independently, allowing for sharp discontinuities in the tangent of the Curve.


Constants.curvePointBezierHandleTypes.aligned
[type: string] 
The left and right handles are always colinear with the position.


Constants.curvePointBezierHandleTypes.symmetric
[type: string] 
The left and right handles are always colinear with the position, and both handles are the same distance from the position.





Constants.curveTypes
[type: dictionary] 
The available curve types.


Constants.curveTypes.bezier
[type: string] 
Each CurvePoint has left and right handles, allowing for manual control of the Curve's tangent, including sharp discontinuities. The Curve passes through all CurvePoints.


Constants.curveTypes.hermite
[type: string] 
Each CurvePoint has a right handle, allowing for manual control of the Curve's tangent and enforcing a smoothly continuous tangent. The Curve passes through all CurvePoints.


Constants.curveTypes.cardinal
[type: string] 
Each CurvePoint has no handles, and the Curve's tangent is automatically computed based on the surrounding CurvePoints, producing a smoothly continuous tangent. The Curve starts at the second CurvePoint and ends at the second to last CurvePoint, and passes through all intermediate CurvePoints. At least 4 CurvePoints are required.


Constants.curveTypes.basis
[type: string] 
Also known as a B-spline. Each CurvePoint has no handles, and the Curve's tangent is automatically computed based on the surrounding CurvePoints. The Curve starts at the second CurvePoint and ends at the second to last CurvePoint. The curve will not necessarily pass through any of the CurvePoints, but will exhibit smoothly continuous tangent and acceleration when using 'evaluateT'. At least 4 CurvePoints are required.





Constants.keyframedValueTypes
[type: dictionary] 
The available KeyframedValue property types, determining how a KeyframedValue's value is evaluated.


Constants.keyframedValueTypes.floatingPoint
[type: string] 
An interpolated numeric value.


Constants.keyframedValueTypes.boolean
[type: string] 
A stepped true/false value.


Constants.keyframedValueTypes.string
[type: string] 
A stepped string value.


Constants.keyframedValueTypes.invoke
[type: string] 
No value - getValue instead reports the Keyframes crossed since the previous call, used for firing invocations.





Constants.keyframedValueInterpolationTypes
[type: dictionary] 
The available KeyframedValue interpolation types, determining how numeric values are interpolated between Keyframes.


Constants.keyframedValueInterpolationTypes.optimizedBezier
[type: string] 
A fast handle-based curve that approximates a cubic bezier.


Constants.keyframedValueInterpolationTypes.bezier
[type: string] 
A true cubic bezier curve solved from the Keyframe handles.





Constants.keyframeTypes
[type: dictionary] 
The available Keyframe types. A 'left' or 'right' Keyframe is a single stepped Keyframe carrying a discontinuity via its 'value' and 'secondaryValue'. No two Keyframes may share a time.


Constants.keyframeTypes.standard
[type: string] 
A normal, continuous Keyframe.


Constants.keyframeTypes.left
[type: string] 
A stepped Keyframe whose primary 'value' governs the left side of its time and whose 'secondaryValue' governs the right.


Constants.keyframeTypes.right
[type: string] 
A stepped Keyframe whose primary 'value' governs the right side of its time and whose 'secondaryValue' governs the left.





Constants.continueModes
[type: dictionary] 
The available modes for how a KeyframedValue continues beyond its keyframe range (see KeyframedValue.continueLeft and KeyframedValue.continueRight).


Constants.continueModes.constant
[type: string] 
Holds the boundary value beyond the range.


Constants.continueModes.extrapolate
[type: string] 
Continues the endpoint tangent linearly beyond the range (numeric values only - other types hold the boundary value).


Constants.continueModes.loop
[type: string] 
Repeats the animation, wrapping the time back to the start of the range.


Constants.continueModes.pingPong
[type: string] 
Bounces the animation, reflecting the time back and forth across the range.





Constants.faceCullingModes
[type: dictionary] 
The available modes for which side of a triangle a Material culls (see Material.faceCulling and MaterialMaster.faceCulling).


Constants.faceCullingModes.front
[type: string] 
Drops the triangles facing the camera, drawing only those facing away.


Constants.faceCullingModes.back
[type: string] 
Drops the triangles facing away from the camera, drawing only those facing it.


Constants.faceCullingModes.none
[type: string] 
Culls nothing, drawing both sides of every triangle.





Constants.slotReelStates
[type: dictionary] 
Dictionary of available 'reelState' values within the SlotReel.


Constants.slotReelStates.stopped
[type: string] 
For when the SlotReel is stopped.


Constants.slotReelStates.windup
[type: string] 
For when the SlotReel is winding up before it spins.


Constants.slotReelStates.spinFree
[type: string] 
For when the SlotReel freely spinning.


Constants.slotReelStates.stopping
[type: string] 
For when the SlotReel begins to stop, spinning until the symbols in the stopping window are encountered.


Constants.slotReelStates.stopImminent
[type: string] 
This state occurs when the final stopping symbols are active on the SlotReel, and they just need to travel into their final position.


Constants.slotReelStates.bounce
[type: string] 
Right before the SlotReel spin is over, and the symbols are bouncing around to simulate a physical recoil action.





Constants.symbolReelStates
[type: dictionary] 
Dictionary of available 'reelState' values within the SymbolReel.


Constants.symbolReelStates.stopped
[type: string] 
For when the SymbolReel is at rest.


Constants.symbolReelStates.windup
[type: string] 
For when the SymbolReel is winding up before it spins.


Constants.symbolReelStates.spinFree
[type: string] 
For when the SymbolReel is spinning freely, which continues until 'beginStop' or 'slam' is called.


Constants.symbolReelStates.stopping
[type: string] 
For when the SymbolReel begins to stop, spinning until the symbols it needs for its final position are encountered.


Constants.symbolReelStates.stopImminent
[type: string] 
For when the final stopping symbols are visible on the SymbolReel, and only need to travel into their final position.


Constants.symbolReelStates.bounce
[type: string] 
Right before the SymbolReel spin is over, when the symbols recoil to simulate a physical reel coming to rest.





Constants.defaultSymbolTypes
[type: dictionary] 
Dictionary of available 'defaultSymbolType' values within the SymbolReel, selecting which built-in stand-in symbol is built while no 'symbolClassDefinition' has been supplied.


Constants.defaultSymbolTypes.TextBox
[type: string] 
Draws a grey card showing the symbol string itself, which reads clearly while a reel is being laid out.


Constants.defaultSymbolTypes.GraphicObject
[type: string] 
Draws the GraphicAsset whose name matches the symbol, falling back to the WhiteBox for a symbol naming no GraphicAsset in the project.





Constants.cursorMode
[type: dictionary] 
Dictionary of available values for 'nc.cursorMode'.


Constants.cursorMode.autoDetect
[type: string] 
When nc.cursorMode is set to this value, the next cursor event will received will set the cursor mode - if it's a touch event then cursorMode will be set to 'touch', and if the it's a mouse event then cursorMode will be set to 'mouse'.


Constants.cursorMode.mouse
[type: string] 
When in this mode, Incisor is using the mousedown, mouseup, mouseleave, wheel, and mousemove browser events to inform cursor interactions.


Constants.cursorMode.touch
[type: string] 
When in this mode, Incisor is using the touchstart, touchend, touchcancel, and touchmove browser events to inform cursor interactions.










----------------------------------------------------------
Section 205: UiPopupWindow
----------------------------------------------------------


UiPopupWindow
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A ui-specialized vertical LayoutStack that functions as a pop-up window. UI functionality includes:  • pre-configured with LayoutObject functionality.  • uiStyle TextFormats and Colors applied.  • pre-configured with 'UiKeyboardNavigable' functionality.  • uiZoom-enabled.  • pre-configured with 'UiVisualFocus' functionality.  • nearestPixelRendering-enabled.





UiPopupWindow.isOpen
[type: boolean] 
Boolean determining if this UiPopupWindow is displayed/enabled. When this property is set to true, this UiPopupWindow becomes the 'singularFocusObject' and also assumes 'visual focus'.





UiPopupWindow.backgroundPanel
[type: UiPanel] 
A UiPanel that serves as the background to the UiPopupWindow.





UiPopupWindow.topBarLeftStack
[type: LayoutStack] 
The horizontal LayoutStack containing top bar, which includes the 'ex' button and the title TextBox.





UiPopupWindow.topBarBackground
[type: UiPanel] 
A UiPanel that serves as the background to the top bar in the UiPopupWindow.





UiPopupWindow.exButton
[type: UiGraphicButton] 
A UiGraphicButton that serves the 'ex' button in the top-left corner of the UiPopupWindow.





UiPopupWindow.titleText
[type: TextBox] 
The TextBox serving as the top bar title for the UiPopUpWindow.





UiPopupWindow.bodyStack
[type: LayoutStack] 
The LayoutStack containing the main body displayed by this UiPopupWindow.





UiPopupWindow.decisionButtonStack
[type: LayoutStack] 
The horizontal LayoutStack containing decision buttons (UiButtons) displayed in the lower-right corner of this UiPopupWindow.





UiPopupWindow.isMovable
[type: boolean] [default: true] 
Flag determining if the UiPopupWindow can be moved via dragging.





UiPopupWindow.allowEscape
[type: boolean] [default: false] 
Boolean determining if the end-user can press the 'Escape' key, click the 'ex' button, or click outside of the visual focus dimmer background to exit the UiPopupWindow. Setting this value to false would effectively require that the end-user click one of the decision buttons to exit the UiPopupWindow.





UiPopupWindow.setDecisionButtons(decisionNames, rightmostUiButtonIsAutoOutlined)
[type: function] 
A convienience function to bulk-add decision buttons, which are just a series of standardized UiButtons at the bottom of the UiPopupWindow. Once the decision buttons have been added, 'addDecisionButtonTriggerCallback' can be used to add a callback which receives the button's text string, the triggering UiButton itself, and the containing UiPopupWindow as its first three parameters.

UiPopupWindow.setDecisionButtons parameter: decisionNames
[type: [string]] 
An array of strings, where each string will become a UiButton at the bottom of the UiPopupWindow.

UiPopupWindow.setDecisionButtons parameter: rightmostUiButtonIsAutoOutlined
[type: string] [optional] 
Boolean determining if the rightmost decision button is automatically outlined whenever the UiPopupWindow is opened.





UiPopupWindow.addDecisionButtonTriggerCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever a decision button is triggered via the cursor or keyboard navigation. The decision string, the triggering UiButton, and the containing UiPopupWindow itself are sent to the callback as its first three parameters.

UiPopupWindow.addDecisionButtonTriggerCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever a decision button is triggered via the cursor or keyboard navigation.

UiPopupWindow.addDecisionButtonTriggerCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever a decision button is triggered via the cursor or keyboard navigation.

UiPopupWindow.addDecisionButtonTriggerCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that is triggered whenever a decision button is triggered via the cursor or keyboard navigation.





UiPopupWindow.addOpenCloseCallback(callbackOwner, callbackName, callbackArgs)
[type: function] 
Adds a callback that occurs whenever a UiPopupWindow is opened or closed. A boolean indicating if the UiPopupWindow is open, and the UiPopupWindow itself will be sent to the callback as the first two parameters.

UiPopupWindow.addOpenCloseCallback parameter: callbackOwner
[type: object] 
The object owning the callback function that occurs whenever a this UiPopupWindow is opened or closed.

UiPopupWindow.addOpenCloseCallback parameter: callbackName
[type: string] 
The name of the callback function that occurs whenever a this UiPopupWindow is opened or closed.

UiPopupWindow.addOpenCloseCallback parameter: callbackArgs
[type: Array, any] [optional] 
Args for the callback function that occurs whenever a this UiPopupWindow is opened or closed.





UiPopupWindow.awaitClose()
[type: function] 
Asynchronously awaits the closing of the UiPopupWindow.
















































































































































































































































































































































































































----------------------------------------------------------
Section 206: INCISOR
----------------------------------------------------------


INCISOR
[type: class] [NON-INSTANTIABLE] 
Class housing all of the main Incisor functionality. Accessible via 'nc' from anywhere within project code, excluding code within the 'PreloadConfiguration.js' file (that code is executed before 'nc' is instantiated). 





INCISOR.projectName
[type: string] 
The name of the project.





INCISOR.flows
[type: dictionary] [NON-INSTANTIABLE] [requires: module - flowControllers] 
The FlowControllers currently defined in this project. FlowControllers provide a way to organize the general flow of state-based items in a project. For example if your project is a game with an intro, a menu, and several levels, you could create a FlowController named "GameFlowController" and then define and add an 'Intro' FlowState, a 'Menu' FlowState, and 'LevelXX' FlowStates to that FlowController. Within each FlowState in the FlowController, timed callback elements can be added to help define the sequencing within each FlowState. Once created, FlowControllers, FlowStates, and FlowStateElements can be accessed via 'nc.flows'. This class is not meant to be instantiated or provided directly to 'FlowController.addFlowState', rather it is meant to be a class for user-defined FlowStates to extend. Call 'nc.defineFlowController' to create a new FlowController, then use 'nc.flows' to access it. 





INCISOR.sounds
[type: dictionary] [requires: module - sounds] 
Dictionary of all registered Sounds.


INCISOR.sounds.incr_replaceText_soundsDocumentation
[type: dictionary] 






INCISOR.volumeControls
[type: dictionary] [requires: module - sounds] 
Dictionary of all registered VolumeControls.


INCISOR.volumeControls.incr_replaceText_volumeControlsDocumentation
[type: dictionary] 






INCISOR.uiStyle
[type: UiStyle] [requires: module - extendedUi] 
Object housing default TextFormats, and Colors for various Gui objects such as 'UiButton', 'DropDownMenu' and 'PopUpWindow'.





INCISOR.enableIncisorInspectorAutoPositioning
[type: boolean] [default: false] [requires: module - extendedUi] 
Boolean determining if certain automatic positioning features specifically related to the Incisor Inspector are enabled. It should be noted that the Incisor Inspector uses a non-standard coordinate system with (0,0) in the upperleft corner. Automatica positioning features include: automatic placement of UiPopupWindows in the center of the screen and automatic adjustment of UiMenus to avoid them extending outside of the Inspector viewing area.





INCISOR.useNearestPixelRenderingForAllUiItems
[type: boolean] [default: true] 
Boolean determining if 'useNearestPixelRendering' defaults to true for 'UI' items such as UiButton or UiText. In general, you should use 'useNearestPixelRendering' for situations when the area being rendered is the same exact resolution as the RenderTarget it's being used to; it is a means to have 'pixel perfect' TextBox rendering. If the camera is rendering a variable area or an area that doesn't match the RenderTarget being rendered to (such such as when the camera's adaptiveCameraMode is set to 'maximizeSafeZone') then 'useNearestPixelRendering' should not be used and this value should be false.





INCISOR.textures
[type: dictionary] 
Dictionary of all registered Textures.


INCISOR.textures.incr_icons_sheet0
[type: Texture] 
One of the currently defined Textures.


INCISOR.textures.incr_inspectorFont0
[type: Texture] 
One of the currently defined Textures.


INCISOR.textures."NotoSansMono_Condensed-Medium0"
[type: Texture] 
One of the currently defined Textures.


INCISOR.textures.WhiteBox
[type: Texture] 
One of the currently defined Textures.


INCISOR.textures.NullFont_Char0
[type: Texture] 
One of the currently defined Textures.





INCISOR.motionTypes
[type: dictionary] 
Object housing all defined MotionTypes. MotionTypes are used in conjunction with Motions and define a method of continuous change for numeric properties.


INCISOR.motionTypes.Pendulum
[type: MotionType] 
The 'Pendulum' MotionType. This MotionType smoothly swings the value or values back and forth between the lower and upper bounds. While some MotionTypes are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





INCISOR.uiZoom
[type: UiZoom] 
Object housing functionality associated with the user interface zoom, which enables end-users to increase or decrease the overall size of text and other user interface items (when those items have uiZoom functionality enabled).





INCISOR.videos
[type: dictionary] [requires: module - videos] 
Dictionary of all registered Videos. When compressed video assets (mp4 or webm) are included in a project a Texture, Geometry, GraphicAsset, and Video with that same name are created in Incisor. Once included, any GraphicObject can be set to the corresponding GraphicAsset, and the associated Video object can control the video's playback. It should be noted that the visual content of any instance or use of the GraphicAsset will be same everywhere - as video's content is pushed to the associated texture, all objects using that Texture will see the same content. Videos in Incisor rely entirely on the browser's decoding and playback capabilities, which typically don't support rapid/repeated changes to video properties. In practice, videos perform well when playing once normally or free-running, but do not do well with a lot of rapid time jumps or scrubbing. Video formats are not uniformly supported for use within all browsers, and their use is not advised within projects meant to be universally accessible. Acceptable extensions for video files include ".mp4" and ".webm", and while webm (VP8 or VP9) typically supports transparency, there are currently no video formats that support transparency on any Apple mobile or desktop products.





INCISOR.fontNames
[type: dictionary] 
Dictionary of the names of the fonts available within this project.


INCISOR.fontNames.NullFont
[type: string] 
The 'NullFont' font name string.


INCISOR.fontNames.incr_inspectorFont
[type: string] 
The 'incr_inspectorFont' font name string.


INCISOR.fontNames.MonoSpace
[type: string] 
The 'MonoSpace' font name string.





INCISOR.effectControllers
[type: dictionary] 
Dictionary of EffectControllerDefinitions for all of the registered EffectControllers.


INCISOR.effectControllers.fillColor
[type: fillColor_Definition] 
The info-object for the 'fillColor' EffectController.


INCISOR.effectControllers.mainTexture
[type: mainTexture_Definition] 
The info-object for the 'mainTexture' EffectController.


INCISOR.effectControllers.colorMultiply
[type: colorMultiply_Definition] 
The info-object for the 'colorMultiply' EffectController.


INCISOR.effectControllers.shapify
[type: shapify_Definition] 
The info-object for the 'shapify' EffectController.


INCISOR.effectControllers.incr_TwoColorGradient
[type: incr_TwoColorGradient_Definition] 
The info-object for the 'incr_TwoColorGradient' EffectController.


INCISOR.effectControllers.incr_TwoColorGradient_color0
[type: incr_TwoColorGradient_color0_Definition] 
The info-object for the 'incr_TwoColorGradient_color0' EffectController.


INCISOR.effectControllers.incr_TwoColorGradient_color1
[type: incr_TwoColorGradient_color1_Definition] 
The info-object for the 'incr_TwoColorGradient_color1' EffectController.


INCISOR.effectControllers.shear
[type: shear_Definition] 
The info-object for the 'shear' EffectController.


INCISOR.effectControllers.shear_center
[type: shear_center_Definition] 
The info-object for the 'shear_center' EffectController.





INCISOR.paths
[type: Paths] 
Object housing functionality manipulate paths including 'splitPath', 'getFileName', and 'getParentDirectory'.





INCISOR.projectConfiguration
[type: ProjectConfiguration] 
Object housing the configuration settings for this project. Many of the members of this object are customizable on a 'per configuration' basis by editing the 'ProjectSettings' file within the project. The user-customizable 'PreloadConfiguration' code is executed within this object, so members created within that code will be accessible on this object.





INCISOR.appEvents
[type: dictionary] 
Object housing Incisor® AppEvents, which enable callbacks for software events including screen updates, cursor/pointer/mouse events, keyboard events, and many more.


INCISOR.appEvents.fixedUpdate
[type: AppEvent] 
The fixed updater AppEvent occurs in an automatically repeating manner at a rate dictated by 'nc.targetFixedUpdateRate' (defaults to 60 fps). This AppEvent should be used to drive the logic and sequencing in a given project. It is a 'fixed' updater because it will be called at the designated rate regardless of 'dropped' screen updates, and logic/sequencing using this AppEvent will never experience 'time slippage' due to any software performance issues.


INCISOR.appEvents.lateFixedUpdate
[type: AppEvent] 
The fixed updater AppEvent occurs in an automatically repeating manner at a rate dictated by 'nc.targetFixedUpdateRate' (defaults to 60 fps). This AppEvent should be used to drive the logic and sequencing in a given project. It is a 'fixed' updater because it will be called at the designated rate regardless of 'dropped' screen updates, and logic/sequencing using this AppEvent will never experience 'time slippage' due to any software performance issues. This AppEvent will always happen after the 'fixedUpdate' AppEvent. This AppEvent is 'ordered', meaning callbacks added can provide a 'callbackOrder' parameter, which is used to determine the execution order of callbacks.


INCISOR.appEvents.preShutdown
[type: AppEvent] 
The preShutdown AppEvent occurs one time, when 'nc.shutDown' is called. It happens after the automatic iterative AppEvents have stopped but before anything is torn down, and is the place to release what Incisor® has no knowledge of, such as timers and subscriptions to outside systems. Callbacks are awaited. The software is already stopped, so a callback cannot rely on further updates. This AppEvent is 'ordered', meaning callbacks added can provide a 'callbackOrder' parameter, which is used to determine the execution order of callbacks.


INCISOR.appEvents.screenUpdate
[type: AppEvent] 
The screen updater AppEvent occurs in an automatically repeating manner at a rate dictated by 'nc.targetScreenUpdateRate' (defaults to 60 fps). This AppEvent should only be used to drive processes that are tied to rendering - it occurs before each auto-render of the Cameras. It is a 'screen' updater because it is only called when the system's performance allows - if project logic or sequencing are tied to this AppEvent, they may experience 'time slippage' if there are any software performance issues.


INCISOR.appEvents.lateScreenUpdate
[type: AppEvent] 
The late updater AppEvent occurs in an automatically repeating manner at a rate dictated by 'nc.targetScreenUpdateRate' (defaults to 60 fps). This AppEvent should only be used to drive processes that are tied to rendering - it occurs after each auto-render of the Cameras. It is a 'late' updater because it is called after rendering, and can be used to wrap up rendering processes, and prep for the next render. Much like the 'screenUpdate', the lateScreenUpdate only happens when system performance allows, and so would experience time slippage with performance issues. This AppEvent will always happen after the 'screenUpdate'. This AppEvent is 'ordered', meaning callbacks added can provide a 'callbackOrder' parameter, which is used to determine the execution order of callbacks.


INCISOR.appEvents.start
[type: AppEvent] 
The start AppEvent occurs one time after ProjectMain.init (pr.init) has been called, which happens directly before the automatic iterative appEvents (i.e. fixedUpdate, screenUpdate etc...) begin. This AppEvent can be used to perform tasks which require that all SceneObjects and CustomAddOns to be 'in place' and set up before running. An example use of this AppEvent would be within a CustomAddOn that resides on an item inside a Construct - if you put code that references other CustomAddOns in a constructor, there's no guarantee that the other CustomAddOns or their owners will be populated yet. So in this case it would be better to run that same code in a 'start' callback, which waits for all of the setup before running. It should be noted that callbacks added after the official 'start' occurs will be invoked on the next fixedUpdate. This AppEvent is 'ordered', meaning callbacks added can provide a 'callbackOrder' parameter, which is used to determine the execution order of callbacks.


INCISOR.appEvents.keyboardEvent
[type: AppEvent] 
The keyboardEvent is triggered for all keyboard events such as 'keydown' and 'keyup'. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.canvasResize
[type: AppEvent] 
The canvasResize is triggered any time a key canvas is resized. The native browser-triggered event will be sent to all callbacks as their first parameter.


INCISOR.appEvents.keyDown
[type: AppEvent] 
The keyDown is triggered any time a key on the keyboard is pushed down. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.keyUp
[type: AppEvent] 
The keyUp is triggered any time a key on the keyboard that was previously pushed down is released. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.cursorMove
[type: AppEvent] 
The cursorMove is triggered any time the cursor is moved. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.cursorPress
[type: AppEvent] 
The cursorPress is triggered any time the cursor is 'pressed down', which would be either by clicking the mouse button, or touching a touch-screen device. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.cursorRelease
[type: AppEvent] 
The cursorRelease is triggered any time the cursor is 'let up', which would be either by realeasing the mouse button, or lifting a finger from a touch-screen device. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.cursorScroll
[type: AppEvent] 
The cursorScroll is triggered any time mouse scroll wheel is used. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.contextMenu
[type: AppEvent] 
The contextMenu is triggered when the context menu (right-click dropdown menu) is accessed. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.cursorLeave
[type: AppEvent] 
The cursorLeave is triggered any time the cursor leaves the canvas altogether. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.cursorEvent
[type: AppEvent] 
The cursorEvent is triggered any time the cursorMove, cursorPress, cursorRelease, cursorScroll, or contextMenu events are triggered. Use this AppEvent if you want to have a single callback receive the feedback from all of the cursor events. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.focusChange
[type: AppEvent] 
The focusChange AppEvent is triggered any time 'nc.singularFocusObject' is set to a new object. A FocusChangeInfo object will be sent to all callbacks as their first parameter - this object contains references to the object that is losing focus, as well as the object gaining focus.


INCISOR.appEvents.osFocusChange
[type: AppEvent] 
The osFocusChange AppEvent is triggered any time the OS changes its focus to or from the browser/app running this instance of Incisor®. The status of the browser/app ('focused' or 'unfocused') will be sent to all callbacks as their first parameter.


INCISOR.appEvents.visibilityChange
[type: AppEvent] 
The visibilityChange AppEvent is triggered any time the OS-level visibility of the browser/app running this instance of Incisor® changes. The status of the browser/app ('hidden' or 'visible') will be sent to all callbacks as their first parameter. This AppEvent is 'ordered', meaning callbacks added can provide a 'callbackOrder' parameter, which is used to determine the execution order of callbacks.


INCISOR.appEvents.clipboardEvent
[type: AppEvent] 
The clipboardEvent is triggered any time the browser encounters a 'copy', 'cut', or 'paste' event, affecting the OS clipboard. Use this AppEvent if you want to have a single callback receive the feedback from all of the clipboard events. The native browser-triggered event will be sent to all callbacks as their first parameter. Callbacks added to this AppEvent also have a 'singular focus option', meaning they can require that a particular object be 'focused' in order for the callback to be invoked - this enables certain functionality related to user-input to be restricted to the appropriate contexts within a UI.


INCISOR.appEvents.uiZoomChange
[type: AppEvent] 
The uiZoomChange AppEvent is triggered any time nc.uiZoom.totalZoom is changed, which can happen when nc.uiZoom.zoomValue changes or when the browser's devicePixelRatio changes. The updated totalZoom value will be sent to all callbacks as their first parameter.





INCISOR.pauseEvents
[type: dictionary] 
Object housing all defined PauseEvents. A given PauseEvent can be used as a parameter in 'nc.pause' and 'nc.resume' to pause and resume various time-based and user-interaction processes. Pausable processes react to pausing or resuming with PauseEvents unless those processes have a given PauseEvent as part of their designated 'pauseImmunity', which can determined in the parameters of a pausable-process-initiating method.


INCISOR.pauseEvents.MainPauseEvent
[type: PauseEvent] 
One of the currently defined PauseEvents.


INCISOR.pauseEvents.InspectorPauseEvent
[type: PauseEvent] 
One of the currently defined PauseEvents.





INCISOR.speedControls
[type: dictionary] 
Object housing all defined SpeedControls. SpeedControls can be used to control the speed of time-based sequencing processes such as Motions, Swoops, or Timelines. Applicable processes can subscribe to multiple SpeedControls - the 'speed' values of all of the SpeedControls a process subscribes to are multiplied together to determine the overall pacing of the given time-based process.


INCISOR.speedControls.MainSpeedControl
[type: SpeedControl] 
One of the currently defined SpeedControls.





INCISOR.defaultPauseImmunity
[type: [PauseEvent], PauseEvent] [default: [nc.pauseEvents.MainPauseEvent]] 
This is the pause immunity that is automatically applied if the 'pauseImmunity' parameter of any pausable-process-initiating method is left undefined. This value can be changed between big blocks of code to distinguish how groups of functionality react to different pauseEvents without needing to include specific 'pauseImmunity' for every single process initiated within each block.





INCISOR.defaultSpeedControl
[type: [SpeedControl], SpeedControl] [default: [nc.speedControls.MainSpeedControl]] 
The SpeedControl(s) that are automatically applied if the 'speedControl' parameter is left undefined in any method that initiates a speed controllable process. This value can be changed between big blocks of code to distinguish how groups of functionality interact with different sets of SpeedControls without needing to include specific 'speedControl' parameters for every single applicable process initiated within each block.





INCISOR.defaultFocusFallback
[type: SceneObject] [default: undefined] 
The default focusFallback value for new SceneObjects. This property can be changed at the top of any block of code where a lot of related SceneObjects are instantiated, and as a result all of those SceneObjects will receive the same new default focusFallback value.





INCISOR.targetFixedUpdateRate
[type: number] [default: 60] 
The number of times per second that the fixedUpdate will occur.





INCISOR.targetScreenUpdateRate
[type: number] [default: 60] 
The number of times per second that the screenUpdate will occur.





INCISOR.softwareSpeed
[type: number] [default: 1] 
When changed from 1, this value will increase or decrease the pacing of the fixedUpdate (independently from the 'targetFixedUpdateRate'), as well as the playback rate of all sounds played. The screenUpdate is not effected by this value. Manipulating this value can serve as a 'fast-forward' for the entire project.





INCISOR.singularFocusObject
[type: SceneObject] 
The singularFocusObject determines which callbacks connected to certain user-input AppEvents are invoked. For example, when a 'keyboardEvent' callback is added, a 'singularFocusRequirements' parameter can be supplied and that callback will only be invoked if the singularFocusObject is listed in the supplied 'singularFocusRequirements'. This is a way of adding keyboard AppEvent callbacks that will only be called if an associated contextual object is 'focused'.





INCISOR.singularFocusButtonPressRequirements
[type: [Button]] [default: undefined] 
Optional array of Buttons that can be supplied while a given object is the singularFocusObject. When populated, two behaviors are enforced: (1) a cursor press anywhere outside of the listed Buttons will result in nc.relinquishFocus being called, and (2) all button input (including cursorIn, hover, and press events) is ignored for any Button not in the array. This ensures that only the listed Buttons can interact with the user while the singular focus object is active, preventing other interactive elements from responding to cursor activity. When a TextBox or UiTextField is focused via editing or selecting, this value is automatically set to that element, so that clicking away un-focuses it and other interactive elements do not respond to cursor hover or press events in the meantime. When this property is undefined, button input is not affected by focus state at all.





INCISOR.hiddenUpdating
[type: boolean] [default: false;] 
Flag determining if this project will continue its processes in any way while it is hidden by the OS.





INCISOR.hiddenScreenUpdating
[type: boolean] [default: false;] 
Flag determining if this project's ScreenUpdate will occur while it is hidden by the OS.





INCISOR.maxReconciliationTime
[type: number] [default: 1;] 
In the event that tasks within the 'fixedUpdate' and 'lateFixedUpdate' processes take longer than their alloted time for sustained periods, a sort of 'computational pile-up' can occur, where more instructions are scheduled per second that can be completed. This property limits the amount of 'catching up' that the system will try to do to, effectively allowing time to slip in these processes to avoid such computational pile-up. It should be noted that this value corresponds to the the maximum reconciliation time for when nc.hiddenUpdating is set to false.





INCISOR.maxHiddenReconciliationTime
[type: number] [default: 10;] 
In the event that tasks within the 'fixedUpdate' and 'lateFixedUpdate' processes take longer than their alloted time for sustained periods, a sort of 'computational pile-up' can occur, where more instructions are scheduled per second that can be completed. This property limits the amount of 'catching up' that the system will try to do to, effectively allowing time to slip in these processes to avoid such computational pile-up. It should be noted that this value corresponds to the the maximum reconciliation time for when nc.hiddenUpdating is set to true.





INCISOR.cursorMode
[type: string] [default: "autoDetect"] 
Flag determining which events are informing cursor interaction. When nc.cursorMode is set to 'autoDetect', the next cursor event will received will set the cursor mode; if it's a touch event then cursorMode will be set to 'touch', and if the it's a mouse event then cursorMode will be set to 'mouse'. When nc.cursorMode is set to 'mouse', Incisor is using the mousedown, mouseup, mouseleave, wheel, and mousemove browser events to inform cursor interactions. When nc.cursorMode is set to 'touch', Incisor is using the touchstart, touchend, touchcancel, and touchmove browser events to inform cursor interactions.





INCISOR.particleSystemDefs
[type: dictionary] 
Dictionary of all registered ParticleSystemDefinitions.


INCISOR.particleSystemDefs.incr_replaceText_particleSystemsDocumentation
[type: dictionary] 






INCISOR.fileIO
[type: FileIO] [requires: module - fileIO] 
Object housing functionality to perform file IO tasks such as 'writeTextFile', 'moveTo', 'createDirectory' an more. This functionality only exists within un-built projects, and also requires that the user account has access to the FileIO features.





INCISOR.visualFocusObject
[type: UiVisualFocus] [requires: module - extendedUi] 
Read-only property denoting which object (if any) is currently visually focused. 'VisualFocus' is a mode that focuses the end-user's attention the given SceneObject by placing it in front of a dimmer layer whenever the object is the the current 'singularFocusObject'. See 'SceneObject.configureUiVisualFocus' for more information.





INCISOR.visualFocusEnabled
[type: boolean] [default: true] [requires: module - extendedUi] 
Boolean determining if the entire Visual Focus system is enabled.  'VisualFocus' is a mode that focuses the end-user's attention the given SceneObject by placing it in front of a dimmer layer whenever the object is the the current 'singularFocusObject'. See 'SceneObject.configureUiVisualFocus' for more information.





INCISOR.visualFocusDimmerAmount
[type: number] [default: .5] 
Number determining how strong the visual focus dimmer is on a scale of 0 to 1.





INCISOR.effectNodes
[type: dictionary] 
Dictionary of all defined EffectNodes.


INCISOR.effectNodes.FillColor
[type: EffectNode] 
One of the currently defined EffectNodes.


INCISOR.effectNodes.SampleMainTexture
[type: EffectNode] 
One of the currently defined EffectNodes.


INCISOR.effectNodes.ColorMultiply
[type: EffectNode] 
One of the currently defined EffectNodes.


INCISOR.effectNodes.Shapify
[type: EffectNode] 
One of the currently defined EffectNodes.


INCISOR.effectNodes.MaskingReturn
[type: EffectNode] 
One of the currently defined EffectNodes.


INCISOR.effectNodes.incr_TwoColorGradient
[type: EffectNode] 
One of the currently defined EffectNodes.


INCISOR.effectNodes.Shear
[type: EffectNode] 
One of the currently defined EffectNodes.





INCISOR.multiTapInterval
[type: number] [default: 0.25] 
The max amount of time between two Button presses for the Button presses to be considered part of the same 'doubleTap' or 'tripleTap'.





INCISOR.maskGroups
[type: dictionary] 
The MaskGroups available in this project.


INCISOR.maskGroups.MainMaskGroup
[type: MaskGroup] 
One of the currently defined MaskGroups.





INCISOR.cameras
[type: dictionary] 
Dictionary of all registered Cameras in this project.


INCISOR.cameras.MainCamera
[type: Camera] 
One of the currently defined Cameras.





INCISOR.mainCamera
[type: OrthographicCamera, PerspectiveCamera] 
The 'MainCamera' Camera.





INCISOR.loadingTiers
[type: dictionary] 
Dictionary of loading tiers - each loading tier has a number designation. Loading tiers are a means to organize AssetComponents into separately downloadable groups.


INCISOR.loadingTiers.100
[type: number] 
The numeric designation of the '100' loading tier.





INCISOR.pixelsObjects
[type: PixelsObjects] 
Object housing functionality for PixelsObjects, which are RGBA bitmap images in a simple, 'data-only' format, used for basic image access and manipulation.





INCISOR.scenes
[type: dictionary] 
Dictionary of all registered Scenes in this project. Scenes are the root SceneObjects in hierarchies. All SceneObjects are either Scenes or descendants of Scenes.


INCISOR.scenes.MainScene
[type: Scene] 
One of the currently defined Scenes.





INCISOR.layers
[type: dictionary] 
Dictionary of all registered Layers in this project.


INCISOR.layers.DefaultLayer
[type: Layer] 
One of the currently defined Layers.


INCISOR.layers.PageLayer
[type: Layer] 
One of the currently defined Layers.


INCISOR.layers.UiVisualFocusDimmerLayer
[type: Layer] 
One of the currently defined Layers.


INCISOR.layers.UiVisualFocusLayer
[type: Layer] 
One of the currently defined Layers.





INCISOR.mainScene
[type: Scene] 
The 'MainScene' Scene.





INCISOR.layersByScene
[type: LayersByScene] 
A 2D dictionary that lists the available Layers in each Scene. These dictionaries are not ordered, for the order of the Layers in a given Scene, see 'Scene.layerOrderLedger'.





INCISOR.timeStamp
[type: TimeStamp] 
Object housing functionality for time stamps, the Incisor® standardized format for date and time.





INCISOR.defaultDepthTesting
[type: boolean] [default: false] 
The default value for the 'depthTest' property on all GraphicObject Materials. It should be noted that some GraphicAssets may have Material presets that determine a specific value for 'depthTest', and those Material presets supersede this value.





INCISOR.defaultDepthWriting
[type: boolean] [default: true] 
The default value for the 'depthWrite' property on all GraphicObject Materials. It should be noted that some GraphicAssets may have Material presets that determine a specific value for 'depthWrite', and those Material presets supersede this value.





INCISOR.defaultTransparency
[type: boolean] [default: true] 
The default value for the 'transparent' property on all GraphicObject Materials. It should be noted that some GraphicAssets may have Material presets that determine a specific value for 'transparent', and those Material presets supersede this value.





INCISOR.constructDefs
[type: dictionary] 
Dictionary of available ConstructDefinitions.





INCISOR.urlParameterIterator
[type: UrlParameterIterator] [requires: module - urlParameterIterator] 
Object housing testing functionality that enables a project to refresh itself repeatedly with different url parameters. Such functionality can help with batch testing of a project's configurations or settings. To use this functionality, first call the 'UrlParameterIteration.setup' method, passing it an array of objects where each object represents the url parameters you would like the browser to refresh with. When ready to start the iteration, call 'UrlParameterIteration.start'. Then add the desired functionality per url parameter - be sure to implement what you want conditionally based on the url params (otherwise everything will happen on every refresh). When the desired tasks (testing, screen shots, etc...) have completed for each set of url parameters, call 'UrlParameterIteration.next', this will proceed to refresh with the next set of url parameters.





INCISOR.phraseIDs
[type: dictionary] 
Dictionary of the phraseIDs contained in the ProjectTranscript. Using phraseIDs to populate TextBoxes and TextAssemblies will enable the text content to be dynamically populated based on the current language setting of the project.


INCISOR.phraseIDs."Hello World"
[type: string] 
One of the phrases defined in the ProjectTranscript.


INCISOR.phraseIDs."Goodbye World"
[type: string] 
One of the phrases defined in the ProjectTranscript.





INCISOR.phrases
[type: dictionary] 
Dictionary of the phrases contained in the ProjectTranscript (listed by phraseID). Using phraseIDs to populate TextBoxes and TextAssemblies will enable the text content to be dynamically populated based on the current language setting of the project.


INCISOR.phrases."Hello World"
[type: string] 
One of the phrases defined in the ProjectTranscript.


INCISOR.phrases."Goodbye World"
[type: string] 
One of the phrases defined in the ProjectTranscript.





INCISOR.publishing
[type: Publishing] [requires: unpublished only] 
Object housing functionality for publishing projects.





INCISOR.precomps
[type: dictionary] 
Dictionary of Precomps





INCISOR.blendingModes
[type: dictionary] 
Dictionary of all blending mode names — both built-in ("none", "standard", "add", "subtract", "multiply") and any custom modes defined via nc.defineCustomBlendingMode — keyed by name. Use this to check whether a blending mode name is valid, or to iterate all available modes.


INCISOR.blendingModes.none
[type: string] 
A blending mode name.


INCISOR.blendingModes.standard
[type: string] 
A blending mode name.


INCISOR.blendingModes.add
[type: string] 
A blending mode name.


INCISOR.blendingModes.subtract
[type: string] 
A blending mode name.


INCISOR.blendingModes.multiply
[type: string] 
A blending mode name.


INCISOR.blendingModes.screen
[type: string] 
A blending mode name.





INCISOR.customBlendingModes
[type: dictionary] 
Dictionary of all defined CustomBlendingModes, keyed by name. Each entry's name is also registered in 'nc.blendingModes'.


INCISOR.customBlendingModes.incr_replaceText_customBlendingModesDocumentation
[type: dictionary] 






INCISOR.graphicAssets
[type: dictionary] 
Dictionary of all registered GraphicAssets.


INCISOR.graphicAssets.WhiteBox
[type: GraphicAsset] 
One of the currently defined GraphicAssets.


INCISOR.graphicAssets.WhiteTriangle
[type: GraphicAsset] 
One of the currently defined GraphicAssets.


INCISOR.graphicAssets.NullFont_Char0
[type: GraphicAsset] 
One of the currently defined GraphicAssets.





INCISOR.customAddOnDefs
[type: dictionary] [NON-INSTANTIABLE] 
A dictionary of the CustomAddOn definitions currently registered with this project. CustomAddOns are objects containing modular user-defined functionality that can be added to different types of SceneObjects in the GUI. The type of the particular CustomAddOn determines what type of SceneObject it can be added to. For example, a CustomAddOn_SceneObject can be added to all objects that inherit from SceneObject, while a CustomAddOn_Button can only be added to objects that inherit from Button. To add a CustomAddOn in code, simply create a new instance of the CustomAddOn, passing the owning object as the parameter. To make a CustomAddOn available in the Incisor inspector build a class that extends one of the CustomAddOn types within a 'codeAsset' file, then call 'nc.registerCustomAddOn' in a 'runBeforeInit' block to register the new CustomAddOn type with the GUI. Once a CustomAddOn is added to another object, it can be found in that object's 'customAddOns' member, which is a dictionary of CustomAddOns. 





INCISOR.renderTargets
[type: dictionary] 
Dictionary of all registered RenderTargets in this project. RenderTargets are objects that contain Textures to render to, as well as settings for how those textures may be resized automatically based on environmental factors such as canvas size, canvas aspect ratio, and the current asset package scale.


INCISOR.renderTargets.MainRenderTarget
[type: RenderTarget] 
One of the currently defined RenderTargets.





INCISOR.globalRenderTargetResolutionScaler
[type: number] [default: 1] 
Value that multiplies the resolution scale of all RenderTargets whose 'globalRenderTargetResolutionScaling' property is true.





INCISOR.mainRenderTarget
[type: RenderTarget] 
The main canvas RenderTarget.





INCISOR.defaultTimelineTimeSnap
[type: number] [default: 0.02] 
The default keyframe-time snap grid (in time units) that a brand-new Timeline adopts as its timeSnap. Sourced from the project's 'defaultTimelineTimeSnap' setting; defaults to 0.02 for projects that predate the setting. Existing Timelines keep their own stored timeSnap.





INCISOR.customObjectDefs
[type: dictionary] [NON-INSTANTIABLE] 
A dictionary of the CustomObject definitions currently registered with this project. CustomAddOns are objects containing modular user-defined functionality that can be added to different types of SceneObjects in the GUI. The type of the particular CustomAddOn determines what type of SceneObject it can be added to. For example, a CustomAddOn_SceneObject can be added to all objects that inherit from SceneObject, while a CustomAddOn_Button can only be added to objects that inherit from Button. To add a CustomAddOn in code, simply create a new instance of the CustomAddOn, passing the owning object as the parameter. To make a CustomAddOn available in the Incisor inspector build a class that extends one of the CustomAddOn types within a 'codeAsset' file, then call 'nc.registerCustomAddOn' in a 'runBeforeInit' block to register the new CustomAddOn type with the GUI. Once a CustomAddOn is added to another object, it can be found in that object's 'customAddOns' member, which is a dictionary of CustomAddOns. 





INCISOR.incisorApp
[type: IncisorApp] [requires: unpublished only] 
Object housing functionality allowing for direct interactions with the Incisor® application from within the javascript runtime. Such functionality includes the ability to get/set project and application settings, initiate the hosting of files in local directories, script the opening of new browser tabs, and perform other transactions with the Incisor® application.





INCISOR.incisorAppBasic
[type: IncisorAppBasic] [requires: unpublished only] 
Object housing basic functionality allowing for direct interactions with the Incisor® application from within the javascript runtime. Such functionality includes the ability to get the list of optional code modules from the Incisor™ application. See 'nc.incisorApp' for many more application interaction options.





INCISOR.tweenTypes
[type: dictionary] 
Object housing all defined TweenTypes. TweenTypes are used in conjunction with 'Swoopers' and define a method of numeric property interpolation between any two values or sets of values. TweenTypes can vary the timing of interpolation between two sets of values, as well as the path of the interpolation.


INCISOR.tweenTypes.Linear
[type: TweenType] 
The 'Linear' TweenType. This TweenType interpolates linearly between the current value/values and the end value/values. While some TweenTypes are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.


INCISOR.tweenTypes.Ease
[type: TweenType] 
The 'Ease' TweenType. This TweenType interpolates between the current value/values and the end value/values smoothly, accelerating from the starting values, and decelarating as the ending values are approached. While some TweenTypes are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.


INCISOR.tweenTypes.ExtremeEaseOut
[type: TweenType] 
The 'ExtremeEaseOut' TweenType. This TweenType changes very slowly at first and speeds up. While some TweenTypes are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.


INCISOR.tweenTypes.ExtremeEaseIn
[type: TweenType] 
The 'ExtremeEaseIn' TweenType. This TweenType changes very quickly at first and slows down. While some TweenTypes are included in projects automatically, many must first be added to the project as 'codeAsset' files using the 'TemplateLibrary' menu.





INCISOR.geometries
[type: dictionary] 
Dictionary of all registered Geometries.


INCISOR.geometries.WhiteBox
[type: Geometry] 
One of the currently defined Geometries.


INCISOR.geometries.WhiteTriangle
[type: Geometry] 
One of the currently defined Geometries.


INCISOR.geometries.NullFont_Char0
[type: Geometry] 
One of the currently defined Geometries.





INCISOR.canvasElement
[type: HTMLCanvasElement] 
The main canvas element for this project.





INCISOR.mainModifierKey
[type: string] 
The name of the keyboard key that serves as the main modifier key for keyboard input. For example while editing the text in a TextBox, the nc.mainModifierKey + the "A" key will select all. This property defaults to 'Control', unless the browser indicates it is running on OSX, in which case it defaults to 'Meta'.





INCISOR.constants
[type: Constants] 
Object housing predefined constant values for various Incisor® options and modes.





INCISOR.keyDownStates
[type: object] 
Dictionary with the current state of each key on the keyboard, regardless of pause states or focused objects (see nc.singularFocusObject). This can be used used to check the state of modifier keys such as the 'shift' or 'option' key. If the key in question is down, this object will have a member (with the key as the name) that is true, otherise the member will be undefined.





INCISOR.incisorExtensions_project
[type: object] [requires: unpublished only] 
The object housing the Incisor project extensions scope. This property will be undefined if the requirements are met, or if there are no project extensions.





INCISOR.incisorExtensions_global
[type: object] [requires: unpublished only] 
The object housing the Incisor global extensions scope. This property will be undefined if the requirements are met, or if there are no global extensions.





INCISOR.addWarningFilter(callbackOwner, callbackName, callbackArgs)
[type: function] 
A method to add a function that can filter Incisor warnings. Provide a function that take a warning string as its parameter. Use the given string to determine wether to return true or false. If the given function returns false, the warning in question is not displayed.

INCISOR.addWarningFilter parameter: callbackOwner
[type: object] 
The object owning the callback function.

INCISOR.addWarningFilter parameter: callbackName
[type: string] 
The name of the callback function.

INCISOR.addWarningFilter parameter: callbackArgs
[type: [any], any] [optional] 
Parameters for the callback function. Paremeters provided here will be supplied to the callback as subsequent parameters to the warning string, which will always be provided as the initial parameter.





INCISOR.removeWarningFilter(callbackOwner, callbackName)
[type: function] 
Removes the given callback

INCISOR.removeWarningFilter parameter: callbackOwner
[type: object] 
The object owning the callback function.

INCISOR.removeWarningFilter parameter: callbackName
[type: string] 
The name of the callback function.





INCISOR.inheritMatrix4(obj)
[type: function] 
Adds Matrix4 functionality to the object supplied.

INCISOR.inheritMatrix4 parameter: obj
[type: object] 
The object that Martix4 functionality is being added to.





INCISOR.defineFlowController(name, pauseImmunity, speedControl)
[type: function] 
Defines a new FlowController FlowControllers provide a way to organize the general flow of state-based items in a project. For example if your project is a game with an intro, a menu, and several levels, you could create a FlowController named "GameFlowController" and then define and add an 'Intro' FlowState, a 'Menu' FlowState, and 'LevelXX' FlowStates to that FlowController. Within each FlowState in the FlowController, timed callback elements can be added to help define the sequencing within each FlowState. Once created, FlowControllers, FlowStates, and FlowStateElements can be accessed via 'nc.flows'. This class is not meant to be instantiated or provided directly to 'FlowController.addFlowState', rather it is meant to be a class for user-defined FlowStates to extend. Use 'nc.flows' to access the newly defined FlowController.

INCISOR.defineFlowController parameter: name
[type: string] 
The name of the new FlowController

INCISOR.defineFlowController parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this FlowController will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

INCISOR.defineFlowController parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this FlowController is affected by.





INCISOR.defineSyncedLoopingTrackGroup(name, includedSounds)
[type: function] [requires: module - sounds] 
Defines a new group of sounds that will stay synced while looping. Sounds in HTML5 run on a separate thread from the main javascript thread, and as a result there can be small delays between the instructions to play sounds, and when the sounds actually play. These discrepancies can lead to difficulty with keeping multiple looping tracks in sync. This function creates a group of sounds whose instructions are linked in a way that keeps them in sync, regardless of pausing/resuming, changes to volume, or lazy-loaded sounds starting mid-stream.

INCISOR.defineSyncedLoopingTrackGroup parameter: name
[type: string] 
The name of the new SyncedLoopingTrackGroup. This name must be unique among SyncedLoopingTrackGroups.

INCISOR.defineSyncedLoopingTrackGroup parameter: includedSounds
[type: [Sound]] 
Array of Sounds to include in the SyncedLoopingTrackGroup.





INCISOR.defineVolumeControl(name)
[type: function] [returns: VolumeControl] [requires: module - sounds] 
Defines a new VolumeControl. VolumeControls are a way to control the volumes of groups of sounds, much like a 'audio bus'. To make a particular Sound subscribe to a VolumeControl, add the VolumeControl to the Sound's 'volumeControl' array.

INCISOR.defineVolumeControl parameter: name
[type: string] 
The name of the new VolumeControl. This name must be unique among VolumeControls.





INCISOR.defineTexture(name, source)
[type: function] [returns: Texture] 
Defines a new Texture from a supplied PixelsObject or Base64 string. For a list of all available Textures, see 'nc.textures'.

INCISOR.defineTexture parameter: name
[type: string] 
The name of the new Texture. This name must be unique among registered Textures.

INCISOR.defineTexture parameter: source
[type: PixelsObject, string] 
The source for this new Texture - either a PixelsObject or the base64 string .





INCISOR.defineTextures(names, sources)
[type: function] [returns: [Texture]] 
Defines new Textures from a supplied array of PixelsObjects or Base64 strings. Use this function instead of 'nc.defineTexture' when creating many textures, as it is able to asynchronously multi-task the creation of the Textures, making it faster in that scenario.

INCISOR.defineTextures parameter: names
[type: [string]] 
The names of the new Textures. Each name must be unique among registered Textures.

INCISOR.defineTextures parameter: sources
[type: [PixelsObject], [string]] 
The sources for these new Textures - either an array of PixelsObjects or the array of base64 strings.





INCISOR.defineMotionType(name, motionFunction, motionControllerNames, motionControllerDefaultValues, description, controllerDescriptions)
[type: function] [returns: MotionType] 
Defines a new MotionType. MotionTypes are used in conjunction with 'Motions' and define a method of continuous change for numeric properties. The MotionType 'Pendulum' is automatically defined, which defines a smooth sinusoidal oscillation between the lower and upper bounds. All defined MotionTypes can be found at 'nc.motionTypes'.

INCISOR.defineMotionType parameter: name
[type: string] 
The name of the new MotionType.

INCISOR.defineMotionType parameter: motionFunction
[type: function] 
The function controlling the continuous change of the numeric properties being affected by the Motion using this MotionType. This function should be implemented to take a single 'Motion' parameter, using it's 'progress', 'lowerBound', 'upperBound', 'motionSpeed', and 'motionArgs' members to calculate and return an array of current values.

INCISOR.defineMotionType parameter: motionControllerNames
[type: [string]] [optional] 
The names of optional controllers that can be used to dynamically affect the nature of the motion type.

INCISOR.defineMotionType parameter: motionControllerDefaultValues
[type: [number]] [optional] 
The default values of optional controllers that can be used to dynamically affect the nature of the motion type.

INCISOR.defineMotionType parameter: description
[type: string] [optional] 
The description of the MotionType - this will appear in the autocomplete documentation.

INCISOR.defineMotionType parameter: controllerDescriptions
[type: [string]] [optional] 
The descriptions of the MotionType controllers - these will appear in the autocomplete documentation.

example:
// Objective: Define a custom MotionType.
// Expected Result: The white box will move continuously in a circular motion.

function moveInCircleFunction(motion) {   
    let progress = motion.progress;
    // Calculate circle center and radius.
    let centerX = (motion.lowerBounds[0]+motion.upperBounds[0])*.5;
    let centerY = (motion.lowerBounds[1]+motion.upperBounds[1])*.5;
    let radiusX = motion.upperBounds[0]-centerX;
    let radiusY = motion.upperBounds[1]-centerY;
    // Apply circle math.
    motion.currentValues[0]=centerX+radiusX*Math.cos(progress*Math.PI);
    motion.currentValues[1]=centerY+radiusY*Math.sin(progress*Math.PI);
    motion.currentValues[2]=0;
}

// Define 'MoveInCircle' Motion
nc.defineMotionType(
    "MoveInCircle",
    moveInCircleFunction,
    undefined,
    undefined,
    "This MotionType moves x and y components in a circle."
 );

 // Create a GraphicObject.
 let graphicObject = new GraphicObject();
 // Add a motion to the GraphicObject's position using the 'MoveInCircle' TweenType. A 'Motion' object is returned and can be manipulted.
 let motion = graphicObject.position.addMotion.each([-300,-100,0],[300,100,10],1,nc.motionTypes.MoveInCircle);





INCISOR.addMotion(propertyOwners, propertyNames, lowerBounds, upperBounds, motionSpeed, motionType, pauseImmunity, speedControl, eventCallbackOwner, eventCallbackName)
[type: function] [returns: Motion] 
Adds a motion defining a continuous change a given numeric property or set of properties, and returns a Motion object, which can be used to control the motion dynamically.

INCISOR.addMotion parameter: propertyOwners
[type: object, [object]] 
The object or array of objects owning the numeric properties to add motion to.

INCISOR.addMotion parameter: propertyNames
[type: string, [string]] 
The name or array of names of the numeric properties to add motion to.

INCISOR.addMotion parameter: lowerBounds
[type: number, [number]] 
The lower bounds for the motion being added.

INCISOR.addMotion parameter: upperBounds
[type: number, [number]] 
The upper bounds for the motion being added.

INCISOR.addMotion parameter: motionSpeed
[type: number] [default: 1] [optional] 
The speed factor for the added motion.

INCISOR.addMotion parameter: motionType
[type: MotionType] [default: nc.motionTypes.Pendulum] [optional] 
The MotionType, determining the nature of the motion being added.

INCISOR.addMotion parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Motion will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

INCISOR.addMotion parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Motion is affected by.

INCISOR.addMotion parameter: eventCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the motion.

INCISOR.addMotion parameter: eventCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the motion.

example:
// Objective: Add motion to the white box along the x axis.
// Expected Result: The white box should continuously move back and forth.

let whiteSquare = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "WhiteSquare" );
// add motion to the "x" property of the position of the white square
nc.addMotion( whiteSquare.position, "x", -500, 500, .5 );





INCISOR.inheritTextAssembly(obj, parent, name)
[type: function] 
Adds TextAssembly functionality to the object supplied.

INCISOR.inheritTextAssembly parameter: obj
[type: object] 
The object that TextAssembly functionality is being added to.

INCISOR.inheritTextAssembly parameter: parent
[type: SceneObject] [optional] 
The SceneObject that will become the new TextAssembly's parent in the Scene hierarchy.

INCISOR.inheritTextAssembly parameter: name
[type: string] [optional] 
The name of the new TextAssembly.





INCISOR.addTextAssembly(parent, name)
[type: function] [returns: TextAssembly] 
Adds a TextAssembly as a child of the given SceneObject.

INCISOR.addTextAssembly parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The SceneObject that will become the new TextAssembly's parent in the Scene hierarchy.

INCISOR.addTextAssembly parameter: name
[type: string] [default: 'TextBox'] [optional] 
The name of the new TextAssembly.

example:
// Objective: Add a TextAssembly.
// Expected Result: You will see the text "Incisor - Build It Once." on screen.

let textAssembly = nc.addTextAssembly( nc.mainScene );
textAssembly.string = "Incisor - Build It Once."





INCISOR.getSearchFilterScore(filterString, candidateStrings, candidateStringWeights)
[type: function] [returns: number] 
Scores how well a search filter matches one or more candidate strings, for ranking and filtering lists and menus. This is the single standardized search scorer used throughout Incisor's inspector UI (searchable menus, large-list menus, and the inspector panels' search fields). The filter is split into whitespace-separated tokens; each token is scored against each candidate string and the results are summed (optionally weighted per candidate). A single token scores against a single candidate as follows: exact match = 1, case-insensitive exact match = 0.8, case-insensitive prefix match = 0.75, substring match = 0.5, case-insensitive substring match = 0.25, otherwise 0. A returned score greater than 0 indicates a match; higher scores are more relevant. Because the filter is tokenized, multi-word searches match across candidates and across word order (e.g. 'hero jump' matches 'Hero-JumpTimeline').

INCISOR.getSearchFilterScore parameter: filterString
[type: string] 
The search text. Split on spaces into tokens.

INCISOR.getSearchFilterScore parameter: candidateStrings
[type: [string]] 
The string(s) to score the filter against (for example an item's name, or [name, description]).

INCISOR.getSearchFilterScore parameter: candidateStringWeights
[type: [number]] [optional] 
Optional per-candidate multipliers, parallel to candidateStrings. Each defaults to 1.





INCISOR.sanitizeNameForCode(name)
[type: function] [returns: string] 
Sanitizes the provided name to make it suitable for code by removing any leading digits, spaces, or special characters.

INCISOR.sanitizeNameForCode parameter: name
[type: string] 
The name to be sanitized.





INCISOR.saveScreenShot(path, isPathRelative)
[type: function] [returns: string] 
Saves a screen shot of the project, and returns the path of the new screen shot.

INCISOR.saveScreenShot parameter: path
[type: string] 
The path to the screenshot. If left undefined, a timestamped screen shot will be placed in the directory indicated by 'ProjectSettings.screenShotDestination'.

INCISOR.saveScreenShot parameter: isPathRelative
[type: boolean] 
Boolean determining if the screen shot's path is relative to the project.





INCISOR.defineEffectController(name, baseType, componentNames, defaultValues, mixMode, likelyRanges, effectControllerDescription, componentDescriptions)
[type: function] 
EffectControllers provide the ability to dynamically control EffectNodes and their resulting visual effects. EffectControllers are generally one of 3 base types, Vectors, numbers, and Textures. Once defined, EffectControllers will be generally available on all SceneObjects, Materials, MaterialMaster, CharacterMaterial objects; It should be noted that while these objects will have all EffectControllers as members, only the EffectControllers tied to the objects' current EffectNodes will cause any change visually. It should also be noted EffectControllers with 'mixMode=materialOnly' will not be available on SceneObjects for inheritance, and will instead only be on Material and MaterialMaster objects for direct manipulation.

INCISOR.defineEffectController parameter: name
[type: string] 
The name of the new EffectController. This name must be unique, and it must not contain any javascript delimeters (no spaces, commas, periods, etc...)

INCISOR.defineEffectController parameter: baseType
[type: string] 
The base type of the new EffectController. For a list of available base types, see 'nc.constants.effectControllerBaseTypes'.

INCISOR.defineEffectController parameter: componentNames
[type: [string]] 
An array of names for the components of this EffectController. An example would be ['magnitude', 'brightness', 'fadeAmount']. It should be noted that EffectControllers with componentNames ["red","green","blue","alpha"] will automatically have type 'Color', and similarly componentNames ["x","y", etc...] will have the associated 'Vector' type. For non-Vector types this can be left undefined.

INCISOR.defineEffectController parameter: defaultValues
[type: [number], number, Texture] 
An array of numbers (for Vector baseTypes), number (for number baseTypes), or Texture (for Texture baseTypes) that serve as the default value(s) for this EffectController's components.

INCISOR.defineEffectController parameter: mixMode
[type: string] 
The means by which parent and child EffectControllers' values are blended together. Please note that a mixMode value of 'materialOnly' means that the given EffectController will only appear directly on Material and MaterialMaster objects, and therefore no mixing of values will ever take place. For a list of available mixModes, see 'nc.constants.effectControllerMixModes'.

INCISOR.defineEffectController parameter: likelyRanges
[type: [[number]], [number]] [default: [[0,10] [optional] 
A list of likely ranges for the components of this EffectController. This is used to inform the Incisor® GUI, specifically the sensativity of EffectoController 'sliders'. A 'number' EffectController takes a flat range such as [0,10], while a Vector takes one range per component such as [[0,1],[0,180]]. A flat range given to a Vector applies to every component.,[0,10]...]]

INCISOR.defineEffectController parameter: effectControllerDescription
[type: string] [default: ""] [optional] 
Optional description to help populate IDE autocomplete related to this EffectController.

INCISOR.defineEffectController parameter: componentDescriptions
[type: [string], string] [default: [] [optional] 
Optional list of component descriptions to help populate IDE autocomplete related to this EffectController.]





INCISOR.defineAppEvent(eventName, hasSingularFocusScheme, isOrdered, hasConsumableCallbacks)
[type: function] [returns: AppEvent] 
Defines a new custom Incisor® AppEvent that can have callbacks added and can be triggered using 'AppEvent.trigger'.

INCISOR.defineAppEvent parameter: eventName
[type: string] 
The name of the new AppEvent being defined.

INCISOR.defineAppEvent parameter: hasSingularFocusScheme
[type: boolean] [default: false] [optional] 
Flag indicating if this AppEvent will have a 'singular focus scheme' which is a system that restricts callback invocation to items associated with the currently 'focused' object as determined by nc.singularFocusObject.

INCISOR.defineAppEvent parameter: isOrdered
[type: boolean] [default: false] [optional] 
Flag indicating if this AppEvent will be 'ordered', which allows callbacks added to this AppEvent to be provided a callback order number, which is then used to sort the callbacks when the AppEvent is triggered.

INCISOR.defineAppEvent parameter: hasConsumableCallbacks
[type: boolean] [default: false] [optional] 
Flag indicating if this AppEvent removes callbacks after one invocation.

example:
// Objective: Trigger a custom AppEvent.
// Expected Result: You will see a green square.

// create a white box GraphicObject
this.whiteBox = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "WhiteBox" );

// define a custom AppEvent and add its callback
nc.defineAppEvent( "MyCustomAppEvent" );
nc.appEvents.MyCustomAppEvent.addCallback( this, "myAppEventCallback" );

// the AppEvent callback will update the fillColor of the box
this.myAppEventCallback = function( r, g, b, a ) {
    this.whiteBox.fillColor = new Color( r, g, b, a );
}

// trigger my AppEvent passing in parameters as an array (set the red and blue to zero)
nc.appEvents.MyCustomAppEvent.trigger( [0, 1, 0, 1] );





INCISOR.definePauseEvent(pauseEventName)
[type: function] [returns: PauseEvent] 
Defines a new PauseEvent. The various time-based and user-interaction processes in Incisor® can be paused by calling 'nc.pause' with a PauseEvent parameter. Pausable processes can also opt out of being paused by providing a 'pauseImmunity' list during their initiation (as will be indicated in initiating method parameters). The pauseImmunity list is a list of PauseEvents that the given process will be immune to. All defined PauseEvents can be found at 'nc.pauseEvents'.

INCISOR.definePauseEvent parameter: pauseEventName
[type: string] 
The name of the new PauseEvent.





INCISOR.pause(pauseEvent)
[type: function] 
Pauses the various time-based and user-interaction processes that can be paused by the supplied PauseEvent. Processes that list the supplied PauseEvent in their 'pauseImmunity' will be immune to this pause.

INCISOR.pause parameter: pauseEvent
[type: PauseEvent] 
The PauseEvent being triggered. Available PauseEvents can be found in 'nc.pauseEvents'.

example:
// Objective: Pause and resume motion.
// Expected Result: The white box will move up and down along the y axis for 3 seconds, then pause for 3 seconds, then resume again.

// create a GraphicObject with the white box asset
let graphic = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Box" );
// add motion to the position of this GraphicObject along the y axis with a motion speed of 2
graphic.position.addMotion.y( -300, 300, 2 );
// create a PauseEvent
nc.definePauseEvent("BoxPause");
// wait 3 seconds, then call "pause", passing BoxPause as the PauseEvent
nc.waitThen( 3, nc, "pause", [nc.pauseEvents.BoxPause] );
       
// wait 6 seconds, then call "resume"
// NOTE: At this point, "resume" is paused by the BoxPause event. This is why we must also
// pass the BoxPause event as the "pauseImmunity" parameter.
nc.waitThen( 6, nc, "resume", nc.pauseEvents.BoxPause , undefined, nc.pauseEvents.BoxPause );





INCISOR.resume(pauseEvent)
[type: function] 
Resumes the processes that were paused by the supplied PauseEvent. Some processes may not resume if they are still being affected by other PauseEvents.

INCISOR.resume parameter: pauseEvent
[type: PauseEvent] 
The PauseEvent being resumed. Available PauseEvents can be found in 'nc.pauseEvents'.

example:
// Objective: Pause and resume motion.
// Expected Result: The white box will move up and down along the y axis for 3 seconds, then pause for 3 seconds, then resume again.

// create a GraphicObject with the white box asset
let graphic = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Box" );
// add motion to the position of this GraphicObject along the y axis with a motion speed of 2
graphic.position.addMotion.y( -300, 300, 2 );
// create a PauseEvent
nc.definePauseEvent("BoxPause");
// wait 3 seconds, then call "pause", passing BoxPause as the PauseEvent
nc.waitThen( 3, nc, "pause", [nc.pauseEvents.BoxPause] );
       
// wait 6 seconds, then call "resume"
// NOTE: At this point, "resume" is paused by the BoxPause event. This is why we must also
// pass the BoxPause event as the "pauseImmunity" parameter.
nc.waitThen( 6, nc, "resume", nc.pauseEvents.BoxPause , undefined, nc.pauseEvents.BoxPause );





INCISOR.defineSpeedControl(speedControlName)
[type: function] [returns: SpeedControl] 
Defines a new SpeedControl. SpeedControls can be used to control the speed of time-based sequencing processes such as Motions, Swoops, or Timelines. Applicable processes can subscribe to multiple SpeedControls; the 'speed' values of all of the SpeedControls a process subscribes to are multiplied together to determine the overall pacing of the given time-based process. All defined SpeedControls can be found at 'nc.speedControls'.

INCISOR.defineSpeedControl parameter: speedControlName
[type: string] 
The name of the new SpeedControl.





INCISOR.getAllEventRecipients()
[type: function] [returns: object] 
Returns a dictionary containing lists of all active callbacks per AppEvent.





INCISOR.relinquishFocus()
[type: function] 
Sets nc.singularFocusObject to nc.singularFocusObject.focusFallback.





INCISOR.copyToClipboard(text)
[type: function] 
Copies the given text to the clipboard.

INCISOR.copyToClipboard parameter: text
[type: string] 
The text to be copied to the clipboard.





INCISOR.getClipboardText()
[type: function] [returns: string] 
Retrieves text from the clipboard.





INCISOR.editGeometry(geometry, callbackOwner, callbackName, callbackArgs)
[type: function] [returns: GeometryEditor] 
Asyncronously retrieves a GeometryEditor to enable the editing of the Geometry provided. Please note that before you attempt to do any editing, the source Geometry must be loaded; you must either asyncronously await this function call, or provide a callback, which will be called once the souece Geometry is loaded. The first parameter of the callback will be the desired GeometryEditor.

INCISOR.editGeometry parameter: geometry
[type: Geometry] 
The source Geometry to be edited.

INCISOR.editGeometry parameter: callbackOwner
[type: object] [optional] 
The object owning the callback that will be called when the source Geometry loads.

INCISOR.editGeometry parameter: callbackName
[type: string] [optional] 
The name of the callback that will be called when the source Geometry loads.

INCISOR.editGeometry parameter: callbackArgs
[type: Array, any] [optional] 
The arguments for the callback that will be called when the source Geometry loads.





INCISOR.defineParticleSystem(name)
[type: function] [returns: ParticleSystemDefinition] 
Defines a new ParticleSystemDefinition. This can then be used to instantiate a new ParticleSystem. Multiple ParticleSystemDefinitions that use the same ParticleSystemDefinition will share the Geometry and EffectNode created by the ParticleSystemDefinition. Therefore, creation of additional ParticleSystemDefinitions that use the same ParticleSystemDefinition incur much less memory usage and initialization time compared to multiple ParticleSystemDefinitions that each use their own ParticleSystemDefinition.

INCISOR.defineParticleSystem parameter: name
[type: string] 
The name of the ParticleSystemDefinition.





INCISOR.addParticleSystem(particleSystemDefinition, parent, name, pauseImmunity, speedControl)
[type: function] [returns: ParticleSystem] 
Adds a ParticleSystem set to the provided ParticleSystemDefinition as a child of the given SceneObject.

INCISOR.addParticleSystem parameter: particleSystemDefinition
[type: ParticleSystemDefinition] [default: nc.particleSystemDefs.MainParticleSystem] [optional] 
The definition used to build this ParticleSystem. If left undefined, then 'MainParticleSystem' will be chosen - if 'MainParticleSystem' is not yet defined, it will automatically be defined and then used as the default.

INCISOR.addParticleSystem parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The SceneObject that will become the new ParticleSystem's parent in the Scene hierarchy.

INCISOR.addParticleSystem parameter: name
[type: string] [default: 'ParticleSystem'] [optional] 
The name of the new ParticleSystem.

INCISOR.addParticleSystem parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this ParticleSystem will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

INCISOR.addParticleSystem parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this ParticleSystem is affected by.

example:
// Objective: Add a ParticleSystem.
// Expected Result: You will see white triangles continuously "bursting" out from the center of the screen.

// add a ParticleSystem using the predefined "BurstWithGravity" ParticleSystemDefinition
let particles = nc.addParticleSystem( nc.particleSystemDefs.BurstWithGravity, nc.mainScene, "MyParticles" );
particles.playbackController.play();





INCISOR.inheritParticleSystemRamp1(obj)
[type: function] 
Adds ParticleSystemRamp1 functionality to the object supplied.

INCISOR.inheritParticleSystemRamp1 parameter: obj
[type: object] 
The object that ParticleSystemRamp1 functionality is being added to.





INCISOR.inheritParticleSystemRamp2(obj)
[type: function] 
Adds ParticleSystemRamp2 functionality to the object supplied.

INCISOR.inheritParticleSystemRamp2 parameter: obj
[type: object] 
The object that ParticleSystemRamp2 functionality is being added to.





INCISOR.inheritParticleSystemRamp3(obj)
[type: function] 
Adds ParticleSystemRamp3 functionality to the object supplied.

INCISOR.inheritParticleSystemRamp3 parameter: obj
[type: object] 
The object that ParticleSystemRamp3 functionality is being added to.





INCISOR.inheritParticleSystemRamp4(obj)
[type: function] 
Adds ParticleSystemRamp4 functionality to the object supplied.

INCISOR.inheritParticleSystemRamp4 parameter: obj
[type: object] 
The object that ParticleSystemRamp4 functionality is being added to.





INCISOR.inheritSceneObject(obj, name, pauseImmunity, speedControl)
[type: function] 
Adds PlaybackController functionality to the object supplied.

INCISOR.inheritSceneObject parameter: obj
[type: object] 
The object that PlaybackController functionality is being added to.

INCISOR.inheritSceneObject parameter: name
[type: string] [default: "PlaybackController"] [optional] 
The name of the PlaybackController.

INCISOR.inheritSceneObject parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this PlaybackController will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

INCISOR.inheritSceneObject parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this PlaybackController is affected by.





INCISOR.getAncestors(sceneObject)
[type: function] [returns: [SceneObject]] 
Returns a list of all of the ancesters of the given SceneObject. Ancesters consist of the SceneObject's parent, and that parent's parent, etc...

INCISOR.getAncestors parameter: sceneObject
[type: SceneObject] 
The SceneObject whose ancestors will be listed.





INCISOR.getDescendants(sceneObject, enabledOnly, includeEnclosedScenes)
[type: function] [returns: [SceneObject]] 
Returns a list of all of the descendants of the given SceneObject. Descendants consist of the SceneObject's children, and their children, etc...

INCISOR.getDescendants parameter: sceneObject
[type: SceneObject] 
The SceneObject whose descendants will be listed.

INCISOR.getDescendants parameter: enabledOnly
[type: boolean] [default: true] 
Boolean determining if only enabled SceneObjects are added to the returned list.

INCISOR.getDescendants parameter: includeEnclosedScenes
[type: boolean] [default: false] 
Boolean determining if sub-descendants of ScrollingPanels' Scenes will be included in the returned list.





INCISOR.addSceneObject(parent, name)
[type: function] [returns: SceneObject] 
Adds a SceneObject as a child of the given SceneObject.

INCISOR.addSceneObject parameter: parent
[type: SceneObject] [optional] 
The SceneObject that will be the new SceneObject's parent.

INCISOR.addSceneObject parameter: name
[type: string] [default: 'SceneObject'] [optional] 
The name of the new SceneObject.

example:
// Objective: Add a SceneObject with a graphic and rotate it.
// Expected Result: The white box has rotated 45 degrees into a diamond shape.

// Create a SceneObject using the SceneObject constructor. This will add "MySceneObject" to the main scene.
let mySceneObject = nc.addSceneObject( nc.mainScene, "MySceneObject" );
// Add a GraphicObject to the SceneObject using the GraphicObject constructor.
// Note: To use a custom graphic, add your image file to the assets directory and access it using nc.graphicAssets['MyImage']
new GraphicObject( nc.graphicAssets.WhiteBox, mySceneObject, "MyGraphicObject" );
// Rotate the SceneObject 45 degrees around the z axis.
mySceneObject.rotation.z = 45;





INCISOR.assessCumulativeLoadingTierRequirements(sceneObject, ignoreCachedAssessment)
[type: function] [returns: [number]] 
Returns the list of LoadingTiers that must be loaded for the given SceneObject, its descendants, and all Textures and Geometries to be fully loaded.

INCISOR.assessCumulativeLoadingTierRequirements parameter: sceneObject
[type: SceneObject] 
The SceneObject whose LoadingTier will be assessed.

INCISOR.assessCumulativeLoadingTierRequirements parameter: ignoreCachedAssessment
[type: boolean] [default: false] [optional] 
Boolean determining if any cached assessments will be ignored, forcing an entirely new assessment to be made.





INCISOR.defineEffectNode(name, vertexNodeSupport, vertexNode, fragmentNodeSupport, fragmentNode, associatedEffectControllers, requiresDerivativesShaderExtension, requiresFragDepthShaderExtension, requiresDrawBuffersShaderExtension, requiresTextureLODShaderExtension, description)
[type: function] [returns: EffectNode] 
Defines a new EffectNode. Defined EffectNodes are available at 'nc.effectNodes'. EffectNodes are GPU-driven visual effects assigned to SceneObjects, GraphicObjects, and ultimately Materials. Each EffectNode can be manipulated dynamically by one or more EffectControllers, which are accessable as direct members of the given SceneObject or Material. When a GraphicObject is set to a particular GraphicAsset, it's Materials adopt the GraphicAsset's EffectNode and EffectController presets by default, but they can be customized at any time.

INCISOR.defineEffectNode parameter: name
[type: string] 
The name of the new EffectNode. This name must be unique among EffectNodes.

INCISOR.defineEffectNode parameter: vertexNodeSupport
[type: [string], string] 
The portion of the GLSL shader code for this EffectNode above the 'vertex main'. This segment of code is where uniform and varying variables for the vertex portion of this effect are likely to be declared.

INCISOR.defineEffectNode parameter: vertexNode
[type: string] 
The portion of the GLSL shader code for this EffectNode within the 'vertex main'. This segment of code is is where this effect can make its adjustments to the 'vertex' vec3.

INCISOR.defineEffectNode parameter: fragmentNodeSupport
[type: [string], string] 
The portion of the GLSL shader code for this EffectNode above the 'fragment main'. This segment of code is where uniform and varying variables for the fragment portion of this effect are likely to be declared.

INCISOR.defineEffectNode parameter: fragmentNode
[type: string] 
The portion of the GLSL shader code for this EffectNode within the 'fragment main'. This segment of code is is where this effect can make its adjustments to the 'fragment' vec4.

INCISOR.defineEffectNode parameter: associatedEffectControllers
[type: [EffectControllerDefinition], EffectControllerDefinition] 
The array of the EffectController that this EffectNode is associated with. These EffectControllers will be the means of dynamic manipulation for this EffectNode's visual effects. See 'nc.effectControllers' for a list of available EffectControllers.

INCISOR.defineEffectNode parameter: requiresDerivativesShaderExtension
[type: boolean] [default: false] [optional] 
Boolean determining if the shader of any Material with this EffectNode is compiled to support the 'FragDepth' extension.

INCISOR.defineEffectNode parameter: requiresFragDepthShaderExtension
[type: boolean] [default: false] [optional] 
Boolean determining if the shader of any Material with this EffectNode is compiled to support the 'FragDepth' extension.

INCISOR.defineEffectNode parameter: requiresDrawBuffersShaderExtension
[type: boolean] [default: false] [optional] 
Boolean determining if the shader of any Material with this EffectNode is compiled to support the 'DrawBuffers' extension.

INCISOR.defineEffectNode parameter: requiresTextureLODShaderExtension
[type: boolean] [default: false] [optional] 
Boolean determining if the shader of any Material with this EffectNode is compiled to support the 'TextureLOD' extension.

INCISOR.defineEffectNode parameter: description
[type: string] [default: ""] [optional] 
An optional human-readable description of what this EffectNode does, shown in the inspector tooltip.





INCISOR.inheritButton(obj, graphicAsset, parent, name)
[type: function] 
Adds Button functionality to the object supplied.

INCISOR.inheritButton parameter: obj
[type: object] 
The object that Button functionality is being added to.

INCISOR.inheritButton parameter: graphicAsset
[type: GraphicAsset] [default: nc.graphicAssets.WhiteBox] [optional] 
The GraphicAsset that the new Button will initially be set to. For a list of available GraphicAssets, see 'nc.graphicAssets'.

INCISOR.inheritButton parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The SceneObject that will become the new Button's parent in the Scene hierarchy.

INCISOR.inheritButton parameter: name
[type: string] [default: 'Button'] [optional] 
The name of the new Button.





INCISOR.addButton(graphicAsset, parent, name)
[type: function] [returns: Button] 
Adds a Button set to the provided GraphicAsset as a child of the given SceneObject.

INCISOR.addButton parameter: graphicAsset
[type: GraphicAsset] [default: nc.graphicAssets.WhiteBox] [optional] 
The GraphicAsset that the new Button will initially be set to. For a list of available GraphicAssets, see 'nc.graphicAssets'.

INCISOR.addButton parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The SceneObject that will become the new Button's parent in the Scene hierarchy.

INCISOR.addButton parameter: name
[type: string] [default: 'Button'] [optional] 
The name of the new Button.

example:
// Objective: Use Incisor to add a Button.
// Expected Result: The console should display all of the properties of the new button. 

let button = nc.addButton( nc.graphicAssets.WhiteBox, nc.mainScene, "MyButton" );
console.log(button);





INCISOR.inheritGraphicObject(obj, graphicAsset, parent, name)
[type: function] 
Adds GraphicObject functionality to the object supplied.

INCISOR.inheritGraphicObject parameter: obj
[type: object] 
The object that GraphicObject functionality is being added to.

INCISOR.inheritGraphicObject parameter: graphicAsset
[type: GraphicAsset] [default: nc.graphicAssets.WhiteBox] [optional] 
The GraphicAsset that the new GraphicObject will initially be set to. For a list of available GraphicAssets, see 'nc.graphicAssets'.

INCISOR.inheritGraphicObject parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The SceneObject that will become the new GraphicObject's parent in the Scene hierarchy.

INCISOR.inheritGraphicObject parameter: name
[type: string] [default: 'GraphicObject'] [optional] 
The name of the new GraphicObject.





INCISOR.addGraphicObject(graphicAsset, parent, name)
[type: function] [returns: GraphicObject] 
Adds a GraphicObject set to the provided GraphicAsset as a child of the given SceneObject.

INCISOR.addGraphicObject parameter: graphicAsset
[type: GraphicAsset] [default: nc.graphicAssets.WhiteBox] [optional] 
The GraphicAsset that the new GraphicObject will initially be set to. For a list of available GraphicAssets, see 'nc.graphicAssets'.

INCISOR.addGraphicObject parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The SceneObject that will become the new GraphicObject's parent in the Scene hierarchy.

INCISOR.addGraphicObject parameter: name
[type: string] [default: 'GraphicObject'] [optional] 
The name of the new GraphicObject.

example:
// Objective: Use Incisor to add a GraphicObject, rotate it, change its color and move its position.
// Expected Result: You should see a blue, diamond shaped box, moved up and left of center. 

let graphicObject = nc.addGraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "MyGraphicObject" );

// rotate 45 degrees around the z axis to create a "diamond" shape
graphicObject.rotation.z = 45;
// set the red and green channels to zero to make the box blue
graphicObject.colorMultiply.red = 0;
graphicObject.colorMultiply.green = 0;
// move the box up and to the left
graphicObject.position.x = -500;
graphicObject.position.y = 500;





INCISOR.defineMaskGroup(maskGroupName)
[type: function] [returns: MaskGroup] 
Defines a new MaskGroup. MaskGroups can be used to selectively render partial areas of GraphicObjects. Once a MaskGroup is defined, GraphicObjects can be made into 'masks', which results in their shape contributing to the MaskGroup area. GraphicObjects can also be made into 'masked', which results in them only rendering within the designated MaskGroup area. Please note that the masking area is calculated off of the full-fill Geometry of the 'mask' GraphicObjects; the transperancy of pixels within a 'mask' GraphicObject does not make any difference to masking.

INCISOR.defineMaskGroup parameter: maskGroupName
[type: string] 
The name of the new MaskGroup. This must be a unique name among MaskGroups.

example:
// Objective: Use a mask to reveal only a portion of the phrase "Hello World."
// Expected Result: You will see the word "World." on screen.

// define "MyMask"
let maskGroup = nc.defineMaskGroup( "MyMask" );
 
// create a TextBox
let textBox = nc.addTextBox( nc.mainScene );
textBox.string = "Hello World.";
textBox.masking.makeMasked( nc.maskGroups.MyMask ); // mask it with "MyMask"

// create a GraphicObject rectangle and position it to cover the word "World."
this.masker = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Masker" );
this.masker.scale.x = 2; // rectangle
this.masker.position.x = 75; // position
this.masker.masking.makeMask( nc.maskGroups.MyMask ); // make it a masker for "MyMask"





INCISOR.inheritOrthographicCamera(obj, parent, name)
[type: function] 
Adds OrthographicCamera functionality to the object supplied.

INCISOR.inheritOrthographicCamera parameter: obj
[type: object] 
The object that Camera functionality is being added to.

INCISOR.inheritOrthographicCamera parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The parent of the new Camera.

INCISOR.inheritOrthographicCamera parameter: name
[type: string] [optional] 
The name of the new Camera.





INCISOR.addOrthographicCamera(parent, name)
[type: function] [returns: OrthographicCamera] 
Adds an OrthographicCamera to the given parent.

INCISOR.addOrthographicCamera parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The SceneObject that will become the new OrthographicCamera's parent.

INCISOR.addOrthographicCamera parameter: name
[type: string] [default: OrthographicCamera] [optional] 
The name of the new OrthographicCamera. This name must be unique among camera names.





INCISOR.loadTier(tier, prioritize)
[type: function] 
Initiates the process of loading all of the assets in a given loading tier. This function does not need to be called for 'auto-loaded' LoadingTiers.

INCISOR.loadTier parameter: tier
[type: number] 
The desired tier for loading. For a list of available LoadingTiers, see nc.LoadingTiers.

INCISOR.loadTier parameter: prioritize
[type: boolean] [default: false] [optional] 
Bool determining if the tier in question will jump to the frot of the loading queue.





INCISOR.addTierLoadedCallback(tiers, callbackOwner, callbackName, callbackArgs, callbackOrder)
[type: function] 
Adds a callback that will be called once the designated tier(s) are loaded. A callback order can be provided to rank the order of the given callback.

INCISOR.addTierLoadedCallback parameter: tiers
[type: number, [number]] 
The tier or tiers whose loading will trigger this callback.

INCISOR.addTierLoadedCallback parameter: callbackOwner
[type: object] 
The object owning the callback function.

INCISOR.addTierLoadedCallback parameter: callbackName
[type: string] 
The name of the callback function.

INCISOR.addTierLoadedCallback parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the callback function.

INCISOR.addTierLoadedCallback parameter: callbackOrder
[type: number] [default: 0] [optional] 
Number designating the order the callback will be invoked relative to the other callbacks associated with this tier. A lower callbackOrder equates to an earlier callback.





INCISOR.awaitLoadedTiers(tiers)
[type: function] 
An awaitable asyncronous function that delays until the specified tier(s) are loaded.

INCISOR.awaitLoadedTiers parameter: tiers
[type: number, [number]] 
The tier or tiers whose loading is being awaited.





INCISOR.inheritScene(obj, name)
[type: function] 
Adds Scene functionality to the object supplied.

INCISOR.inheritScene parameter: obj
[type: object] 
The object that Scene functionality is being added to.

INCISOR.inheritScene parameter: name
[type: string] 
The name of the new Scene.





INCISOR.defineLayer(name, scene, placeBehindThisLayer)
[type: function] 
Defines a new Layer within a Scene.

INCISOR.defineLayer parameter: name
[type: string] 
The name of the new Layer.

INCISOR.defineLayer parameter: scene
[type: Scene] [default: nc.mainScene] [optional] 
The Scene in which to define a new layer.

INCISOR.defineLayer parameter: placeBehindThisLayer
[type: Layer] [default: nc.layers.DefaultLayer] [optional] 
Supply this optional Layer, and the newly defined Layer will be populated behind the provided Layer.





INCISOR.addScene(name)
[type: function] [returns: Scene] 
Adds a Scene to the project.

INCISOR.addScene parameter: name
[type: string] [default: 'Scene'] [optional] 
The name of the new Scene. The name of the Scene must be unique.





INCISOR.inheritScrollingPanel(obj, parent, name)
[type: function] 
Adds ScrollingPanel functionality to the object supplied.

INCISOR.inheritScrollingPanel parameter: obj
[type: object] 
The object that ScrollingPanel functionality is being added to.

INCISOR.inheritScrollingPanel parameter: parent
[type: SceneObject] [optional] 
The SceneObject that will become the new ScrollingPanel's parent in the Scene hierarchy.

INCISOR.inheritScrollingPanel parameter: name
[type: string] [default: 'ScrollingPanel'] [optional] 
The name of the new ScrollingPanel.





INCISOR.dispose(objectForDisposal)
[type: function] 
Removes the provided object from all Incisor® registries. Send any object slated for deletion to this function to ensure that references to the object are not being kept in Incisor®'s regestries. Doing this can help prevent memory leaks.

INCISOR.dispose parameter: objectForDisposal
[type: object] 
The object that will be disposed.





INCISOR.shutDown()
[type: function] 
Stops this Incisor® software permanently and releases what it holds outside of its own object graph: the main loop, the page's event listeners, the WebGL context, and the audio context. Use this when a host page needs to take the software down, such as a published project embedded in a page that later navigates away from it. The 'preShutdown' AppEvent is triggered first, giving project code a chance to release anything Incisor® has no knowledge of. Calling this more than once is harmless. The software cannot be restarted afterwards - load it again instead. It can also be called from outside of the software as 'incr_habitat_[projectCodeName].shutDown()'.





INCISOR.defineConstruct(name, blueprint)
[type: function] [returns: ConstructDefinition] 
A means to manually create a ConstructDefinition. It should be noted that most users will not need to use this function, as Constructs are typically created in the Incisor® GUI.

INCISOR.defineConstruct parameter: name
[type: string] 
The name of the new ConstructDefinition. This name must be a unique class name, must not start with digits, and must not contain special characters or spaces.

INCISOR.defineConstruct parameter: blueprint
[type: Blueprint] [optional] 
Object containing the core instructions for recreating the collection of objects that will define this Construct. The function 'nc.gatherObjectBlueprint' can be used to get a Blueprint object from a pre-existing object. If this parameter is left undefined, then an empty Construct is defined.





INCISOR.gatherObjectBlueprint(sceneObject, includeRoot, includeDescendants)
[type: function] 
This function can be used to collect the core information needed to define a Construct based on a group of objects whithin a Scene. Just provide a root SceneObject and information about its entire sub-hierarchy will be gathered and returned in the form of a 'Blueprint' object, which can then be used to define Constructs using 'nc.defineConstruct'. It should be noted that most users will not need to use this functionality; it is used in the Creation of Constructs, which are typically just created in the Incisor® GUI.

INCISOR.gatherObjectBlueprint parameter: sceneObject
[type: SceneObject] 
The root SceneObject to gather a Blueprint for.

INCISOR.gatherObjectBlueprint parameter: includeRoot
[type: boolean] [default: true] [optional] 
If true, the provided root will be included in the construct, if false the root will be omitted.

INCISOR.gatherObjectBlueprint parameter: includeDescendants
[type: boolean] [default: true] [optional] 
Boolean determining if the descendants will be included in the gathered blueprint.





INCISOR.recreateObjectFromBlueprint(parent, blueprint)
[type: function] [returns: SceneObject] 
Recreates the objects stored in the Blueprint, placing them in the provided parent SceneObject, and returning the newly created root-most object(s). This functionality is the foundation for Incisor® Constructs.

INCISOR.recreateObjectFromBlueprint parameter: parent
[type: SceneObject] 
The SceneObject that will be the parent of the newly recreated collection of objects.

INCISOR.recreateObjectFromBlueprint parameter: blueprint
[type: Blueprint] 
The blueprint containing the information about the collection of objects that will be recreated.





INCISOR.duplicateViaBlueprint(source, parent, includeDescendants)
[type: function] [returns: SceneObject] 
Duplicates the given source object according to its 'blueprint', which is the serialized form of objects used by Constructs. It should be noted that this form of duplication will only capture values for standard components and properties - customizations will be lost in the process.

INCISOR.duplicateViaBlueprint parameter: source
[type: SceneObject] 
The source object for the duplication.

INCISOR.duplicateViaBlueprint parameter: parent
[type: SceneObject] 
The SceneObject that will become the new copy's parent.

INCISOR.duplicateViaBlueprint parameter: includeDescendants
[type: boolean] [default: true] [optional] 
Boolean determining if the source object's descendants will be included in the duplicate.





INCISOR.getPhrase(phraseID, dynamicValues)
[type: function] [returns: string] 
Retrieves the given phrase from the ProjectTranscript. This function is similar to using 'nc.phrases' to fetch phrases, but additionaly it includes a parameter that can be used to populate dynamic values in phrases with dynamic value tags (i.e. '{value:myDynamicValue}'). To populate a dynamic value in a phrase containing a dynamic value tag, include a dictionary with the dynamic values in the 'dynamicValues' parameter (i.e. {myDynamicValue:1000}).

INCISOR.getPhrase parameter: phraseID
[type: string] 
The ID of the phrase to be fetched. A dictionary of phraseIDs can be found at 'nc.phraseIDs'.

INCISOR.getPhrase parameter: dynamicValues
[type: object] [optional] 
Optional dictionary of dynamic values to be populated within the phrase.





INCISOR.definePrecomp(name, coreWidth, coreHeight, autoRender, isOrthographic)
[type: function] [returns: Precomp] 
Defines a new Precomp with the given name.

INCISOR.definePrecomp parameter: name
[type: string] 
The name of the new Precomp. This name must be unique among Precomps, GraphicAssets, Geometries, and Textures.

INCISOR.definePrecomp parameter: coreWidth
[type: number] 
The number informing the initial coreViewWidth of the Precomp's Camera, and the initial coreWidth of the Precomp's RenderTarget.

INCISOR.definePrecomp parameter: coreHeight
[type: number] 
The number informing the initial coreViewHeight of the Precomp's Camera, and the initial coreHeight of the Precomp's RenderTarget.

INCISOR.definePrecomp parameter: autoRender
[type: boolean] 
The initial 'autoRender' setting for the Precomp's Camera. It should be noted that if autoRender is set to false, an internal callback will automatically render this Precomp once when its content is loaded.

INCISOR.definePrecomp parameter: isOrthographic
[type: boolean] [default: true] [optional] 
Boolean determining if the Camera associated with this Precomp is Orthographic. If false the associated Camera will be a PerspectiveCamera.





INCISOR.defineCustomBlendingMode(name)
[type: function] [returns: CustomBlendingMode] 
Creates and returns a new CustomBlendingMode with the given name. The new CustomBlendingMode is stored in 'nc.customBlendingModes' and its name is added to 'nc.blendingModes', making it immediately usable as a blending mode name string on any Material.

INCISOR.defineCustomBlendingMode parameter: name
[type: string] 
The name of the new CustomBlendingMode. This name must be unique among CustomBlendingModes.





INCISOR.waitThen(duration, callbackOwner, callbackName, callbackArgs, name, pauseImmunity, speedControl)
[type: function] 
Sets up a WaitThen (from an internal pool), invoking the given callback after the specified delay. Since the WaitThen being used here is internal, the object itself cannot be referenced; to stop a pooled WaitThen, call 'nc.stopAllWaitThensByName' or 'nc.stopAllWaitThensByCallback'.

INCISOR.waitThen parameter: duration
[type: number] 
Seconds before the callback will occur.

INCISOR.waitThen parameter: callbackOwner
[type: object] 
The object owning the callback function that is called when the WaitThen completes.

INCISOR.waitThen parameter: callbackName
[type: string] 
The name of the function that is called when the WaitThen completes.

INCISOR.waitThen parameter: callbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the WaitThen completes.

INCISOR.waitThen parameter: name
[type: string] [default: "WaitThen"] [optional] 
The name of this WaitThen.

INCISOR.waitThen parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this WaitThen will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

INCISOR.waitThen parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this WaitThen is affected by.

example:
// Objective: Use a waitThen function
// Expected Result: The screen will show "Wait for it..." for 3 seconds then "Incisor!" will appear.

this.textBox = new TextBox( nc.mainScene );
this.textBox.string = "Wait for it...";

// call waitThen with a duration of 3 seconds
nc.waitThen( 3, this, "waitThenCallback" );

this.waitThenCallback = function() {
    this.textBox.string = "Incisor!";
}





INCISOR.stopAllWaitThensByName(name, performCallback)
[type: function] 
Stops all currently active WaitThens whose name matches the name given.

INCISOR.stopAllWaitThensByName parameter: name
[type: string] 
The name of the WaitThens to stop.

INCISOR.stopAllWaitThensByName parameter: performCallback
[type: boolean] [default: false] [optional] 
Boolean determining if the callback function will be called immediately, or if it will be skipped entirely.





INCISOR.stopAllWaitThensByCallback(callbackOwner, callbackName, performCallback)
[type: function] 
Stops all currently active WaitThens whose callback info matches the given callback info.

INCISOR.stopAllWaitThensByCallback parameter: callbackOwner
[type: object] 
The owner of the callback associated with the WaitThens to stop.

INCISOR.stopAllWaitThensByCallback parameter: callbackName
[type: string] 
The name of the callback associated with the WaitThens to stop.

INCISOR.stopAllWaitThensByCallback parameter: performCallback
[type: boolean] [default: false] [optional] 
Boolean determining if the callback function will be called immediately, or if it will be skipped entirely.





INCISOR.inheritWaitThen(obj, name)
[type: function] 
Adds WaitThen functionality to the supplied object.

INCISOR.inheritWaitThen parameter: obj
[type: object] 
The object to give WaitThen functionality to.

INCISOR.inheritWaitThen parameter: name
[type: string] 
The name of the new WaitThen object.





INCISOR.defineGraphicAssetFromPixelsObject(name, pixelsObject, includeNormals)
[type: function] [returns: GraphicAsset] 
Defines a new GraphicAsset from a supplied PixelsObject. See 'nc.graphicAssets' for a list of all available GraphicAssets.

INCISOR.defineGraphicAssetFromPixelsObject parameter: name
[type: string] 
The name of the new GraphicAsset. This name must be unique among registered GraphicAssets, Geometries, and Textures.

INCISOR.defineGraphicAssetFromPixelsObject parameter: pixelsObject
[type: PixelsObject] 
The PixelsObject that will be the source for this new GraphicAsset.

INCISOR.defineGraphicAssetFromPixelsObject parameter: includeNormals
[type: boolean] [default: false] [optional] 
Boolean determining if the vertex data in the geometry of the new GraphicAsset will have the 'normals' attribute.





INCISOR.defineGraphicAssetFromRenderTarget(name, renderTarget, disconnectFromRenderTarget, includeNormals)
[type: function] [returns: GraphicAsset] 
Defines a new GraphicAsset based on the RenderTarget supplied. Unless otherwise specified, this GraphicAsset will have a dynamic connection to the RenderTarget, so that if the RenderTarget is rendered to, GraphicObjects set to this new GraphicAsset will reflect new contents of the RenderTarget. See 'nc.graphicAssets' for a list of all available GraphicAssets.

INCISOR.defineGraphicAssetFromRenderTarget parameter: name
[type: string] 
The name of the new GraphicAsset. This name must be unique among registered GraphicAssets, Geometries, and Textures.

INCISOR.defineGraphicAssetFromRenderTarget parameter: renderTarget
[type: RenderTarget] 
The RenderTarget that will be the source for this new GraphicAsset.

INCISOR.defineGraphicAssetFromRenderTarget parameter: disconnectFromRenderTarget
[type: boolean] [default: false] [optional] 
Boolean determining if the new GraphicAsset will maintain a dynamic connection to the supplied RenderTarget.

INCISOR.defineGraphicAssetFromRenderTarget parameter: includeNormals
[type: boolean] [default: false] [optional] 
Boolean determining if the vertex data in the geometry of the new GraphicAsset will have the 'normals' attribute.





INCISOR.defineGraphicAssetFromTextureAndGeometry(name, texture, geometry)
[type: function] [returns: GraphicAsset] 
Defines a new GraphicAsset based on the Texture and Geometry supplied. See 'nc.graphicAssets' for a list of all available GraphicAssets.

INCISOR.defineGraphicAssetFromTextureAndGeometry parameter: name
[type: string] 
The name of the new GraphicAsset. This name must be unique among registered GraphicAssets.

INCISOR.defineGraphicAssetFromTextureAndGeometry parameter: texture
[type: Texture] 
The Texture that will be the source Texture for this new GraphicAsset.

INCISOR.defineGraphicAssetFromTextureAndGeometry parameter: geometry
[type: Geometry] 
The Geometry that will be the source Geometry for this new GraphicAsset.





INCISOR.defineGraphicAssetFromImageBase64(name, imageBase64)
[type: function] [returns: GraphicAsset] 
Defines a new GraphicAsset based on the image base64 supplied. See 'nc.graphicAssets' for a list of all available GraphicAssets.

INCISOR.defineGraphicAssetFromImageBase64 parameter: name
[type: string] 
The name of the new GraphicAsset. This name must be unique among registered GraphicAssets.

INCISOR.defineGraphicAssetFromImageBase64 parameter: imageBase64
[type: string] 
The base64 string for the image to be made into a GraphicAsset.





INCISOR.registerCustomAddOn(classDefinition, description)
[type: function] [returns: CustomAddOnDefinition] 
Registers the given class definition as a CustomAddOn with the Incisor inspector. Once registered, instances of the given object can be added to other objects using the GUI (in the Construct Editor etc...).

INCISOR.registerCustomAddOn parameter: classDefinition
[type: object] 
The desired class definition to register with the Incisor inspector as a CustomAddOn. The provided class definition must inherit from a 'CustomAddOn' type such as 'CustomAddOn_SceneObject' or 'CustomAddOn_GraphicObject'.

INCISOR.registerCustomAddOn parameter: description
[type: string] [optional] 
An optional description of this CustomAddOn, displayed as a tooltip in the inspector GUI.





INCISOR.registerCustomAddOnProperty(classDefinition, propertyType, propertyPath, description)
[type: function] [returns: RegisteredProperty] 
Registers a property of the given CustomAddOn with Incisor. Registered properties are accessible for monitoring and manipulating within the inspector. Registered properties can also be flagged as 'persistent', which enables their values to be stored in containing Constructs.

INCISOR.registerCustomAddOnProperty parameter: classDefinition
[type: object] 
The class definition of the CustomAddOn for which to register a property.

INCISOR.registerCustomAddOnProperty parameter: propertyType
[type: string] 
The type of the property to register. The available types can be found in constants.registeredPropertyTypes

INCISOR.registerCustomAddOnProperty parameter: propertyPath
[type: [string], string] 
The path to the desired property to register in terms of member names. If the property owned directly by the CustomAddOn, the name of the property can be provided as a single string. If the property is a sub-member of a property, each accessing member should be listed in an Array, or a single 'dot-separated' string can be provided.

INCISOR.registerCustomAddOnProperty parameter: description
[type: string] [optional] 
An optional description of this registered property, displayed as a tooltip in the inspector GUI.





INCISOR.inheritRenderTarget(obj, name, coreWidth, coreHeight)
[type: function] 
Adds RenderTarget functionality to the supplied object.

INCISOR.inheritRenderTarget parameter: obj
[type: object] 
The object to give RenderTarget funcionality to.

INCISOR.inheritRenderTarget parameter: name
[type: string] 
The name given to the RenderTarget. This name must be unique.

INCISOR.inheritRenderTarget parameter: coreWidth
[type: number] 
The base width value of this RenderTarget, prior to the application of any automatic resolution or aspect ratio adjustments that can occur.

INCISOR.inheritRenderTarget parameter: coreHeight
[type: number] 
The base height value of this RenderTarget, prior to the application of any automatic resolution or aspect ratio adjustments that can occur.





INCISOR.inheritLayoutStack(obj, parent, name)
[type: function] 
Adds LayoutStack functionality to the object supplied.

INCISOR.inheritLayoutStack parameter: obj
[type: object] 
The object that LayoutStack functionality is being added to.

INCISOR.inheritLayoutStack parameter: parent
[type: SceneObject] [optional] 
The SceneObject that will become the new LayoutStack's parent in the Scene hierarchy.

INCISOR.inheritLayoutStack parameter: name
[type: string] [default: 'LayoutStack'] [optional] 
The name of the new LayoutStack.





INCISOR.addLayoutStack(parent, name)
[type: function] [returns: LayoutStack] 
Adds a LayoutStack as a child of the given SceneObject.

INCISOR.addLayoutStack parameter: parent
[type: SceneObject] [optional] 
The SceneObject that will be the new LayoutStack's parent.

INCISOR.addLayoutStack parameter: name
[type: string] [default: 'LayoutStack'] [optional] 
The name of the new LayoutStack.

example:
// Objective: Use a LayoutStack to vertically align elements.
// Expected Result: You will see 3 elements stacked vertically.

// create a TextAssembly
let text = new TextAssembly( nc.mainScene, "MyText" );
text.string = "With Incisor, you need only build it once.";

// create a white box GraphicObject
let whiteBox = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "MyWhiteBox" );

// create a link
let link = new TextBox( nc.mainScene, "MyButton" );
link.string = "Click Here";
link.colorMultiply = new Color( 0, 0, 1, 1 );
link.scale.x = .5;
link.scale.y = .5;

// add a LayoutStack to the main Scene and add 3 elements to it
let layoutStack = nc.addLayoutStack( nc.mainScene, "MyLayoutStack" );
layoutStack.addElements( [text, whiteBox, link ] );
layoutStack.isVertical = true; // set vertical alignment





INCISOR.inheritLazyUpdater(obj, updateCallbackOwner, updateCallbackName, updateCallbackArgs)
[type: function] 
Adds LazyUpdater functionality to the object supplied.

INCISOR.inheritLazyUpdater parameter: obj
[type: object] 
The object that LazyUpdater functionality is being added to.

INCISOR.inheritLazyUpdater parameter: updateCallbackOwner
[type: object] 
The object owning the callback function being managed by this LazyUpdater.

INCISOR.inheritLazyUpdater parameter: updateCallbackName
[type: string] 
The name of the callback function being managed by this LazyUpdater.

INCISOR.inheritLazyUpdater parameter: updateCallbackArgs
[type: Array, any] [optional] 
Arguments for the callback function.





INCISOR.gatherKeyframedValueBlueprint(keyframedValue, omitTimeSnap)
[type: function] [returns: object] 
Gathers a serializable blueprint object describing the given KeyframedValue — its valueType (when not the default), interpolation (when not the default), timeSnap and valueSnap (when not the default), and its Keyframes. Use recreateKeyframedValueFromBlueprint to rebuild a KeyframedValue from the result.

INCISOR.gatherKeyframedValueBlueprint parameter: keyframedValue
[type: KeyframedValue] 
The KeyframedValue to serialize.

INCISOR.gatherKeyframedValueBlueprint parameter: omitTimeSnap
[type: boolean] [default: false] [optional] 
When true, the timeSnap is never written to the blueprint. Used for Timeline-owned properties, whose Timeline stores a single timeSnap for them all.





INCISOR.recreateKeyframedValueFromBlueprint(blueprint)
[type: function] [returns: KeyframedValue] 
Recreates a KeyframedValue from a blueprint produced by gatherKeyframedValueBlueprint.

INCISOR.recreateKeyframedValueFromBlueprint parameter: blueprint
[type: object] 
The blueprint to recreate from.





INCISOR.registerCustomObject(classDefinition, description)
[type: function] [returns: CustomObjectDefinition] 
Registers the given class definition as a CustomObject with the Incisor inspector. Once registered, instances of the given object can be added to Constructs using the GUI (in the Construct Editor etc...). As a side effect of registration, a 'customObjectDefinition' property is set on the class's prototype, pointing to the returned CustomObjectDefinition. This means all instances of the class will have a 'customObjectDefinition' member that provides a reference back to their CustomObjectDefinition.

INCISOR.registerCustomObject parameter: classDefinition
[type: object] 
The desired class definition to register with the Incisor inspector as a CustomObject. The provided class definition must inherit from a standard hierarchy object type such as SceneObject, GraphicObject, or Button etc...

INCISOR.registerCustomObject parameter: description
[type: string] [optional] 
An optional description of this CustomObject, displayed as a tooltip in the inspector GUI.





INCISOR.registerCustomObjectProperty(classDefinition, propertyType, propertyPath, description)
[type: function] [returns: RegisteredProperty] 
Registers a property of the given CustomObject with Incisor. Registered properties are accessible for monitoring and manipulating within the inspector. Registered properties can also be flagged as 'persistent', which enables their values to be stored in containing Constructs.

INCISOR.registerCustomObjectProperty parameter: classDefinition
[type: object] 
The class definition of the CustomObject for which to register a property.

INCISOR.registerCustomObjectProperty parameter: propertyType
[type: string] 
The type of the property to register. The available types can be found in constants.registeredPropertyTypes

INCISOR.registerCustomObjectProperty parameter: propertyPath
[type: [string], string] 
The path to the desired property to register in terms of member names. If the property owned directly by the CustomObject, the name of the property can be provided as a single string. If the property is a sub-member of a property, each accessing member should be listed in an Array, or a single 'dot-separated' string can be provided.

INCISOR.registerCustomObjectProperty parameter: description
[type: string] [optional] 
An optional description of this registered property, displayed as a tooltip in the inspector GUI.





INCISOR.inheritTextFormat(obj, fontName, characterScaleX, characterScaleY, kerning, verticalShift, lineHeightMultiplier)
[type: function] 
Adds TextFormat functionality to the object supplied.

INCISOR.inheritTextFormat parameter: obj
[type: object] 
The object that TextFormat functionality is being added to.

INCISOR.inheritTextFormat parameter: fontName
[type: string] [default: "MainFont"] [optional] 
The name of the font that characters with this TextFormat will use.

INCISOR.inheritTextFormat parameter: characterScaleX
[type: number] [default: 1] [optional] 
The x-axis scale multiplier for the characters that use this TextFormat.

INCISOR.inheritTextFormat parameter: characterScaleY
[type: number] [default: 1] [optional] 
The y-axis scale multiplier for the characters that use this TextFormat.

INCISOR.inheritTextFormat parameter: kerning
[type: number] [default: 0] [optional] 
Number representing an added or reduced spacing between the characters that use this TextFormat

INCISOR.inheritTextFormat parameter: verticalShift
[type: number] [default: 0] [optional] 
Number representing a veritcal offset that will be applied to the characters that use this TextForamt.

INCISOR.inheritTextFormat parameter: lineHeightMultiplier
[type: number] [default: 1] [optional] 
Number that multiplies the effective layout height of the characters that use this TextFormat.





INCISOR.defineTweenType(name, tweenFunction, tweenControllerNames, tweenControllerDefaultValues, description, controllerDescriptions)
[type: function] [returns: TweenType] 
Defines a new TweenType. TweenTypes are used in conjunction with Swoopers and define a method of interpolation between any two values or sets of values. The TweenType 'Linear' is automatically defined, and it defines a perfectly even interpolation between the startValues and endValues. TweenTypes can vary the timing of interpolation between two sets of values, as well as the path of the interpolation. All defined TweenTypes can be found at 'nc.tweenTypes'.

INCISOR.defineTweenType parameter: name
[type: string] 
The name of the new TweenType.

INCISOR.defineTweenType parameter: tweenFunction
[type: function] 
The function controlling the interpolation between values. This function should be implemented to take a single 'Swooper' parameter, using it's 'progress', 'startValues', 'endValues', and 'tweenArgs' members to calculate and set its 'currentValues' property.

INCISOR.defineTweenType parameter: tweenControllerNames
[type: [string]] [optional] 
The names of optional controllers that can be used to dynamically affect the nature of the motion for this TweenType.

INCISOR.defineTweenType parameter: tweenControllerDefaultValues
[type: [number]] [optional] 
The default values of th optional controllers that can be used to dynamically affect the nature of the motion for this TweenType.

INCISOR.defineTweenType parameter: description
[type: string] [optional] 
The description of the TweenType - this will appear in the autocomplete documentation.

INCISOR.defineTweenType parameter: controllerDescriptions
[type: [string]] [optional] 
The descriptions of the TweenType controllers - these will appear in the autocomplete documentation.

example:
// Objective: Define a custom TweenType.
// Expected Result: The white box will zigzag while moving up along the y axis.

// create a white box
let graphic = new GraphicObject( nc.graphicAssets.WhiteBox, nc.mainScene, "Box" );

// define a TweenType function. Use the given swooper progress 
// to update the box's position as it completes its swoop
let myTweenFunction = function( swooper ) {
    let progress = swooper.progress;
  
    let updatedX = swooper.currentValues[0] ? swooper.currentValues[0] : 0;
    let updatedY = swooper.endValues[1] * progress;

     if ( progress < .20 ) {
         updatedX += 10 * progress;
     } else if ( progress >= .20 && progress < .40 ) {
         updatedX -= 8 * progress;
     } else if ( progress >= .40 && progress < .60 ) {
         updatedX += 6 * progress;
     } else if ( progress >= .60 && progress < .80 ) {
         updatedX -= 4 * progress;
     } else {
         updatedX += 2 * progress;
     }
 
     swooper.currentValues = [ updatedX, updatedY, 0 ];

 }

// define the TweenType with our custom function and swoop the box's position
let myTweenType = nc.defineTweenType( "MyTweenType", myTweenFunction );
graphic.position.swoop.each( [0,500,0], 10, myTweenType );





INCISOR.swoopValue(propertyOwner, propertyName, endValue, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, updaterCallbackOwner, updaterCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) a given numeric property from its current value to a designated end value over a duration.

INCISOR.swoopValue parameter: propertyOwner
[type: object] 
The object owning the numeric property to be swooped.

INCISOR.swoopValue parameter: propertyName
[type: string] 
The name of the numeric property to be swooped.

INCISOR.swoopValue parameter: endValue
[type: number] 
The ending value for the numeric property being swooped.

INCISOR.swoopValue parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

INCISOR.swoopValue parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

INCISOR.swoopValue parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

INCISOR.swoopValue parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

INCISOR.swoopValue parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

INCISOR.swoopValue parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

INCISOR.swoopValue parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

INCISOR.swoopValue parameter: updaterCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

INCISOR.swoopValue parameter: updaterCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.

example:
// Objective: Adjust the motion speed of a "bouncing" white box.
// Expected Result: The white box will bounce, gradually slowing down over a period of 5 seconds, then it will gradually speed back up over a period of 5 seconds.

// Create a GraphicObject using the white box GraphicAsset and add it to the main Scene.
let myGraphicObject = new GraphicObject( nc.graphicAssets.whiteBox, nc.mainScene, "MyGraphicObject" );
// Give the box motion along the y axis. Set the speed to 2.
myGraphicObject.position.addMotion.y(-300,300,2);
 
// Swoop the 'speed' property of the MainSpeedControl down to .05 over a period of 5 seconds and provide callback arguments to swoop the 'speed' property again back up to speed 1 over a period of 10 seconds.
nc.swoopValue( 
            nc.speedControls.MainSpeedControl, 
            "speed", 
            .05, 
            5, 
            undefined, 
            nc, 
            "swoopValue", 
            [nc.speedControls.MainSpeedControl, "speed", 1, 10] 
            );





INCISOR.swoopValues(propertyOwners, propertyNames, endValues, duration, tweenType, completionCallbackOwner, completionCallbackName, completionCallbackArgs, pauseImmunity, speedControl, updaterCallbackOwner, updaterCallbackName)
[type: function] [returns: Swooper] 
Swoops (interpolates) a given set of numeric properties from their current values to a designated set of end values over a duration.

INCISOR.swoopValues parameter: propertyOwners
[type: [object]] 
The object or objects owning the numeric properties to be swooped.

INCISOR.swoopValues parameter: propertyNames
[type: [string]] 
The names of the numeric property to be swooped.

INCISOR.swoopValues parameter: endValues
[type: [number]] 
The ending values for the numeric properties being swooped. Any value left undefined leaves that property untouched by this Swooper.

INCISOR.swoopValues parameter: duration
[type: number] [default: 0] [optional] 
The duration for the interpolation.

INCISOR.swoopValues parameter: tweenType
[type: TweenType] [default: nc.tweenTypes.Linear] [optional] 
The TweenType, determining the method of interpolation.

INCISOR.swoopValues parameter: completionCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called when the Swooper completes.

INCISOR.swoopValues parameter: completionCallbackName
[type: string] [optional] 
The name of the function that is called when the Swooper completes.

INCISOR.swoopValues parameter: completionCallbackArgs
[type: Array, any] [optional] 
Arguments for the function that is called when the Swooper completes.

INCISOR.swoopValues parameter: pauseImmunity
[type: PauseEvent, [PauseEvent]] [default: nc.defaultPauseImmunity] [optional] 
The PauseEvent or Array of PauseEvents that this Swooper will be immune to. Set this parameter to [] to create callbacks with no immunity. If this parameter is left undefined, the current value of 'nc.defaultPauseImmunity' will be used. The value for 'nc.defaultPauseImmunity' defaults to [], but can be changed at any time.

INCISOR.swoopValues parameter: speedControl
[type: SpeedControl, [SpeedControl]] [default: nc.defaultSpeedControl] [optional] 
The SpeedControl or Array of SpeedControls that this Swooper is affected by.

INCISOR.swoopValues parameter: updaterCallbackOwner
[type: object] [optional] 
The object owning the callback function that is called with each fixedUpdate during the swooping process.

INCISOR.swoopValues parameter: updaterCallbackName
[type: string] [optional] 
The name of the function that is called with each fixedUpdate during the swooping process.





INCISOR.inheritCurve(obj, parent, name)
[type: function] 
Adds Curve functionality to the object supplied.

INCISOR.inheritCurve parameter: obj
[type: object] 
The object that Curve functionality is being added to.

INCISOR.inheritCurve parameter: parent
[type: SceneObject] 
The SceneObject that will become the new Curve's parent in the Scene hierarchy.

INCISOR.inheritCurve parameter: name
[type: string] [default: 'Curve'] 
The name of the new Curve.





INCISOR.addCurve(parent, name)
[type: function] 
Adds a SceneObject as a child of the given SceneObject.

INCISOR.addCurve parameter: parent
[type: SceneObject] 
The SceneObject that will become the new Curve's parent in the Scene hierarchy.

INCISOR.addCurve parameter: name
[type: string] [default: 'Curve'] 
The name of the new Curve.





INCISOR.inheritVector4(obj, x, y, z, w)
[type: function] 
Adds Vector4 functionality to the supplied object.

INCISOR.inheritVector4 parameter: obj
[type: object] 
The object to give Vector4 functionality to.

INCISOR.inheritVector4 parameter: x
[type: number] [default: 0] [optional] 
The value for the first component.

INCISOR.inheritVector4 parameter: y
[type: number] [default: 0] [optional] 
The value for the second component.

INCISOR.inheritVector4 parameter: z
[type: number] [default: 0] [optional] 
The value for the third component.

INCISOR.inheritVector4 parameter: w
[type: number] [default: 0] [optional] 
The value for the forth component.





INCISOR.inheritVector3(obj, x, y, z)
[type: function] 
Adds Vector3 functionality to the supplied object.

INCISOR.inheritVector3 parameter: obj
[type: object] 
The object to give Vector3 functionality to.

INCISOR.inheritVector3 parameter: x
[type: number] [default: 0] [optional] 
The value for the first component.

INCISOR.inheritVector3 parameter: y
[type: number] [default: 0] [optional] 
The value for the second component.

INCISOR.inheritVector3 parameter: z
[type: number] [default: 0] [optional] 
The value for the third component.





INCISOR.inheritVector2(obj, x, y)
[type: function] 
Adds Vector2 functionality to the supplied object.

INCISOR.inheritVector2 parameter: obj
[type: object] 
The object to give Vector2 functionality to.

INCISOR.inheritVector2 parameter: x
[type: number] [default: 0] [optional] 
The value for the first component.

INCISOR.inheritVector2 parameter: y
[type: number] [default: 0] [optional] 
The value for the second component.





INCISOR.inheritVector1(obj, x)
[type: function] 
Adds Vector1 functionality to the supplied object.

INCISOR.inheritVector1 parameter: obj
[type: object] 
The object to give Vector1 functionality to.

INCISOR.inheritVector1 parameter: x
[type: number] [default: 0] [optional] 
The value for the first component.





INCISOR.defineGeometry(name, createBox)
[type: function] [returns: GeometryEditor] 
Defines a new square 100x100 Geometry, and returns a GeometryEditor object for further customization.

INCISOR.defineGeometry parameter: name
[type: string] 
The name of the new Geometry being defined. This name must be unique among Geometries.

INCISOR.defineGeometry parameter: createBox
[type: boolean] [default: true] 
Whether to initialize the geometry with a 100x100 box with positon and uv attributes.





INCISOR.addSymbolReel(parent, name)
[type: function] [returns: SymbolReel] [requires: module - symbolReels] 
Creates a new SymbolReel and returns it.

INCISOR.addSymbolReel parameter: parent
[type: SceneObject] [optional] 
The parent of the new SymbolReel.

INCISOR.addSymbolReel parameter: name
[type: string] [optional] 
The name of the new SymbolReel.





INCISOR.getCanvasPixelResolution()
[type: function] [returns: Vector2] 
Returns a Vector2 with the pixel resolution of nc.mainRenderTarget.





INCISOR.inheritTextBox(obj, parent, name)
[type: function] 
Adds TextBox functionality to the object supplied.

INCISOR.inheritTextBox parameter: obj
[type: object] 
The object that TextBox functionality is being added to.

INCISOR.inheritTextBox parameter: parent
[type: SceneObject] [optional] 
The SceneObject that will become the new TextBox's parent in the Scene hierarchy.

INCISOR.inheritTextBox parameter: name
[type: string] [optional] 
The name of the new TextBox.





INCISOR.addTextBox(parent, name)
[type: function] [returns: TextBox] 
Adds a TextBox as a child of the given SceneObject.

INCISOR.addTextBox parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The SceneObject that will become the new TextBox's parent in the Scene hierarchy.

INCISOR.addTextBox parameter: name
[type: string] [default: 'TextBox'] [optional] 
The name of the new TextBox.

example:
// Objective: Add a TextBox.
// Expected Result: You will see the text "Incisor - Build It Once." on screen.

let textBox = nc.addTextBox( nc.mainScene );
textBox.string = "Incisor - Build It Once."





INCISOR.inheritCursorInputOverrideButton(obj, graphicAsset, parent, name)
[type: function] 
Adds CursorInputOverrideButton functionality to the object supplied.

INCISOR.inheritCursorInputOverrideButton parameter: obj
[type: object] 
The object that CursorInputOverrideButton functionality is being added to.

INCISOR.inheritCursorInputOverrideButton parameter: graphicAsset
[type: GraphicAsset] [default: nc.graphicAssets.WhiteBox] [optional] 
The GraphicAsset that the new CursorInputOverrideButton will initially be set to. For a list of available GraphicAssets, see 'nc.graphicAssets'.

INCISOR.inheritCursorInputOverrideButton parameter: parent
[type: SceneObject] [default: nc.mainScene] [optional] 
The SceneObject that will become the new CursorInputOverrideButton's parent in the Scene hierarchy.

INCISOR.inheritCursorInputOverrideButton parameter: name
[type: string] [default: 'CursorInputOverrideButton'] [optional] 
The name of the new CursorInputOverrideButton.





INCISOR.simulateKeyDown(key, code)
[type: function] 
Simulates a key being pressed down, which triggers the 'keyDown' and 'keyboardEvent' AppEvents and sets the key's member of nc.keyDownStates. The key stays down until simulateKeyUp is called with the same key.

INCISOR.simulateKeyDown parameter: key
[type: string] 
The key as the browser names it, such as 'a', 'Enter', 'Shift' or 'ArrowLeft'.

INCISOR.simulateKeyDown parameter: code
[type: string] [optional] 
The physical key as the browser names it, such as 'KeyA' or 'NumpadEnter'. If left undefined it is made from the key.





INCISOR.simulateKeyUp(key, code)
[type: function] 
Simulates a key being released, which triggers the 'keyUp' and 'keyboardEvent' AppEvents and clears the key's member of nc.keyDownStates.

INCISOR.simulateKeyUp parameter: key
[type: string] 
The key as the browser names it, such as 'a', 'Enter', 'Shift' or 'ArrowLeft'.

INCISOR.simulateKeyUp parameter: code
[type: string] [optional] 
The physical key as the browser names it, such as 'KeyA' or 'NumpadEnter'. If left undefined it is made from the key.





INCISOR.simulateKeyPress(key, code)
[type: function] 
Simulates a key being pressed and released straight away. For a key that has to be held across frames, call simulateKeyDown and simulateKeyUp instead.

INCISOR.simulateKeyPress parameter: key
[type: string] 
The key as the browser names it, such as 'a', 'Enter', 'Shift' or 'ArrowLeft'.

INCISOR.simulateKeyPress parameter: code
[type: string] [optional] 
The physical key as the browser names it, such as 'KeyA' or 'NumpadEnter'. If left undefined it is made from the key.





INCISOR.inheritSupervisor(obj, owner)
[type: function] 
Adds Supervisor functionality to the object supplied.

INCISOR.inheritSupervisor parameter: obj
[type: object] 
The object that Supervisor functionality is being added to.

INCISOR.inheritSupervisor parameter: owner
[type: SceneObject] 
The SceneObject owning the visual components associated with the Supervisor.





INCISOR. Welcome to Incisor!
[type: information] 
Incisor® is a comprehensive platform that enables developers and designers to build high-quality interactive software and gaming products. The platform consists of JavaScript or TypeScript APIs, a customizable GUI, and other tools bundled together into a single application. Incisor® can be used to create extremely lightweight apps that operate on any target device or EGM - all from a single codebase. With Incisor®, your team can Build It Once.

The primary driving force behind Incisor® is making the development of commercial-grade software more collaborative, efficient, flexible, and generally straightforward. Whether your focus is on highly optimized products downloadable at a fraction of the size without sacrificing quality, or creating 4k resolution products for the casino floor, Incisor® is the only solution. The platform incorporates countless efficiencies into both the production process and the published result, enabling not only better products, but better development










----------------------------------------------------------
Section 207: Supervisor
----------------------------------------------------------


Supervisor
[type: class] [requires: module - extendedUi] 
A Supervisor is a class that helps manage the processes behind UI components that allow the end-user to monitor and adjust values and properties during runtime. For example, the UiNumberSupervisor_TextField type is a specialized UiTextField that contains an additional Supervisor member, and its purpose is to serve as a visual 'supervisor' for any numeric property, displaying the current value as it changes, and updating the value if the end-user types a new number into the UiTextField. The Supervisor object itself houses callbacks for setting the target property, getting the target property, and updating the associated visual compoenents (i.e. setting the string in the UiTextField to the target number value).





Supervisor.type
[type: string] 
Type identifier.





Supervisor.inheritedTypes
[type: object] 
Dictionary object listing all of the types this object is compatible with.





Supervisor.supervisedPropertyGetterCallbackOwner
[type: object] 
The owner of the callback function that is called whenever this Supervisor needs to retrieve the property being supervised. The provided callback function must return the value being supervised.





Supervisor.supervisedPropertyGetterCallbackName
[type: string] 
The name of the callback function that is called whenever this Supervisor needs to retrieve the property being supervised. The provided callback function must return the value being supervised.





Supervisor.supervisedPropertyGetterCallbackArgs
[type: any] 
Arguments for the callback function that is called whenever this Supervisor needs to retrieve the property being supervised. The provided callback function must return the value being supervised.





Supervisor.supervisedPropertySetterCallbackOwner
[type: object] 
The owner of the callback function that is called whenever this Supervisor sets the value of the property being supervised. The provided callback function will receive the new value for the property as its first parameter.





Supervisor.supervisedPropertySetterCallbackName
[type: string] 
The name of the callback function that is called whenever this Supervisor sets the value of the property being supervised. The provided callback function will receive the new value for the property as its first parameter.





Supervisor.supervisedPropertySetterCallbackArgs
[type: any] 
Arguments for the callback function that is called whenever this Supervisor sets the value of the property being supervised. The provided callback function will receive the new value for the property as its first parameter.





Supervisor.updateVisualsCallbackOwner
[type: object] 
The owner of the callback function that is called whenever this Supervisor updates the visuals to reflect changes to the value of the property being supervised. The provided callback function will receive the up-to-date property value as its first parameter.





Supervisor.updateVisualsCallbackName
[type: string] 
The name of the callback function that is called whenever this Supervisor updates the visuals to reflect changes to the value of the property being supervised. The provided callback function will receive the up-to-date property value as its first parameter.





Supervisor.updateVisualsCallbackArgs
[type: any] 
Arguments for the callback function that is called whenever this Supervisor updates the visuals to reflect changes to the value of the property being supervised. The provided callback function will receive the up-to-date property value as its first parameter.





Supervisor.setSupervisedProperty(value)
[type: function] 
Sets the supervised property's value. This call is invoked upon the end-user manipulation of the associated visual components.

Supervisor.setSupervisedProperty parameter: value
[type: any] 
The value to set the supervised property to.





Supervisor.performStandardSetup(supervisedPropertyOwner, supervisedPropertyName, validationFunctionOwner, validationFunctionName)
[type: function] 
Creates and connects to 'standard' setter and getter functions that are simply defined by getting an property (by owner and name), and setting a property (by owner and name); For more custom functionality, such as conditional getting and setting functionality, custom getter and setter functions can be built and linked to directly using 'supervisedPropertyGetterCallbackOwner', 'supervisedPropertyGetterCallbackName', 'supervisedPropertySetterCallbackOwner', and 'supervisedPropertySetterCallbackName'.

Supervisor.performStandardSetup parameter: supervisedPropertyOwner
[type: object] 
The owner of the propertry being supervised.

Supervisor.performStandardSetup parameter: supervisedPropertyName
[type: string] 
The name of the propertry being supervised.

Supervisor.performStandardSetup parameter: validationFunctionOwner
[type: object] [optional] 
The owner of an optional validation function. This function receives, sanitizes, and returns the supervised property.

Supervisor.performStandardSetup parameter: validationFunctionName
[type: string] [optional] 
The name of an optional validation function. This function receives, sanitizes, and returns the supervised property.





Supervisor.performStandardSetupForMultiSupervision(standardSetupPropertyOwnerArray, supervisedPropertyName, validationFunctionOwner, validationFunctionName)
[type: function] 
Creates and connects to 'standard' setter and getter functions for "multi-supervision" scenarios; For more custom functionality, such as conditional getting and setting functionality, custom getter and setter functions can be built and linked to directly using 'supervisedPropertyGetterCallbackOwner', 'supervisedPropertyGetterCallbackName', 'supervisedPropertySetterCallbackOwner', and 'supervisedPropertySetterCallbackName'.

Supervisor.performStandardSetupForMultiSupervision parameter: standardSetupPropertyOwnerArray
[type: Array] 
The array where the objects owning the supervised properties will be referenced.

Supervisor.performStandardSetupForMultiSupervision parameter: supervisedPropertyName
[type: string, [string]] 
The name of the propertry being supervised. An array can be supplied here if the supervised property not a direct member.

Supervisor.performStandardSetupForMultiSupervision parameter: validationFunctionOwner
[type: object] [optional] 
The owner of an optional validation function. This function receives, sanitizes, and returns the supervised property.

Supervisor.performStandardSetupForMultiSupervision parameter: validationFunctionName
[type: string] [optional] 
The name of an optional validation function. This function receives, sanitizes, and returns the supervised property.










----------------------------------------------------------
Section 208: UxMenuItem
----------------------------------------------------------


UxMenuItem
[type: class] [extends: LayoutStack] [requires: module - extendedUi] 
A specialized user interface object designed specifically for use within the Incisor Inspector. Items with the 'Ux' prefix are currently experimental and their use is not yet recommended. All such objects are pre-configured with LayoutObject functionality, have uiStyle TextFormats and Colors applied, are 'UiKeyboardNavigable', and are uiZoom-enabled. This particular object is a specialized horizontal LayoutStack containing the text and icon components that comprise an option within a UxMenu. UxMenuItems are typically created through UxMenu.addMenuItem() or UxMenu.addMenuItemWithSubMenu().





UxMenuItem.menuItemTriggerClosesMenus
[type: boolean] [default: true] 
Boolean determining if triggering this UxMenuItem automatically closes its parent menu hierarchy. For menu items that open subMenus, this value is typically false.





UxMenuItem.mainText
[type: UiText] 
The main UiText showing the primary string for this UxMenuItem.





UxMenuItem.mainButton
[type: Button] 
The main Button panel for this UxMenuItem. This item is used for cursor interaction and highlight feedback.





UxMenuItem.leftIcon
[type: UiText] 
The UiText used to show an optional icon on the left side of this UxMenuItem. This item is enabled automatically when accessed.





UxMenuItem.leftIconGraphicAsset
[type: GraphicAsset] [default: undefined] 
The GraphicAsset used for the optional left-side icon in this UxMenuItem.





UxMenuItem.rightIcon
[type: UiText] 
The UiText used to show an optional icon on the right side of this UxMenuItem. This item is enabled automatically when accessed.





UxMenuItem.rightIconGraphicAsset
[type: GraphicAsset] [default: undefined] 
The GraphicAsset used for the optional right-side icon in this UxMenuItem.





UxMenuItem.secondaryText
[type: UiText] 
The optional secondary UiText shown to the right of the main text in this UxMenuItem. This item is enabled automatically when accessed.





UxMenuItem.outline
[type: UiOutline] 
An outline around this UxMenuItem that indicates when the end-user navigates to it via the keyboard.





UxMenuItem.parentMenu
[type: UxMenu] 
The UxMenu that owns this UxMenuItem.





UxMenuItem.subMenu
[type: UxMenu] 
If this UxMenuItem opens a subMenu, this property contains the associated UxMenu. Otherwise this value is undefined.





UxMenuItem.isActive
[type: boolean] [default: true] 
Boolean determining if this UxMenuItem is currently interactive. When false, the UxMenuItem is dimmed and removed from keyboard/cursor interaction.

INCISOR CONSTRUCT FILE SCHEMA

IncisorConstructSchema.txt

INCISOR CONSTRUCT FILE SCHEMA

This document describes the complete format of an Incisor Construct file (a ".construct" file), including its objects, Timelines, AnimatedProperties and keyframes. It is written for anyone, human or LLM, who needs to create or edit a Construct file directly instead of through the GUI.

Everything below describes the current format. Write files exactly as described here.


OVERVIEW

A Construct file is a JSON file with the extension ".construct". It lives in the project's Assets directory and the file name (without the extension) is the name of the Construct. The name must be usable as a class name: letters, digits and underscores only, it must not start with a digit, and it must not match the name of an existing GraphicAsset, Texture, Geometry or Precomp.

When a project loads, Incisor reads each .construct file and calls nc.defineConstruct with its four top-level sections. The resulting definition is available as nc.constructDefs.<ConstructName>, and code creates an instance with nc.constructDefs.<ConstructName>.add(parent, name).

A Construct is a reusable group of objects (GraphicObjects, TextBoxes, Buttons, ParticleSystems, other Constructs and so on) arranged in a hierarchy, plus any number of named Timelines that animate properties of those objects.

The most important rule when writing a Construct file by hand: the loader applies only the keys that are present. Any key that is absent leaves the object at its normal default. The GUI writes a key only when its value differs from the default, so files saved by Incisor are compact. Writing a default value explicitly is always safe, except where noted below ("enabled" in particular).


TOP LEVEL STRUCTURE

A Construct file has exactly four top-level keys. All four should always be present.

    {
        "blueprint": { ... },
        "timelines": { ... },
        "layers": [ ... ],
        "constructSettings": { ... }
    }

An empty Construct looks like this:

    {
        "blueprint": {"type":"Blueprint","hierarchy":{},"objects":[]},
        "timelines": {},
        "layers": [],
        "constructSettings": {"targetScene":"MainScene","defaultTimeline":"NeutralState"}
    }


constructSettings

    targetScene       string. The name of the Scene the Construct's objects are added to when the Construct is
                      added through the GUI. "MainScene" unless the project defines other Scenes.
    defaultTimeline   string. The name of the Timeline that has full weight (influence 1) when an instance is
                      created, so its keyframe values are what the instance shows at first. "NeutralState" means
                      no Timeline is given weight and the objects show their own stored values. It does not
                      start the Timeline playing, that is up to the Timeline's autoplayMode. It must name a
                      Timeline in this file's "timelines" section (or be "NeutralState"). A Construct has one
                      default Timeline at most.
    spineImportVersion  number. Written only by the Spine importer. Never write it by hand.


layers

An array of layer names (strings) defined for the Construct's own Scene, which matters when the Construct generates a Precomp (see "Cameras"). Use [] when the objects only use layers the project already defines.


blueprint

    type        always the string "Blueprint".
    hierarchy   an object describing the parent and child structure. See "Hierarchy" below.
    objects     an array holding one entry per object. See "Objects" below.


HIERARCHY

"objects" is a flat array. "hierarchy" says how those objects are nested. Each key in the hierarchy is the index (as a string) of an entry in "objects", and its value is another hierarchy object listing that object's children.

The top level of the hierarchy lists the objects that are direct children of the Construct itself. The Construct is not an entry in "objects".

Example: four objects, where object 0 and object 1 are children of the Construct, and objects 2 and 3 are children of object 1.

    "hierarchy": {"0":{}, "1":{"2":{}, "3":{}}}

Rules:
- Every index in "objects" must appear exactly once in the hierarchy.
- Children are created after their parent, in key order. Sibling order in the hierarchy is the order they are added, which is the order they appear in the Hierarchy panel.
- Objects that cannot be created are skipped, along with their entire subtree. The usual causes are a missing graphic asset or a nested Construct whose definition does not exist.


OBJECTS

Each entry in "objects" describes one object. The keys below are the keys common to all objects. Keys specific to an object type follow in the next sections.

    i         number. The object's own index in the array. Written for readability, the loader uses the
              array position. Keep it equal to the array position.
    type      string. The object type. Omit it for a plain SceneObject. Valid values: "SceneObject",
              "GraphicObject", "Button", "TextBox", "TextAssembly", "OrthographicCamera",
              "PerspectiveCamera", "Construct", "ParticleSystem", "Curve", "SymbolReel", "SpineBone",
              "SpinePath".
    name      string. The object's name. If absent, the type name is used.
    uid       string. A unique id for the object within this Construct, 16 decimal digits such as
              "4821937701265534". Timelines refer to objects by uid, so every object that any
              AnimatedProperty targets must have one. Generate each uid randomly and make sure no two
              objects share one. If an object has no uid the loader assigns one, but a Timeline can then
              not target it.
    enabled   boolean. Write it only as false. The loader disables the object whenever the key is present,
              whatever its value. Omit the key for an enabled object.
    position  [x, y, z]. Omit when [0,0,0].
    rotation  [x, y, z] in degrees. Omit when [0,0,0].
    scale     [x, y, z]. Omit when [1,1,1].

Also possible on any object:

    effectControllerValues   object. Object-level EffectController values. See "EffectController values".
    customAddOns             object. CustomAddOn property values. See "CustomAddOns and CustomObjects".
    customObjectDefinition   object. See "CustomAddOns and CustomObjects".


GRAPHICOBJECT AND BUTTON KEYS

Type "GraphicObject" or "Button". A Button has every key a GraphicObject has.

    graphicAsset    string. The name of the GraphicAsset. Required, and it must exist in the project. An
                    unknown name breaks the load, so check names before writing.
    visible         boolean. Write it only as false.
    layer           string. The name of the layer. Omit for "DefaultLayer". If the named layer does not exist
                    in the project, the object stays on the default layer.
    subLayer        number. Draw order within the layer. Omit for 0.
    frustumCulling  boolean. Write it only as false.
    masking         object. See "Masking".
    materials       array. See "Materials".
    spriteSetter    object. See "SpriteSetter".
    graphicExpander object. See "GraphicExpander".
    pivotPointAdjuster  object. Any of "position" [x,y,z], "rotation" [x,y,z], "scale" [x,y,z], each omitted
                    when it holds its default. The object is "{}" when the adjuster exists with all defaults.


MATERIALS

"materials" is an array with one entry per Material on the object. For a GraphicObject the Materials come from the GraphicAsset, so entry 0 is the first Material. If the array has more entries than the object has Materials, the extras are ignored.

Each entry:

    effectNodes            array of EffectNode names, in order, for example
                           ["SampleMainTexture","ColorMultiply"]. Always include it. Names that are not
                           defined are skipped. "MaskingReturn" is always skipped, since masking supplies it.
    effectControllerValues object. The Material's EffectController values. See "EffectController values".
    textureValues          object mapping an EffectController name to a Texture name. Only needed when a
                           Material uses a Texture other than the one its GraphicAsset supplies. An unknown
                           Texture name falls back to WhiteBox.
    blendingMode           string: "none", "standard", "add", "subtract", "multiply" or "screen". Omit for
                           "standard".
    faceCulling            string: "front", "back" or "none". Omit for "none".
    depthTest              boolean. Omit for false.
    depthWrite             boolean. Omit for true.
    transparent            boolean. Omit for true.

When a Material entry is loaded, the Material's EffectNodes are replaced with the listed ones and all of its EffectController values are reset to their defaults before the listed values are applied. So the entry is the complete description of the Material's EffectNodes and values.


EFFECTCONTROLLER VALUES

An "effectControllerValues" object maps an EffectController name to its value.

- An EffectController whose base type is "number" takes a number.
- An EffectController whose base type is "Vector2", "Vector3" or "Vector4" takes an array of numbers, one per component, in the controller's component order. A color is a Vector4 with the components red, green, blue, alpha, so a color is written [r, g, b, a] with each value from 0 to 1. Other vector controllers use x, y, z, w or controller-specific component names.
- Names that are not defined EffectControllers are skipped.
- Values equal to the EffectController's default are omitted by Incisor, so an absent name means "default".
- Texture-type EffectControllers are never written here. Use a Material's "textureValues".

There are two scopes:

    Material-level    in a Material's "effectControllerValues". Applies to that Material only.
    Object-level      in the object's own "effectControllerValues". These are EffectControllers whose mix
                      mode is not "materialOnly". They affect the object and its descendants. A value
                      equal to the neutral value for the mix mode (0 for "addition", 1 for
                      "multiplication") is omitted.


MASKING

    "masking": {
        "enabled": true,
        "type": "mask",
        "invert": true,
        "maskGroups": ["MainMaskGroup"]
    }

    enabled     boolean. Required.
    type        "masked" or "mask". Omit for "masked", which is an object clipped by the mask groups. Write
                "mask" for an object that is itself a mask for the groups.
    invert      boolean. Write it only as true.
    maskGroups  array of MaskGroup names. Required. If any listed MaskGroup does not exist in the project,
                the whole masking entry is skipped silently.


SPRITESETTER

A GraphicObject that cycles through a list of GraphicAssets (a sprite animation) has a "spriteSetter" entry. The object's "graphicAsset" must be the first GraphicAsset of the sequence.

    "spriteSetter": {
        "autoplayMode": "loop",
        "initialTime": 0,
        "playbackRate": 24,
        "startValue": 0,
        "endValue": 11,
        "keyGraphicAsset": "Explosion_00"
    }

    autoplayMode   "none", "loop" or "once". "loop" and "once" start playing when the object is created.
    initialTime    number. The starting playhead position.
    playbackRate   number. Playback speed in frames per second.
    startValue     number. The first playhead value.
    endValue       number. The last playhead value.
    keyGraphicAsset  string. The name of the first GraphicAsset. The rest of the sequence is derived from
                     this one. Use it when the sequence is the group that follows from the key GraphicAsset.
    graphicAssetList array of GraphicAsset names. Use this instead of keyGraphicAsset when the sequence is
                     an explicit list that the naming alone would not give.

Write exactly one of keyGraphicAsset and graphicAssetList.


GRAPHICEXPANDER

A GraphicObject using a 9-slice style expander has a "graphicExpander" entry.

    symmetric true:
        "graphicExpander": {"symmetric":true, "expandableWidth":w, "expandableHeight":h,
                            "expandedWidth":w2, "expandedHeight":h2}
    symmetric false:
        "graphicExpander": {"symmetric":false,
                            "expandableArea":[left,right,bottom,top],
                            "expandedArea":[left,right,bottom,top]}


TEXTBOX AND TEXTASSEMBLY KEYS

Type "TextBox" or "TextAssembly". A TextBox is a Button, so it accepts the GraphicObject and Button keys above except "graphicAsset" (a TextBox makes its own).

    string                   string. The text.
    phraseID                 string. The ID of a localized phrase. When present it is used instead of "string".
                             Write one or the other.
    horizontalJustification  "left", "center" or "right". Omit for "left".
    verticalJustification    "top", "center" or "bottom". Omit for "top".
    boxWidth                 number. Omit for 0 (the text sizes itself).
    boxHeight                number. Omit for 0.
    wrapToFit                boolean. Omit for true.
    scaleToFit               boolean. Omit for true.
    baselinePosition         number. Omit for 0.22.
    textFormat               object. See below.

textFormat:

    fontName            string. The name of a font defined in the project. Required.
    characterScaleX     number. Omit for 1.
    characterScaleY     number. Omit for 1.
    kerning             number. Omit for 0.
    verticalShift       number. Omit for 0.
    lineHeightMultiplier number. Always write it explicitly.
    characterMaterial   object with "effectNodes" (array of EffectNode names, for example
                        ["SampleMainTexture","ColorMultiply"]) and "effectControllerValues" (see
                        "EffectController values"). This is the Material applied to each character.

TextBox-only keys:

    pivotPoint                [x, y]. Omit for [0,0].
    isTrimmed                 boolean. Write it only as true.
    editingMode               string. Omit for "none".
    tabEndsEditing            boolean. Write it only as false.
    returnEndsEditing         boolean. Write it only as false.
    numHorizontalGridSegments number. Omit for 2.
    numVerticalGridSegments   number. Omit for 2.

A TextBox also takes "materials" and object-level "effectControllerValues" as described above. Its text color is usually an object-level or Material-level "colorMultiply".


CAMERAS

An object of type "OrthographicCamera" or "PerspectiveCamera" inside a Construct makes the Construct generate a Precomp. The first camera found in the blueprint is the Precomp camera. The Precomp renders the Construct's contents into a GraphicAsset named after the Construct, which can then be used like any other GraphicAsset.

OrthographicCamera:

    coreViewWidth, coreViewHeight         number. The camera's view size.
    viewNear, viewFar                     number. The near and far clip distances.
    constructPrecompTargetWidth,
    constructPrecompTargetHeight          number. The pixel size of the generated render target.

PerspectiveCamera:

    coreViewAngleHorizontal,
    coreViewAngleVertical                 number. The view angles.
    viewNear, viewFar                     number.
    constructPrecompTargetWidth,
    constructPrecompTargetHeight          number.

Always write all of these keys for a camera. A camera is normally positioned back from the scene, for example position [0,0,1000] with viewFar 2000.


CONSTRUCT (NESTED)

An object of type "Construct" is an instance of another Construct.

    constructDefinition   string. The name of the Construct to instantiate. If no Construct with that name is
                          defined, the object and its children are skipped.

A nested Construct's own contents are not stored in the parent. Only the nested Construct itself, its transform and its own keys are written.


PARTICLESYSTEM

    particleSystemDefinition   string. The name of a ParticleSystemDefinition in the project. Required.
    playbackController         object. Required, with the same five keys as a Timeline's playback fields:
                               "autoplayMode", "initialTime", "playbackRate", "startValue", "endValue".

A ParticleSystem also takes the GraphicObject keys listed above, except "graphicAsset", "spriteSetter" and "graphicExpander".


CURVE

    curveAttributes   An opaque serialized description of the curve. Create Curves in the GUI. Do not write
                      this by hand.


SYMBOLREEL

A SymbolReel for slot games. Every key is omitted when it holds the default shown.

    defaultSymbolType        string. Omit for "TextBox".
    numMainSymbols           number. Omit for 3.
    numTopBufferSymbols      number. Omit for 1.
    numBottomBufferSymbols   number. Omit for 1.
    spinSpeed                number. Omit for -0.25.
    windupDuration           number. Omit for 0.25.
    windupMagnitude          number. Omit for 1.
    bounceDuration           number. Omit for 0.25.
    bounceMagnitude          number. Omit for 1.
    pathPositionSnap         number. Omit for 0.01.
    initialReelData          array. The authored starting symbols.
    pathValues               object mapping a path name to a keyframed value (see "KeyframedValue" below).
    windupCurve              a keyframed value.
    bounceCurve              a keyframed value.

SymbolReels are normally created and tuned in the GUI.


SPINEBONE AND SPINEPATH

These types are produced by the Spine importer. Do not author them by hand. Re-import the Spine animation instead.


CUSTOMADDONS AND CUSTOMOBJECTS

Persistent properties of a CustomAddOn or CustomObject are stored by value.

    "customAddOns": {
        "MyAddOn": {
            "properties": [
                {"propertyPath": ["speed"], "value": 3},
                {"propertyPath": ["options","enabled"], "value": true}
            ]
        }
    }

    "customObjectDefinition": {
        "name": "MyCustomObject",
        "properties": [ {"propertyPath": ["health"], "value": 100} ]
    }

Each property has "propertyPath" (an array of property names from the add-on or object down to the value) and "value" (a string, number or boolean matching the property's registered type). The add-on or object definition must exist in the project, otherwise it is skipped.


TIMELINES

"timelines" maps a Timeline name to a Timeline. There is always an implicit empty Timeline named "NeutralState" that holds the object's rest values. Never write a "NeutralState" entry.

    "timelines": {
        "Intro": { ... },
        "Idle":  { ... }
    }

Timeline names should be simple identifiers (letters, digits and underscores, not starting with a digit). They appear in property paths such as "timelines.Intro.time" and in code as instance.timelines.Intro.

Each Timeline:

    autoplayMode   string: "none", "loop" or "once". Always write it.
    initialTime    number. The playhead time when the Timeline is created. Always write it.
    playbackRate   number. Playback speed, 1 is normal. Always write it.
    startValue     number. The time the Timeline starts at, usually 0. Always write it.
    endValue       number. The time the Timeline ends at, which is its duration when startValue is 0. Always
                   write it.
    timeSnap       number. The grid, in seconds, that every keyframe time in this Timeline snaps to. Omit it
                   for the default of 1/60. Write it only for a different grid, for example 0.01.
    animatedProperties  array of AnimatedProperty entries. Always write it, even when empty.

A Timeline with autoplayMode "loop" starts playing when the Construct instance is created, "once" plays once, and "none" waits for code to call play(). Whether a Timeline's values show at all depends on its weight. The Timeline named as "defaultTimeline" in constructSettings starts with weight 1, and any other Timeline starts with weight 0 until code or another Timeline raises it.


ANIMATEDPROPERTIES

An AnimatedProperty drives one property of one object (or one global) from keyframes on a Timeline.

    {
        "propertyPath": ["position","x"],
        "sceneObjectUid": "4821937701265534",
        "interpolation": "bezier",
        "keyframes": [ ... ]
    }

    propertyPath     array of strings. The path to the property, from the owning object. Required. The valid
                     paths are listed below.
    sceneObjectUid   string. The uid of the object that owns the property. Required for object properties.
                     Omit it only for global paths ("nc.sounds..." and "nc.appEvents..."). The object must be
                     the Construct root's descendant with that uid, or the property is skipped (with a
                     warning in development).
    type             string: "floatingPoint", "boolean", "string" or "invoke". Omit for "floatingPoint". The
                     valid type for a path is fixed by the path, see below.
    interpolation    string: "optimizedBezier" or "bezier". Omit for "optimizedBezier". Only meaningful for
                     "floatingPoint".
    valueSnap        number. Snaps keyframe values to multiples of this number. Floating point only.
                     Omit for no snapping.
    continueLeft     string. What the value does before the first keyframe: "constant" (hold the first
                     value), "extrapolate", "loop" or "pingPong". Omit for "constant".
    continueRight    string. The same, after the last keyframe. Omit for "constant".
    parameters       A parameter schema for an "invoke" property whose parameters the user declares, such
                     as an app event trigger. Omit it for every other property.
    keyframes        array of keyframes. Required.

When several Timelines animate the same property, their values are blended by Timeline weight: floating point values by weighted sum, booleans by logical OR, and strings by the highest-weight Timeline. "invoke" properties are not blended. Each Timeline invokes its own keyframes.


propertyPath values

All numeric properties are type "floatingPoint". An array element in angle brackets is replaced by a real name.

On every SceneObject:

    ["enabled"]                                   boolean
    ["position","x"], ["position","y"], ["position","z"]       floatingPoint
    ["rotation","x"], ["rotation","y"], ["rotation","z"]       floatingPoint, degrees
    ["scale","x"], ["scale","y"], ["scale","z"]                floatingPoint

On a GraphicObject (and Button, TextBox):

    ["visible"]                                   boolean
    ["subLayer"]                                  floatingPoint
    ["layer"]                                     string, a layer name
    ["graphicAsset"]                              string, a GraphicAsset name

EffectControllers at the object level (mix mode not "materialOnly", gathered from the object and its descendants):

    [<effectControllerName>, <componentName>]     floatingPoint, for a Vector controller, for example
                                                  ["colorMultiply","alpha"] or ["sheen","progress"]
    [<effectControllerName>]                      floatingPoint, for a "number" controller

EffectControllers and blending on a specific Material (index <i> counts from 0):

    ["material","<i>","blendingMode"]             string, a blending mode name
    ["material","<i>",<effectControllerName>,<componentName>]   floatingPoint
    ["material","<i>",<effectControllerName>]                    floatingPoint, for a "number" controller

Color components are named red, green, blue, alpha. The component names of other controllers are listed in the Object panel.

Text (TextBox and TextAssembly):

    ["string"]                                    string
    ["phraseID"]                                  string

GraphicExpander (when the object has one):

    symmetric:      ["graphicExpander","expandableWidth"], ["graphicExpander","expandableHeight"],
                    ["graphicExpander","expandedWidth"], ["graphicExpander","expandedHeight"]
    not symmetric:  ["graphicExpander","expandableAreaLeft"], "...Right", "...Bottom", "...Top",
                    ["graphicExpander","expandedAreaLeft"], "...Right", "...Bottom", "...Top"

Sprite animation (SpriteSetter):

    ["spriteSetter","value"]                      floatingPoint
    ["spriteSetter","playbackRate"]               floatingPoint
    ["spriteSetter","play"], ["spriteSetter","pause"], ["spriteSetter","stop"], ["spriteSetter","playOnce"]
                                                  invoke

ParticleSystem:

    ["playbackController","time"]                 floatingPoint
    ["playbackController","playbackRate"]         floatingPoint
    ["playbackController","play"], ["playbackController","pause"], ["playbackController","stop"],
    ["playbackController","playOnce"]             invoke

On the Construct root (the object that holds the Timelines), for each Timeline in the Construct other than "NeutralState". These are offered once the Construct has at least one Timeline besides "NeutralState":

    ["timelines","<timelineName>","time"]         floatingPoint
    ["timelines","<timelineName>","weight"]       floatingPoint
    ["timelines","<timelineName>","playbackRate"] floatingPoint
    ["timelines","<timelineName>","play"], "pause", "stop", "playOnce", "playAndTakeWeight",
    "playOnceAndTakeWeight"                       invoke

Global properties, written without a sceneObjectUid:

    ["nc","sounds","<soundName>","mainVolume"]    floatingPoint
    ["nc","sounds","<soundName>","play"], "pause", "stop", "playOnce"   invoke
    ["nc","appEvents","<eventName>","trigger"]    invoke, for an AppEvent defined with nc.defineAppEvent

Properties of CustomObjects and CustomAddOns:

    custom object:   the property's own "propertyPath", a function is "invoke", a number is "floatingPoint",
                     a boolean is "boolean"
    custom add-on:   ["customAddOns","<addOnName>", ...the property's own propertyPath]

Spine skeletons (the root bone of an imported Spine animation):

    ["skinStates","<skinName>"]                   boolean. The skin's active state. Skin names that contain a
                                                  dot are not supported.

A path that is not in this list for the owning object is rejected. Always match the object's type and its actual EffectControllers, Materials and Timelines.


KEYFRAMES

    {"time": 0.5, "value": 120, "rightHandleValue": 4.2, "rightHandleSpan": 0.4}

    time    number. Seconds on the Timeline. It snaps to the Timeline's timeSnap grid. Two keyframes of one
            property that land on the same snapped time are merged into one and the newest wins, so never
            give one property two keyframes on the same snapped time. Write keyframes in ascending time order.
    value   The value at that time. A number for "floatingPoint", true or false for "boolean", a string for
            "string". Omit for "invoke".
    type    string: "standard", "left" or "right". Omit for "standard". See "Step keyframes".
    secondaryValue  The value on the far side of a step. Written only on "left" and "right" keyframes.
    leftHandleValue, leftHandleSpan, rightHandleValue, rightHandleSpan
            Bezier handles. See "Handles". Write a handle's value and span together, never one alone.
    invocationParameters   object. Parameters passed to the invoked function at this keyframe. Write it only
                           when it has parameters. Used by "invoke" properties.


Value types and stepping

- "floatingPoint" keyframes are interpolated between keyframes using the property's interpolation.
- "boolean" and "string" properties are stepped. The value holds until the next keyframe and then changes at once, so there are no handles on them.
- "invoke" properties have no values. Each keyframe is a moment at which the function named by the path is called. The callback fires when the playhead crosses the keyframe time. Parameters are given in "invocationParameters".


Handles

Each floating point keyframe can carry a left handle and a right handle that shape the curve on either side. They are only meaningful when the interpolation is "bezier" or "optimizedBezier". Without handles a segment is a straight line.

    rightHandleValue   number. The handle's height, as an offset from the keyframe's value (positive is
                       above it, negative is below).
    rightHandleSpan    number from 0.01 to 0.99. How far along the segment to the next keyframe the handle
                       sits, as a fraction of that segment's duration.
    leftHandleValue    number. The same, measured from the keyframe's value, for the segment before it.
    leftHandleSpan     number from 0.01 to 0.99. The fraction of the previous segment's duration, counted
                       back from this keyframe.

A segment is shaped by the right handle of its left keyframe and the left handle of its right keyframe. Both, either or neither can be present. Spans outside 0.01 to 0.99 are clamped. For "optimizedBezier", the two spans of one segment are also scaled down if they add up to more than 1. A handle value of 0 gives a flat tangent.

The first keyframe of a property has no left handle and the last has no right handle.


Step keyframes

A "left" or "right" keyframe produces a jump at a single time with two values, instead of a smooth change.

    {"time": 0.5, "type": "left",  "value": 540, "secondaryValue": -1500}
    {"time": 0.1, "type": "right", "value": -569, "secondaryValue": -1500}

- type "right": "value" is the value from this time forward. "secondaryValue" is the value the segment before it approaches. At the exact time, the property reads "value".
- type "left": "value" is the value the segment before it ends on, including at the exact time. "secondaryValue" is the value the segment after it starts from.

"secondaryValue" is only meaningful on these two types.


KEYFRAMEDVALUE

A "keyframed value" is the same structure as an AnimatedProperty without the "propertyPath" and "sceneObjectUid": the keys "type", "interpolation", "valueSnap", "continueLeft", "continueRight" and "keyframes" described above. SymbolReel uses them for "pathValues", "windupCurve" and "bounceCurve". It also accepts a "timeSnap" number, written only when it differs from 0.02.


AUTHORING CHECKLIST

- All four top-level keys are present. "blueprint.type" is "Blueprint".
- Every object index appears exactly once in "hierarchy".
- Every uid is a unique 16 digit string. Every "sceneObjectUid" in a Timeline names an existing object.
- Every graphicAsset, layer, MaskGroup, font, EffectNode, EffectController, Texture, Construct and ParticleSystemDefinition name exists in the project. Missing names are mostly skipped silently, which makes the object disappear or lose features without an error.
- Write "enabled" only as false, "visible" only as false.
- Each Timeline has all five playback keys and an "animatedProperties" array.
- Each property path is one of the valid paths for its object and its "type" matches the path.
- Keyframes ascend in time and no two share a snapped time.
- Handles are written as a value and span pair, spans from 0.01 to 0.99.
- "defaultTimeline" names an existing Timeline or "NeutralState".


EXAMPLE 1: A SMALL CONSTRUCT WITH ONE TIMELINE

A panel, a label and a one second slide-in animation. The "defaultTimeline" starts it automatically.

    {
        "blueprint": {
            "type": "Blueprint",
            "hierarchy": {"0":{"1":{}}},
            "objects": [
                {
                    "i": 0,
                    "type": "GraphicObject",
                    "name": "Panel",
                    "uid": "4821937701265534",
                    "position": [-600, 0, 0],
                    "scale": [4, 2, 1],
                    "graphicAsset": "WhiteBox",
                    "materials": [
                        {
                            "effectNodes": ["SampleMainTexture","ColorMultiply"],
                            "effectControllerValues": {"colorMultiply": [0.1, 0.2, 0.5, 1]}
                        }
                    ]
                },
                {
                    "i": 1,
                    "type": "TextBox",
                    "name": "Label",
                    "uid": "7203918456620187",
                    "position": [0, 0, 0],
                    "subLayer": 0.01,
                    "string": "Hello",
                    "horizontalJustification": "center",
                    "textFormat": {
                        "fontName": "SampleFont",
                        "lineHeightMultiplier": 1,
                        "characterMaterial": {"effectNodes": ["SampleMainTexture"], "effectControllerValues": {}}
                    }
                }
            ]
        },
        "timelines": {
            "SlideIn": {
                "autoplayMode": "none",
                "initialTime": 0,
                "playbackRate": 1,
                "startValue": 0,
                "endValue": 1,
                "animatedProperties": [
                    {
                        "propertyPath": ["position","x"],
                        "sceneObjectUid": "4821937701265534",
                        "interpolation": "bezier",
                        "keyframes": [
                            {"time": 0, "value": -600, "rightHandleValue": 400, "rightHandleSpan": 0.4},
                            {"time": 1, "value": 0, "leftHandleValue": -100, "leftHandleSpan": 0.4}
                        ]
                    }
                ]
            }
        },
        "layers": [],
        "constructSettings": {"targetScene": "MainScene", "defaultTimeline": "SlideIn"}
    }


EXAMPLE 2: BOOLEAN, INVOKE AND STEP PROPERTIES

The Timeline "Reveal" below shows a boolean that turns an object on at 0.25 seconds, a sprite-animation call fired at 0.1 seconds and a floating point property with a step.

    "Reveal": {
        "autoplayMode": "none",
        "initialTime": 0,
        "playbackRate": 1,
        "startValue": 0,
        "endValue": 2,
        "animatedProperties": [
            {
                "type": "boolean",
                "propertyPath": ["enabled"],
                "sceneObjectUid": "7203918456620187",
                "keyframes": [
                    {"time": 0, "value": false},
                    {"time": 0.25, "value": true}
                ]
            },
            {
                "type": "invoke",
                "propertyPath": ["spriteSetter","playOnce"],
                "sceneObjectUid": "5560129984413076",
                "keyframes": [ {"time": 0.1} ]
            },
            {
                "propertyPath": ["scale","y"],
                "sceneObjectUid": "4821937701265534",
                "interpolation": "bezier",
                "keyframes": [
                    {"time": 0, "value": 0.5},
                    {"time": 1, "type": "left", "value": 1, "secondaryValue": 2},
                    {"time": 2, "value": 2}
                ]
            }
        ]
    }

In the last property, "scale.y" eases from 0.5 up to 1 at time 1, then jumps to 2 and holds 2 until time 2.

Incisor® Example Projects

IncisorExampleProjects.txt

Incisor® Example Projects
This document is part of the compiled knowledge base for the Incisor® Software Development Platform.
Any use of this content is subject to the INCISOR® end user license and terms of use agreement.
https://www.incisordev.com/eultua
2026.11.05.12.18.08






----------------------------------------------------------
TABLE OF CONTENTS:
----------------------------------------------------------
Section 1: IncisorExampleGalleryJS_textMap
Section 2: IncisorSlotTemplateJS_textMap
Section 3: IncisorSlotTemplateTS_textMap










----------------------------------------------------------
Section 1: IncisorExampleGalleryJS_textMap
----------------------------------------------------------


INCISOR PROJECT PLAIN TEXT MAP
============================================================
Project: Incisor Example Gallery JS
Generated: 2026-11-03T17:34:36.675Z
Project Language: JavaScript

Excluded:
- AssetCache and its contents
- Publishing
- AutoSave
- IncisorAPI.js
- IncisorAPI.d.ts

TABLE OF CONTENTS
============================================================
Incisor Example Gallery JS
    Assets/
        002 TextBox/
            TextBox/
                CenterWinFont/
                    CenterWinFont_Char{0000-8482}.png (112 files)
                    CenterWinFont_Char{0000-8482}.png.ncData (112 files)
                CenterWinFont.ncData
            TextBox.ncData
        005 Sprite Setter/
            SpriteSetter/
                CoinSequence/
                    CoinFlip_{00-29}.png (30 files)
                    CoinFlip_{00-29}.png.ncData (30 files)
                CoinSequence.ncData
            SpriteSetter.ncData
        CodeAssets/
            BlinnPhongLighting.codeAsset.js
            Bounce.codeAsset.js
            MatCap.codeAsset.js
            NormalMap.codeAsset.js
            Sway.codeAsset.js
            WindupOvershoot.codeAsset.js
        General (autoloaded)/
            General/
                ExampleFont/
                    ExampleFont_Char{0000-8482}.png (114 files)
                    ExampleFont_Char{0000-8482}.png.ncData (114 files)
                Arrow.png
                Arrow.png.ncData
                Ball.png
                Ball.png.ncData
                ExampleFont.ncData
                ExampleViewerConstruct.construct
                ExampleViewerConstruct.construct.ncData
                Frame.png
                Frame.png.ncData
                Logo.png
                Logo.png.ncData
                NeonButton.png
                NeonButton.png.ncData
            SampleAssets/
                icons/
                    icon_caret.png
                    icon_caret.png.ncData
                    icon_checkmark.png
                    icon_checkmark.png.ncData
                    icon_ex.png
                    icon_ex.png.ncData
                    icon_magnifyingglass.png
                    icon_magnifyingglass.png.ncData
                    icon_minus.png
                    icon_minus.png.ncData
                    icon_sliderarrows.png
                    icon_sliderarrows.png.ncData
                    icon_sliderarrowsapart.png
                    icon_sliderarrowsapart.png.ncData
                IncisorsaurusAnim/
                    PNGs/
                        Incisorsaurus_0000_Finger.png
                        Incisorsaurus_0000_Finger.png.ncData
                        Incisorsaurus_0001_Finger2.png
                        Incisorsaurus_0001_Finger2.png.ncData
                        Incisorsaurus_0002_Forearm.png
                        Incisorsaurus_0002_Forearm.png.ncData
                        Incisorsaurus_0003_Thumb.png
                        Incisorsaurus_0003_Thumb.png.ncData
                        Incisorsaurus_0004_Sleeve.png
                        Incisorsaurus_0004_Sleeve.png.ncData
                        Incisorsaurus_0005_UpperArm.png
                        Incisorsaurus_0005_UpperArm.png.ncData
                        Incisorsaurus_0006_Pupil.png
                        Incisorsaurus_0006_Pupil.png.ncData
                        Incisorsaurus_0007_Eyebrow.png
                        Incisorsaurus_0007_Eyebrow.png.ncData
                        Incisorsaurus_0008_Eyebrow.png
                        Incisorsaurus_0008_Eyebrow.png.ncData
                        Incisorsaurus_0009_Eye.png
                        Incisorsaurus_0009_Eye.png.ncData
                        Incisorsaurus_0010_IncisorTooth.png
                        Incisorsaurus_0010_IncisorTooth.png.ncData
                        Incisorsaurus_0011_Head.png
                        Incisorsaurus_0011_Head.png.ncData
                        Incisorsaurus_0012_Pupil.png
                        Incisorsaurus_0012_Pupil.png.ncData
                        Incisorsaurus_0013_Eye.png
                        Incisorsaurus_0013_Eye.png.ncData
                        Incisorsaurus_0014_LowerJaw.png
                        Incisorsaurus_0014_LowerJaw.png.ncData
                        Incisorsaurus_0015_Body.png
                        Incisorsaurus_0015_Body.png.ncData
                        Incisorsaurus_0016_Neck.png
                        Incisorsaurus_0016_Neck.png.ncData
                        Incisorsaurus_0017_Shorts.png
                        Incisorsaurus_0017_Shorts.png.ncData
                        Incisorsaurus_0018_Sneaker.png
                        Incisorsaurus_0018_Sneaker.png.ncData
                        Incisorsaurus_0019_LowerLeg.png
                        Incisorsaurus_0019_LowerLeg.png.ncData
                        Incisorsaurus_0020_Thumb.png
                        Incisorsaurus_0020_Thumb.png.ncData
                        Incisorsaurus_0021_Finger1.png
                        Incisorsaurus_0021_Finger1.png.ncData
                        Incisorsaurus_0022_Finger2.png
                        Incisorsaurus_0022_Finger2.png.ncData
                        Incisorsaurus_0023_Forearm.png
                        Incisorsaurus_0023_Forearm.png.ncData
                        Incisorsaurus_0024_Sleeve.png
                        Incisorsaurus_0024_Sleeve.png.ncData
                        Incisorsaurus_0025_UpperArm.png
                        Incisorsaurus_0025_UpperArm.png.ncData
                        Incisorsaurus_0026_Shorts.png
                        Incisorsaurus_0026_Shorts.png.ncData
                        Incisorsaurus_0027_Sneaker.png
                        Incisorsaurus_0027_Sneaker.png.ncData
                        Incisorsaurus_0028_LowerLeg.png
                        Incisorsaurus_0028_LowerLeg.png.ncData
                        Incisorsaurus_0029_Tail1.png
                        Incisorsaurus_0029_Tail1.png.ncData
                        Incisorsaurus_0030_Tail2.png
                        Incisorsaurus_0030_Tail2.png.ncData
                        Incisorsaurus_0031_Tail3.png
                        Incisorsaurus_0031_Tail3.png.ncData
                        Incisorsaurus_0032_Background.png
                        Incisorsaurus_0032_Background.png.ncData
                        Incisorsaurus_0033_EyeLidTop.png
                        Incisorsaurus_0033_EyeLidTop.png.ncData
                        Incisorsaurus_0034_EyeLidBot.png
                        Incisorsaurus_0034_EyeLidBot.png.ncData
                    Incisorsaurus.construct
                    Incisorsaurus.construct.ncData
                    PNGs.ncData
                SampleParticles/
                    SampleParticle.png
                    SampleParticle.png.ncData
                    SampleParticle2.png
                    SampleParticle2.png.ncData
                icons.ncData
                IncisorsaurusAnim.ncData
                SampleFont.ttf
                SampleFont.ttf.ncData
                SampleParticles.ncData
            stone-granite-4/
                stone-granite-4-NORM.png
                stone-granite-4-NORM.png.ncData
                stone-granite-4-TEX.png
                stone-granite-4-TEX.png.ncData
            Coin.mtl
            Coin.obj
            Coin.obj.ncData
            CoinDiffuse.png
            CoinDiffuse.png.ncData
            CoinFountain.particleSysDef
            CoinFountain.particleSysDef.ncData
            CoinNormals.png
            CoinNormals.png.ncData
            ExampleParticleSystem.particleSysDef
            ExampleParticleSystem.particleSysDef.ncData
            General.ncData
            MainScene.layers
            MainScene.layers.ncData
            matcap.png
            matcap.png.ncData
            SampleAssets.ncData
            Sound0.wav
            Sound0.wav.ncData
            Sound1.wav
            Sound1.wav.ncData
            stone-granite-4.ncData
            suzanne.mtl
            suzanne.obj
            suzanne.obj.ncData
        002 TextBox.ncData
        005 Sprite Setter.ncData
        CodeAssets.ncData
        General (autoloaded).ncData
    ProjectCode/
        IncisorExamples/
            001 TextAssembly.js
            002 TextBox.js
            003 SwoopersAndMotions.js
            004 Sounds.js
            005 SpriteSetter.js
            006 ConstructWithTimelines.js
            007 ParticleSystem.js
            008 Precomp.js
            009 OBJ.js
            010 ObjParticles.js
        PreloadConfiguration/
            PreloadConfiguration.js
        IncisorExampleBaseClass.js
        ProjectMain.js
    Utilities/
        MinificationLists/
            DoNotMinifyLists/
                DoNotMinifyList.json
            MinifyLists/
                MinifyList.json
        ProjectState.json
        ProjectTranscript.json
    Assets.ncData
    jsconfig.json
    ProjectSettings.json
    ReleaseNotes.json

GROUPED REPETITIVE FILES
============================================================
Assets/002 TextBox/TextBox/CenterWinFont/CenterWinFont_Char{0000-8482}.png (112 files) -> grouped repetitive non-text files (112 files)
Assets/002 TextBox/TextBox/CenterWinFont/CenterWinFont_Char{0000-8482}.png.ncData (112 files) -> grouped repetitive text files (112 files)
Assets/005 Sprite Setter/SpriteSetter/CoinSequence/CoinFlip_{00-29}.png (30 files) -> grouped repetitive non-text files (30 files)
Assets/005 Sprite Setter/SpriteSetter/CoinSequence/CoinFlip_{00-29}.png.ncData (30 files) -> grouped repetitive text files (30 files)
Assets/General (autoloaded)/General/ExampleFont/ExampleFont_Char{0000-8482}.png (114 files) -> grouped repetitive non-text files (114 files)
Assets/General (autoloaded)/General/ExampleFont/ExampleFont_Char{0000-8482}.png.ncData (114 files) -> grouped repetitive text files (114 files)

TEXT FILE CONTENTS
============================================================
Assets/002 TextBox/TextBox/CenterWinFont.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/002 TextBox/TextBox.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/005 Sprite Setter/SpriteSetter/CoinSequence.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/005 Sprite Setter/SpriteSetter.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/CodeAssets/BlinnPhongLighting.codeAsset.js
------------------------------------------------------------
class BlinnPhongLighting extends CustomAddOn_GraphicObject {
    constructor(owner) {
        super(owner);
        this._ambientLight = false;
        this._numDirectionalLights = 0;
        this._numPointLights = 0;
        this._numSpotLights = 0;
        this._ambientResponseTexture = false;
        this._specularResponseTexture = false;
        this._specularResponseExponentTexture = false;
        this._normalTexture = false;
        this._ambientResponseColor = false;
        this._specularResponseColor = false;
        this._specularResponseExponent = false;
        let materialPresets = this.owner.graphicAsset.materialPresets;
        for (let m = 0; m < materialPresets.length; ++m) {
            let optionalValues = materialPresets[m]["optionalMaterialValues"];
            if (optionalValues !== undefined) {
                this._ambientResponseTexture = this._ambientResponseTexture || optionalValues.ambientTexture !== undefined;
                this._specularResponseTexture = this._specularResponseTexture || optionalValues.specularTexture !== undefined;
                this._specularResponseExponentTexture = this._specularResponseExponentTexture || optionalValues.specularExponentTexture !== undefined;
                this._normalTexture = this._normalTexture || optionalValues.normalTexture !== undefined;
                this._ambientResponseColor = this._ambientResponseColor || optionalValues.ambientColor !== undefined;
                this._specularResponseColor = this._specularResponseColor || optionalValues.specularColor !== undefined;
                this._specularResponseExponent = this._specularResponseExponent || optionalValues.specularExponent !== undefined;
            }
        }
        this.refresh();
        this.copyPresets();
    }
    onRegisteredPropertiesRestored() {
        this.refresh();
    }
    set ambientLight(val) {
        let _previousValue = this._ambientLight;
        this._ambientLight = val;
        this.refresh();
        if (_previousValue === false && val === true) {
            let materials = this.owner.getMaterials();
            for (let m = 0; m < materials.length; ++m) {
                let material = materials[m];
                material["ambientLightColor"].swoop.each([1, 1, 1, .3]);
            }
        }
    }
    get ambientLight() {
        return this._ambientLight;
    }
    set numDirectionalLights(val) {
        let _previousValue = this._numDirectionalLights;
        this._numDirectionalLights = val;
        this.refresh();
        for (let i = _previousValue; i < val; ++i) {
            let materials = this.owner.getMaterials();
            for (let m = 0; m < materials.length; ++m) {
                let material = materials[m];
                material["directionalLightColor" + i].swoop.each([1, 1, 1, 1]);
            }
        }
    }
    get numDirectionalLights() {
        return this._numDirectionalLights;
    }
    set numPointLights(val) {
        let _previousValue = this._numPointLights;
        this._numPointLights = val;
        this.refresh();
        for (let i = _previousValue; i < val; ++i) {
            let materials = this.owner.getMaterials();
            for (let m = 0; m < materials.length; ++m) {
                let material = materials[m];
                material["pointLightColor" + i].swoop.each([1, 1, 1, 1]);
            }
        }
    }
    get numPointLights() {
        return this._numPointLights;
    }
    set numSpotLights(val) {
        let _previousValue = this._numSpotLights;
        this._numSpotLights = val;
        this.refresh();
        for (let i = _previousValue; i < val; ++i) {
            let materials = this.owner.getMaterials();
            for (let m = 0; m < materials.length; ++m) {
                let material = materials[m];
                material["spotLightColor" + i].swoop.each([1, 1, 1, 1]);
            }
        }
    }
    get numSpotLights() {
        return this._numSpotLights;
    }
    set ambientResponseTexture(val) {
        this._ambientResponseTexture = val;
        this.refresh();
    }
    get ambientResponseTexture() {
        return this._ambientResponseTexture;
    }
    set ambientResponseColor(val) {
        this._ambientResponseColor = val;
        this.refresh();
    }
    get ambientResponseColor() {
        return this._ambientResponseColor;
    }
    set specularResponseTexture(val) {
        this._specularResponseTexture = val;
        this.refresh();
    }
    get specularResponseTexture() {
        return this._specularResponseTexture;
    }
    set specularResponseColor(val) {
        this._specularResponseColor = val;
        this.refresh();
    }
    get specularResponseColor() {
        return this._specularResponseColor;
    }
    set specularResponseExponentTexture(val) {
        this._specularResponseExponentTexture = val;
        this.refresh();
    }
    get specularResponseExponentTexture() {
        return this._specularResponseExponentTexture;
    }
    set specularResponseExponent(val) {
        this._specularResponseExponent = val;
        this.refresh();
    }
    get specularResponseExponent() {
        return this._specularResponseExponent;
    }
    set normalTexture(val) {
        this._normalTexture = val;
        this.refresh();
    }
    get normalTexture() {
        return this._normalTexture;
    }
    refresh() {
        let code = "BlinnPhongLighting_";
        if (this._ambientLight) {
            code += "al_";
        }
        code += this._numPointLights + "pl_" + this._numDirectionalLights + "dl_" + this._numSpotLights + "sl_";
        if (this._ambientResponseTexture) {
            code += "at_";
        }
        if (this._specularResponseTexture) {
            code += "st_";
        }
        if (this._specularResponseExponentTexture) {
            code += "et_";
        }
        if (this._ambientResponseColor) {
            code += "ac_";
        }
        if (this._specularResponseColor) {
            code += "sc_";
        }
        if (this._specularResponseExponent) {
            code += "se_";
        }
        if (this._normalTexture) {
            //check if they have the normal map effect node defined.  if so, use it.  if not, define it and then use it.
            if (nc.effectNodes["NormalMap"] === undefined) {
                if (nc.effectControllers["normalMap_texture"] === undefined)
                    nc.defineEffectController("normalMap_texture", nc.constants.effectControllerBaseTypes.Texture, ["normalMap_texture"], nc.textures.WhiteBox, "addition");
                if (nc.effectControllers["normalMap_strength"] === undefined)
                    nc.defineEffectController("normalMap_strength", "number", ["normalMap_strength"], [1], "addition", [[0, 1]], "The strength of the per-fragment normal perturbation caused by the normal map.");
                if (nc.effectControllers["normalMap_isLeftHanded"] === undefined)
                    nc.defineEffectController("normalMap_isLeftHanded", "number", ["normalMap_isLeftHanded"], [0], "addition", [[0, 1]], "Normal maps created using the DirectX left handed convention will have inverted Y values. Set this value to 1 to corrent this.");
                nc.defineEffectNode("NormalMap", ["varying vec3 camToFrag;", "varying vec3 vertPos;"], "vertPos = (modelMatrix * vec4(vertex, 1.0)).xyz;", [
                    "uniform float normalMap_strength;",
                    "uniform float normalMap_isLeftHanded;",
                    "uniform sampler2D normalMap_texture;",
                    "varying vec3 vertPos;"
                ], "vec4 normalSample = texture2D(normalMap_texture, UV);\n\
                    vec3 Q1 = dFdx(vertPos);\n\
                    vec3 Q2 = dFdy(vertPos);\n\
                    vec2 st1 = dFdx(UV);\n\
                    vec2 st2 = dFdy(UV);\n\
                    vec3 N = normalize(NORMAL);\n\
                    vec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n\
                    vec3 B = -normalize(cross(N, T));\n\
                    mat3 TBN = mat3(T, B, N);\n\
                    vec3 n = normalSample.xyz;\n\
                    n.xy = (n.xy * 2.0 - vec2(1.0)) * normalMap_strength;\n\
                    n.y = normalMap_isLeftHanded > 0.5 ? -n.y : n.y;\n\
                    n = gl_FrontFacing ? n : -n;\n\
                    n = normalize(n);\n\
                    NORMAL = normalize(TBN * n);", [nc.effectControllers["normalMap_texture"], nc.effectControllers["normalMap_strength"], nc.effectControllers["normalMap_isLeftHanded"]], true);
            }
        }
        if (nc.effectNodes[code] === undefined)
            this.createEffectNode(code);
        let materials = this.owner.getMaterials();
        for (let m = 0; m < materials.length; ++m) {
            let material = materials[m];
            let nodes = material.getEffectNodes();
            let existingIndex = nodes.findIndex((node) => node.name.startsWith("BlinnPhongLighting_"));
            let nodeIndex = 0;
            if (existingIndex !== -1) {
                nodeIndex = existingIndex;
                nodes[existingIndex] = nc.effectNodes[code];
            }
            else {
                nodeIndex = nodes.length;
                nodes.push(nc.effectNodes[code]);
            }
            let normalMapNodeIndex = nodes.findIndex((node) => node.name === "NormalMap");
            if (this._normalTexture) {
                //if the effect node list already has normal map, nothing to do.
                //if it doesn't, insert it before this node
                if (normalMapNodeIndex === -1) {
                    nodes.splice(nodeIndex, 0, nc.effectNodes["NormalMap"]);
                }
            }
            else {
                //they're not using a normal map.  if you find one in the list, remove it
                if (normalMapNodeIndex !== -1) {
                    nodes.splice(normalMapNodeIndex, 1);
                }
            }
            material.setEffectNodes(nodes);
        }
    }
    copyPresets() {
        let materials = this.owner.getMaterials();
        let materialPresets = this.owner.graphicAsset.materialPresets;
        for (let m = 0; m < materials.length; ++m) {
            let material = materials[m];
            let optionalValues = materialPresets[m]["optionalMaterialValues"];
            if (optionalValues == undefined)
                continue;
            if (optionalValues.ambientTexture !== undefined && material["ambientResponseTexture"] !== undefined) {
                let texture = nc.textures[optionalValues.ambientTexture];
                if (texture !== undefined) {
                    material["ambientResponseTexture"] = texture;
                }
            }
            if (optionalValues.specularTexture !== undefined && material["specularResponseTexture"] !== undefined) {
                let texture = nc.textures[optionalValues.specularTexture];
                if (texture !== undefined) {
                    material["specularResponseTexture"] = texture;
                }
            }
            if (optionalValues.specularExponentTexture !== undefined && material["specularResponseExponentTexture"] !== undefined) {
                let texture = nc.textures[optionalValues.specularExponentTexture];
                if (texture !== undefined) {
                    material["specularResponseExponentTexture"] = texture;
                }
            }
            if (optionalValues.normalTexture !== undefined && material["normalMap_texture"] !== undefined) {
                let texture = nc.textures[optionalValues.normalTexture];
                if (texture !== undefined) {
                    material["normalMap_texture"] = texture;
                }
            }
            if (optionalValues.ambientColor !== undefined && material["ambientResponseColor"] !== undefined) {
                material["ambientResponseColor"].x = optionalValues.ambientColor[0];
                material["ambientResponseColor"].y = optionalValues.ambientColor[1];
                material["ambientResponseColor"].z = optionalValues.ambientColor[2];
            }
            if (optionalValues.specularColor !== undefined && material["specularResponseColor"] !== undefined) {
                material["specularResponseColor"].x = optionalValues.specularColor[0];
                material["specularResponseColor"].y = optionalValues.specularColor[1];
                material["specularResponseColor"].z = optionalValues.specularColor[2];
            }
            if (optionalValues.specularExponent !== undefined && material["specularResponseExponent"] !== undefined) {
                material["specularResponseExponent"] = optionalValues.specularExponent;
            }
            if (optionalValues.normalStrength !== undefined && material["normalStrength"] !== undefined) {
                material["normalStrength"] = optionalValues.normalStrength;
            }
        }
        // apply the default contour shading style setup
        this.numDirectionalLights = 1;
        this.ambientLight = true;
        for (let m = 0; m < materials.length; ++m) {
            let material = materials[m];
            material["directionalLightDirection0"].swoop.each([-1, -1, -1]);
            material["directionalLightColor0"].swoop.each([1, 1, .5, 1]);
            material["ambientLightColor"].swoop.each([.4, .4, 1, .75]);
        }
    }
    createEffectNode(_encodedName) {
        let _vertSupport = [];
        let _vertNode = "";
        let _fragSupport = [];
        let _fragNode = "";
        let _newEffectControllers = [];
        _vertSupport.push("varying vec3 vertPos;");
        _vertNode += "NORMAL = dot(NORMAL, NORMAL) > .0001 ? NORMAL : vec3(0.0, 0.0, 1.0);\n";
        _vertNode += "vertPos = (modelMatrix * vec4(vertex, 1.0)).xyz;\n";
        _fragSupport.push("varying vec3 vertPos;");
        _fragSupport.push("uniform vec3 ambientResponseColor;");
        _fragSupport.push("uniform vec3 specularResponseColor;");
        _fragSupport.push("uniform float specularResponseExponent;");
        _fragNode += "vec4 diffuseC = fragment;\n";
        if (this._ambientResponseColor) {
            if (nc.effectControllers["ambientResponseColor"] === undefined)
                nc.defineEffectController("ambientResponseColor", "Vector3", ["red", "green", "blue"], [0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1]], "The ambient light response color. Ambient light will be multiplied by this value before contributing to the lighting.", ["The red component of the ambient response.", "The green component of the ambient response.", "The blue component of the ambient response."]);
            _newEffectControllers.push(nc.effectControllers["ambientResponseColor"]);
            _fragNode += "vec3 ambientC = ambientResponseColor;\n";
        }
        else {
            _fragNode += "vec3 ambientC = vec3(1.0);\n";
        }
        if (this._specularResponseColor) {
            if (nc.effectControllers["specularResponseColor"] === undefined)
                nc.defineEffectController("specularResponseColor", "Vector3", ["red", "green", "blue"], [0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1]], "The specular response color. Specular highlight colors will be multiplied by this value.", ["The red component of the specular response.", "The green component of the specular response.", "The blue component of the specular response."]);
            _newEffectControllers.push(nc.effectControllers["specularResponseColor"]);
            _fragNode += "vec3 specularC = specularResponseColor;\n";
        }
        else {
            _fragNode += "vec3 specularC = vec3(0.0);\n";
        }
        if (this._specularResponseExponent) {
            if (nc.effectControllers["specularResponseExponent"] === undefined)
                nc.defineEffectController("specularResponseExponent", "number", ["specularResponseExponent"], [0], "addition", [[0, 1000]], "The specular exponent. With higher exponent values, specular reflections will become sharper.");
            _newEffectControllers.push(nc.effectControllers["specularResponseExponent"]);
            _fragNode += "float specularE = specularResponseExponent;\n";
        }
        else {
            _fragNode += "float specularE = 500.0;\n";
        }
        let _defaultTexture = nc.textures.WhiteBox;
        _fragNode += "vec3 normal = normalize(NORMAL);";
        if (this._ambientResponseTexture) {
            if (nc.effectControllers["ambientResponseTexture"] === undefined)
                nc.defineEffectController("ambientResponseTexture", "Texture", [], _defaultTexture, "materialOnly");
            _newEffectControllers.push(nc.effectControllers["ambientResponseTexture"]);
            _fragSupport.push("uniform sampler2D ambientResponseTexture;");
            _fragNode += "ambientC *= texture2D(ambientResponseTexture, UV).rgb;\n";
        }
        if (this._specularResponseTexture) {
            if (nc.effectControllers["specularResponseTexture"] === undefined)
                nc.defineEffectController("specularResponseTexture", "Texture", [], _defaultTexture, "materialOnly");
            _newEffectControllers.push(nc.effectControllers["specularResponseTexture"]);
            _fragSupport.push("uniform sampler2D specularResponseTexture;");
            _fragNode += "specularC *= texture2D(specularResponseTexture, UV).rgb;\n";
        }
        if (this._specularResponseExponentTexture) {
            if (nc.effectControllers["specularResponseExponentTexture"] === undefined)
                nc.defineEffectController("specularResponseExponentTexture", "Texture", [], _defaultTexture, "materialOnly");
            _newEffectControllers.push(nc.effectControllers["specularResponseExponentTexture"]);
            _fragSupport.push("uniform sampler2D specularResponseExponentTexture;");
            _fragNode += "specularE *= dot(texture2D(specularResponseExponentTexture, UV).rgb, vec3(0.2126, 0.7152, 0.0722));\n";
        }
        // ambient light
        if (this._ambientLight) {
            let _name = "ambientLightColor";
            if (nc.effectControllers[_name] === undefined)
                nc.defineEffectController(_name, "Vector4", ["red", "green", "blue", "alpha"], [0, 0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1], [0, 1]], "The color of the ambient light ", ["The light color's red value", "The light color's green value", "The light color's blue value", "The light color's alpha value, which can be used to control the brightness of the light."]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
        }
        // directional lights
        for (let i = 0; i < this._numDirectionalLights; ++i) {
            // color
            let _name = "directionalLightColor" + i;
            if (nc.effectControllers[_name] === undefined)
                nc.defineEffectController(_name, "Vector4", ["red", "green", "blue", "alpha"], [0, 0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1], [0, 1]], "The color of directional light " + i, ["The light color's red value", "The light color's green value", "The light color's blue value", "The light color's alpha value, which can be used to control the brightness of the light."]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
            // direction
            _name = "directionalLightDirection" + i;
            if (nc.effectControllers[_name] === undefined)
                nc.defineEffectController(_name, "Vector3", ["x", "y", "z"], [0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1]], "The direction of directional light " + i, ["The X component of the light's direction", "The Y component of the light's direction", "The z component of the light's direction"]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec3 " + _name + ";");
        }
        // point lights
        for (let i = 0; i < this._numPointLights; ++i) {
            // color
            let _name = "pointLightColor" + i;
            if (nc.effectControllers[_name] === undefined)
                nc.defineEffectController(_name, "Vector4", ["red", "green", "blue", "alpha"], [0, 0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1], [0, 1]], "The color of directional light " + i, ["The light color's red value", "The light color's green value", "The light color's blue value", "The light color's alpha value, which can be used to control the brightness of the light."]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
            // position
            _name = "pointLightPosition" + i;
            if (nc.effectControllers[_name] === undefined)
                nc.defineEffectController(_name, "Vector3", ["x", "y", "z"], [0, 0, 0], "addition", [[0, 300], [0, 300], [0, 300]], "The position of point light " + i, ["The X component of the light's position", "The Y component of the light's position", "The z component of the light's position"]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec3 " + _name + ";");
        }
        // spot lights
        for (let i = 0; i < this._numSpotLights; ++i) {
            // color
            let _name = "spotLightColor" + i;
            if (nc.effectControllers[_name] === undefined)
                nc.defineEffectController(_name, "Vector4", ["red", "green", "blue", "alpha"], [0, 0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1], [0, 1]], "The color of spot light " + i, ["The light color's red value", "The light color's green value", "The light color's blue value", "The light color's alpha value, which can be used to control the brightness of the light."]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
            // position
            _name = "spotLightPosition" + i;
            if (nc.effectControllers[_name] === undefined)
                nc.defineEffectController(_name, "Vector4", ["X", "Y", "Z", "feather"], [0, 0, 0, 0], "addition", [[0, 300], [0, 300], [0, 300], [0, 1]], "The position of spot light " + i + " and the edge blurriness", ["The X component of the light's position", "The Y component of the light's position", "The z component of the light's position", "The amount to feather the edge of the light cone"]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
            // direction
            _name = "spotLightDirection" + i;
            if (nc.effectControllers[_name] === undefined)
                nc.defineEffectController(_name, "Vector4", ["X", "Y", "Z", "coneAngle"], [0, 0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1], [0, 180]], "The direction of spotlight light " + i, ["The X component of the light's direction", "The Y component of the light's direction", "The z component of the light's direction", "The angle of the spot light cone"]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
        }
        //we need to know the ray from the camera to the fragment to work out the reflective portions (specular).
        // for a ortho camera, we use the optical axis of the camera instead, so the rays to all fragments are parallel.
        _fragNode += "vec3 toCam = isOrthographic ? cameraModelMatrix[2].xyz : cameraModelMatrix[3].xyz - vertPos;\n";
        _fragNode += "toCam = normalize(toCam);\n";
        _fragNode += "vec3 ambientContribution = vec3(0.0);\n";
        _fragNode += "vec3 diffuseContribution = vec3(0.0);\n";
        _fragNode += "vec3 specularContribution = vec3(0.0);\n";
        _fragNode += "vec3 toLight;\n";
        _fragNode += "float lightDistance2;\n";
        _fragNode += "vec3 fixedLightDirection;\n";
        _fragNode += "float lightDotNormal;\n";
        _fragNode += "vec3 halfDir;\n";
        _fragNode += "float specAngle;\n";
        _fragNode += "float specular;\n";
        _fragNode += "vec3 lightC;\n";
        _fragNode += "float halfFeather;\n";
        _fragNode += "float coneAngle;\n";
        _fragNode += "float coneStrength;\n";
        if (this._ambientLight) {
            _fragNode += "ambientContribution = ambientC * ambientLightColor.rgb * ambientLightColor.a;\n";
        }
        for (let i = 0; i < this._numDirectionalLights; ++i) {
            _fragNode += "fixedLightDirection = dot(directionalLightDirection" + i + ", directionalLightDirection" + i + ") > .0001 ? directionalLightDirection" + i + " : vec3(0.0, 0.0, 1.0);\n";
            _fragNode += "toLight = -normalize(fixedLightDirection);\n";
            _fragNode += "lightDotNormal = dot(toLight, normal);\n";
            _fragNode += "halfDir = normalize(toLight + toCam);\n";
            _fragNode += "specAngle = max(dot(halfDir, normal), 0.0);\n";
            _fragNode += "specular = pow(specAngle, specularE) * step(0.0, lightDotNormal);\n";
            _fragNode += "lightC = directionalLightColor" + i + ".rgb * directionalLightColor" + i + ".a;\n";
            _fragNode += "diffuseContribution += lightC * max(lightDotNormal, 0.0);\n";
            _fragNode += "specularContribution += specularC * specular * lightC;\n";
        }
        for (let i = 0; i < this._numPointLights; ++i) {
            _fragNode += "toLight = pointLightPosition" + i + " - vertPos;\n";
            _fragNode += "lightDistance2 = dot(toLight, toLight)*0.0001;\n";
            _fragNode += "toLight = normalize(toLight);";
            _fragNode += "lightDotNormal = dot(toLight, normal);\n";
            _fragNode += "halfDir = normalize(toLight + toCam);\n";
            _fragNode += "specAngle = max(dot(halfDir, normal), 0.0);\n";
            _fragNode += "specular = pow(specAngle, specularE) * step(0.0, lightDotNormal);\n";
            _fragNode += "lightC = pointLightColor" + i + ".rgb * pointLightColor" + i + ".a / lightDistance2;\n";
            _fragNode += "diffuseContribution += lightC * max(lightDotNormal, 0.0);\n";
            _fragNode += "specularContribution += specularC * specular * lightC;\n";
        }
        for (let i = 0; i < this._numSpotLights; ++i) {
            _fragNode += "toLight = spotLightPosition" + i + ".xyz - vertPos;\n";
            _fragNode += "lightDistance2 = dot(toLight, toLight)*0.0001;\n";
            _fragNode += "toLight = normalize(toLight);";
            _fragNode += "lightDotNormal = dot(toLight, normal);\n";
            _fragNode += "halfDir = normalize(toLight + toCam);\n";
            _fragNode += "specAngle = max(dot(halfDir, normal), 0.0);\n";
            _fragNode += "specular = pow(specAngle, specularE) * step(0.0, lightDotNormal);\n";
            _fragNode += "lightC = spotLightColor" + i + ".rgb * spotLightColor" + i + ".a / lightDistance2;\n";
            _fragNode += "fixedLightDirection = dot(spotLightDirection" + i + ".xyz, spotLightDirection" + i + ".xyz) > .0001 ? normalize(spotLightDirection" + i + ".xyz) : vec3(0.0, 0.0, 1.0);\n";
            _fragNode += "halfFeather = max(spotLightPosition" + i + ".w, .0001) * .5 * 3.14159 / 180.0;";
            _fragNode += "coneAngle = spotLightDirection" + i + ".w * 3.14159 / 180.0;";
            _fragNode += "coneStrength = smoothstep(coneAngle + halfFeather, coneAngle - halfFeather, acos(dot(toLight, -fixedLightDirection)));\n";
            _fragNode += "diffuseContribution += lightC * max(lightDotNormal, 0.0) * coneStrength;\n";
            _fragNode += "specularContribution += specularC * specular * lightC * coneStrength;\n";
        }
        _fragNode += "fragment.rgb = diffuseC.rgb;\n";
        _fragNode += "fragment.rgb *= ambientContribution + diffuseContribution;\n";
        _fragNode += "fragment.rgb += specularContribution;\n";
        _fragNode += "fragment.rgb = min(fragment.rgb, vec3(1.0)) * diffuseC.a;\n";
        nc.defineEffectNode(_encodedName, _vertSupport, _vertNode, _fragSupport, _fragNode, _newEffectControllers, true);
    }
}
CODE.runBeforeInit___begin;
CODE.includeIf___unpublished;
this.filterEffectNodeWarning = function (warning) {
    if (warning.indexOf('Construct requires') !== -1) {
        if (warning.indexOf("EffectNode") !== -1) {
            if (warning.indexOf("BlinnPhongLighting_") !== -1 || warning.indexOf("NormalMap") !== -1) {
                return false;
            }
        }
        if (warning.indexOf("EffectController") !== -1) {
            if (warning.indexOf("normalMap_texture") !== -1 ||
                warning.indexOf("normalMap_strength") !== -1 ||
                warning.indexOf("normalMap_isLeftHanded") !== -1 ||
                warning.indexOf("ambientResponseColor") !== -1 ||
                warning.indexOf("specularResponseColor") !== -1 ||
                warning.indexOf("specularResponseExponent") !== -1 ||
                warning.indexOf("ambientResponseTexture") !== -1 ||
                warning.indexOf("specularResponseTexture") !== -1 ||
                warning.indexOf("specularResponseExponentTexture") !== -1 ||
                warning.indexOf("ambientLightColor") !== -1 ||
                warning.indexOf("directionalLightColor") !== -1 ||
                warning.indexOf("directionalLightDirection") !== -1 ||
                warning.indexOf("pointLightColor") !== -1 ||
                warning.indexOf("pointLightPosition") !== -1 ||
                warning.indexOf("spotLightColor") !== -1 ||
                warning.indexOf("spotLightPosition") !== -1 ||
                warning.indexOf("spotLightDirection") !== -1) {
                return false;
            }
        }
    }
    return true;
};
nc.addWarningFilter(this, "filterEffectNodeWarning");
CODE.includeEnd___unpublished;
nc.registerCustomAddOn(BlinnPhongLighting);
var registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.boolean, "ambientLight");
registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.number, "numDirectionalLights");
registeredProperty.validationList = [0, 1, 2, 3, 4, 5, 6, 7, 8];
registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.number, "numPointLights");
registeredProperty.validationList = [0, 1, 2, 3, 4, 5, 6, 7, 8];
registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.number, "numSpotLights");
registeredProperty.validationList = [0, 1, 2, 3, 4, 5, 6, 7, 8];
registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.boolean, "ambientResponseColor");
registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.boolean, "ambientResponseTexture");
registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.boolean, "specularResponseColor");
registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.boolean, "specularResponseTexture");
registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.boolean, "specularResponseExponent");
registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.boolean, "specularResponseExponentTexture");
registeredProperty = nc.registerCustomAddOnProperty(BlinnPhongLighting, constants.registeredPropertyTypes.boolean, "normalTexture");
CODE.runBeforeInit___end;


Assets/CodeAssets/Bounce.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
/** Define the motion function.
* @param {Motion} motion
*/
var bounce_motionTypeFunction = function (motion) {
    for (let i = 0; i < motion.numProperties; ++i) {
        motion.currentValues[i] = motion.lowerBounds[i] + Math.abs(Math.sin(motion.progress * Math.PI) * (motion.upperBounds[i] - motion.lowerBounds[0]));
    }
};
// Define 'Bounce' Motion
nc.defineMotionType("Bounce", bounce_motionTypeFunction, undefined, undefined, "This MotionType bounces off of the lower bounds and falls from the upper bounds.");
// Example Usage:
// let graphicObject = new GraphicObject();
// let motion = graphicObject.position.addMotion.y(-100,200,1,nc.motionTypes.Bounce);
// motion.swoopInfluence(0,10);
CODE.runBeforeInit___end;


Assets/CodeAssets/MatCap.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
nc.defineEffectController("matCap_texture", nc.constants.effectControllerBaseTypes.Texture, ["matCap_texture"], nc.textures.WhiteBox, "addition");
nc.defineEffectController("matCap_additive", nc.constants.effectControllerBaseTypes.number, ["matCap_additive"], [0], "addition", [[0, 1]], "Controls how the MatCap color is combined with the existing color.  0 multiplies the two colors, and 1 adds the two colors.");
nc.defineEffectNode("MatCap", ["varying vec3 camToFrag;"], "camToFrag = isOrthographic ? cameraModelMatrix[2].xyz : (modelMatrix * vec4(vertex, 1.0)).xyz - cameraModelMatrix[3].xyz;", [
    "vec2 matCapUV(vec3 eye, vec3 norm)\n\
            {\n\
                vec3 V = eye;\n\
                vec3 Z = -V;\n\
                vec3 up = vec3(0.0, 1.0, 0.0);\n\
                if (abs(dot(up, Z)) > 0.999)\n\
                    up = vec3(1.0, 0.0, 0.0);\n\
                vec3 X = normalize(cross(up, Z));\n\
                vec3 Y = cross(Z, X);\n\
                vec3 N = norm;\n\
                vec3 N_view = vec3(\n\
                    dot(N, X),\n\
                    dot(N, Y),\n\
                    dot(N, Z)\n\
                );\n\
                return N_view.xy * .5 + vec2(.5);\n\
            }",
    "varying vec3 camToFrag;",
    "uniform sampler2D matCap_texture;",
    "uniform float matCap_additive;"
], "vec2 matUV = matCapUV(normalize(camToFrag), normalize(NORMAL));\n\
        vec4 sample = texture2D(matCap_texture, matUV);\n\
        fragment = mix(fragment * sample, vec4(fragment.rgb + sample.rgb, fragment.a), matCap_additive);", [nc.effectControllers.matCap_texture, nc.effectControllers.matCap_additive]);
CODE.runBeforeInit___end;


Assets/CodeAssets/NormalMap.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
nc.defineEffectController("normalMap_texture", nc.constants.effectControllerBaseTypes.Texture, ["normalMap_texture"], nc.textures.WhiteBox, "addition");
nc.defineEffectController("normalMap_strength", "number", ["normalMap_strength"], [1], "addition", [[0, 1]], "The strength of the per-fragment normal perturbation caused by the normal map.");
nc.defineEffectController("normalMap_isLeftHanded", "number", ["normalMap_isLeftHanded"], [0], "addition", [[0, 1]], "Normal maps created using the DirectX left handed convention will have inverted Y values. Set this value to 1 to corrent this.");
nc.defineEffectNode("NormalMap", ["varying vec3 camToFrag;", "varying vec3 vertPos;"], "vertPos = (modelMatrix * vec4(vertex, 1.0)).xyz;", [
    "uniform float normalMap_strength;",
    "uniform float normalMap_isLeftHanded;",
    "uniform sampler2D normalMap_texture;",
    "varying vec3 vertPos;"
], "vec4 normalSample = texture2D(normalMap_texture, UV);\n\
        vec3 Q1 = dFdx(vertPos);\n\
        vec3 Q2 = dFdy(vertPos);\n\
        vec2 st1 = dFdx(UV);\n\
        vec2 st2 = dFdy(UV);\n\
        vec3 N = normalize(NORMAL);\n\
        vec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n\
        vec3 B = -normalize(cross(N, T));\n\
        mat3 TBN = mat3(T, B, N);\n\
        vec3 n = normalSample.xyz;\n\
        n.xy = (n.xy * 2.0 - vec2(1.0)) * normalMap_strength;\n\
        n.y = normalMap_isLeftHanded > 0.5 ? -n.y : n.y;\n\
        n = gl_FrontFacing ? n : -n;\n\
        n = normalize(n);\n\
        NORMAL = normalize(TBN * n);", [nc.effectControllers.normalMap_texture, nc.effectControllers.normalMap_strength, nc.effectControllers.normalMap_isLeftHanded], true);
CODE.runBeforeInit___end;


Assets/CodeAssets/Sway.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
/** Define the motion function.
* @param {Motion} motion
*/
var sway_motionTypeFunction = function (motion) {
    if (motion.workspace.speedRandomizer0 === undefined) {
        motion.workspace.speedRandomizer0 = [];
        motion.workspace.speedRandomizer1 = [];
        motion.workspace.offsetRandomizer0 = [];
        motion.workspace.offsetRandomizer1 = [];
        for (let i = 0; i < motion.numProperties; ++i) {
            motion.workspace.speedRandomizer0[i] = Math.random() * .7 + .65;
            motion.workspace.speedRandomizer1[i] = Math.random() * .7 + .65;
            motion.workspace.offsetRandomizer0[i] = Math.random() * 100;
            motion.workspace.offsetRandomizer1[i] = Math.random() * 100;
        }
    }
    for (let i = 0; i < motion.numProperties; ++i) {
        let t = .5 + (.5 * (Math.sin(Math.PI * motion.progress * motion.workspace.speedRandomizer0[i] + motion.workspace.offsetRandomizer0[i]) * Math.sin(Math.PI * motion.progress * motion.workspace.speedRandomizer1[i] + motion.workspace.offsetRandomizer1[i])));
        motion.currentValues[i] = motion.lowerBounds[i] + (motion.upperBounds[i] - motion.lowerBounds[i]) * t;
    }
};
// Define 'Sway' Motion
nc.defineMotionType("Sway", sway_motionTypeFunction, undefined, undefined, "This MotionType sways a value/all values with different randomness applied to each oscillation.");
// Example Usage:
// let graphicObject = new GraphicObject();
// let motion = graphicObject.position.addMotion.each([-500,-500,0],[500,500,0],1,nc.motionTypes.Sway);
// motion.swoopInfluence(0,10);
CODE.runBeforeInit___end;


Assets/CodeAssets/WindupOvershoot.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
/** Define the tween function.
* @param {Swooper} swooper
*/
var windupOvershoot_tweenTypeFunction = function (swooper) {
    let progress = swooper.progress;
    progress = -.35 * Math.sin(progress * 2 * Math.PI) + progress;
    for (let i = 0; i < swooper.numProperties; i++) {
        swooper.currentValues[i] = swooper.startValues[i] * (1 - progress) + swooper.endValues[i] * progress;
    }
};
//Define 'WindupOvershoot' TweenType
nc.defineTweenType("WindupOvershoot", windupOvershoot_tweenTypeFunction, [], [], "This TweenType initially moves away from the end value, then moves past the end value, then reaches it.", []);
// Example of how to use this TweenType
// let graphicObject = new GraphicObject();
// let swooper = graphicObject.position.swoop.x(200,2,nc.tweenTypes.WindupOvershoot;
CODE.runBeforeInit___end;


Assets/General (autoloaded)/General/Arrow.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/General/Ball.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/General/ExampleFont.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.
- imageConfigurations.resolutionScaleX is 0.25 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.25 instead of the default null.
- imageConfigurations.spriteSheet is "ExampleFontSpriteSheet" instead of the default null.

Assets/General (autoloaded)/General/ExampleViewerConstruct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{
				"1":{},
				"2":{},
				"3":{},
				"4":{},
				"5":{}
			},
			"6":{},
			"7":{},
			"8":{},
			"9":{},
			"10":{},
			"11":{},
			"12":{},
			"13":{},
			"14":{},
			"15":{},
			"16":{}
		},
		"objects":[
			{"i":0,"name":"HeaderContainer","uid":"9324943410865637"},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Logo",
				"uid":"3155806767424395",
				"position":[-322.8258760557877,929.3606657694763,0],
				"graphicAsset":"Logo",
				"layer":"ExampleViewBack",
				"subLayer":0.2,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":2,
				"type":"TextBox",
				"name":"Header",
				"uid":"8601968333464712",
				"position":[144.8887430159829,967.6435132049863,0],
				"layer":"ExampleViewBack",
				"subLayer":0.2,
				"string":"INCISOR®",
				"boxWidth":680,
				"boxHeight":60,
				"wrapToFit":false,
				"textFormat":{
					"fontName":"ExampleFont",
					"characterScaleX":0.2,
					"characterScaleY":0.2,
					"kerning":0.2911999999999997,
					"lineHeightMultiplier":0.7055999999999985,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":3,
				"type":"TextBox",
				"name":"Header2",
				"uid":"8243299883454200",
				"position":[144.8887430159829,888.1744640099448,0],
				"layer":"ExampleViewBack",
				"subLayer":0.2,
				"string":"EXAMPLE GALLERY",
				"boxWidth":680,
				"boxHeight":60,
				"wrapToFit":false,
				"textFormat":{
					"fontName":"ExampleFont",
					"characterScaleX":0.2,
					"characterScaleY":0.2,
					"kerning":0.2911999999999997,
					"lineHeightMultiplier":0.7055999999999985,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":4,
				"type":"GraphicObject",
				"name":"FrameTopMask",
				"uid":"9294529578273990",
				"position":[-176.20000000000002,971.9998746733619,0],
				"scale":[5.8,1,1],
				"graphicAsset":"WhiteBox",
				"layer":"ExampleViewBack",
				"masking":{"enabled":true,"type":"mask","maskGroups":["MainMaskGroup"]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":5,
				"type":"GraphicObject",
				"name":"FrameTop",
				"uid":"1210444123396127",
				"position":[0,810,0],
				"graphicAsset":"Frame",
				"layer":"ExampleViewBack",
				"masking":{"enabled":true,"invert":true,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"graphicExpander":{"symmetric":true,"expandableWidth":0,"expandableHeight":0,"expandedWidth":1680,"expandedHeight":180}
			},
			{"i":6,"name":"DropDownContainer","uid":"8103945474038330","position":[0,730,0]},
			{
				"i":7,
				"type":"TextBox",
				"name":"InfoText",
				"uid":"3400759463160801",
				"position":[0,400,0],
				"layer":"ExampleViewBack",
				"subLayer":0.2,
				"string":"Here is some text....",
				"boxWidth":1680,
				"boxHeight":240,
				"textFormat":{
					"fontName":"ExampleFont",
					"characterScaleX":0.1,
					"characterScaleY":0.1,
					"kerning":0.25,
					"lineHeightMultiplier":0.8,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[1,1,1,0.7]}
					}
				]
			},
			{
				"i":8,
				"type":"Button",
				"name":"ArrowLeft",
				"uid":"3225250562076744",
				"position":[-940,-180,0],
				"scale":[-1,1,1],
				"graphicAsset":"Arrow",
				"subLayer":1,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":9,
				"type":"GraphicObject",
				"name":"ArrowLeftMask",
				"uid":"3605471006291737",
				"position":[-940,-180,0],
				"scale":[-1.1,1.1,1],
				"graphicAsset":"Arrow",
				"masking":{"enabled":true,"type":"mask","maskGroups":["MainMaskGroup"]},
				"materials":[
					{"effectNodes":["MaskingReturn","SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":10,
				"type":"Button",
				"name":"ArrowRight",
				"uid":"7929723575140769",
				"position":[940,-180,0],
				"graphicAsset":"Arrow",
				"subLayer":1,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":11,
				"type":"GraphicObject",
				"name":"ArrowRightMask",
				"uid":"2678862816527769",
				"position":[940,-180,0],
				"scale":[1.1,1.1,1],
				"graphicAsset":"Arrow",
				"masking":{"enabled":true,"type":"mask","maskGroups":["MainMaskGroup"]},
				"materials":[
					{"effectNodes":["MaskingReturn","SampleMainTexture","ColorMultiply"]}
				]
			},
			{"i":12,"name":"ExampleContainer","uid":"8033732532920258","position":[0,-180,0]},
			{
				"i":13,
				"type":"GraphicObject",
				"name":"FrameGallery",
				"uid":"9728966508477202",
				"position":[0,-180,0],
				"graphicAsset":"Frame",
				"layer":"ExampleViewBack",
				"masking":{"enabled":true,"invert":true,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"graphicExpander":{"symmetric":true,"expandableWidth":0,"expandableHeight":0,"expandedWidth":1680,"expandedHeight":1420}
			},
			{
				"i":14,
				"type":"GraphicObject",
				"name":"Background",
				"uid":"4794385668598383",
				"enabled":false,
				"scale":[21.6,21.6,1],
				"graphicAsset":"WhiteBox",
				"materials":[
					{
						"effectNodes":["FillColor","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.5,0.2,0.2,0.2]}
					}
				]
			},
			{
				"i":15,
				"type":"TextBox",
				"name":"PublishedProjectNote",
				"uid":"3802839170640686",
				"position":[0,-1000,0],
				"layer":"ExampleViewBack",
				"subLayer":0.2,
				"string":"* Download the source project to view code and fully explore these examples in the Incisor inspector.",
				"boxWidth":1680,
				"boxHeight":50,
				"textFormat":{
					"fontName":"ExampleFont",
					"characterScaleX":0.1,
					"characterScaleY":0.1,
					"kerning":0.25,
					"lineHeightMultiplier":0.8,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[1,1,1,0.7]}
					}
				]
			},
			{
				"i":16,
				"type":"TextBox",
				"name":"CopyrightLine",
				"uid":"2363112326629437",
				"position":[0,-1055,0],
				"layer":"ExampleViewBack",
				"subLayer":0.2,
				"string":"CopyrightLine",
				"horizontalJustification":"center",
				"boxWidth":1680,
				"boxHeight":50,
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.5,
					"characterScaleY":0.5,
					"kerning":0.25,
					"lineHeightMultiplier":0.8,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[1,1,1,0.25]}
					}
				]
			}
		]
	},
	"timelines":{
		"NextRight":{
			"autoplay":false,
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":0.5,
			"animatedProperties":[
				{
					"sceneObject":[5],
					"sceneObjectUid":"8033732532920258",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":0},
						{
							"time":0.06666666666666667,
							"value":0,
							"leftHandleValue":43.20440213644378,
							"leftHandleSpan":0.4194346289752653,
							"rightHandleValue":-240.4119209130447,
							"rightHandleSpan":0.5201989552926716
						},
						{"time":0.25,"value":-5000},
						{"time":0.26666666666666666,"value":5000},
						{
							"time":0.43333333333333335,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":65,
							"rightHandleSpan":0.5441938770318023
						},
						{"time":0.5,"value":0}
					]
				},
				{
					"type":"binary",
					"sceneObject":[5],
					"sceneObjectUid":"8033732532920258",
					"propertyPath":["enabled"],
					"keyframes":[
						{"time":0.23333333333333334,"value":true},
						{"time":0.25,"value":false},
						{"time":0.26666666666666666,"value":true}
					]
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NextRight"}
}

Assets/General (autoloaded)/General/ExampleViewerConstruct.construct.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/General/Frame.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/General/Logo.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/General/NeonButton.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/icons/icon_caret.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/icons/icon_checkmark.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/icons/icon_ex.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/icons/icon_magnifyingglass.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/icons/icon_minus.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/icons/icon_sliderarrows.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/icons/icon_sliderarrowsapart.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0000_Finger.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0001_Finger2.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0002_Forearm.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0003_Thumb.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0004_Sleeve.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0005_UpperArm.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0006_Pupil.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0007_Eyebrow.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0008_Eyebrow.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0009_Eye.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0010_IncisorTooth.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0011_Head.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0012_Pupil.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0013_Eye.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0014_LowerJaw.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0015_Body.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0016_Neck.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0017_Shorts.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0018_Sneaker.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0019_LowerLeg.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0020_Thumb.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0021_Finger1.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0022_Finger2.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0023_Forearm.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0024_Sleeve.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0025_UpperArm.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0026_Shorts.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0027_Sneaker.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0028_LowerLeg.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0029_Tail1.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0030_Tail2.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0031_Tail3.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0032_Background.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0033_EyeLidTop.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs/Incisorsaurus_0034_EyeLidBot.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/Incisorsaurus.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{
				"3":{
					"4":{
						"5":{
							"6":{
								"7":{},
								"8":{},
								"9":{}
							}
						}
					},
					"10":{
						"11":{
							"12":{
								"13":{}
							},
							"14":{
								"15":{},
								"16":{},
								"17":{},
								"18":{}
							},
							"19":{
								"20":{},
								"21":{},
								"22":{},
								"23":{}
							}
						}
					},
					"24":{
						"25":{
							"26":{}
						}
					},
					"27":{
						"28":{
							"29":{}
						}
					},
					"30":{
						"31":{
							"32":{
								"33":{},
								"34":{},
								"35":{}
							}
						}
					},
					"36":{
						"37":{
							"38":{}
						}
					}
				},
				"39":{}
			},
			"40":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"REF2",
				"uid":"2420332769746991",
				"enabled":false,
				"position":[0,0,-6.875],
				"graphicAsset":"Incisorsaurus_0027_Sneaker",
				"subLayer":-0.34375,
				"effectControllerValues":{"colorMultiply":[0,1,0,1]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"REF1",
				"uid":"2551457183054903",
				"enabled":false,
				"position":[0,0,-1.25],
				"graphicAsset":"Incisorsaurus_0018_Sneaker",
				"subLayer":-0.0625,
				"effectControllerValues":{"colorMultiply":[0,1,0,1]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{"i":2,"name":"Controller","uid":"6320565315338379"},
			{
				"i":3,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0015_Body",
				"uid":"8391582935630722",
				"position":[0,0,0.625],
				"graphicAsset":"Incisorsaurus_0015_Body",
				"subLayer":0.03125,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":4,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0004_Sleeve",
				"uid":"2384190589896712",
				"position":[50,12,7.5],
				"graphicAsset":"Incisorsaurus_0004_Sleeve",
				"subLayer":0.375,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-50,-12,0]}
			},
			{
				"i":5,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0005_UpperArm",
				"uid":"7867263794671971",
				"position":[-6,-4,6.875],
				"graphicAsset":"Incisorsaurus_0005_UpperArm",
				"subLayer":0.34375,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-44,-8,0]}
			},
			{
				"i":6,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0002_Forearm",
				"uid":"6920407712169353",
				"position":[-21,-20,8.75],
				"graphicAsset":"Incisorsaurus_0002_Forearm",
				"subLayer":0.4375,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-23,12,0]}
			},
			{
				"i":7,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0000_Finger",
				"uid":"6810001299241983",
				"position":[-20,18,10],
				"graphicAsset":"Incisorsaurus_0000_Finger",
				"subLayer":0.5,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-3,-6,0]}
			},
			{
				"i":8,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0001_Finger2",
				"uid":"7093717081710033",
				"position":[-29,19,9.375],
				"graphicAsset":"Incisorsaurus_0001_Finger2",
				"subLayer":0.46875,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[6,-7,0]}
			},
			{
				"i":9,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0003_Thumb",
				"uid":"5094167623322140",
				"position":[-35,6,8.125],
				"graphicAsset":"Incisorsaurus_0003_Thumb",
				"subLayer":0.40625,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[12,6,0]}
			},
			{
				"i":10,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0016_Neck",
				"uid":"1508420040038582",
				"position":[17,3,0],
				"graphicAsset":"Incisorsaurus_0016_Neck",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-17,-3,0]}
			},
			{
				"i":11,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0011_Head",
				"uid":"7499394871464999",
				"position":[45,76,3.125],
				"graphicAsset":"Incisorsaurus_0011_Head",
				"subLayer":0.15625,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-62,-79,0]}
			},
			{
				"i":12,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0014_LowerJaw",
				"uid":"3564406880715364",
				"position":[-6,-12,1.25],
				"graphicAsset":"Incisorsaurus_0014_LowerJaw",
				"subLayer":0.0625,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-56,-67,0]}
			},
			{
				"i":13,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0010_IncisorTooth",
				"uid":"6285776537131904",
				"position":[-82,-38,3.75],
				"graphicAsset":"Incisorsaurus_0010_IncisorTooth",
				"subLayer":0.1875,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[26,-29,0]}
			},
			{
				"i":14,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0009_Eye",
				"uid":"6390538378695131",
				"position":[-24,37,4.375],
				"graphicAsset":"Incisorsaurus_0009_Eye",
				"subLayer":0.21875,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-38,-116,0]}
			},
			{
				"i":15,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0033_EyeLidTop",
				"uid":"9479680484821566",
				"position":[-3,-21,0],
				"graphicAsset":"Incisorsaurus_0033_EyeLidTop",
				"visible":false,
				"subLayer":0.4,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-34,-95,0]}
			},
			{
				"i":16,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0034_EyeLidBot",
				"uid":"6179257533270162",
				"position":[-1,22,0],
				"graphicAsset":"Incisorsaurus_0034_EyeLidBot",
				"visible":false,
				"subLayer":0.4,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-37,-139,0]}
			},
			{
				"i":17,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0006_Pupil",
				"uid":"9581766268073749",
				"position":[3,-1,6.25],
				"graphicAsset":"Incisorsaurus_0006_Pupil",
				"subLayer":0.3125,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-41,-115,0]}
			},
			{
				"i":18,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0008_Eyebrow",
				"uid":"8525312094228609",
				"position":[0,22,5],
				"graphicAsset":"Incisorsaurus_0008_Eyebrow",
				"subLayer":0.25,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-38,-138,0]}
			},
			{
				"i":19,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0013_Eye",
				"uid":"9949218593034493",
				"position":[-131,69,1.875],
				"graphicAsset":"Incisorsaurus_0013_Eye",
				"subLayer":0.09375,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[69,-148,0]}
			},
			{
				"i":20,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0033_EyeLidTop2",
				"uid":"7536035516883604",
				"position":[2.0000000000000284,-21,0],
				"graphicAsset":"Incisorsaurus_0033_EyeLidTop",
				"visible":false,
				"subLayer":0.127,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-34,-95,0]}
			},
			{
				"i":21,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0034_EyeLidBot2",
				"uid":"4732324271843092",
				"position":[6,19,0],
				"graphicAsset":"Incisorsaurus_0034_EyeLidBot",
				"visible":false,
				"subLayer":0.127,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-37,-139,0]}
			},
			{
				"i":22,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0012_Pupil",
				"uid":"3935974948706458",
				"position":[2,2,2.5],
				"graphicAsset":"Incisorsaurus_0012_Pupil",
				"subLayer":0.125,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[67,-150,0]}
			},
			{
				"i":23,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0007_Eyebrow",
				"uid":"9003131496764060",
				"position":[-5,16,5.625],
				"graphicAsset":"Incisorsaurus_0007_Eyebrow",
				"subLayer":0.28125,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[74,-164,0]}
			},
			{
				"i":24,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0017_Shorts",
				"uid":"6331146838850387",
				"position":[28,-76,-0.625],
				"graphicAsset":"Incisorsaurus_0017_Shorts",
				"subLayer":-0.03125,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-28,76,0]}
			},
			{
				"i":25,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0019_LowerLeg",
				"uid":"9868125099917119",
				"position":[0,-19,-1.875],
				"graphicAsset":"Incisorsaurus_0019_LowerLeg",
				"subLayer":-0.09375,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-28,95,0]}
			},
			{
				"i":26,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0018_Sneaker",
				"uid":"1001230710194815",
				"position":[12,-56,-1.25],
				"graphicAsset":"Incisorsaurus_0018_Sneaker",
				"subLayer":-0.0625,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-40,151,0]}
			},
			{
				"i":27,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0026_Shorts",
				"uid":"2333391500121242",
				"position":[-14,-64,-6.25],
				"graphicAsset":"Incisorsaurus_0026_Shorts",
				"subLayer":-0.3125,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[14,64,0]}
			},
			{
				"i":28,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0028_LowerLeg",
				"uid":"0520431315092932",
				"position":[-2,-13,-7.5],
				"graphicAsset":"Incisorsaurus_0028_LowerLeg",
				"subLayer":-0.375,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[16,77,0]}
			},
			{
				"i":29,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0027_Sneaker",
				"uid":"3249685385429677",
				"position":[14,-60,-6.875],
				"graphicAsset":"Incisorsaurus_0027_Sneaker",
				"subLayer":-0.34375,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[2,137,0]}
			},
			{
				"i":30,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0024_Sleeve",
				"uid":"7554277963686835",
				"position":[-10,4,-5],
				"graphicAsset":"Incisorsaurus_0024_Sleeve",
				"subLayer":-0.25,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[10,-4,0]}
			},
			{
				"i":31,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0025_UpperArm",
				"uid":"2911500322993584",
				"position":[-7,2,-5.625],
				"graphicAsset":"Incisorsaurus_0025_UpperArm",
				"subLayer":-0.28125,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[17,-6,0]}
			},
			{
				"i":32,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0023_Forearm",
				"uid":"6553804298258501",
				"position":[-29,-11,-4.375],
				"graphicAsset":"Incisorsaurus_0023_Forearm",
				"subLayer":-0.21875,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[46,5,0]}
			},
			{
				"i":33,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0020_Thumb",
				"uid":"2868200568303867",
				"position":[-14,-4,-2.5],
				"graphicAsset":"Incisorsaurus_0020_Thumb",
				"subLayer":-0.125,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[60,9,0]}
			},
			{
				"i":34,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0021_Finger1",
				"uid":"3744948094957698",
				"position":[-24,9,-3.125],
				"graphicAsset":"Incisorsaurus_0021_Finger1",
				"subLayer":-0.15625,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[70,-4,0]}
			},
			{
				"i":35,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0022_Finger2",
				"uid":"3994121489944880",
				"position":[-34,7,-3.75],
				"graphicAsset":"Incisorsaurus_0022_Finger2",
				"subLayer":-0.1875,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[80,-2,0]}
			},
			{
				"i":36,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0029_Tail1",
				"uid":"2638073987214413",
				"position":[45,-78,-8.125],
				"graphicAsset":"Incisorsaurus_0029_Tail1",
				"subLayer":-0.40625,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-45,78,0]}
			},
			{
				"i":37,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0030_Tail2",
				"uid":"1614695340706421",
				"position":[38,-22,-8.75],
				"graphicAsset":"Incisorsaurus_0030_Tail2",
				"subLayer":-0.4375,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-83,100,0]}
			},
			{
				"i":38,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0031_Tail3",
				"uid":"3516176508336800",
				"position":[44,7,-9.375],
				"graphicAsset":"Incisorsaurus_0031_Tail3",
				"subLayer":-0.46875,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"pivotPointAdjuster":{"position":[-127,93,0]}
			},
			{
				"i":39,
				"type":"GraphicObject",
				"name":"Incisorsaurus_0032_Background",
				"uid":"1276373979985091",
				"enabled":false,
				"position":[0,0,-10],
				"graphicAsset":"Incisorsaurus_0032_Background",
				"subLayer":-0.5,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":40,
				"type":"GraphicObject",
				"name":"Floor",
				"uid":"3201523667536051",
				"enabled":false,
				"position":[0,-217.00000000000009,0],
				"scale":[5,1,1],
				"graphicAsset":"WhiteBox",
				"subLayer":-0.9,
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			}
		]
	},
	"timelines":{
		"Idle":{
			"autoplay":true,
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":3,
			"animatedProperties":[
				{
					"sceneObject":[2,0,0],
					"sceneObjectUid":"2384190589896712",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":40},
						{"time":3,"value":40}
					]
				},
				{
					"sceneObject":[2,0,0,0,0],
					"sceneObjectUid":"6920407712169353",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":50},
						{"time":1.9666666666666666,"value":42.00000000000017},
						{"time":3,"value":50}
					]
				},
				{
					"sceneObject":[2,0,0,0,0],
					"sceneObjectUid":"6920407712169353",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-21},
						{"time":3,"value":-21}
					]
				},
				{
					"sceneObject":[2,0,0,0,0],
					"sceneObjectUid":"6920407712169353",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-24},
						{"time":3,"value":-24}
					]
				},
				{
					"sceneObject":[2,0,0,0,0,0],
					"sceneObjectUid":"6810001299241983",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":64.99999999999997},
						{"time":0.8333333333333334,"value":88.20999999999998},
						{"time":3,"value":64.99999999999997}
					]
				},
				{
					"sceneObject":[2,0,0,0,0,1],
					"sceneObjectUid":"7093717081710033",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":70.99999999999955},
						{"time":1.95,"value":88.99999999999966},
						{"time":3,"value":70.99999999999955}
					]
				},
				{
					"sceneObject":[2,0,0,0,0,2],
					"sceneObjectUid":"5094167623322140",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,4],
					"sceneObjectUid":"7554277963686835",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":46.00000000000023},
						{"time":3,"value":46.00000000000023}
					]
				},
				{
					"sceneObject":[2,0,4,0,0],
					"sceneObjectUid":"6553804298258501",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":11.000000000000114},
						{"time":0.9,"value":2.200000000000112},
						{"time":3,"value":11.000000000000114}
					]
				},
				{
					"sceneObject":[2,0,4,0,0,1],
					"sceneObjectUid":"3744948094957698",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":57.99999999999966},
						{"time":2.033333333333333,"value":92},
						{"time":3,"value":57.99999999999966}
					]
				},
				{
					"sceneObject":[2,0,4,0,0,2],
					"sceneObjectUid":"3994121489944880",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":10.999999999999545},
						{"time":1.1666666666666667,"value":40.559999999999555},
						{"time":3,"value":10.999999999999545}
					]
				},
				{"sceneObject":[2,0,4,0,0,0],"sceneObjectUid":"2868200568303867","propertyPath":["rotation","z"],"keyframes":[]},
				{
					"sceneObject":[2,0],
					"sceneObjectUid":"8391582935630722",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.5,"value":-5.000000000000341},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0],
					"sceneObjectUid":"8391582935630722",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.5,"value":-6.000000000000455},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,2],
					"sceneObjectUid":"6331146838850387",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.5,"value":7.000000000000455},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,3],
					"sceneObjectUid":"2333391500121242",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.5,"value":7},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,2,0],
					"sceneObjectUid":"9868125099917119",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.5,"value":12.000000000000568},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,3,0],
					"sceneObjectUid":"0520431315092932",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.5,"value":12},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,3,0,0],
					"sceneObjectUid":"3249685385429677",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.5,"value":-12},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,2,0,0],
					"sceneObjectUid":"1001230710194815",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.5,"value":-12},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0],
					"sceneObjectUid":"8391582935630722",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.5,"value":-2.0000000000001705},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,5,0,0],
					"sceneObjectUid":"3516176508336800",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":1.8499999999999999,"value":-38.999999999999545},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,5,0],
					"sceneObjectUid":"1614695340706421",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":1.15,"value":29.000000000000227},
						{"time":3,"value":0,"leftHandleValue":0,"leftHandleSpan":0.4}
					]
				},
				{
					"sceneObject":[2,0,5],
					"sceneObjectUid":"2638073987214413",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.4166666666666667,"value":20,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":3,"value":0,"leftHandleValue":0,"leftHandleSpan":0.4}
					]
				},
				{
					"sceneObject":[2,0,1],
					"sceneObjectUid":"1508420040038582",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.1166666666666667,"value":16},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1,0],
					"sceneObjectUid":"7499394871464999",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1.1166666666666667,"value":-6.999999999999886},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1,0],
					"sceneObjectUid":"7499394871464999",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":45},
						{"time":1.1166666666666667,"value":49.00488894657149},
						{"time":3,"value":45}
					]
				},
				{
					"sceneObject":[2,0,1,0],
					"sceneObjectUid":"7499394871464999",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":76},
						{"time":1.1166666666666667,"value":70.64742910488785},
						{"time":3,"value":76}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,1,0],
					"sceneObjectUid":"9479680484821566",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0.35,"value":false},
						{"time":0.5333333333333333,"value":true},
						{"time":0.6833333333333333,"value":false}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,1,1],
					"sceneObjectUid":"6179257533270162",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0.35,"value":false},
						{"time":0.5333333333333333,"value":true},
						{"time":0.6833333333333333,"value":false}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,2,0],
					"sceneObjectUid":"7536035516883604",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0.35,"value":false},
						{"time":0.5333333333333333,"value":true},
						{"time":0.6833333333333333,"value":false}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,2,1],
					"sceneObjectUid":"4732324271843092",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0.35,"value":false},
						{"time":0.5333333333333333,"value":true},
						{"time":0.6833333333333333,"value":false}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,0],
					"sceneObjectUid":"7536035516883604",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.5333333333333333,"value":1},
						{"time":0.6,"value":1.457},
						{"time":0.6666666666666666,"value":1}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,1],
					"sceneObjectUid":"4732324271843092",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.5333333333333333,"value":1},
						{"time":0.6,"value":1.437},
						{"time":0.6666666666666666,"value":1}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,0],
					"sceneObjectUid":"9479680484821566",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.5333333333333333,"value":1},
						{"time":0.6,"value":1.4569999999999999},
						{"time":0.6666666666666666,"value":1},
						{"time":3.533333333333333,"value":1}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,1],
					"sceneObjectUid":"6179257533270162",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.5333333333333333,"value":1},
						{"time":0.6,"value":1.4369999999999998},
						{"time":0.6666666666666666,"value":1}
					]
				},
				{
					"sceneObject":[2,0,1,0,0],
					"sceneObjectUid":"3564406880715364",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":2.216666666666667,"value":2},
						{"time":3,"value":0}
					]
				},
				{
					"sceneObject":[2,0,4,0,0],
					"sceneObjectUid":"6553804298258501",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-29},
						{"time":3,"value":-29}
					]
				},
				{
					"sceneObject":[2,0,4,0,0],
					"sceneObjectUid":"6553804298258501",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-11},
						{"time":3,"value":-11}
					]
				},
				{
					"sceneObject":[2,0,1,0,0,0],
					"sceneObjectUid":"6285776537131904",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":9.000000000000114},
						{"time":1.3,"value":4.999999999999886},
						{"time":3,"value":9.000000000000114}
					]
				}
			]
		},
		"Growl":{
			"autoplay":false,
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":1,
			"animatedProperties":[
				{
					"sceneObject":[2,0],
					"sceneObjectUid":"8391582935630722",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":20},
						{"time":0.43333333333333335,"value":-20},
						{"time":0.8666666666666667,"value":-20},
						{"time":0.9166666666666666,"value":-20},
						{"time":1,"value":20}
					]
				},
				{
					"sceneObject":[2,0,0],
					"sceneObjectUid":"2384190589896712",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-6.951281279275903},
						{"time":0.48333333333333334,"value":48.17122780105047},
						{"time":0.9166666666666667,"value":48.17122780105047},
						{"time":1,"value":-6.951281279275903}
					]
				},
				{
					"sceneObject":[2,0,0,0,0],
					"sceneObjectUid":"6920407712169353",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-15.168181781207087},
						{"time":0.6833333333333333,"value":51.758421858597586},
						{"time":0.9166666666666666,"value":51.758421858597586},
						{"time":0.9166666666666667,"value":51.758421858597586},
						{"time":1,"value":-15.168181781207087}
					]
				},
				{
					"sceneObject":[2,0,0,0,0,0],
					"sceneObjectUid":"6810001299241983",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":119},
						{"time":0.26666666666666666,"value":-14.660162601626062},
						{"time":0.6833333333333333,"value":-31.316666666666777},
						{"time":1,"value":119}
					]
				},
				{
					"sceneObject":[2,0,0,0,0,1],
					"sceneObjectUid":"7093717081710033",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":89.99999999999989},
						{"time":0.26666666666666666,"value":-34.04878048780507},
						{"time":0.6833333333333333,"value":-48.500000000000036},
						{"time":1,"value":89.99999999999989}
					]
				},
				{
					"sceneObject":[2,0,0,0,0,2],
					"sceneObjectUid":"5094167623322140",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.26666666666666666,"value":2.9999999999998863},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1],
					"sceneObjectUid":"1508420040038582",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":8.00000000000017},
						{"time":0.43333333333333335,"value":-18.361252553669566},
						{"time":0.8666666666666667,"value":-18.361252553669566},
						{"time":1,"value":8.00000000000017}
					]
				},
				{
					"sceneObject":[2,0,1,0],
					"sceneObjectUid":"7499394871464999",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.43333333333333335,"value":-43.55924921783316},
						{"time":0.8666666666666667,"value":-31.55924921783305},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1,0,0],
					"sceneObjectUid":"3564406880715364",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.43333333333333335,"value":34.00000000000006},
						{"time":0.9,"value":24.00000000000017},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,3],
					"sceneObjectUid":"8525312094228609",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.13333333333333333,"value":44.85456069435834},
						{"time":0.9166666666666666,"value":44.85456069435834},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,3],
					"sceneObjectUid":"9003131496764060",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.13333333333333333,"value":-60},
						{"time":0.9166666666666666,"value":-60},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,2],
					"sceneObjectUid":"6331146838850387",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-20},
						{"time":0.43333333333333335,"value":21.631100797988836},
						{"time":0.8666666666666667,"value":21.631100797988836},
						{"time":0.9166666666666666,"value":21.631100797988836},
						{"time":1,"value":-20}
					]
				},
				{
					"sceneObject":[2,0,2,0],
					"sceneObjectUid":"9868125099917119",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,2,0,0],
					"sceneObjectUid":"1001230710194815",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,3],
					"sceneObjectUid":"2333391500121242",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-20},
						{"time":0.43333333333333335,"value":-28.238951708824175},
						{"time":0.8666666666666667,"value":-28.238951708824175},
						{"time":0.9166666666666666,"value":-28.238951708824175},
						{"time":1,"value":-20}
					]
				},
				{
					"sceneObject":[2,0,3,0],
					"sceneObjectUid":"0520431315092932",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.43333333333333335,"value":6.691200501056566},
						{"time":0.9,"value":17.99120050105656},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,3,0,0],
					"sceneObjectUid":"3249685385429677",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,4],
					"sceneObjectUid":"7554277963686835",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-7},
						{"time":0.6666666666666666,"value":67.84447945928017},
						{"time":0.9166666666666667,"value":67.84447945928017},
						{"time":1,"value":-7}
					]
				},
				{
					"sceneObject":[2,0,4,0,0],
					"sceneObjectUid":"6553804298258501",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-39.000000000000114},
						{"time":1,"value":-39.000000000000114}
					]
				},
				{
					"sceneObject":[2,0,4,0,0,0],
					"sceneObjectUid":"2868200568303867",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,4,0,0,1],
					"sceneObjectUid":"3744948094957698",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,4,0,0,2],
					"sceneObjectUid":"3994121489944880",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,5],
					"sceneObjectUid":"2638073987214413",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.31666666666666665,"value":50.12246410997099},
						{"time":0.8500000000000071,"value":50.12246410997099},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,5,0],
					"sceneObjectUid":"1614695340706421",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.43333333333333335,"value":23.05377827503876},
						{"time":0.8500000000000071,"value":23.05377827503876},
						{"time":0.8666666666666667,"value":23.05377827503876},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,5,0,0],
					"sceneObjectUid":"3516176508336800",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.8500000000000071,"value":-53.21788354104447},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0],
					"sceneObjectUid":"8391582935630722",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-23.7908732980256},
						{"time":0.21666666666666667,"value":-0.4540610816883377},
						{"time":0.43333333333333335,"value":27.903624432674526},
						{"time":0.8666666666666667,"value":27.903624432674526},
						{"time":0.9166666666666666,"value":26.229999999999322},
						{"time":1,"value":-23.7908732980256}
					]
				},
				{
					"sceneObject":[2,0],
					"sceneObjectUid":"8391582935630722",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-22.325413052726688},
						{"time":0.21666666666666667,"value":-4.476239158179611},
						{"time":0.43333333333333335,"value":5.837293473636958},
						{"time":0.8666666666666667,"value":5.837293473636958},
						{"time":0.9166666666666666,"value":5.000000000000341},
						{"time":1,"value":-22.325413052726688}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,2,1],
					"sceneObjectUid":"4732324271843092",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.05000000000000002,"value":true},
						{"time":0.5,"value":false},
						{"time":0.9333333333333333,"value":false},
						{"time":1,"value":false},
						{"time":1.05,"value":true},
						{"time":2,"value":false}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,0],
					"sceneObjectUid":"7536035516883604",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.05000000000000002,"value":1},
						{"time":0.1166666666666667,"value":1.457},
						{"time":0.4166666666666667,"value":1.457},
						{"time":0.43333333333333335,"value":1.457},
						{"time":0.48333333333333334,"value":1},
						{"time":0.8666666666666667,"value":1.457},
						{"time":0.9166666666666667,"value":1},
						{"time":1.05,"value":1}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,2,0],
					"sceneObjectUid":"7536035516883604",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.05000000000000002,"value":true},
						{"time":0.5,"value":false},
						{"time":0.9333333333333333,"value":false},
						{"time":1,"value":false},
						{"time":1.05,"value":true},
						{"time":2,"value":false}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,1],
					"sceneObjectUid":"4732324271843092",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.05000000000000002,"value":1},
						{"time":0.1166666666666667,"value":1.437},
						{"time":0.4166666666666667,"value":1.437},
						{"time":0.43333333333333335,"value":1.437},
						{"time":0.48333333333333334,"value":1},
						{"time":0.8666666666666667,"value":1.437},
						{"time":0.9166666666666667,"value":1},
						{"time":1.05,"value":1}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,0],
					"sceneObjectUid":"9479680484821566",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.05,"value":1},
						{"time":0.1166666666666667,"value":1.4569999999999999},
						{"time":0.43333333333333335,"value":1.4569999999999999},
						{"time":0.48333333333333334,"value":1},
						{"time":0.9166666666666667,"value":1},
						{"time":1.05,"value":1}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,1,0],
					"sceneObjectUid":"9479680484821566",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.05000000000000002,"value":true},
						{"time":0.5,"value":false},
						{"time":0.9333333333333333,"value":false},
						{"time":1,"value":false},
						{"time":1.05,"value":true},
						{"time":2,"value":false}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,1],
					"sceneObjectUid":"6179257533270162",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.05000000000000002,"value":1},
						{"time":0.1166666666666667,"value":1.4369999999999998},
						{"time":0.43333333333333335,"value":1.4369999999999998},
						{"time":0.48333333333333334,"value":1},
						{"time":0.8666666666666667,"value":1.4369999999999998},
						{"time":0.9166666666666667,"value":1},
						{"time":1.05,"value":1}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,1,1],
					"sceneObjectUid":"6179257533270162",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.05000000000000002,"value":true},
						{"time":0.5,"value":false},
						{"time":0.9333333333333333,"value":false},
						{"time":1,"value":false},
						{"time":1.05,"value":true},
						{"time":2,"value":false}
					]
				},
				{
					"sceneObject":[2,0,1,0],
					"sceneObjectUid":"7499394871464999",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":44.99999999999999},
						{"time":0.43333333333333335,"value":13.521295162059399},
						{"time":0.8666666666666667,"value":13.521295162059399},
						{"time":1,"value":44.99999999999999}
					]
				},
				{
					"sceneObject":[2,0,1,0],
					"sceneObjectUid":"7499394871464999",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":75.99999999999999},
						{"time":0.43333333333333335,"value":46.42670366472185},
						{"time":0.8666666666666667,"value":46.42670366472185},
						{"time":1,"value":75.99999999999999}
					]
				},
				{
					"sceneObject":[2,0,1,0,0,0],
					"sceneObjectUid":"6285776537131904",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-10.959999999999999},
						{"time":0.18333333333333332,"value":13.879615384615382},
						{"time":0.23333333333333334,"value":-10},
						{"time":0.2833333333333333,"value":15},
						{"time":0.3333333333333333,"value":-10},
						{"time":0.3833333333333333,"value":15},
						{"time":0.4333333333333333,"value":-10},
						{"time":0.43333333333333335,"value":-10},
						{"time":0.48333333333333334,"value":15},
						{"time":0.5333333333333333,"value":-10},
						{"time":0.6,"value":12.369999999999996},
						{"time":0.9,"value":18.000000000000114},
						{"time":1,"value":-10.959999999999999}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,2],
					"sceneObjectUid":"9581766268073749",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-9},
						{"time":0.55,"value":3},
						{"time":0.9166666666666666,"value":3},
						{"time":0.9833333333333334,"value":3},
						{"time":1,"value":-9}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,2],
					"sceneObjectUid":"9581766268073749",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0.55,"value":-1},
						{"time":0.9166666666666666,"value":-1},
						{"time":0.9833333333333334,"value":-1}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,2],
					"sceneObjectUid":"3935974948706458",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-4.999999999999773},
						{"time":0.55,"value":2},
						{"time":0.9166666666666666,"value":2},
						{"time":0.9833333333333334,"value":2},
						{"time":1,"value":-4.999999999999773}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,2],
					"sceneObjectUid":"3935974948706458",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-3.0000000000004547},
						{"time":0.55,"value":2},
						{"time":0.9166666666666666,"value":2},
						{"time":0.9833333333333334,"value":2},
						{"time":1,"value":-3.0000000000004547}
					]
				},
				{
					"type":"binary",
					"sceneObject":[1],
					"sceneObjectUid":"2551457183054903",
					"propertyPath":["enabled"],
					"keyframes":[
						{"time":0,"value":false}
					]
				},
				{
					"type":"binary",
					"sceneObject":[0],
					"sceneObjectUid":"2420332769746991",
					"propertyPath":["enabled"],
					"keyframes":[
						{"time":0,"value":false}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,3],
					"sceneObjectUid":"8525312094228609",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.13333333333333333,"value":8.881784197001252E-16},
						{"time":0.9166666666666666,"value":8.881784197001252E-16},
						{"time":1,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,3],
					"sceneObjectUid":"8525312094228609",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":22},
						{"time":0.13333333333333333,"value":21.99999999999997},
						{"time":0.9166666666666666,"value":21.99999999999997},
						{"time":1,"value":22}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,3],
					"sceneObjectUid":"9003131496764060",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-5},
						{"time":0.13333333333333333,"value":-2},
						{"time":0.9166666666666666,"value":-2},
						{"time":1,"value":-5}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,3],
					"sceneObjectUid":"9003131496764060",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":16},
						{"time":1,"value":16}
					]
				},
				{
					"type":"binary",
					"sceneObject":[3],
					"sceneObjectUid":"3201523667536051",
					"propertyPath":["enabled"],
					"keyframes":[
						{"time":0,"value":false}
					]
				},
				{
					"sceneObject":[3],
					"sceneObjectUid":"3201523667536051",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.13333333333333333,"value":20}
					]
				},
				{
					"sceneObject":[2,0,2],
					"sceneObjectUid":"6331146838850387",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":29.072717498534818},
						{"time":0.43333333333333335,"value":30.650108541630743},
						{"time":0.8666666666666667,"value":30.650108541630743},
						{"time":0.9166666666666666,"value":30.650108541630743},
						{"time":1,"value":29.072717498534818}
					]
				},
				{
					"sceneObject":[2,0,2],
					"sceneObjectUid":"6331146838850387",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-75.49940813555983},
						{"time":0.43333333333333335,"value":-84.72660488859148},
						{"time":0.8666666666666667,"value":-84.72660488859148},
						{"time":0.9166666666666666,"value":-84.72660488859148},
						{"time":1,"value":-75.49940813555983}
					]
				},
				{
					"sceneObject":[2,0,2,0],
					"sceneObjectUid":"9868125099917119",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-1.6736244326750125},
						{"time":1,"value":-1.6736244326750125}
					]
				},
				{
					"sceneObject":[2,0,2,0],
					"sceneObjectUid":"9868125099917119",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-10.627065263632986},
						{"time":1,"value":-10.627065263632986}
					]
				},
				{
					"sceneObject":[2,0,3,0],
					"sceneObjectUid":"0520431315092932",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-2.8368122163376004},
						{"time":0.43333333333333335,"value":-8.429748079355818},
						{"time":0.8666666666666667,"value":-8.429748079355818},
						{"time":0.9166666666666666,"value":-8.429748079355818},
						{"time":1,"value":-2.8368122163376004}
					]
				},
				{
					"sceneObject":[2,0,3,0],
					"sceneObjectUid":"0520431315092932",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-0.44059789544930084},
						{"time":0.43333333333333335,"value":-16.761715288860145},
						{"time":0.8666666666666667,"value":-16.761715288860145},
						{"time":0.9166666666666666,"value":-16.761715288860145},
						{"time":1,"value":-0.44059789544930084}
					]
				},
				{
					"sceneObject":[2,0,3],
					"sceneObjectUid":"2333391500121242",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-8.204506399665657},
						{"time":0.43333333333333335,"value":-5.554397858035458},
						{"time":0.8666666666666667,"value":-5.554397858035458},
						{"time":0.9166666666666666,"value":-5.554397858035458},
						{"time":1,"value":-8.204506399665657}
					]
				},
				{
					"sceneObject":[2,0,3],
					"sceneObjectUid":"2333391500121242",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-55.41703791920194},
						{"time":0.43333333333333335,"value":-65.14482653667396},
						{"time":0.8666666666666667,"value":-65.14482653667396},
						{"time":0.9166666666666666,"value":-65.14482653667396},
						{"time":1,"value":-55.41703791920194}
					]
				},
				{
					"sceneObject":[2,0,0,0,0],
					"sceneObjectUid":"6920407712169353",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-24.57144172558384},
						{"time":0.6833333333333333,"value":-21.571441725583043},
						{"time":0.9166666666666666,"value":-21.571441725583043},
						{"time":1,"value":-24.57144172558384}
					]
				},
				{
					"sceneObject":[2,0,0,0,0],
					"sceneObjectUid":"6920407712169353",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-19.267844740007185},
						{"time":0.6833333333333333,"value":-22.267844740006957},
						{"time":0.9166666666666666,"value":-22.267844740006957},
						{"time":1,"value":-19.267844740007185}
					]
				}
			]
		},
		"Walk":{
			"autoplay":false,
			"initialTime":0,
			"playbackRate":1.25,
			"startValue":0,
			"endValue":4,
			"animatedProperties":[
				{
					"type":"binary",
					"sceneObject":[1],
					"sceneObjectUid":"2551457183054903",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0,"value":false}
					]
				},
				{
					"type":"binary",
					"sceneObject":[0],
					"sceneObjectUid":"2420332769746991",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0,"value":false}
					]
				},
				{
					"sceneObject":[2,0,0],
					"sceneObjectUid":"2384190589896712",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0.5488355722708611},
						{"time":0.5,"value":48.37799972954032},
						{"time":1,"value":0.5488355722708611},
						{"time":1.5,"value":48.37799972954032},
						{"time":2,"value":0.5488355722708611},
						{"time":2.5,"value":48.37799972954032},
						{"time":3,"value":0.5488355722708611},
						{"time":3.5,"value":48.37799972954032},
						{"time":4,"value":0.5488355722708611}
					]
				},
				{
					"sceneObject":[2,0,0,0,0],
					"sceneObjectUid":"6920407712169353",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{
							"time":0,
							"value":18.108003355603504,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5,
							"value":-7.639366102612521,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1,
							"value":18.108003355603504,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":-7.639366102612521,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2,
							"value":18.108003355603504,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2.5,
							"value":-7.639366102612521,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3,
							"value":18.108003355603504,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3.5,
							"value":-7.639366102612521,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":4,
							"value":18.108003355603504,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					]
				},
				{
					"sceneObject":[2,0,0,0,0,0],
					"sceneObjectUid":"6810001299241983",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{
							"time":0,
							"value":-30.000000000000398,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6166666666666667,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3166666666666667,
							"value":64,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2,
							"value":-30.000000000000398,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2.6166666666666667,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3.3166666666666664,
							"value":64,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":4,
							"value":-30.000000000000398,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					]
				},
				{
					"sceneObject":[2,0,0,0,0,1],
					"sceneObjectUid":"7093717081710033",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{
							"time":0,
							"value":-8.999999999999545,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1333333333333333,
							"value":29.00000000000051,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2,
							"value":-8.999999999999545,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2.4333333333333336,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3.1333333333333333,
							"value":29.00000000000051,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":4,
							"value":-8.999999999999545,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					]
				},
				{
					"sceneObject":[2,0,0,0,0,2],
					"sceneObjectUid":"5094167623322140",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{
							"time":0,
							"value":32.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.8166666666666667,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5166666666666666,
							"value":-36.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2,
							"value":32.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2.8166666666666664,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3.5166666666666666,
							"value":-36.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":4,
							"value":32.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					]
				},
				{
					"sceneObject":[2,0,1],
					"sceneObjectUid":"1508420040038582",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{
							"time":0,
							"value":9.999999999999773,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.4299999999999533,
							"rightHandleSpan":0.3022052127021831
						},
						{"time":0.25,"value":0,"leftHandleValue":1.1699999999999735,"leftHandleSpan":0.36507329025077967},
						{"time":0.75,"value":0,"rightHandleValue":2.2099999999999502,"rightHandleSpan":0.3930146580501591},
						{
							"time":1,
							"value":9.999999999999773,
							"leftHandleValue":-0.5849999999999868,
							"leftHandleSpan":0.3650732902507797,
							"rightHandleValue":-0.5199999999999882,
							"rightHandleSpan":0.35110260635109153
						},
						{"time":1.25,"value":0,"leftHandleValue":2.404999999999946,"leftHandleSpan":0.40698534194984726},
						{"time":1.75,"value":0,"rightHandleValue":1.8199999999999736,"rightHandleSpan":0.3720586322006269},
						{
							"time":2,
							"value":9.999999999999773,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.4299999999999533,
							"rightHandleSpan":0.3022052127021831
						},
						{"time":2.25,"value":0,"leftHandleValue":1.1699999999999735,"leftHandleSpan":0.36507329025077967},
						{"time":2.75,"value":0,"rightHandleValue":2.2099999999999502,"rightHandleSpan":0.3930146580501591},
						{
							"time":3,
							"value":9.999999999999773,
							"leftHandleValue":-0.5849999999999868,
							"leftHandleSpan":0.3650732902507797,
							"rightHandleValue":-0.5199999999999882,
							"rightHandleSpan":0.35110260635109153
						},
						{"time":3.25,"value":0,"leftHandleValue":2.404999999999946,"leftHandleSpan":0.40698534194984726},
						{"time":3.75,"value":0,"rightHandleValue":1.8199999999999736,"rightHandleSpan":0.3720586322006269},
						{
							"time":4,
							"value":9.999999999999773,
							"leftHandleValue":-1.5599999999999798,
							"leftHandleSpan":0.3441172644012506,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					]
				},
				{
					"sceneObject":[2,0,1,0],
					"sceneObjectUid":"7499394871464999",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-13.999999999999886,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":0.25,"value":0},
						{
							"time":0.5,
							"value":-13.999999999999886,
							"leftHandleValue":-0.09216744688769885,
							"leftHandleSpan":0.2602931610031187,
							"rightHandleValue":0,
							"rightHandleSpan":0.23933713515358657
						},
						{"time":0.75,"value":0},
						{
							"time":1,
							"value":-13.999999999999886,
							"leftHandleValue":-0.09216744688769885,
							"leftHandleSpan":0.2602931610031187,
							"rightHandleValue":0,
							"rightHandleSpan":0.23933713515358657
						},
						{"time":1.25,"value":0},
						{
							"time":1.5,
							"value":-13.999999999999886,
							"leftHandleValue":-0.09216744688769885,
							"leftHandleSpan":0.2602931610031187,
							"rightHandleValue":0,
							"rightHandleSpan":0.23933713515358657
						},
						{"time":1.500000000000004,"value":-13.999999999999886,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":1.75,"value":0},
						{"time":2,"value":-13.999999999999886,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":2.25,"value":0},
						{
							"time":2.5,
							"value":-13.999999999999886,
							"leftHandleValue":-0.09216744688769885,
							"leftHandleSpan":0.2602931610031187,
							"rightHandleValue":0,
							"rightHandleSpan":0.23933713515358657
						},
						{"time":2.75,"value":0},
						{
							"time":3,
							"value":-13.999999999999886,
							"leftHandleValue":-0.09216744688769885,
							"leftHandleSpan":0.2602931610031187,
							"rightHandleValue":0,
							"rightHandleSpan":0.23933713515358657
						},
						{"time":3.25,"value":0},
						{
							"time":3.5,
							"value":-13.999999999999886,
							"leftHandleValue":-0.09216744688769885,
							"leftHandleSpan":0.2602931610031187,
							"rightHandleValue":0,
							"rightHandleSpan":0.23933713515358657
						},
						{"time":3.500000000000004,"value":-13.999999999999886,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":3.75,"value":0},
						{
							"time":4,
							"value":-13.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					]
				},
				{
					"sceneObject":[2,0,1,0,0],
					"sceneObjectUid":"3564406880715364",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7166666666666667,"value":10},
						{"time":1.6166666666666667,"value":10},
						{"time":2,"value":0},
						{"time":2.716666666666667,"value":10},
						{"time":3.6166666666666667,"value":10},
						{"time":4,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1,0,0,0],
					"sceneObjectUid":"6285776537131904",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":14.00000000000017},
						{"time":0.7166666666666667,"value":10},
						{"time":1.283333333333324,"value":-0.6533894589983977},
						{"time":1.6166666666666667,"value":10},
						{"time":2,"value":14.00000000000017},
						{"time":2.716666666666667,"value":10},
						{"time":3.283333333333324,"value":-0.6533894589983977},
						{"time":3.6166666666666667,"value":10},
						{"time":4,"value":14.00000000000017}
					]
				},
				{
					"sceneObject":[2,0,2],
					"sceneObjectUid":"6331146838850387",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":30},
						{"time":0.5,"value":-36.99999999999966},
						{"time":0.75,"value":0},
						{"time":1,"value":30},
						{"time":1.5,"value":-36.99999999999966},
						{"time":1.75,"value":0},
						{"time":2,"value":30},
						{"time":2.5,"value":-36.99999999999966},
						{"time":2.75,"value":0},
						{"time":3,"value":30},
						{"time":3.5,"value":-36.99999999999966},
						{"time":3.75,"value":0},
						{"time":4,"value":30}
					]
				},
				{
					"sceneObject":[2,0,2,0],
					"sceneObjectUid":"9868125099917119",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":13},
						{"time":0.25,"value":15.252554098897223},
						{"time":0.5,"value":0},
						{"time":0.75,"value":0},
						{"time":1,"value":13},
						{"time":1.25,"value":15.252554098897223},
						{"time":1.5,"value":0},
						{"time":1.75,"value":0},
						{"time":2,"value":13},
						{"time":2.25,"value":15.252554098897223},
						{"time":2.5,"value":0},
						{"time":2.75,"value":0},
						{"time":3,"value":13},
						{"time":3.25,"value":15.252554098897223},
						{"time":3.5,"value":0},
						{"time":3.75,"value":0},
						{"time":4,"value":13}
					]
				},
				{
					"sceneObject":[2,0,2,0,0],
					"sceneObjectUid":"1001230710194815",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":16.080087455487934},
						{"time":0.5,"value":-6.999999999999204},
						{"time":0.75,"value":0},
						{"time":1,"value":16.080087455487934},
						{"time":1.5,"value":-6.999999999999204},
						{"time":1.75,"value":0},
						{"time":2,"value":16.080087455487934},
						{"time":2.5,"value":-6.999999999999204},
						{"time":2.75,"value":0},
						{"time":3,"value":16.080087455487934},
						{"time":3.5,"value":-6.999999999999204},
						{"time":3.75,"value":0},
						{"time":4,"value":16.080087455487934}
					]
				},
				{
					"sceneObject":[2,0,3],
					"sceneObjectUid":"2333391500121242",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-37},
						{"time":0.25,"value":0},
						{"time":0.5,"value":30},
						{"time":1,"value":-37},
						{"time":1.25,"value":0},
						{"time":1.5,"value":30},
						{"time":2,"value":-37},
						{"time":2.25,"value":0},
						{"time":2.5,"value":30},
						{"time":3,"value":-37},
						{"time":3.25,"value":0},
						{"time":3.5,"value":30},
						{"time":4,"value":-37}
					]
				},
				{
					"sceneObject":[2,0,3,0],
					"sceneObjectUid":"0520431315092932",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.25,"value":0},
						{"time":0.5,"value":13},
						{"time":0.75,"value":15},
						{"time":1,"value":0},
						{"time":1.25,"value":0},
						{"time":1.5,"value":13},
						{"time":1.75,"value":15},
						{"time":2,"value":0},
						{"time":2.25,"value":0},
						{"time":2.5,"value":13},
						{"time":2.75,"value":15},
						{"time":3,"value":0},
						{"time":3.25,"value":0},
						{"time":3.5,"value":13},
						{"time":3.75,"value":15},
						{"time":4,"value":0}
					]
				},
				{
					"sceneObject":[2,0,3,0,0],
					"sceneObjectUid":"3249685385429677",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-7},
						{"time":0.25,"value":0},
						{"time":1,"value":-7},
						{"time":1.25,"value":0},
						{"time":2,"value":-7},
						{"time":2.25,"value":0},
						{"time":3,"value":-7},
						{"time":3.25,"value":0},
						{"time":4,"value":-7}
					]
				},
				{
					"sceneObject":[2,0,4],
					"sceneObjectUid":"7554277963686835",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":76.95690066032763},
						{"time":0.5,"value":15.956900660327292},
						{"time":1,"value":76.95690066032763},
						{"time":1.5,"value":15.956900660327292},
						{"time":2,"value":76.95690066032763},
						{"time":2.5,"value":15.956900660327292},
						{"time":3,"value":76.95690066032763},
						{"time":3.5,"value":15.956900660327292},
						{"time":4,"value":76.95690066032763}
					]
				},
				{
					"sceneObject":[2,0,4,0,0],
					"sceneObjectUid":"6553804298258501",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-41.56009044100986},
						{"time":1.5,"value":-0.1100904410100938},
						{"time":2,"value":-41.56009044100986},
						{"time":3.5,"value":-0.1100904410100938},
						{"time":4,"value":-41.56009044100986}
					]
				},
				{
					"sceneObject":[2,0,4,0,0,0],
					"sceneObjectUid":"2868200568303867",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":33},
						{"time":0.45,"value":-18.513513513513402},
						{"time":1.5,"value":-34.99999999999932},
						{"time":2,"value":33},
						{"time":2.45,"value":-18.513513513513402},
						{"time":3.5,"value":-34.99999999999932},
						{"time":4,"value":33}
					]
				},
				{
					"sceneObject":[2,0,4,0,0,1],
					"sceneObjectUid":"3744948094957698",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":-30},
						{"time":0.5166666666666606,"value":28.000000000000227},
						{"time":2,"value":-30},
						{"time":2.5166666666666604,"value":28.000000000000227},
						{"time":4,"value":-30}
					]
				},
				{
					"sceneObject":[2,0,4,0,0,2],
					"sceneObjectUid":"3994121489944880",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{
							"time":0,
							"value":41.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9833333333333394,
							"value":-36.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.9999999999999998,
							"value":41.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2.9833333333333396,
							"value":-36.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":4,
							"value":41.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					]
				},
				{
					"sceneObject":[2,0,5],
					"sceneObjectUid":"2638073987214413",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{
							"time":0.25,
							"value":15.499999999999773,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":0.5,"value":-14.999999999999773},
						{"time":1,"value":19.66666666666659,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":1.5,"value":-14.999999999999773},
						{
							"time":1.75,
							"value":12.500000000000568,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0},
						{
							"time":2.25,
							"value":15.499999999999773,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2.5,"value":-14.999999999999773},
						{"time":3,"value":19.66666666666659,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":3.5,"value":-14.999999999999773},
						{
							"time":3.75,
							"value":12.500000000000568,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":4,"value":0}
					]
				},
				{
					"sceneObject":[2,0,5,0],
					"sceneObjectUid":"1614695340706421",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.25,"value":12.499999999999773,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":0.5,"value":-11},
						{"time":0.75,"value":5.500000000000227,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":1,"value":0},
						{"time":1.25,"value":12.499999999999773,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":1.5,"value":-11},
						{"time":1.75,"value":5.500000000000227,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":2,"value":0},
						{"time":2.25,"value":12.499999999999773,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":2.5,"value":-11},
						{"time":2.75,"value":5.500000000000227,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":3,"value":0},
						{"time":3.25,"value":12.499999999999773,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":3.5,"value":-11},
						{"time":3.75,"value":5.500000000000227,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":4,"value":0}
					]
				},
				{
					"sceneObject":[2,0,5,0,0],
					"sceneObjectUid":"3516176508336800",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.25,"value":22.00000000000017,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":0.5,"value":11.999999999999886},
						{"time":0.75,"value":27.99999999999949,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":1,"value":0},
						{"time":1.25,"value":22.00000000000017,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":1.5,"value":11.999999999999886},
						{"time":1.75,"value":27.99999999999949,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":2,"value":0},
						{"time":2.25,"value":22.00000000000017,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":2.5,"value":11.999999999999886},
						{"time":2.75,"value":27.99999999999949,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":3,"value":0},
						{"time":3.25,"value":22.00000000000017,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":3.5,"value":11.999999999999886},
						{"time":3.75,"value":27.99999999999949,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":4,"value":0}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,1,0],
					"sceneObjectUid":"9479680484821566",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.18333333333333332,"value":true},
						{"time":0.3333333333333333,"value":false},
						{"time":2.4,"value":false},
						{"time":2.583333333333333,"value":true},
						{"time":2.7333333333333334,"value":false},
						{"time":4,"value":false}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,1,1],
					"sceneObjectUid":"6179257533270162",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.18333333333333332,"value":true},
						{"time":0.3333333333333333,"value":false},
						{"time":2.4,"value":false},
						{"time":2.583333333333333,"value":true},
						{"time":2.7333333333333334,"value":false},
						{"time":4,"value":false}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,2,0],
					"sceneObjectUid":"7536035516883604",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.18333333333333332,"value":true},
						{"time":0.3333333333333333,"value":false},
						{"time":2.4,"value":false},
						{"time":2.583333333333333,"value":true},
						{"time":2.7333333333333334,"value":false},
						{"time":4,"value":false}
					]
				},
				{
					"type":"binary",
					"sceneObject":[2,0,1,0,2,1],
					"sceneObjectUid":"4732324271843092",
					"propertyPath":["visible"],
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.18333333333333332,"value":true},
						{"time":0.3333333333333333,"value":false},
						{"time":2.4,"value":false},
						{"time":2.583333333333333,"value":true},
						{"time":2.7333333333333334,"value":false},
						{"time":4,"value":false}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,0],
					"sceneObjectUid":"7536035516883604",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.18333333333333332,"value":1},
						{"time":0.25,"value":1.457},
						{"time":0.31666666666666665,"value":1},
						{"time":2.583333333333333,"value":1},
						{"time":2.65,"value":1.457},
						{"time":2.7166666666666663,"value":1}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,1],
					"sceneObjectUid":"4732324271843092",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.18333333333333332,"value":1},
						{"time":0.25,"value":1.437},
						{"time":0.31666666666666665,"value":1},
						{"time":2.583333333333333,"value":1},
						{"time":2.65,"value":1.437},
						{"time":2.7166666666666663,"value":1}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,0],
					"sceneObjectUid":"9479680484821566",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.18333333333333332,"value":1},
						{"time":0.25,"value":1.4569999999999999},
						{"time":0.31666666666666665,"value":1},
						{"time":2.583333333333333,"value":1},
						{"time":2.65,"value":1.4569999999999999},
						{"time":2.7166666666666663,"value":1}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,1],
					"sceneObjectUid":"6179257533270162",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0.18333333333333332,"value":1},
						{"time":0.25,"value":1.4369999999999998},
						{"time":0.31666666666666665,"value":1},
						{"time":2.583333333333333,"value":1},
						{"time":2.65,"value":1.4369999999999998},
						{"time":2.7166666666666663,"value":1}
					]
				},
				{
					"sceneObject":[2,0,2],
					"sceneObjectUid":"6331146838850387",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":17.000000000000227},
						{"time":0.5,"value":4.547473508864641E-13},
						{"time":0.75,"value":28},
						{"time":1,"value":17.000000000000227},
						{"time":1.75,"value":28},
						{"time":2,"value":17.000000000000227},
						{"time":2.5,"value":4.547473508864641E-13},
						{"time":2.75,"value":28},
						{"time":3,"value":17.000000000000227},
						{"time":3.75,"value":28},
						{"time":4,"value":17.000000000000227}
					]
				},
				{
					"sceneObject":[2,0,2],
					"sceneObjectUid":"6331146838850387",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-76},
						{"time":0.25,"value":-62.14802177501184},
						{"time":0.5,"value":-76},
						{"time":0.75,"value":-76},
						{"time":1,"value":-76},
						{"time":1.25,"value":-62.14802177501184},
						{"time":1.5,"value":-76},
						{"time":1.75,"value":-76},
						{"time":2,"value":-76},
						{"time":2.25,"value":-62.14802177501184},
						{"time":2.5,"value":-76},
						{"time":2.75,"value":-76},
						{"time":3,"value":-76},
						{"time":3.25,"value":-62.14802177501184},
						{"time":3.5,"value":-76},
						{"time":3.75,"value":-76},
						{"time":4,"value":-76}
					]
				},
				{
					"sceneObject":[2,0,2,0],
					"sceneObjectUid":"9868125099917119",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.25,"value":-4.099786191007238},
						{"time":0.5,"value":-6.254164122663006},
						{"time":0.75,"value":0},
						{"time":1,"value":0},
						{"time":1.25,"value":-4.099786191007238},
						{"time":1.5,"value":-6.254164122663006},
						{"time":1.75,"value":0},
						{"time":2,"value":0},
						{"time":2.25,"value":-4.099786191007238},
						{"time":2.5,"value":-6.254164122663006},
						{"time":2.75,"value":0},
						{"time":3,"value":0},
						{"time":3.25,"value":-4.099786191007238},
						{"time":3.5,"value":-6.254164122663006},
						{"time":3.75,"value":0},
						{"time":4,"value":0}
					]
				},
				{
					"sceneObject":[2,0,2,0],
					"sceneObjectUid":"9868125099917119",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-19},
						{"time":0.25,"value":-18.91548878174605},
						{"time":0.5,"value":-27.28391433643315},
						{"time":0.75,"value":-19},
						{"time":1,"value":-19},
						{"time":1.25,"value":-18.91548878174605},
						{"time":1.5,"value":-27.28391433643315},
						{"time":1.75,"value":-19},
						{"time":2,"value":-19},
						{"time":2.25,"value":-18.91548878174605},
						{"time":2.5,"value":-27.28391433643315},
						{"time":2.75,"value":-19},
						{"time":3,"value":-19},
						{"time":3.25,"value":-18.91548878174605},
						{"time":3.5,"value":-27.28391433643315},
						{"time":3.75,"value":-19},
						{"time":4,"value":-19}
					]
				},
				{
					"sceneObject":[2,0,3],
					"sceneObjectUid":"2333391500121242",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-5.287129881986356},
						{"time":0.25,"value":-14},
						{"time":0.5,"value":-11.861389645959067},
						{"time":1,"value":-5.287129881986356},
						{"time":1.25,"value":-14},
						{"time":1.5,"value":-11.861389645959067},
						{"time":2,"value":-5.287129881986356},
						{"time":2.25,"value":-14},
						{"time":2.5,"value":-11.861389645959067},
						{"time":3,"value":-5.287129881986356},
						{"time":3.25,"value":-14},
						{"time":3.5,"value":-11.861389645959067},
						{"time":4,"value":-5.287129881986356}
					]
				},
				{
					"sceneObject":[2,0,3],
					"sceneObjectUid":"2333391500121242",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-69.47532970416466},
						{"time":0.25,"value":-70.60112672136648},
						{"time":0.5,"value":-65.42598911249414},
						{"time":0.75,"value":-54.95065940832954},
						{"time":1,"value":-69.47532970416466},
						{"time":1.25,"value":-70.60112672136648},
						{"time":1.5,"value":-65.42598911249414},
						{"time":1.75,"value":-54.95065940832954},
						{"time":2,"value":-69.47532970416466},
						{"time":2.25,"value":-70.60112672136648},
						{"time":2.5,"value":-65.42598911249414},
						{"time":2.75,"value":-54.95065940832954},
						{"time":3,"value":-69.47532970416466},
						{"time":3.25,"value":-70.60112672136648},
						{"time":3.5,"value":-65.42598911249414},
						{"time":3.75,"value":-54.95065940832954},
						{"time":4,"value":-69.47532970416466}
					]
				},
				{
					"sceneObject":[2,0,3,0],
					"sceneObjectUid":"0520431315092932",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-1.3344229036031432},
						{"time":0.25,"value":-2},
						{"time":0.5,"value":-0.003268710809429365},
						{"time":1,"value":-1.3344229036031432},
						{"time":1.25,"value":-2},
						{"time":1.5,"value":-0.003268710809429365},
						{"time":2,"value":-1.3344229036031432},
						{"time":2.25,"value":-2},
						{"time":2.5,"value":-0.003268710809429365},
						{"time":3,"value":-1.3344229036031432},
						{"time":3.25,"value":-2},
						{"time":3.5,"value":-0.003268710809429365},
						{"time":4,"value":-1.3344229036031432}
					]
				},
				{
					"sceneObject":[2,0,3,0],
					"sceneObjectUid":"0520431315092932",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-17.15136632386897},
						{"time":0.25,"value":-13},
						{"time":0.5,"value":-25.454098971606918},
						{"time":1,"value":-17.15136632386897},
						{"time":1.25,"value":-13},
						{"time":1.5,"value":-25.454098971606918},
						{"time":2,"value":-17.15136632386897},
						{"time":2.25,"value":-13},
						{"time":2.5,"value":-25.454098971606918},
						{"time":3,"value":-17.15136632386897},
						{"time":3.25,"value":-13},
						{"time":3.5,"value":-25.454098971606918},
						{"time":4,"value":-17.15136632386897}
					]
				},
				{
					"sceneObject":[2,0,2,0,0],
					"sceneObjectUid":"1001230710194815",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":12.000000000000007},
						{"time":0.5,"value":8.00000000000012},
						{"time":0.75,"value":12},
						{"time":1,"value":12.000000000000007},
						{"time":1.5,"value":8.00000000000012},
						{"time":1.75,"value":12},
						{"time":2,"value":12.000000000000007},
						{"time":2.5,"value":8.00000000000012},
						{"time":2.75,"value":12},
						{"time":3,"value":12.000000000000007},
						{"time":3.5,"value":8.00000000000012},
						{"time":3.75,"value":12},
						{"time":4,"value":12.000000000000007}
					]
				},
				{
					"sceneObject":[2,0,2,0,0],
					"sceneObjectUid":"1001230710194815",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-56},
						{"time":1,"value":-56},
						{"time":2,"value":-56},
						{"time":3,"value":-56},
						{"time":4,"value":-56}
					]
				},
				{
					"sceneObject":[2,0,3,0,0],
					"sceneObjectUid":"3249685385429677",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":14},
						{"time":0.5,"value":14},
						{"time":1,"value":14},
						{"time":1.5,"value":14},
						{"time":2,"value":14},
						{"time":2.5,"value":14},
						{"time":3,"value":14},
						{"time":3.5,"value":14},
						{"time":4,"value":14}
					]
				},
				{
					"sceneObject":[2,0,3,0,0],
					"sceneObjectUid":"3249685385429677",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-60},
						{"time":0.5,"value":-60},
						{"time":1,"value":-60},
						{"time":1.5,"value":-60},
						{"time":2,"value":-60},
						{"time":2.5,"value":-60},
						{"time":3,"value":-60},
						{"time":3.5,"value":-60},
						{"time":4,"value":-60}
					]
				},
				{
					"sceneObject":[2,0],
					"sceneObjectUid":"8391582935630722",
					"propertyPath":["position","y"],
					"keyframes":[
						{
							"time":0,
							"value":0,
							"leftHandleValue":0.22627394977070237,
							"leftHandleSpan":0.2533078190532746,
							"rightHandleValue":-0.3975073410988312,
							"rightHandleSpan":0.20752327880723315
						},
						{"time":0.25,"value":-16,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":0.5,
							"value":0,
							"leftHandleValue":0.22627394977070237,
							"leftHandleSpan":0.2533078190532746,
							"rightHandleValue":-0.3975073410988312,
							"rightHandleSpan":0.20752327880723315
						},
						{
							"time":0.7666666666666666,
							"value":-16,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1,
							"value":0,
							"leftHandleValue":0.22627394977070237,
							"leftHandleSpan":0.2533078190532746,
							"rightHandleValue":-0.3975073410988312,
							"rightHandleSpan":0.20752327880723315
						},
						{
							"time":1.2666666666666666,
							"value":-16,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":0,
							"leftHandleValue":0.22627394977070237,
							"leftHandleSpan":0.2533078190532746,
							"rightHandleValue":-0.3975073410988312,
							"rightHandleSpan":0.20752327880723315
						},
						{"time":1.75,"value":-16,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":2,
							"value":0,
							"leftHandleValue":0.22627394977070237,
							"leftHandleSpan":0.2533078190532746,
							"rightHandleValue":-0.3975073410988312,
							"rightHandleSpan":0.20752327880723315
						},
						{"time":2.25,"value":-16,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":2.5,
							"value":0,
							"leftHandleValue":0.22627394977070237,
							"leftHandleSpan":0.2533078190532746,
							"rightHandleValue":-0.3975073410988312,
							"rightHandleSpan":0.20752327880723315
						},
						{
							"time":2.7666666666666666,
							"value":-16,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3,
							"value":0,
							"leftHandleValue":0.22627394977070237,
							"leftHandleSpan":0.2533078190532746,
							"rightHandleValue":-0.3975073410988312,
							"rightHandleSpan":0.20752327880723315
						},
						{
							"time":3.2666666666666666,
							"value":-16,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3.5,
							"value":0,
							"leftHandleValue":0.22627394977070237,
							"leftHandleSpan":0.2533078190532746,
							"rightHandleValue":-0.3975073410988312,
							"rightHandleSpan":0.20752327880723315
						},
						{"time":3.75,"value":-16,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":4,
							"value":0,
							"leftHandleValue":0.22627394977070237,
							"leftHandleSpan":0.2533078190532746,
							"rightHandleValue":-0.3975073410988312,
							"rightHandleSpan":0.20752327880723315
						}
					]
				},
				{
					"sceneObject":[2,0,0],
					"sceneObjectUid":"2384190589896712",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":50},
						{"time":0.5,"value":50},
						{"time":1,"value":50},
						{"time":1.5,"value":50},
						{"time":2,"value":50},
						{"time":2.5,"value":50},
						{"time":3,"value":50},
						{"time":3.5,"value":50},
						{"time":4,"value":50}
					]
				},
				{
					"sceneObject":[2,0,0],
					"sceneObjectUid":"2384190589896712",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":12},
						{"time":0.5,"value":12},
						{"time":1,"value":12},
						{"time":1.5,"value":12},
						{"time":2,"value":12},
						{"time":2.5,"value":12},
						{"time":3,"value":12},
						{"time":3.5,"value":12},
						{"time":4,"value":12}
					]
				},
				{
					"sceneObject":[2,0,4],
					"sceneObjectUid":"7554277963686835",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0.5,"value":-10},
						{"time":1.5,"value":-10},
						{"time":2.5,"value":-10},
						{"time":3.5,"value":-10}
					]
				},
				{
					"sceneObject":[2,0,4],
					"sceneObjectUid":"7554277963686835",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0.5,"value":4},
						{"time":1.5,"value":4},
						{"time":2.5,"value":4},
						{"time":3.5,"value":4}
					]
				},
				{
					"sceneObject":[2,0,4,0,0],
					"sceneObjectUid":"6553804298258501",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0.5,"value":-25.999999999999773},
						{"time":1.5,"value":-25.999999999999773},
						{"time":2.5,"value":-25.999999999999773},
						{"time":3.5,"value":-25.999999999999773}
					]
				},
				{
					"sceneObject":[2,0,4,0,0],
					"sceneObjectUid":"6553804298258501",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":1.5,"value":-11},
						{"time":3.5,"value":-11}
					]
				},
				{
					"sceneObject":[2,0,0,0,0],
					"sceneObjectUid":"6920407712169353",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":-21},
						{"time":0.5,"value":-25.9665461232594},
						{"time":1,"value":-21},
						{"time":1.5,"value":-25.9665461232594},
						{"time":2,"value":-21},
						{"time":2.5,"value":-25.9665461232594},
						{"time":3,"value":-21},
						{"time":3.5,"value":-25.9665461232594},
						{"time":4,"value":-21}
					]
				},
				{
					"sceneObject":[2,0,0,0,0],
					"sceneObjectUid":"6920407712169353",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-20,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":0.5,
							"value":-19.90092783504243,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":1,"value":-20,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":1.5,
							"value":-19.90092783504243,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":-20,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":2.5,
							"value":-19.90092783504243,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":3,"value":-20,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":3.5,
							"value":-19.90092783504243,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":4,"value":-20,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4}
					]
				},
				{
					"sceneObject":[2,0,1,0],
					"sceneObjectUid":"7499394871464999",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":43.27080992980978},
						{
							"time":0.5,
							"value":52.270809929809666,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":1,"value":34.88309553887801},
						{
							"time":1.5,
							"value":52.270809929809666,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":43.27080992980978},
						{
							"time":2.5,
							"value":52.270809929809666,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":3,"value":34.88309553887801},
						{
							"time":3.5,
							"value":52.270809929809666,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":4,"value":43.27080992980978}
					]
				},
				{
					"sceneObject":[2,0,1,0],
					"sceneObjectUid":"7499394871464999",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":62.1937780665519},
						{"time":0.25,"value":76},
						{
							"time":0.4999999999999959,
							"value":68.19377806655201,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":0.75,"value":76},
						{"time":1,"value":62.1937780665519,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":1.25,"value":76},
						{
							"time":1.499999999999996,
							"value":68.19377806655201,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":1.75,"value":76},
						{"time":2,"value":62.1937780665519},
						{"time":2.25,"value":76},
						{
							"time":2.499999999999996,
							"value":68.19377806655201,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2.75,"value":76},
						{"time":3,"value":62.1937780665519,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":3.25,"value":76},
						{
							"time":3.499999999999996,
							"value":68.19377806655201,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":3.75,"value":76},
						{"time":4,"value":62.1937780665519}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,3],
					"sceneObjectUid":"8525312094228609",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0.3999999999999999,"value":0},
						{"time":0.6666666666666665,"value":12.000000000000057},
						{"time":2.4,"value":0},
						{"time":2.6666666666666665,"value":12.000000000000057},
						{"time":4,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,3],
					"sceneObjectUid":"8525312094228609",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0.3999999999999999,"value":0},
						{"time":0.6666666666666665,"value":-4.000000000000227},
						{"time":4,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,3],
					"sceneObjectUid":"8525312094228609",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0.3999999999999999,"value":22},
						{"time":0.8499999999999999,"value":29.999999999999318},
						{"time":2.4,"value":22},
						{"time":2.85,"value":29.999999999999318},
						{"time":4,"value":22}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,3],
					"sceneObjectUid":"9003131496764060",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0.3999999999999999,"value":-5},
						{"time":0.6666666666666665,"value":3.0000000000004547},
						{"time":4,"value":-5}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,3],
					"sceneObjectUid":"9003131496764060",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":16},
						{"time":0.44999999999999996,"value":23.000000000000114},
						{"time":2,"value":16},
						{"time":2.45,"value":23.000000000000114},
						{"time":4,"value":16}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,3],
					"sceneObjectUid":"9003131496764060",
					"propertyPath":["rotation","z"],
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.26666666666666666,"value":-17.000000000000114},
						{"time":2,"value":0},
						{"time":2.2666666666666666,"value":-17.000000000000114},
						{"time":4,"value":0}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,2],
					"sceneObjectUid":"3935974948706458",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":2},
						{"time":0.5333333333333333,"value":-0.9999999999994316},
						{"time":2.6,"value":-0.9999999999994316},
						{"time":2.65,"value":2},
						{"time":4,"value":2}
					]
				},
				{
					"sceneObject":[2,0,1,0,2,2],
					"sceneObjectUid":"3935974948706458",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":2},
						{"time":0.5333333333333333,"value":-2.209999999999999},
						{"time":2.6,"value":-2.209999999999999},
						{"time":2.65,"value":2},
						{"time":4,"value":2}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,2],
					"sceneObjectUid":"9581766268073749",
					"propertyPath":["position","x"],
					"keyframes":[
						{"time":0,"value":3},
						{"time":0.5333333333333333,"value":-6.18},
						{"time":2.6,"value":-6.18},
						{"time":2.65,"value":3},
						{"time":4,"value":3}
					]
				},
				{
					"sceneObject":[2,0,1,0,1,2],
					"sceneObjectUid":"9581766268073749",
					"propertyPath":["position","y"],
					"keyframes":[
						{"time":0,"value":-1},
						{"time":2.65,"value":-1},
						{"time":4,"value":-1}
					]
				},
				{
					"type":"binary",
					"sceneObject":[3],
					"sceneObjectUid":"3201523667536051",
					"propertyPath":["enabled"],
					"keyframes":[
						{"time":3.4875000000000305,"value":false}
					]
				},
				{
					"sceneObject":[3],
					"sceneObjectUid":"3201523667536051",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":3.183333333333371,"value":20}
					]
				}
			]
		},
		"Run":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":4,
			"animatedProperties":[
				{
					"type":"boolean",
					"keyframes":[
						{"time":0,"value":false}
					],
					"propertyPath":["visible"],
					"sceneObjectUid":"2551457183054903"
				},
				{
					"type":"boolean",
					"keyframes":[
						{"time":0,"value":false}
					],
					"propertyPath":["visible"],
					"sceneObjectUid":"2420332769746991"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5488355722708611},
						{"time":0.5,"value":48.37799972954032},
						{"time":1,"value":0.5488355722708611},
						{"time":1.5,"value":48.37799972954032},
						{"time":2,"value":0.5488355722708611},
						{"time":2.5,"value":48.37799972954032},
						{"time":3,"value":0.5488355722708611},
						{"time":3.5,"value":48.37799972954032},
						{"time":4,"value":0.5488355722708611}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"2384190589896712"
				},
				{
					"keyframes":[
						{
							"time":0,
							"value":18.108003355603504,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5,
							"value":-7.639366102612521,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1,
							"value":18.108003355603504,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":-7.639366102612521,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2,
							"value":18.108003355603504,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2.5,
							"value":-7.639366102612521,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3,
							"value":18.108003355603504,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3.5,
							"value":-7.639366102612521,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":4,
							"value":18.108003355603504,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"6920407712169353"
				},
				{
					"keyframes":[
						{
							"time":0,
							"value":-30.000000000000398,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6166666666666667,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3166666666666667,
							"value":64,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2,
							"value":-30.000000000000398,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2.6166666666666667,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3.3166666666666664,
							"value":64,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":4,
							"value":-30.000000000000398,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"6810001299241983"
				},
				{
					"keyframes":[
						{
							"time":0,
							"value":-8.999999999999545,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1333333333333333,
							"value":29.00000000000051,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2,
							"value":-8.999999999999545,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2.433333333333333,"value":0,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":3.1333333333333333,
							"value":29.00000000000051,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":4,
							"value":-8.999999999999545,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"7093717081710033"
				},
				{
					"keyframes":[
						{
							"time":0,
							"value":32.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.8166666666666667,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5166666666666666,
							"value":-36.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2,
							"value":32.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2.8166666666666664,
							"value":0,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":3.5166666666666666,
							"value":-36.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":4,
							"value":32.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"5094167623322140"
				},
				{
					"keyframes":[
						{
							"time":0,
							"value":9.999999999999773,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.4299999999999533,
							"rightHandleSpan":0.3022052127021831
						},
						{"time":0.25,"value":0,"leftHandleValue":1.1699999999999735,"leftHandleSpan":0.36507329025077967},
						{"time":0.75,"value":0,"rightHandleValue":2.2099999999999502,"rightHandleSpan":0.3930146580501591},
						{
							"time":1,
							"value":9.999999999999773,
							"leftHandleValue":-0.5849999999999868,
							"leftHandleSpan":0.3650732902507797,
							"rightHandleValue":-0.5199999999999882,
							"rightHandleSpan":0.35110260635109153
						},
						{"time":1.25,"value":0,"leftHandleValue":2.404999999999946,"leftHandleSpan":0.40698534194984726},
						{"time":1.75,"value":0,"rightHandleValue":1.8199999999999736,"rightHandleSpan":0.3720586322006269},
						{
							"time":2,
							"value":9.999999999999773,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.4299999999999533,
							"rightHandleSpan":0.3022052127021831
						},
						{"time":2.25,"value":0,"leftHandleValue":1.1699999999999735,"leftHandleSpan":0.36507329025077967},
						{"time":2.75,"value":0,"rightHandleValue":2.2099999999999502,"rightHandleSpan":0.3930146580501591},
						{
							"time":3,
							"value":9.999999999999773,
							"leftHandleValue":-0.5849999999999868,
							"leftHandleSpan":0.3650732902507797,
							"rightHandleValue":-0.5199999999999882,
							"rightHandleSpan":0.35110260635109153
						},
						{"time":3.25,"value":0,"leftHandleValue":2.404999999999946,"leftHandleSpan":0.40698534194984726},
						{"time":3.75,"value":0,"rightHandleValue":1.8199999999999736,"rightHandleSpan":0.3720586322006269},
						{
							"time":4,
							"value":9.999999999999773,
							"leftHandleValue":-1.5599999999999798,
							"leftHandleSpan":0.3441172644012506,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"1508420040038582"
				},
				{
					"keyframes":[
						{"time":0,"value":-13.999999999999886,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":0.25,"value":0},
						{
							"time":0.5,
							"value":-13.999999999999886,
							"leftHandleValue":-0.09216744688769885,
							"leftHandleSpan":0.2602931610031187,
							"rightHandleValue":0,
							"rightHandleSpan":0.23933713515358657
						},
						{"time":0.75,"value":0},
						{
							"time":1,
							"value":-13.999999999999886,
							"leftHandleValue":-0.09216744688769885,
							"leftHandleSpan":0.2602931610031187,
							"rightHandleValue":0,
							"rightHandleSpan":0.23933713515358657
						},
						{"time":1.25,"value":0},
						{"time":1.5,"value":-13.999999999999886,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":1.75,"value":0},
						{"time":2,"value":-13.999999999999886,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":2.25,"value":0},
						{
							"time":2.5,
							"value":-13.999999999999886,
							"leftHandleValue":-0.09216744688769885,
							"leftHandleSpan":0.2602931610031187,
							"rightHandleValue":0,
							"rightHandleSpan":0.23933713515358657
						},
						{"time":2.75,"value":0},
						{
							"time":3,
							"value":-13.999999999999886,
							"leftHandleValue":-0.09216744688769885,
							"leftHandleSpan":0.2602931610031187,
							"rightHandleValue":0,
							"rightHandleSpan":0.23933713515358657
						},
						{"time":3.25,"value":0},
						{"time":3.5,"value":-13.999999999999886,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":3.75,"value":0},
						{
							"time":4,
							"value":-13.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"7499394871464999"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7166666666666667,"value":10},
						{"time":1.6166666666666667,"value":10},
						{"time":2,"value":0},
						{"time":2.716666666666667,"value":10},
						{"time":3.6166666666666667,"value":10},
						{"time":4,"value":0}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"3564406880715364"
				},
				{
					"keyframes":[
						{"time":0,"value":14.00000000000017},
						{"time":0.7166666666666667,"value":10},
						{"time":1.2833333333333332,"value":-0.6533894589983977},
						{"time":1.6166666666666667,"value":10},
						{"time":2,"value":14.00000000000017},
						{"time":2.716666666666667,"value":10},
						{"time":3.283333333333333,"value":-0.6533894589983977},
						{"time":3.6166666666666667,"value":10},
						{"time":4,"value":14.00000000000017}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"6285776537131904"
				},
				{
					"keyframes":[
						{"time":0,"value":37.00000000000023},
						{"time":0.35,"value":-38.59999999999988},
						{"time":0.5,"value":-46.999999999999886},
						{"time":0.6833333333333333,"value":0},
						{"time":1,"value":37.00000000000023},
						{"time":1.35,"value":-38.59999999999988},
						{"time":1.5,"value":-46.999999999999886},
						{"time":1.6833333333333333,"value":0},
						{"time":2,"value":37.00000000000023},
						{"time":2.35,"value":-38.59999999999988},
						{"time":2.5,"value":-46.999999999999886},
						{"time":2.683333333333333,"value":0},
						{"time":3,"value":37.00000000000023},
						{"time":3.35,"value":-38.59999999999988},
						{"time":3.5,"value":-46.999999999999886},
						{"time":3.683333333333333,"value":0},
						{"time":4,"value":37.00000000000023},
						{"time":4.35,"value":-38.59999999999988},
						{"time":4.5,"value":-46.999999999999886},
						{"time":4.683333333333334,"value":0},
						{"time":5,"value":37.00000000000023},
						{"time":5.35,"value":-38.59999999999988},
						{"time":5.5,"value":-46.999999999999886},
						{"time":5.683333333333334,"value":0},
						{"time":6,"value":37.00000000000023},
						{"time":6.35,"value":-38.59999999999988},
						{"time":6.5,"value":-46.999999999999886},
						{"time":6.683333333333334,"value":0},
						{"time":7,"value":37.00000000000023},
						{"time":7.35,"value":-38.59999999999988},
						{"time":7.5,"value":-46.999999999999886},
						{"time":7.683333333333334,"value":0},
						{"time":8,"value":37.00000000000023}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"6331146838850387"
				},
				{
					"keyframes":[
						{"time":0,"value":13.999999999999432},
						{"time":0.35,"value":-15.700000000000568},
						{"time":0.5,"value":-19.00000000000057},
						{"time":0.6833333333333333,"value":0},
						{"time":0.8333333333333334,"value":-4},
						{"time":1,"value":13.999999999999432},
						{"time":1.35,"value":-15.700000000000568},
						{"time":1.5,"value":-19.00000000000057},
						{"time":1.6833333333333333,"value":0},
						{"time":1.8333333333333333,"value":-4},
						{"time":2,"value":13.999999999999432},
						{"time":2.35,"value":-15.700000000000568},
						{"time":2.5,"value":-19.00000000000057},
						{"time":2.683333333333333,"value":0},
						{"time":2.8333333333333335,"value":-4},
						{"time":3,"value":13.999999999999432},
						{"time":3.35,"value":-15.700000000000568},
						{"time":3.5,"value":-19.00000000000057},
						{"time":3.683333333333333,"value":0},
						{"time":3.8333333333333335,"value":-4},
						{"time":4,"value":13.999999999999432},
						{"time":4.35,"value":-15.700000000000568},
						{"time":4.5,"value":-19.00000000000057},
						{"time":4.683333333333334,"value":0},
						{"time":4.833333333333333,"value":-4},
						{"time":5,"value":13.999999999999432},
						{"time":5.35,"value":-15.700000000000568},
						{"time":5.5,"value":-19.00000000000057},
						{"time":5.683333333333334,"value":0},
						{"time":5.833333333333333,"value":-4},
						{"time":6,"value":13.999999999999432},
						{"time":6.35,"value":-15.700000000000568},
						{"time":6.5,"value":-19.00000000000057},
						{"time":6.683333333333334,"value":0},
						{"time":6.833333333333333,"value":-4},
						{"time":7,"value":13.999999999999432},
						{"time":7.35,"value":-15.700000000000568},
						{"time":7.5,"value":-19.00000000000057},
						{"time":7.683333333333334,"value":0},
						{"time":7.833333333333333,"value":-4},
						{"time":8,"value":13.999999999999432}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"9868125099917119"
				},
				{
					"keyframes":[
						{"time":0,"value":30.080087455487593},
						{"time":0.18333333333333332,"value":2.6800874554870706},
						{"time":0.35,"value":3.0000874554872157},
						{"time":0.5,"value":3.080087455487252},
						{"time":0.6833333333333333,"value":0},
						{"time":1,"value":30.080087455487593},
						{"time":1.1833333333333333,"value":2.6800874554870706},
						{"time":1.35,"value":3.0000874554872157},
						{"time":1.5,"value":3.080087455487252},
						{"time":1.6833333333333333,"value":0},
						{"time":2,"value":30.080087455487593},
						{"time":2.183333333333333,"value":2.6800874554870706},
						{"time":2.35,"value":3.0000874554872157},
						{"time":2.5,"value":3.080087455487252},
						{"time":2.683333333333333,"value":0},
						{"time":3,"value":30.080087455487593},
						{"time":3.183333333333333,"value":2.6800874554870706},
						{"time":3.35,"value":3.0000874554872157},
						{"time":3.5,"value":3.080087455487252},
						{"time":3.683333333333333,"value":0},
						{"time":4,"value":30.080087455487593},
						{"time":4.183333333333334,"value":2.6800874554870706},
						{"time":4.35,"value":3.0000874554872157},
						{"time":4.5,"value":3.080087455487252},
						{"time":4.683333333333334,"value":0},
						{"time":5,"value":30.080087455487593},
						{"time":5.183333333333334,"value":2.6800874554870706},
						{"time":5.35,"value":3.0000874554872157},
						{"time":5.5,"value":3.080087455487252},
						{"time":5.683333333333334,"value":0},
						{"time":6,"value":30.080087455487593},
						{"time":6.183333333333334,"value":2.6800874554870706},
						{"time":6.35,"value":3.0000874554872157},
						{"time":6.5,"value":3.080087455487252},
						{"time":6.683333333333334,"value":0},
						{"time":7,"value":30.080087455487593},
						{"time":7.183333333333334,"value":2.6800874554870706},
						{"time":7.35,"value":3.0000874554872157},
						{"time":7.5,"value":3.080087455487252},
						{"time":7.683333333333334,"value":0},
						{"time":8,"value":30.080087455487593}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"1001230710194815"
				},
				{
					"keyframes":[
						{"time":-0.5,"value":37},
						{"time":-0.15,"value":-38},
						{"time":0,"value":-47},
						{"time":0.18333333333333332,"value":0},
						{"time":0.5,"value":37},
						{"time":0.85,"value":-38},
						{"time":1,"value":-47},
						{"time":1.1833333333333333,"value":0},
						{"time":1.5,"value":37},
						{"time":1.8499999999999999,"value":-38},
						{"time":2,"value":-47},
						{"time":2.183333333333333,"value":0},
						{"time":2.5,"value":37},
						{"time":2.85,"value":-38},
						{"time":3,"value":-47},
						{"time":3.183333333333333,"value":0},
						{"time":3.5,"value":37},
						{"time":3.85,"value":-38},
						{"time":4,"value":-47},
						{"time":4.183333333333334,"value":0},
						{"time":4.5,"value":37},
						{"time":4.85,"value":-38},
						{"time":5,"value":-47},
						{"time":5.183333333333334,"value":0},
						{"time":5.5,"value":37}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"2333391500121242"
				},
				{
					"keyframes":[
						{"time":-0.5,"value":14},
						{"time":-0.15,"value":-15.7},
						{"time":0,"value":-19},
						{"time":0.18333333333333332,"value":0},
						{"time":0.3333333333333333,"value":-4},
						{"time":0.5,"value":14},
						{"time":0.85,"value":-15.7},
						{"time":1,"value":-19},
						{"time":1.1833333333333333,"value":0},
						{"time":1.3333333333333333,"value":-4},
						{"time":1.5,"value":14},
						{"time":1.8499999999999999,"value":-15.7},
						{"time":2,"value":-19},
						{"time":2.183333333333333,"value":0},
						{"time":2.3333333333333335,"value":-4},
						{"time":2.5,"value":14},
						{"time":2.85,"value":-15.7},
						{"time":3,"value":-19},
						{"time":3.183333333333333,"value":0},
						{"time":3.3333333333333335,"value":-4},
						{"time":3.5,"value":14},
						{"time":3.85,"value":-15.7},
						{"time":4,"value":-19},
						{"time":4.183333333333334,"value":0},
						{"time":4.333333333333333,"value":-4},
						{"time":4.5,"value":14},
						{"time":4.85,"value":-15.7},
						{"time":5,"value":-19},
						{"time":5.183333333333334,"value":0},
						{"time":5.333333333333333,"value":-4},
						{"time":5.5,"value":14}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"0520431315092932"
				},
				{
					"keyframes":[
						{"time":-0.5,"value":30},
						{"time":-0.31666666666666665,"value":2.6},
						{"time":-0.15,"value":3},
						{"time":0,"value":3},
						{"time":0.18333333333333332,"value":0},
						{"time":0.5,"value":30},
						{"time":0.6833333333333333,"value":2.6},
						{"time":0.85,"value":3},
						{"time":1,"value":3},
						{"time":1.1833333333333333,"value":0},
						{"time":1.5,"value":30},
						{"time":1.6833333333333333,"value":2.6},
						{"time":1.8499999999999999,"value":3},
						{"time":2,"value":3},
						{"time":2.183333333333333,"value":0},
						{"time":2.5,"value":30},
						{"time":2.683333333333333,"value":2.6},
						{"time":2.85,"value":3},
						{"time":3,"value":3},
						{"time":3.183333333333333,"value":0},
						{"time":3.5,"value":30},
						{"time":3.683333333333333,"value":2.6},
						{"time":3.85,"value":3},
						{"time":4,"value":3},
						{"time":4.183333333333334,"value":0},
						{"time":4.5,"value":30},
						{"time":4.683333333333334,"value":2.6},
						{"time":4.85,"value":3},
						{"time":5,"value":3},
						{"time":5.183333333333334,"value":0},
						{"time":5.5,"value":30}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"3249685385429677"
				},
				{
					"keyframes":[
						{"time":0,"value":76.95690066032763},
						{"time":0.5,"value":15.956900660327292},
						{"time":1,"value":76.95690066032763},
						{"time":1.5,"value":15.956900660327292},
						{"time":2,"value":76.95690066032763},
						{"time":2.5,"value":15.956900660327292},
						{"time":3,"value":76.95690066032763},
						{"time":3.5,"value":15.956900660327292},
						{"time":4,"value":76.95690066032763}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"7554277963686835"
				},
				{
					"keyframes":[
						{"time":0,"value":-41.56009044100986},
						{"time":1.5,"value":-0.1100904410100938},
						{"time":2,"value":-41.56009044100986},
						{"time":3.5,"value":-0.1100904410100938},
						{"time":4,"value":-41.56009044100986}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"6553804298258501"
				},
				{
					"keyframes":[
						{"time":0,"value":33},
						{"time":0.45,"value":-18.513513513513402},
						{"time":1.5,"value":-34.99999999999932},
						{"time":2,"value":33},
						{"time":2.45,"value":-18.513513513513402},
						{"time":3.5,"value":-34.99999999999932},
						{"time":4,"value":33}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"2868200568303867"
				},
				{
					"keyframes":[
						{"time":0,"value":-30},
						{"time":0.5166666666666666,"value":28.000000000000227},
						{"time":2,"value":-30},
						{"time":2.5166666666666666,"value":28.000000000000227},
						{"time":4,"value":-30}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"3744948094957698"
				},
				{
					"keyframes":[
						{
							"time":0,
							"value":41.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5,
							"value":41.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9833333333333333,
							"value":-36.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1,
							"value":41.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":41.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2,
							"value":41.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":2.9833333333333334,
							"value":-36.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{
							"time":4,
							"value":41.999999999999886,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"3994121489944880"
				},
				{
					"keyframes":[
						{"time":0,"value":-12.999999999999886},
						{
							"time":0.25,
							"value":15.499999999999773,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":0.5,"value":-12.999999999999886},
						{"time":1,"value":-12.999999999999886},
						{"time":1.5,"value":-12.999999999999886},
						{
							"time":1.75,
							"value":12.500000000000568,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0},
						{
							"time":2.25,
							"value":15.499999999999773,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2.5,"value":-14.999999999999773},
						{"time":3,"value":19.66666666666659,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":3.5,"value":-14.999999999999773},
						{
							"time":3.75,
							"value":12.500000000000568,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":4,"value":-12.999999999999886}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"2638073987214413"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.25,"value":12.499999999999773,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":0.5,"value":0},
						{"time":0.75,"value":5.500000000000227,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":1,"value":0},
						{"time":1.25,"value":12.499999999999773,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":1.5,"value":0},
						{"time":1.75,"value":5.500000000000227,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":2,"value":0},
						{"time":2.25,"value":12.499999999999773,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":2.5,"value":-11},
						{"time":2.75,"value":5.500000000000227,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":3,"value":0},
						{"time":3.25,"value":12.499999999999773,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":3.5,"value":-11},
						{"time":3.75,"value":5.500000000000227,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":4,"value":0}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"1614695340706421"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.25,"value":22.00000000000017,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":0.5,"value":11.999999999999886},
						{"time":0.75,"value":27.99999999999949,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":1,"value":0},
						{"time":1.25,"value":22.00000000000017,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":1.5,"value":11.999999999999886},
						{"time":1.75,"value":27.99999999999949,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":2,"value":0},
						{"time":2.25,"value":22.00000000000017,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":2.5,"value":11.999999999999886},
						{"time":2.75,"value":27.99999999999949,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":3,"value":0},
						{"time":3.25,"value":22.00000000000017,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":3.5,"value":11.999999999999886},
						{"time":3.75,"value":27.99999999999949,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":4,"value":0}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"3516176508336800"
				},
				{
					"type":"boolean",
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.18333333333333332,"value":true},
						{"time":0.3333333333333333,"value":false},
						{"time":2.4,"value":false},
						{"time":2.5833333333333335,"value":true},
						{"time":2.7333333333333334,"value":false},
						{"time":4,"value":false}
					],
					"propertyPath":["visible"],
					"sceneObjectUid":"9479680484821566"
				},
				{
					"type":"boolean",
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.18333333333333332,"value":true},
						{"time":0.3333333333333333,"value":false},
						{"time":2.4,"value":false},
						{"time":2.5833333333333335,"value":true},
						{"time":2.7333333333333334,"value":false},
						{"time":4,"value":false}
					],
					"propertyPath":["visible"],
					"sceneObjectUid":"6179257533270162"
				},
				{
					"type":"boolean",
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.18333333333333332,"value":true},
						{"time":0.3333333333333333,"value":false},
						{"time":2.4,"value":false},
						{"time":2.5833333333333335,"value":true},
						{"time":2.7333333333333334,"value":false},
						{"time":4,"value":false}
					],
					"propertyPath":["visible"],
					"sceneObjectUid":"7536035516883604"
				},
				{
					"type":"boolean",
					"keyframes":[
						{"time":0,"value":false},
						{"time":0.18333333333333332,"value":true},
						{"time":0.3333333333333333,"value":false},
						{"time":2.4,"value":false},
						{"time":2.5833333333333335,"value":true},
						{"time":2.7333333333333334,"value":false},
						{"time":4,"value":false}
					],
					"propertyPath":["visible"],
					"sceneObjectUid":"4732324271843092"
				},
				{
					"keyframes":[
						{"time":0.18333333333333332,"value":1},
						{"time":0.25,"value":1.457},
						{"time":0.31666666666666665,"value":1},
						{"time":2.5833333333333335,"value":1},
						{"time":2.65,"value":1.457},
						{"time":2.716666666666667,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7536035516883604"
				},
				{
					"keyframes":[
						{"time":0.18333333333333332,"value":1},
						{"time":0.25,"value":1.437},
						{"time":0.31666666666666665,"value":1},
						{"time":2.5833333333333335,"value":1},
						{"time":2.65,"value":1.437},
						{"time":2.716666666666667,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"4732324271843092"
				},
				{
					"keyframes":[
						{"time":0.18333333333333332,"value":1},
						{"time":0.25,"value":1.4569999999999999},
						{"time":0.31666666666666665,"value":1},
						{"time":2.5833333333333335,"value":1},
						{"time":2.65,"value":1.4569999999999999},
						{"time":2.716666666666667,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9479680484821566"
				},
				{
					"keyframes":[
						{"time":0.18333333333333332,"value":1},
						{"time":0.25,"value":1.4369999999999998},
						{"time":0.31666666666666665,"value":1},
						{"time":2.5833333333333335,"value":1},
						{"time":2.65,"value":1.4369999999999998},
						{"time":2.716666666666667,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"6179257533270162"
				},
				{
					"keyframes":[
						{"time":0,"value":28},
						{"time":0.35,"value":-6.199999999999896},
						{"time":0.5,"value":-9.999999999999886},
						{"time":0.6833333333333333,"value":28},
						{"time":0.8333333333333334,"value":28},
						{"time":1,"value":28},
						{"time":1.35,"value":-6.199999999999896},
						{"time":1.5,"value":-9.999999999999886},
						{"time":1.6833333333333333,"value":28},
						{"time":1.8333333333333333,"value":28},
						{"time":2,"value":28},
						{"time":2.35,"value":-6.199999999999896},
						{"time":2.5,"value":-9.999999999999886},
						{"time":2.683333333333333,"value":28},
						{"time":2.8333333333333335,"value":28},
						{"time":3,"value":28},
						{"time":3.35,"value":-6.199999999999896},
						{"time":3.5,"value":-9.999999999999886},
						{"time":3.683333333333333,"value":28},
						{"time":3.8333333333333335,"value":28},
						{"time":4,"value":28},
						{"time":4.35,"value":-6.199999999999896},
						{"time":4.5,"value":-9.999999999999886},
						{"time":4.683333333333334,"value":28},
						{"time":4.833333333333333,"value":28},
						{"time":5,"value":28},
						{"time":5.35,"value":-6.199999999999896},
						{"time":5.5,"value":-9.999999999999886},
						{"time":5.683333333333334,"value":28},
						{"time":5.833333333333333,"value":28},
						{"time":6,"value":28},
						{"time":6.35,"value":-6.199999999999896},
						{"time":6.5,"value":-9.999999999999886},
						{"time":6.683333333333334,"value":28},
						{"time":6.833333333333333,"value":28},
						{"time":7,"value":28},
						{"time":7.35,"value":-6.199999999999896},
						{"time":7.5,"value":-9.999999999999886},
						{"time":7.683333333333334,"value":28},
						{"time":7.833333333333333,"value":28},
						{"time":8,"value":28}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6331146838850387"
				},
				{
					"keyframes":[
						{"time":0,"value":-76},
						{"time":0.18333333333333332,"value":-57},
						{"time":0.35,"value":-72.2},
						{"time":0.5,"value":-76},
						{"time":0.6833333333333333,"value":-56},
						{"time":0.8333333333333334,"value":-76},
						{"time":1,"value":-76},
						{"time":1.1833333333333333,"value":-57},
						{"time":1.35,"value":-72.2},
						{"time":1.5,"value":-76},
						{"time":1.6833333333333333,"value":-56},
						{"time":1.8333333333333333,"value":-76},
						{"time":2,"value":-76},
						{"time":2.183333333333333,"value":-57},
						{"time":2.35,"value":-72.2},
						{"time":2.5,"value":-76},
						{"time":2.683333333333333,"value":-56},
						{"time":2.8333333333333335,"value":-76},
						{"time":3,"value":-76},
						{"time":3.183333333333333,"value":-57},
						{"time":3.35,"value":-72.2},
						{"time":3.5,"value":-76},
						{"time":3.683333333333333,"value":-56},
						{"time":3.8333333333333335,"value":-76},
						{"time":4,"value":-76},
						{"time":4.183333333333334,"value":-57},
						{"time":4.35,"value":-72.2},
						{"time":4.5,"value":-76},
						{"time":4.683333333333334,"value":-56},
						{"time":4.833333333333333,"value":-76},
						{"time":5,"value":-76},
						{"time":5.183333333333334,"value":-57},
						{"time":5.35,"value":-72.2},
						{"time":5.5,"value":-76},
						{"time":5.683333333333334,"value":-56},
						{"time":5.833333333333333,"value":-76},
						{"time":6,"value":-76},
						{"time":6.183333333333334,"value":-57},
						{"time":6.35,"value":-72.2},
						{"time":6.5,"value":-76},
						{"time":6.683333333333334,"value":-56},
						{"time":6.833333333333333,"value":-76},
						{"time":7,"value":-76},
						{"time":7.183333333333334,"value":-57},
						{"time":7.35,"value":-72.2},
						{"time":7.5,"value":-76},
						{"time":7.683333333333334,"value":-56},
						{"time":7.833333333333333,"value":-76},
						{"time":8,"value":-76}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6331146838850387"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.8333333333333334,"value":0},
						{"time":1,"value":0},
						{"time":1.8333333333333333,"value":0},
						{"time":2,"value":0},
						{"time":2.8333333333333335,"value":0},
						{"time":3,"value":0},
						{"time":3.8333333333333335,"value":0},
						{"time":4,"value":0},
						{"time":4.833333333333333,"value":0},
						{"time":5,"value":0},
						{"time":5.833333333333333,"value":0},
						{"time":6,"value":0},
						{"time":6.833333333333333,"value":0},
						{"time":7,"value":0},
						{"time":7.833333333333333,"value":0},
						{"time":8,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9868125099917119"
				},
				{
					"keyframes":[
						{"time":0,"value":-19},
						{"time":0.8333333333333334,"value":-19},
						{"time":1,"value":-19},
						{"time":1.8333333333333333,"value":-19},
						{"time":2,"value":-19},
						{"time":2.8333333333333335,"value":-19},
						{"time":3,"value":-19},
						{"time":3.8333333333333335,"value":-19},
						{"time":4,"value":-19},
						{"time":4.833333333333333,"value":-19},
						{"time":5,"value":-19},
						{"time":5.833333333333333,"value":-19},
						{"time":6,"value":-19},
						{"time":6.833333333333333,"value":-19},
						{"time":7,"value":-19},
						{"time":7.833333333333333,"value":-19},
						{"time":8,"value":-19}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9868125099917119"
				},
				{
					"keyframes":[
						{"time":-0.5,"value":16.000000000000227},
						{"time":0.18333333333333332,"value":-14},
						{"time":0.3333333333333333,"value":8.000000000000167},
						{"time":0.5,"value":16.000000000000227},
						{"time":1.1833333333333333,"value":-14},
						{"time":1.3333333333333333,"value":8.000000000000167},
						{"time":1.5,"value":16.000000000000227},
						{"time":2.183333333333333,"value":-14},
						{"time":2.3333333333333335,"value":8.000000000000167},
						{"time":2.5,"value":16.000000000000227},
						{"time":3.183333333333333,"value":-14},
						{"time":3.3333333333333335,"value":8.000000000000167},
						{"time":3.5,"value":16.000000000000227},
						{"time":4.183333333333334,"value":-14},
						{"time":4.333333333333333,"value":8.000000000000167},
						{"time":4.5,"value":16.000000000000227},
						{"time":5.183333333333334,"value":-14},
						{"time":5.333333333333333,"value":8.000000000000167},
						{"time":5.5,"value":16.000000000000227}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2333391500121242"
				},
				{
					"keyframes":[
						{"time":-0.5,"value":-64},
						{"time":-0.31666666666666665,"value":-48},
						{"time":-0.15,"value":-64},
						{"time":0.18333333333333332,"value":-44},
						{"time":0.3333333333333333,"value":-64},
						{"time":0.5,"value":-64},
						{"time":0.6833333333333333,"value":-48},
						{"time":0.85,"value":-64},
						{"time":1.1833333333333333,"value":-44},
						{"time":1.3333333333333333,"value":-64},
						{"time":1.5,"value":-64},
						{"time":1.6833333333333333,"value":-48},
						{"time":1.8499999999999999,"value":-64},
						{"time":2.183333333333333,"value":-44},
						{"time":2.3333333333333335,"value":-64},
						{"time":2.5,"value":-64},
						{"time":2.683333333333333,"value":-48},
						{"time":2.85,"value":-64},
						{"time":3.183333333333333,"value":-44},
						{"time":3.3333333333333335,"value":-64},
						{"time":3.5,"value":-64},
						{"time":3.683333333333333,"value":-48},
						{"time":3.85,"value":-64},
						{"time":4.183333333333334,"value":-44},
						{"time":4.333333333333333,"value":-64},
						{"time":4.5,"value":-64},
						{"time":4.683333333333334,"value":-48},
						{"time":4.85,"value":-64},
						{"time":5.183333333333334,"value":-44},
						{"time":5.333333333333333,"value":-64},
						{"time":5.5,"value":-64}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"2333391500121242"
				},
				{
					"keyframes":[
						{"time":-0.5,"value":-2},
						{"time":0.18333333333333332,"value":-2},
						{"time":0.3333333333333333,"value":-2},
						{"time":0.5,"value":-2},
						{"time":1.1833333333333333,"value":-2},
						{"time":1.3333333333333333,"value":-2},
						{"time":1.5,"value":-2},
						{"time":2.183333333333333,"value":-2},
						{"time":2.3333333333333335,"value":-2},
						{"time":2.5,"value":-2},
						{"time":3.183333333333333,"value":-2},
						{"time":3.3333333333333335,"value":-2},
						{"time":3.5,"value":-2},
						{"time":4.183333333333334,"value":-2},
						{"time":4.333333333333333,"value":-2},
						{"time":4.5,"value":-2},
						{"time":5.183333333333334,"value":-2},
						{"time":5.333333333333333,"value":-2},
						{"time":5.5,"value":-2}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0520431315092932"
				},
				{
					"keyframes":[
						{"time":-0.5,"value":-13},
						{"time":0.18333333333333332,"value":-13},
						{"time":0.3333333333333333,"value":-13},
						{"time":0.5,"value":-13},
						{"time":1.1833333333333333,"value":-13},
						{"time":1.3333333333333333,"value":-13},
						{"time":1.5,"value":-13},
						{"time":2.183333333333333,"value":-13},
						{"time":2.3333333333333335,"value":-13},
						{"time":2.5,"value":-13},
						{"time":3.183333333333333,"value":-13},
						{"time":3.3333333333333335,"value":-13},
						{"time":3.5,"value":-13},
						{"time":4.183333333333334,"value":-13},
						{"time":4.333333333333333,"value":-13},
						{"time":4.5,"value":-13},
						{"time":5.183333333333334,"value":-13},
						{"time":5.333333333333333,"value":-13},
						{"time":5.5,"value":-13}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"0520431315092932"
				},
				{
					"keyframes":[
						{"time":0,"value":12},
						{"time":0.8333333333333334,"value":12},
						{"time":1,"value":12},
						{"time":1.8333333333333333,"value":12},
						{"time":2,"value":12},
						{"time":2.8333333333333335,"value":12},
						{"time":3,"value":12},
						{"time":3.8333333333333335,"value":12},
						{"time":4,"value":12},
						{"time":4.833333333333333,"value":12},
						{"time":5,"value":12},
						{"time":5.833333333333333,"value":12},
						{"time":6,"value":12},
						{"time":6.833333333333333,"value":12},
						{"time":7,"value":12},
						{"time":7.833333333333333,"value":12},
						{"time":8,"value":12}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1001230710194815"
				},
				{
					"keyframes":[
						{"time":0,"value":-56},
						{"time":0.8333333333333334,"value":-56},
						{"time":1,"value":-56},
						{"time":1.8333333333333333,"value":-56},
						{"time":2,"value":-56},
						{"time":2.8333333333333335,"value":-56},
						{"time":3,"value":-56},
						{"time":3.8333333333333335,"value":-56},
						{"time":4,"value":-56},
						{"time":4.833333333333333,"value":-56},
						{"time":5,"value":-56},
						{"time":5.833333333333333,"value":-56},
						{"time":6,"value":-56},
						{"time":6.833333333333333,"value":-56},
						{"time":7,"value":-56},
						{"time":7.833333333333333,"value":-56},
						{"time":8,"value":-56}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1001230710194815"
				},
				{
					"keyframes":[
						{"time":-0.5,"value":14},
						{"time":0.18333333333333332,"value":14},
						{"time":0.3333333333333333,"value":14},
						{"time":0.5,"value":14},
						{"time":1.1833333333333333,"value":14},
						{"time":1.3333333333333333,"value":14},
						{"time":1.5,"value":14},
						{"time":2.183333333333333,"value":14},
						{"time":2.3333333333333335,"value":14},
						{"time":2.5,"value":14},
						{"time":3.183333333333333,"value":14},
						{"time":3.3333333333333335,"value":14},
						{"time":3.5,"value":14},
						{"time":4.183333333333334,"value":14},
						{"time":4.333333333333333,"value":14},
						{"time":4.5,"value":14},
						{"time":5.183333333333334,"value":14},
						{"time":5.333333333333333,"value":14},
						{"time":5.5,"value":14}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3249685385429677"
				},
				{
					"keyframes":[
						{"time":-0.5,"value":-60},
						{"time":0.18333333333333332,"value":-60},
						{"time":0.3333333333333333,"value":-60},
						{"time":0.5,"value":-60},
						{"time":1.1833333333333333,"value":-60},
						{"time":1.3333333333333333,"value":-60},
						{"time":1.5,"value":-60},
						{"time":2.183333333333333,"value":-60},
						{"time":2.3333333333333335,"value":-60},
						{"time":2.5,"value":-60},
						{"time":3.183333333333333,"value":-60},
						{"time":3.3333333333333335,"value":-60},
						{"time":3.5,"value":-60},
						{"time":4.183333333333334,"value":-60},
						{"time":4.333333333333333,"value":-60},
						{"time":4.5,"value":-60},
						{"time":5.183333333333334,"value":-60},
						{"time":5.333333333333333,"value":-60},
						{"time":5.5,"value":-60}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3249685385429677"
				},
				{
					"keyframes":[
						{"time":0,"value":28.999999999999943},
						{"time":0.18333333333333332,"value":-40.99999999999971},
						{"time":0.5,"value":28.999999999999943},
						{"time":0.6833333333333333,"value":-40.99999999999971},
						{"time":1,"value":28.999999999999943},
						{"time":1.1833333333333333,"value":-40.99999999999971},
						{"time":1.5,"value":28.999999999999943},
						{"time":1.6833333333333333,"value":-40.99999999999971},
						{"time":2,"value":28.999999999999943},
						{"time":2.183333333333333,"value":-40.99999999999971},
						{"time":2.5,"value":28.999999999999943},
						{"time":2.683333333333333,"value":-40.99999999999971},
						{"time":3,"value":28.999999999999943},
						{"time":3.183333333333333,"value":-40.99999999999971},
						{"time":3.5,"value":28.999999999999943},
						{"time":3.683333333333333,"value":-40.99999999999971},
						{"time":4,"value":28.999999999999943}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"8391582935630722"
				},
				{
					"keyframes":[
						{"time":0,"value":50},
						{"time":0.5,"value":50},
						{"time":1,"value":50},
						{"time":1.5,"value":50},
						{"time":2,"value":50},
						{"time":2.5,"value":50},
						{"time":3,"value":50},
						{"time":3.5,"value":50},
						{"time":4,"value":50}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2384190589896712"
				},
				{
					"keyframes":[
						{"time":0,"value":12},
						{"time":0.5,"value":12},
						{"time":1,"value":12},
						{"time":1.5,"value":12},
						{"time":2,"value":12},
						{"time":2.5,"value":12},
						{"time":3,"value":12},
						{"time":3.5,"value":12},
						{"time":4,"value":12}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"2384190589896712"
				},
				{
					"keyframes":[
						{"time":0,"value":-10},
						{"time":0.5,"value":-10},
						{"time":1.5,"value":-10},
						{"time":2.5,"value":-10},
						{"time":3.5,"value":-10},
						{"time":4,"value":-10}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7554277963686835"
				},
				{
					"keyframes":[
						{"time":0,"value":4},
						{"time":0.5,"value":4},
						{"time":1.5,"value":4},
						{"time":2.5,"value":4},
						{"time":3.5,"value":4},
						{"time":4,"value":4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7554277963686835"
				},
				{
					"keyframes":[
						{"time":0,"value":-25.999999999999773},
						{"time":0.5,"value":-25.999999999999773},
						{"time":1.5,"value":-25.999999999999773},
						{"time":2.5,"value":-25.999999999999773},
						{"time":3.5,"value":-25.999999999999773},
						{"time":4,"value":-25.999999999999773}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6553804298258501"
				},
				{
					"keyframes":[
						{"time":0,"value":-11},
						{"time":1.5,"value":-11},
						{"time":3.5,"value":-11},
						{"time":4,"value":-11}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6553804298258501"
				},
				{
					"keyframes":[
						{"time":0,"value":-21},
						{"time":0.5,"value":-25.9665461232594},
						{"time":1,"value":-21},
						{"time":1.5,"value":-25.9665461232594},
						{"time":2,"value":-21},
						{"time":2.5,"value":-25.9665461232594},
						{"time":3,"value":-21},
						{"time":3.5,"value":-25.9665461232594},
						{"time":4,"value":-21}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6920407712169353"
				},
				{
					"keyframes":[
						{"time":0,"value":-20,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":0.5,
							"value":-19.90092783504243,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":1,"value":-20,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":1.5,
							"value":-19.90092783504243,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":-20,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":2.5,
							"value":-19.90092783504243,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":3,"value":-20,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{
							"time":3.5,
							"value":-19.90092783504243,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":4,"value":-20,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6920407712169353"
				},
				{
					"keyframes":[
						{"time":0,"value":43.27080992980978},
						{
							"time":0.5,
							"value":52.270809929809666,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":1,"value":34.88309553887801},
						{
							"time":1.5,
							"value":52.270809929809666,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":43.27080992980978},
						{
							"time":2.5,
							"value":52.270809929809666,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":3,"value":34.88309553887801},
						{
							"time":3.5,
							"value":52.270809929809666,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":4,"value":43.27080992980978}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7499394871464999"
				},
				{
					"keyframes":[
						{"time":0,"value":62.1937780665519},
						{"time":0.25,"value":76},
						{
							"time":0.5,
							"value":68.19377806655201,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":0.75,"value":76},
						{"time":1,"value":62.1937780665519,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":1.25,"value":76},
						{
							"time":1.5,
							"value":68.19377806655201,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":1.75,"value":76},
						{"time":2,"value":62.1937780665519},
						{"time":2.25,"value":76},
						{
							"time":2.5,
							"value":68.19377806655201,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":2.75,"value":76},
						{"time":3,"value":62.1937780665519,"leftHandleValue":0,"leftHandleSpan":0.4,"rightHandleValue":0,"rightHandleSpan":0.4},
						{"time":3.25,"value":76},
						{
							"time":3.5,
							"value":68.19377806655201,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":3.75,"value":76},
						{"time":4,"value":62.1937780665519}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7499394871464999"
				},
				{
					"keyframes":[
						{"time":0.4,"value":0},
						{"time":0.6666666666666666,"value":12.000000000000057},
						{"time":2.4,"value":0},
						{"time":2.6666666666666665,"value":12.000000000000057},
						{"time":4,"value":0}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"8525312094228609"
				},
				{
					"keyframes":[
						{"time":0.4,"value":0},
						{"time":0.6666666666666666,"value":-4.000000000000227},
						{"time":4,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"8525312094228609"
				},
				{
					"keyframes":[
						{"time":0.4,"value":22},
						{"time":0.85,"value":29.999999999999318},
						{"time":2.4,"value":22},
						{"time":2.85,"value":29.999999999999318},
						{"time":4,"value":22}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"8525312094228609"
				},
				{
					"keyframes":[
						{"time":0.4,"value":-5},
						{"time":0.6666666666666666,"value":3.0000000000004547},
						{"time":4,"value":-5}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9003131496764060"
				},
				{
					"keyframes":[
						{"time":0,"value":16},
						{"time":0.45,"value":23.000000000000114},
						{"time":2,"value":16},
						{"time":2.45,"value":23.000000000000114},
						{"time":4,"value":16}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9003131496764060"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.26666666666666666,"value":-17.000000000000114},
						{"time":2,"value":0},
						{"time":2.2666666666666666,"value":-17.000000000000114},
						{"time":4,"value":0}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"9003131496764060"
				},
				{
					"keyframes":[
						{"time":0,"value":2},
						{"time":0.5333333333333333,"value":-0.9999999999994316},
						{"time":2.6,"value":-0.9999999999994316},
						{"time":2.65,"value":2},
						{"time":4,"value":2}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3935974948706458"
				},
				{
					"keyframes":[
						{"time":0,"value":2},
						{"time":0.5333333333333333,"value":-2.209999999999999},
						{"time":2.6,"value":-2.209999999999999},
						{"time":2.65,"value":2},
						{"time":4,"value":2}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3935974948706458"
				},
				{
					"keyframes":[
						{"time":0,"value":3},
						{"time":0.5333333333333333,"value":-6.18},
						{"time":2.6,"value":-6.18},
						{"time":2.65,"value":3},
						{"time":4,"value":3}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9581766268073749"
				},
				{
					"keyframes":[
						{"time":0,"value":-1},
						{"time":2.65,"value":-1},
						{"time":4,"value":-1}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9581766268073749"
				},
				{
					"type":"boolean",
					"keyframes":[
						{"time":2.3333333333333335,"value":false}
					],
					"propertyPath":["enabled"],
					"sceneObjectUid":"3201523667536051"
				},
				{
					"keyframes":[
						{"time":0,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3201523667536051"
				},
				{
					"keyframes":[
						{"time":0.8333333333333334,"value":0}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6320565315338379"
				},
				{
					"keyframes":[
						{"time":0,"value":1.1},
						{"time":0.18333333333333332,"value":0.9},
						{"time":0.5,"value":1.1},
						{"time":0.6833333333333333,"value":0.9},
						{"time":1,"value":1.1},
						{"time":1.1833333333333333,"value":0.9},
						{"time":1.5,"value":1.1},
						{"time":1.6833333333333333,"value":0.9},
						{"time":2,"value":1.1},
						{"time":2.183333333333333,"value":0.9},
						{"time":2.5,"value":1.1},
						{"time":2.683333333333333,"value":0.9},
						{"time":3,"value":1.1},
						{"time":3.183333333333333,"value":0.9},
						{"time":3.5,"value":1.1},
						{"time":3.683333333333333,"value":0.9},
						{"time":4,"value":1.1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"6320565315338379"
				},
				{
					"keyframes":[
						{"time":0.8333333333333334,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"6320565315338379"
				},
				{
					"keyframes":[
						{"time":0,"value":16.999999999999943},
						{"time":0.16666666666666666,"value":-0.8991862025184969},
						{"time":0.5,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":0.6666666666666666,"value":-0.8991862025184969},
						{"time":1,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":1.1666666666666667,"value":-0.8991862025184969},
						{"time":1.5,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":1.6666666666666667,"value":-0.8991862025184969},
						{"time":2,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":2.1666666666666665,"value":-0.8991862025184969},
						{"time":2.5,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":2.6666666666666665,"value":-0.8991862025184969},
						{"time":3,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":3.1666666666666665,"value":-0.8991862025184969},
						{"time":3.5,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4},
						{"time":3.6666666666666665,"value":-0.8991862025184969},
						{"time":4,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"8391582935630722"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.18333333333333332,"value":24.999999999999943},
						{"time":0.5,"value":0},
						{"time":0.6833333333333333,"value":24.999999999999943},
						{"time":1,"value":0},
						{"time":1.1833333333333333,"value":24.999999999999943},
						{"time":1.5,"value":0},
						{"time":1.6833333333333333,"value":24.999999999999943},
						{"time":2,"value":0},
						{"time":2.183333333333333,"value":24.999999999999943},
						{"time":2.5,"value":0},
						{"time":2.683333333333333,"value":24.999999999999943},
						{"time":3,"value":0},
						{"time":3.183333333333333,"value":24.999999999999943},
						{"time":3.5,"value":0},
						{"time":3.683333333333333,"value":24.999999999999943},
						{"time":4,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"8391582935630722"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/Incisorsaurus.construct.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim/PNGs.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/SampleAssets/SampleParticles/SampleParticle.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.
- imageConfigurations.alphaThreshold is 0 instead of the default null.
- imageConfigurations.spriteSheet is "SampleParticles" instead of the default null.
- imageConfigurations.trimMode is "none" instead of the default null.

Assets/General (autoloaded)/SampleAssets/SampleParticles/SampleParticle2.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.
- imageConfigurations.spriteSheet is "SampleParticles" instead of the default null.

Assets/General (autoloaded)/SampleAssets/icons.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.
- imageConfigurations.shapify is true instead of the default null.
- imageConfigurations.shapifyOptimizationLevel is 0.5 instead of the default null.
- imageConfigurations.spriteSheet is "icons_sheet" instead of the default null.

Assets/General (autoloaded)/SampleAssets/IncisorsaurusAnim.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.
- imageConfigurations.resolutionScaleX is 1 instead of the default null.
- imageConfigurations.resolutionScaleY is 1 instead of the default null.

Assets/General (autoloaded)/SampleAssets/SampleFont.ttf.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.
- imageConfigurations.allowAdditiveTrimBuffer is true instead of the default null.
- imageConfigurations.applyAssetPackageScaling is false instead of the default null.
- imageConfigurations.shapify is true instead of the default null.
- imageConfigurations.shapifyEdgeRange is 10 instead of the default null.
- imageConfigurations.spriteSheet is "SampleFont" instead of the default null.
- imageConfigurations.trimBuffer is 10 instead of the default null.
- imageConfigurations.unitsPerPixelX is 0.2 instead of the default null.
- imageConfigurations.unitsPerPixelY is 0.2 instead of the default null.
- imageConfigurations.unitsPerPixelZ is 0.2 instead of the default null.

Assets/General (autoloaded)/SampleAssets/SampleParticles.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/stone-granite-4/stone-granite-4-NORM.png.ncData
------------------------------------------------------------
default ncData file

Assets/General (autoloaded)/stone-granite-4/stone-granite-4-TEX.png.ncData
------------------------------------------------------------
default ncData file

Assets/General (autoloaded)/Coin.obj.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.unitsPerPixelX is 300 instead of the default null.
- imageConfigurations.unitsPerPixelY is 300 instead of the default null.
- imageConfigurations.unitsPerPixelZ is 300 instead of the default null.

Assets/General (autoloaded)/CoinDiffuse.png.ncData
------------------------------------------------------------
default ncData file

Assets/General (autoloaded)/CoinFountain.particleSysDef.ncData
------------------------------------------------------------
default ncData file

Assets/General (autoloaded)/CoinNormals.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.downscalingMode is "mipmapLinear" instead of the default null.
- imageConfigurations.resolutionScaleX is 0.5 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.5 instead of the default null.

Assets/General (autoloaded)/ExampleParticleSystem.particleSysDef.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/General.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/MainScene.layers
------------------------------------------------------------
{"layers":["ExampleViewBack","Examples","ExampleViewFront"]}

Assets/General (autoloaded)/MainScene.layers.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/matcap.png.ncData
------------------------------------------------------------
default ncData file

Assets/General (autoloaded)/SampleAssets.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/Sound0.wav.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/Sound1.wav.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded)/stone-granite-4.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.resolutionScaleX is 0.25 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.25 instead of the default null.
- imageConfigurations.wrapModeH is "repeat" instead of the default null.
- imageConfigurations.wrapModeV is "repeat" instead of the default null.

Assets/General (autoloaded)/suzanne.obj.ncData
------------------------------------------------------------
default ncData file

Assets/002 TextBox.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.
- loadingTier is 2 instead of the default null.

Assets/005 Sprite Setter.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.
- loadingTier is 5 instead of the default null.

Assets/CodeAssets.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.

Assets/General (autoloaded).ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.
- loadingTier is 0.25 instead of the default null.

ProjectCode/IncisorExamples/001 TextAssembly.js
------------------------------------------------------------
class TextAssemblyExample extends IncisorExample {
    constructor(parent, name) {
        // Super
        super(parent, name);
        // Description
        this.descriptionText = "A TextAssembly is a specialized SceneObject that presents a group of GraphicObjects as text. TextAssemblies can be less efficient than TextBoxes, as they result in more SceneObjects being rendered, but TextAssemblies have the advantage of being able to manipulate individual characters freely. The example below uses WaitThens and Motions to move the characters.";
        // Content
        this.setupTextAssembly();
    }
    setupTextAssembly() {
        // Create a new text assembly using the TextAssembly class.
        this.textAssembly = new TextAssembly(this, "TextAssemblyExample");
        // Create a new TextFormat for our text assembly and set it.
        let textAssemblyFormat = new TextFormat(nc.fontNames.SampleFont, 2.5, 2.5);
        this.textAssembly.setTextFormat(textAssemblyFormat);
        // Format various paramaters of the text assembly to values of our choosing.
        this.textAssembly.horizontalJustification = "center";
        this.textAssembly.verticalJustification = "center";
        this.textAssembly.wrapToFit = false;
        this.textAssembly.boxHeight = 300;
        this.textAssembly.boxWidth = 700;
        this.textAssembly.string = "Text Assembly!!";
        // Scale up the entire animation using a swoop.
        // Check out the Swoopers and Motions example for a closer look into this functionality.
        this.textAssembly.scale.swoop.all(2);
        this.moveCharacters();
    }
    moveCharacters() {
        // The getCharacters function returns an array containing the list of GraphicObjects that comprise the TextAssembly's current string.
        this.characters = this.textAssembly.getCharacters();
        let stagger = 0;
        // Loop through all of the characters and add a motion to them, staggering the motion using a waitThen.
        for (let i = 0; i < this.characters.length; i++) {
            let yPosition = this.characters[0].position.y;
            nc.waitThen(stagger, nc, "addMotion", [this.characters[i].position, "y", yPosition - 50, yPosition + 50, 1, nc.motionTypes.Pendulum]);
            stagger += .1;
        }
    }
}
CODE.runBeforeInit___begin;
if (pr.exampleList === undefined) {
    pr.exampleList = [];
}
pr.exampleList.push({ classDefinition: TextAssemblyExample, displayName: "001 TextAssembly", name: "TextAssembly" });
CODE.runBeforeInit___end;


ProjectCode/IncisorExamples/002 TextBox.js
------------------------------------------------------------
class TextBoxExample extends IncisorExample {
    constructor(parent, name) {
        // Super
        super(parent, name);
        // Description
        this.descriptionText = "A TextBox is a specialized Button that that renders text directly to the GraphicAsset/RenderTarget it is connected to. This example demonstrates how a TextBox's string can be constantly updated using an AppEvent, and reset using a Button callback.";
        // Content
        nc.loadTier(nc.loadingTiers[2]);
        nc.addTierLoadedCallback(nc.loadingTiers[2], this, "setupTextBox");
    }
    setupTextBox() {
        // Create a new text box using the TextBox class.
        this.exampleTextBox = new TextBox(this, "exampleTextBox");
        // create a new TextFormat for our text box and set it. 
        let textBoxMeterFormat = new TextFormat(nc.fontNames.CenterWinFont);
        this.exampleTextBox.setTextFormat(textBoxMeterFormat);
        // Format various paramaters of the text assembly to values of our choosing.
        this.exampleTextBox.boxWidth = 600;
        this.exampleTextBox.boxHeight = 300;
        this.exampleTextBox.horizontalJustification = "center";
        this.exampleTextBox.verticalJustification = "center";
        this.exampleTextBox.numHorizontalGridSegments = 40;
        this.exampleTextBox.numVerticalGridSegments = 20;
        // Define an initial value for the text box and convert it to a string. 
        this.textBoxValue = 0;
        this.exampleTextBox.string = this.textBoxValue.toString();
        // Enable the button functionality of the text box.
        this.exampleTextBox.buttonActive = true;
        // Add an updater to change the value of the text box using the built-in "fixedUpdate" app event. "Fixedupdate" by default is called once every frame.
        nc.appEvents.fixedUpdate.addCallback(this, "increment");
        // Add a button press callback that resets the text box.
        this.exampleTextBox.addPressCallback(this, "resetCallback", [this.exampleTextBox]);
        // Scale up the text box using a swoop.
        // Check out the Swoopers and Motions example for a closer look into this functionality.
        this.exampleTextBox.scale.swoop.all(2);
        // nc.effectNodes.
    }
    // This is the callback function we gave to the "fixedUpdate" app event.
    increment() {
        this.textBoxValue += 1;
        this.exampleTextBox.string = this.textBoxValue.toString();
    }
    // This is the function we defined as the button press callback.
    resetCallback(event, camera, textBoxReference) {
        this.textBoxValue = 0;
        textBoxReference.string = this.textBoxValue.toString();
    }
}
CODE.runBeforeInit___begin;
if (pr.exampleList === undefined) {
    pr.exampleList = [];
}
pr.exampleList.push({ classDefinition: TextBoxExample, displayName: "002 TextBox", name: "TextBox" });
CODE.runBeforeInit___end;


ProjectCode/IncisorExamples/003 SwoopersAndMotions.js
------------------------------------------------------------
class SwoopersAndMotionsExample extends IncisorExample {
    constructor(parent, name) {
        // Super
        super(parent, name);
        // Description
        this.descriptionText = "Swooping and Motion are both ways to interpolate numeric values over time. Motion initiates a perpetual movement while swooping is finite. Swooping and Motion can be applied to any numeric value or property. TweenTypes and MotionTypes can also be used to customize interpolation. Additional TweenTypes and MotionTypes can be added to the project via the Library menu. Click on the icons below for examples of Swooping, Motion, TweenTypes and MotionTypes.";
        // Setup for example functionality.
        this.setup();
    }
    // These functions use the swoop method on the button's scale property. Calling swoop.all will apply the swoop to each parameter of the property at once.
    swoopScaleUp() {
        // Using swoop's callback function, we'll add a new press callback to our button that scales it back down.
        this.swoopObject0.scale.swoop.all(1.5, .3, undefined, this.swoopObject0, "addPressCallback", [this, "swoopScaleDown"]);
        // In each function we need to remove the respective press callback from the button so that the callbacks don't conflict with each other.      
        this.swoopObject0.removePressCallback(this, "swoopScaleUp");
    }
    swoopScaleDown() {
        this.swoopObject0.scale.swoop.all(1, .3, undefined, this.swoopObject0, "addPressCallback", [this, "swoopScaleUp"]);
        this.swoopObject0.removePressCallback(this, "swoopScaleDown");
    }
    // These functions use the swoop method on the button's position property. This time we are only swooping the x position of our button.
    swoopPosition() {
        // We can also use tweenTypes to customize our swoops. In these swoops, the tweenType is no longer undefined, and has been set to "WindUpOvershoot." 
        // TweenTypes can be added to the project via the Library menu in the inspector.
        this.swoopObject1.position.swoop.x(400, .3, nc.tweenTypes.WindupOvershoot, this.swoopObject1, "addPressCallback", [this, "returnPosition"]);
        this.swoopObject1.removePressCallback(this, "swoopPosition");
    }
    returnPosition() {
        this.swoopObject1.position.swoop.x(200, .3, nc.tweenTypes.WindupOvershoot, this.swoopObject1, "addPressCallback", [this, "swoopPosition"]);
        this.swoopObject1.removePressCallback(this, "returnPosition");
    }
    // This function uses motions instead of swoopers. Motions are added the same way as swoopers. The major difference between the two is that motions are perpetual and swoopers are finite.
    startColorMotion() {
        // By varying the motion speed of each motion, we can can create a sense of randomness.
        this.swoopObject2.colorMultiply.addMotion.red(0, 1, 0.04);
        this.swoopObject2.colorMultiply.addMotion.green(0, 1, 0.09);
        this.swoopObject2.colorMultiply.addMotion.blue(0, 1, 1.5);
    }
    // This function uses the swoop method on a value independent of the GraphicObject's built-in properties via swoopValue. In this case, we'll swoop the speed of a motion to make it progressively more extreme. 
    startRotation() {
        // In order to swoop any parameters of our motion, we need to get an object instance of the motion.
        let motion = this.swoopObject3.rotation.addMotion.z(-180, 180, .1, nc.motionTypes.Pendulum);
        // Now that we have our motion instance, we'll use swoopValue on the motionSpeed parameter of the motion. 
        nc.swoopValue(motion, "motionSpeed", 1, 5);
    }
    // -- THIS IS SETUP FOR BUTTON FUNCTIONALITY -- //
    setup() {
        // Create a new Button using the Button class.
        this.swoopObject0 = new Button(nc.graphicAssets.Logo, this, "SwoopObject0");
        // Position.swoop.each with a duration of 0 is a convenient way to set all of the object's position parameters at once using a single line of code.
        this.swoopObject0.position.swoop.each([-200, 200, 0], 0);
        // Add a press callback to our button.
        this.swoopObject0.addPressCallback(this, "swoopScaleUp");
        // Repeat this process for a few more buttons.
        this.swoopObject1 = new Button(nc.graphicAssets.Logo, this, "SwoopObject1");
        this.swoopObject1.position.swoop.each([200, 200, 0], 0);
        this.swoopObject1.addPressCallback(this, "swoopPosition");
        this.swoopObject2 = new Button(nc.graphicAssets.Logo, this, "SwoopObject2");
        this.swoopObject2.position.swoop.each([-200, -200, 0], 0);
        this.swoopObject2.addPressCallback(this, "startColorMotion");
        this.swoopObject3 = new Button(nc.graphicAssets.Logo, this, "SwoopObject3");
        this.swoopObject3.position.swoop.each([200, -200, 0], 0);
        this.swoopObject3.addPressCallback(this, "startRotation");
    }
}
CODE.runBeforeInit___begin;
if (pr.exampleList === undefined) {
    pr.exampleList = [];
}
pr.exampleList.push({ classDefinition: SwoopersAndMotionsExample, displayName: "003 SwoopersAndMotions", name: "SwoopersAndMotions" });
CODE.runBeforeInit___end;


ProjectCode/IncisorExamples/004 Sounds.js
------------------------------------------------------------
class SoundsExample extends IncisorExample {
    constructor(parent, name) {
        // Super
        super(parent, name);
        // Description
        this.descriptionText = "A Sound is a specialized playback controller that manages the playback of sound assets. Click on the Buttons below to explore some different functionalities of Sounds.";
        // Setup for example functionality.
        this.setup();
    }
    playSoundOnce() {
        // PlayOnce will play the sound from the beginning one time only and then stop the sound. 
        // PlayOnce also takes a completion callback to be executed once the sound has played through. We'll use this to swoop the background color of the button back to normal. 
        nc.sounds.Sound0.playOnce(this.playOnceButtonBackground.colorMultiply.swoop, "all", [1]);
        // Swoop the background color of the button to indicate it's been pressed.
        // Check out the Swoopers and Motions example for a closer look into this functionality.
        this.playOnceButtonBackground.colorMultiply.swoop.each([.5, 1, .5, 1]);
        // Return the colors of the other buttons to normal. 
        this.playButtonBackground.colorMultiply.swoop.all(1);
        this.pauseButtonBackground.colorMultiply.swoop.all(1);
    }
    playSound() {
        // Play will play the sound continuously in a loop. If the sound is paused, play will resume it from the point at which it was paused.
        nc.sounds.Sound0.play();
        // If this button was pressed during "playOnce", the lazyStop parameter of the sound will still be set to true. 
        // We need to change it back to false so that the sound plays continuously without stopping.
        // However, if the sound was paused, we want our play button to resume the sound from the point it was paused. We don't stop and restart the sound in this case.
        // We can check this against the sound's playbackState parameter.
        if (nc.sounds.Sound0.playbackState !== "paused") {
            nc.sounds.Sound0.lazyStop = false;
            // We also need to make sure the pause button's functionality is reset appropriately. 
            this.pauseButton.removePressCallback(this, "unPauseSound");
            this.pauseButton.addPressCallback(this, "pauseSound");
        }
        // Swoop the color of the button to indicate it's been pressed.
        this.playButtonBackground.colorMultiply.swoop.each([.5, 1, .5, 1]);
        // Return the colors of the other buttons to normal. 
        this.playOnceButtonBackground.colorMultiply.swoop.all(1);
        this.pauseButtonBackground.colorMultiply.swoop.all(1);
    }
    stopSound() {
        // Stop immediately stops the sound and sets the time value to start time, so when it is played again, it will start from its beginning. 
        nc.sounds.Sound0.stop();
        // Swoop the background color of the button to indicate it's been pressed.
        this.stopButtonBackground.colorMultiply.swoop.each([.5, 1, .5, 1], .05, undefined, this.stopButtonBackground.colorMultiply.swoop, "all", [1, .05]);
        // Return the colors of the other buttons to normal. 
        this.playOnceButtonBackground.colorMultiply.swoop.all(1);
        this.playButtonBackground.colorMultiply.swoop.all(1);
        this.pauseButtonBackground.colorMultiply.swoop.all(1);
    }
    pauseSound() {
        // Only pause the sound if it is already playing. Otherwise nothing should happen. 
        if (nc.sounds.Sound0.playbackState === "playing") {
            // Pause will pause the progression of the time value, so when it is played again it will resume from the point at which it was paused.
            nc.sounds.Sound0.pause();
            // We need to remove this button press callback and add a new one so that the button resumes the sound when pressed again. 
            this.pauseButton.removePressCallback(this, "pauseSound");
            this.pauseButton.addPressCallback(this, "unPauseSound");
            // Swoop the background color of the button to indicate it's been pressed.
            this.pauseButtonBackground.colorMultiply.swoop.each([.5, 1, .5, 1]);
        }
    }
    unPauseSound() {
        // Resume playing the sound.
        nc.sounds.Sound0.play();
        // We need to remove this button press callback and add a new one so that the button pauses the sound when pressed again. 
        this.pauseButton.removePressCallback(this, "unPauseSound");
        this.pauseButton.addPressCallback(this, "pauseSound");
        // Return the color of the button to normal.
        this.pauseButtonBackground.colorMultiply.swoop.all(1);
    }
    fadeSound() {
        // Other than the basic playback functions, we can also influence sound paramaters through things such as swooping. 
        // We'll use the swoopValue function on the mainVolume parameter of the sound to fade it out. Then we can use the callback function of the swoop to stop the sound and reset its volume.
        // If the sound is paused or stopped, there's nothing to fade, so we'll only exexute the swoop if the sound is playing. 
        if (nc.sounds.Sound0.playbackState === "playing") {
            nc.swoopValue(nc.sounds.Sound0, "mainVolume", 0, 2, undefined, this, "stopAndResetVolume");
            // Swoop the background color of the button to indicate it's been pressed.
            this.fadeButtonBackground.colorMultiply.swoop.each([.5, 1, .5, 1]);
        }
    }
    stopAndResetVolume() {
        // Stop the sound and set its volume back to 1.
        nc.sounds.Sound0.stop();
        nc.sounds.Sound0.mainVolume = 1;
        // Return the colors of the buttons to normal. 
        this.fadeButtonBackground.colorMultiply.swoop.all(1);
        this.playOnceButtonBackground.colorMultiply.swoop.all(1);
        this.playButtonBackground.colorMultiply.swoop.all(1);
        this.pauseButtonBackground.colorMultiply.swoop.all(1);
    }
    // -- THIS IS SETUP FOR BUTTON FUNCTIONALITY -- //
    setup() {
        // In this example we'll be using text boxes as buttons to switch around the playback functionality of our main button.
        // Create a new text box using the TextBox class.
        this.playOnceButton = new TextBox(this, "Play Once");
        this.playOnceButton.string = "PlayOnce";
        this.playOnceButton.boxWidth = 500;
        this.playOnceButton.horizontalJustification = nc.constants.justifications.center;
        this.playOnceButton.position.swoop.each([-315, 200, 1]);
        // Enable the button functionality of the text box.
        this.playOnceButton.buttonActive = true;
        // Add a press callback function to the button.
        this.playOnceButton.addPressCallback(this, "playSoundOnce");
        // Create a graphic expanded background to make the button look a bit nicer.
        this.playOnceButtonBackground = nc.addGraphicObject(nc.graphicAssets.NeonButton, this.playOnceButton, "PlayOnceButtonBackground");
        this.playOnceButtonBackground.configureGraphicExpander();
        this.playOnceButtonBackground.graphicExpander.expandedWidth = 500;
        this.playOnceButtonBackground.graphicExpander.expandedHeight = 75;
        this.playOnceButtonBackground.subLayer = -.1;
        // Repeat this process for the rest of the buttons.
        this.playButton = new TextBox(this, "Play");
        this.playButton.string = "Play";
        this.playButton.boxWidth = 500;
        this.playButton.horizontalJustification = nc.constants.justifications.center;
        this.playButton.position.swoop.each([315, 200, 1]);
        this.playButton.buttonActive = true;
        this.playButton.addPressCallback(this, "playSound");
        this.playButtonBackground = nc.addGraphicObject(nc.graphicAssets.NeonButton, this.playButton, "PlayButtonBackground");
        this.playButtonBackground.configureGraphicExpander();
        this.playButtonBackground.graphicExpander.expandedWidth = 500;
        this.playButtonBackground.graphicExpander.expandedHeight = 75;
        this.playButtonBackground.subLayer = -.1;
        this.stopButton = new TextBox(this, "Stop");
        this.stopButton.string = "Stop";
        this.stopButton.boxWidth = 500;
        this.stopButton.horizontalJustification = nc.constants.justifications.center;
        this.stopButton.position.swoop.each([-315, 0, 1]);
        this.stopButton.buttonActive = true;
        this.stopButton.addPressCallback(this, "stopSound");
        this.stopButtonBackground = nc.addGraphicObject(nc.graphicAssets.NeonButton, this.stopButton, "StopButtonBackground");
        this.stopButtonBackground.configureGraphicExpander();
        this.stopButtonBackground.graphicExpander.expandedWidth = 500;
        this.stopButtonBackground.graphicExpander.expandedHeight = 75;
        this.stopButtonBackground.subLayer = -.1;
        this.pauseButton = new TextBox(this, "Pause");
        this.pauseButton.string = "Pause";
        this.pauseButton.boxWidth = 500;
        this.pauseButton.horizontalJustification = nc.constants.justifications.center;
        this.pauseButton.position.swoop.each([315, 0, 1]);
        this.pauseButton.buttonActive = true;
        this.pauseButton.addPressCallback(this, "pauseSound");
        this.pauseButtonBackground = nc.addGraphicObject(nc.graphicAssets.NeonButton, this.pauseButton, "PauseButtonBackground");
        this.pauseButtonBackground.configureGraphicExpander();
        this.pauseButtonBackground.graphicExpander.expandedWidth = 500;
        this.pauseButtonBackground.graphicExpander.expandedHeight = 75;
        this.pauseButtonBackground.subLayer = -.1;
        this.fadeButton = new TextBox(this, "Fade");
        this.fadeButton.string = "FadeOut";
        this.fadeButton.boxWidth = 500;
        this.fadeButton.horizontalJustification = nc.constants.justifications.center;
        this.fadeButton.position.swoop.each([0, -200, 1]);
        this.fadeButton.buttonActive = true;
        this.fadeButton.addPressCallback(this, "fadeSound");
        this.fadeButtonBackground = nc.addGraphicObject(nc.graphicAssets.NeonButton, this.fadeButton, "FadeButtonBackground");
        this.fadeButtonBackground.configureGraphicExpander();
        this.fadeButtonBackground.graphicExpander.expandedWidth = 500;
        this.fadeButtonBackground.graphicExpander.expandedHeight = 75;
        this.fadeButtonBackground.subLayer = -.1;
        // Create a new text format for our text boxes using the TextFormat class.
        this.buttonTextFormat = new TextFormat(nc.fontNames.ExampleFont, .25, .25, .2);
        this.buttonTextFormat.characterMaterial.colorMultiply.swoop.each([1, .8, .8, 1]);
        // Apply our text format to all of the buttons.
        this.playOnceButton.setTextFormat(this.buttonTextFormat);
        this.playButton.setTextFormat(this.buttonTextFormat);
        this.stopButton.setTextFormat(this.buttonTextFormat);
        this.pauseButton.setTextFormat(this.buttonTextFormat);
        this.fadeButton.setTextFormat(this.buttonTextFormat);
        // When the example is disabled, stop any sound that's playing.
        this.addEnabledStateChangeCallback(this, "enabledStateChangeCallback");
    }
    enabledStateChangeCallback(state) {
        if (state === false) {
            nc.sounds.Sound0.stop();
        }
    }
}
CODE.runBeforeInit___begin;
if (pr.exampleList === undefined) {
    pr.exampleList = [];
}
pr.exampleList.push({ classDefinition: SoundsExample, displayName: "004 Sounds", name: "Sounds" });
CODE.runBeforeInit___end;


ProjectCode/IncisorExamples/005 SpriteSetter.js
------------------------------------------------------------
class SpriteSetterExample extends IncisorExample {
    constructor(parent, name) {
        // Super
        super(parent, name);
        // Description
        this.descriptionText = "A SpriteSetter is a PlaybackController that switches a GraphicObject's graphicAsset between numerically sequential GraphicAssets. The resulting animation can be inspected and manipulated under 'SpriteSetter' within the 'Object' panel.";
        // Content
        nc.loadTier(nc.loadingTiers[5]);
        nc.addTierLoadedCallback(nc.loadingTiers[5], this, "setupSpriteAnim");
    }
    setupSpriteAnim() {
        // // Make a new GraphicObject using the first frame of the animation as the graphic asset.
        // // Check out Assets/Tier4 - SpriteSetter/CoinSequence for an example of how to name your assets for use as a sprite animation.
        this.spriteAnim = nc.addGraphicObject(nc.graphicAssets.CoinFlip_0, this, "SpriteSetterExample");
        // Call the configureSpriteSetter function on the graphic object and specify the key graphic asset.
        this.spriteAnim.configureSpriteSetter(nc.graphicAssets.CoinFlip_0, 60);
        // The play function plays the animation continuously without stopping.
        this.spriteAnim.spriteSetter.play();
        // Scale up the entire animation using a swoop.
        // Check out the Swoopers and Motions example for a closer look into this functionality.
        this.spriteAnim.scale.swoop.all(2);
    }
}
CODE.runBeforeInit___begin;
if (pr.exampleList === undefined) {
    pr.exampleList = [];
}
pr.exampleList.push({ classDefinition: SpriteSetterExample, displayName: "005 SpriteSetter", name: "SpriteSetter" });
CODE.runBeforeInit___end;


ProjectCode/IncisorExamples/006 ConstructWithTimelines.js
------------------------------------------------------------
class ConstructWithTimelinesExample extends IncisorExample {
    constructor(parent, name) {
        // Super
        super(parent, name);
        // Description
        this.descriptionText = "A Construct is a predefined collection of SceneObjects that can be built and arranged from within the inspector using the Construct panel without coding. Open a Construct panel and select 'Incisorsaurus' to edit this Construct. Constructs can be animated using Timelines, by assigning keyframes to properties associated with objects within the Construct. When a Timeline panel is open, selecting one of a Construct's Timelines will populate that Timeline in the Timeline panel. Constructs can have multiple Timelines and the transitions between the associated animations can be completely seamless, even with variable timing. Click the Buttons below to watch 'Incisorsaurus' switch between states smoothly.";
        // Setup for example functionality.
        this.setup();
    }
    addConstruct() {
        // Add a new instance of the Incisorsaurus construct.
        this.incisorSaurus = nc.constructDefs.Incisorsaurus.add(this, "IncisorSaurus");
        // Access any timelines associated with the construct using .timelines.
        // The default timeline of a construct is NeutralState. In order for playback controller functions to work, we need to set the weight of the timeline we want to manipulate.
        // If no weight is set, calling playback controller functions won't result in any visual changes.
        // Any weight not claimed by the construct's timelines is given to NeutralState.
        this.incisorSaurus.timelines.Idle.weight = 1;
        this.incisorSaurus.timelines.Idle.play();
        // Scale up the construce using a swoop. 
        // Check out the Swoopers and Motions example for a closer look into this functionality.
        this.incisorSaurus.scale.swoop.all(2);
    }
    playWalk() {
        // We can use the 'AndTakeWeight' functions to play a new timeline and swoop its weight up (and the other timelines' weights down) without having to set the weights separately.
        // Swooping the timeline weights will interpolate the animated values of objects within the construct from one timeline to another.
        // PlayAndTakeWeight will tween to the designated timeline over a given duration, then continuously loop it.
        this.incisorSaurus.timelines.Walk.playAndTakeWeight(1);
        // Swoop the background color of the button to indicate it's been pressed.
        this.walkButtonBackground.colorMultiply.swoop.each([.5, 1, .5, 1]);
        // Return the colors of the other buttons to normal. 
        this.runButtonBackground.colorMultiply.swoop.all(1);
        this.growlButtonBackground.colorMultiply.swoop.all(1);
        this.idleButtonBackground.colorMultiply.swoop.all(1);
    }
    playRun() {
        this.incisorSaurus.timelines.Run.playAndTakeWeight(.5);
        // Swoop the background color of the button to indicate it's been pressed.
        this.runButtonBackground.colorMultiply.swoop.each([.5, 1, .5, 1]);
        // Return the colors of the other buttons to normal. 
        this.walkButtonBackground.colorMultiply.swoop.all(1);
        this.growlButtonBackground.colorMultiply.swoop.all(1);
        this.idleButtonBackground.colorMultiply.swoop.all(1);
    }
    playGrowl() {
        // PlayOnceAndTakeWeight will tween to the designated timeline and play it once, then return to a designated timeline.
        // If returnToTimeline is left undefined, the timelines will return to the weights they had before PlayOnceAndTakeWeight was called.
        this.incisorSaurus.timelines.Growl.playOnceAndTakeWeight(.25, .25, undefined, this.growlButtonBackground.colorMultiply.swoop, "all", [1]);
        // Swoop the background color of the button to indicate it's been pressed.
        this.growlButtonBackground.colorMultiply.swoop.each([.5, 1, .5, 1]);
    }
    playIdle() {
        this.incisorSaurus.timelines.Idle.playAndTakeWeight(1);
        // Swoop the background color of the button to indicate it's been pressed.
        this.idleButtonBackground.colorMultiply.swoop.each([.5, 1, .5, 1]);
        // Return the colors of the other buttons to normal. 
        this.runButtonBackground.colorMultiply.swoop.all(1);
        this.growlButtonBackground.colorMultiply.swoop.all(1);
        ;
        this.walkButtonBackground.colorMultiply.swoop.all(1);
    }
    // -- THIS IS SETUP FOR BUTTON FUNCTIONALITY -- //
    setup() {
        // Call the function to set up the Incisorsaurus construct. 
        this.addConstruct();
        // In this example we'll be using text boxes as buttons to play with tweening between various timelines.
        this.walkButton = new TextBox(this.incisorSaurus, "PlayWalk");
        this.walkButton.string = "Walk";
        this.walkButton.boxWidth = 220;
        this.walkButton.horizontalJustification = nc.constants.justifications.center;
        this.walkButton.position.swoop.each([-300, -275, 1]);
        this.walkButton.buttonActive = true;
        this.walkButton.scale.scaleByFactor(.6);
        // Add a press callback to our button that executes a function to change the timeline.
        this.walkButton.addPressCallback(this, "playWalk");
        // Create a graphic expanded background to make the button look a bit nicer.
        this.walkButtonBackground = nc.addGraphicObject(nc.graphicAssets.NeonButton, this.walkButton, "WalkButtonBackground");
        this.walkButtonBackground.configureGraphicExpander();
        this.walkButtonBackground.graphicExpander.expandedWidth = 200;
        this.walkButtonBackground.graphicExpander.expandedHeight = 50;
        this.walkButtonBackground.subLayer = -.1;
        // Repeat this process for the rest of the buttons.
        this.runButton = new TextBox(this.incisorSaurus, "PlayWalk");
        this.runButton.string = "Run";
        this.runButton.boxWidth = 220;
        this.runButton.horizontalJustification = nc.constants.justifications.center;
        this.runButton.position.swoop.each([-99, -275, 1]);
        this.runButton.buttonActive = true;
        this.runButton.scale.scaleByFactor(.6);
        this.runButton.addPressCallback(this, "playRun");
        this.runButtonBackground = nc.addGraphicObject(nc.graphicAssets.NeonButton, this.runButton, "RunButtonBackground");
        this.runButtonBackground.configureGraphicExpander();
        this.runButtonBackground.graphicExpander.expandedWidth = 200;
        this.runButtonBackground.graphicExpander.expandedHeight = 50;
        this.runButtonBackground.subLayer = -.1;
        this.growlButton = new TextBox(this.incisorSaurus, "PlayWalk");
        this.growlButton.string = "Growl";
        this.growlButton.boxWidth = 220;
        this.growlButton.horizontalJustification = nc.constants.justifications.center;
        this.growlButton.position.swoop.each([99, -275, 1]);
        this.growlButton.buttonActive = true;
        this.growlButton.scale.scaleByFactor(.6);
        this.growlButton.addPressCallback(this, "playGrowl");
        this.growlButtonBackground = nc.addGraphicObject(nc.graphicAssets.NeonButton, this.growlButton, "GrowlButtonBackground");
        this.growlButtonBackground.configureGraphicExpander();
        this.growlButtonBackground.graphicExpander.expandedWidth = 200;
        this.growlButtonBackground.graphicExpander.expandedHeight = 50;
        this.growlButtonBackground.subLayer = -.1;
        this.idleButton = new TextBox(this.incisorSaurus, "PlayWalk");
        this.idleButton.string = "Idle";
        this.idleButton.boxWidth = 220;
        this.idleButton.horizontalJustification = nc.constants.justifications.center;
        this.idleButton.position.swoop.each([300, -275, 1]);
        this.idleButton.buttonActive = true;
        this.idleButton.scale.scaleByFactor(.6);
        this.idleButton.addPressCallback(this, "playIdle");
        this.idleButtonBackground = nc.addGraphicObject(nc.graphicAssets.NeonButton, this.idleButton, "IdleButtonBackground");
        this.idleButtonBackground.configureGraphicExpander();
        this.idleButtonBackground.graphicExpander.expandedWidth = 200;
        this.idleButtonBackground.graphicExpander.expandedHeight = 50;
        this.idleButtonBackground.subLayer = -.1;
        this.idleButtonBackground.colorMultiply.swoop.each([.5, 1, .5, 1]);
        // Create a new text format for our text boxes using the TextFormat class.
        this.buttonTextFormat = new TextFormat(nc.fontNames.ExampleFont, .2, .2, .2);
        this.buttonTextFormat.characterMaterial.colorMultiply.swoop.each([1, .8, .8, 1]);
        // Apply our text format to all of the buttons.
        this.walkButton.setTextFormat(this.buttonTextFormat);
        this.runButton.setTextFormat(this.buttonTextFormat);
        this.growlButton.setTextFormat(this.buttonTextFormat);
        this.idleButton.setTextFormat(this.buttonTextFormat);
    }
}
CODE.runBeforeInit___begin;
if (pr.exampleList === undefined) {
    pr.exampleList = [];
}
pr.exampleList.push({ classDefinition: ConstructWithTimelinesExample, displayName: "006 ConstructWithTimelines", name: "ConstructWithTimelines" });
CODE.runBeforeInit___end;


ProjectCode/IncisorExamples/007 ParticleSystem.js
------------------------------------------------------------
class ParticleSystemExample extends IncisorExample {
    constructor(parent, name) {
        // Super
        super(parent, name);
        // Description
        this.descriptionText = "A ParticleSystem is an extremely efficient way to create GPU effects with Incisor. It uses the Geometry and EffectNode created by a ParticleSystemDefinition to manage the behavior of many particles contained within a single SceneObject. ParticleSystems can be defined and edited using the ParticleSystem panel in the inspector, where every aspect of the particle system can be manipulated.";
        // Content
        this.setupParticles();
    }
    setupParticles() {
        // Create a new particle system using the ParticleSystem class. Particle systems can be defined and edited using the Particle System panel in the inspector.
        // Note: an emission time of 0 will emit particles perpetually.
        this.exampleParticles = new ParticleSystem(nc.particleSystemDefs.ExampleParticleSystem, this, "Demo Particles");
        // The play function will play the system continuously without stopping.
        this.exampleParticles.playbackController.play();
        // Scale up the entire particle system using a swoop.
        // Check out the Swoopers and Motions example for a closer look into this functionality.
        this.exampleParticles.scale.swoop.all(2);
    }
}
CODE.runBeforeInit___begin;
if (pr.exampleList === undefined) {
    pr.exampleList = [];
}
pr.exampleList.push({ classDefinition: ParticleSystemExample, displayName: "007 ParticleSystem", name: "ParticleSystem" });
CODE.runBeforeInit___end;


ProjectCode/IncisorExamples/008 Precomp.js
------------------------------------------------------------
class PrecompExample extends IncisorExample {
    constructor(parent, name) {
        // Super
        super(parent, name);
        // Description
        this.descriptionText = "A Precomp, short for 'precomposition', is an object with its own Scene, Camera, RenderTarget, and GraphicAsset. When the Precomp's Camera renders, it informs the associated GraphicAsset, which can be connected to multiple GraphicObjects. Precomps can be used for optimization in many ways. In the example below, we can see three dynamic GraphicObjects generated using only one Precomp.";
        // Content
        this.setupPrecomp();
    }
    setupPrecomp() {
        // Create a new precomp using the precomp class.
        // Since we'll have moving elements in our precomp, we'll set autorender to true so the precomp renders every frame rather than just once. 
        this.precomp = new Precomp("Bouncing Ball Precomp", 400, 400, true);
        // Changing the background color of the precomp's camera will make it easier to see the camera bounds.
        this.precomp.camera.backgroundColor = new Color(.1, .1, .1, 1);
        // Setup and add the ball graphic using our precomp's scene as the parent.
        let precompBall = nc.addGraphicObject(nc.graphicAssets.Ball, this.precomp.scene, "Bouncing Ball");
        precompBall.position.z = 1000;
        precompBall.position.x = 450;
        // Add swoopers to the x position and z rotation of the ball. Swoopers take a callback function that will be executed at the end of the duration of the swoop.
        // Check out the Swoopers and Motions example for a closer look into this functionality.
        precompBall.position.swoop.x(-225, 3, undefined, this, "resetBall", [precompBall]);
        precompBall.rotation.swoop.z(720, 3.35);
        // Add a motion to the position of the ball. Motion types can be added to the project via the Library menu in the inspector.
        precompBall.position.addMotion.y(-250, 50, 1.5, nc.motionTypes.Bounce);
        // Add an position a number of new graphic objects using the graphic asset generated by the precomp that we created.
        // We'll alter each one in different ways to demonstrate that they are independent objects.
        this.myNewPrecomp0 = nc.addGraphicObject(nc.graphicAssets["Bouncing Ball Precomp"], this, "PrecompGraphicObject0");
        this.myNewPrecomp0.position.swoop.each([-300, 150, 0], 0);
        // Flip this object on its x axis.
        this.myNewPrecomp0.scale.x = -1;
        this.myNewPrecomp1 = nc.addGraphicObject(nc.graphicAssets["Bouncing Ball Precomp"], this, "PrecompGraphicObject1");
        this.myNewPrecomp1.position.swoop.each([300, 150, 0], 0);
        // Scale this object down.
        this.myNewPrecomp1.scale.swoop.all(.6);
        this.myNewPrecomp2 = nc.addGraphicObject(nc.graphicAssets["Bouncing Ball Precomp"], this, "PrecompGraphicObject2");
        this.myNewPrecomp2.position.swoop.each([0, -400, 0], 0);
        // Add a swaying motion to this object.
        this.myNewPrecomp2.rotation.addMotion.each([-45, -45, 0], [45, 45, 0], 0.25, nc.motionTypes.Sway);
    }
    // This is the callback function we gave to the swooper. 
    resetBall(precompBall) {
        precompBall.position.x = 450;
        // Another swooper within the function is using a callback to call the function again. This creates a looping effect.
        precompBall.position.swoop.x(-450, 3, undefined, this, "resetBall", [precompBall]);
        precompBall.rotation.z = 0;
        precompBall.rotation.swoop.z(720, 3.35);
    }
}
CODE.runBeforeInit___begin;
if (pr.exampleList === undefined) {
    pr.exampleList = [];
}
pr.exampleList.push({ classDefinition: PrecompExample, displayName: "008 Precomp", name: "Precomp" });
CODE.runBeforeInit___end;


ProjectCode/IncisorExamples/009 OBJ.js
------------------------------------------------------------
class OBJExample extends IncisorExample {
    constructor(parent, name) {
        // Super
        super(parent, name);
        // Description
        this.descriptionText = "OBJ files are 3D models containing geometry and material properties exported from a 3D content creation tool. OBJ files in the Assets directory will automatically create GraphicAssets that can be added to a Scene. Below, the coin model uses the MatCap EffectNode to create a reflection from a MatCap texture asset. The monkey model uses the BlinnPhongLighting Addon to create a material surface dynamically lit by moving lights.";
        // Content
        this.setupOBJs();
    }
    setupOBJs() {
        // Create a container to help rotation the coin
        this.coinContainer = new SceneObject(this, "coinContainer");
        // add the Coin graphic asset created from the OBJ file
        this.coin = new GraphicObject(nc.graphicAssets.Coin, this.coinContainer, "Coin");
        // give it normal map and matcap effect nodes to give it some interesting lighting effects
        this.coin.setEffectNodes([nc.effectNodes.SampleMainTexture, nc.effectNodes.ColorMultiply, nc.effectNodes.NormalMap, nc.effectNodes.MatCap]);
        // brighten the coin
        this.coin.colorMultiply.alpha = 1.4;
        // set up the normal map and matcap textures
        let coinMaterials = this.coin.getMaterials();
        coinMaterials[0].normalMap_texture = nc.textures.CoinNormals;
        coinMaterials[0].matCap_texture = nc.textures.matcap;
        // rotation the coin
        this.coin.rotation.addMotion.x(-30, 30, .1);
        this.coinContainer.rotation.addMotion.y(0, 720, .05);
        // coin goes on the left
        this.coinContainer.position.x = -350;
        // Create a container to help rotation the monkey
        this.monkeyContainer = new SceneObject(this, "monkeyContainer");
        // add the monkey graphic asset created from the OBJ file
        this.monkey = new GraphicObject(nc.graphicAssets.suzanne, this.monkeyContainer, "Coin");
        // create the addon.  we don't really need the reference unless we want to change the light numbers or material properties
        let addon = new BlinnPhongLighting(this.monkey);
        // grab some variables we'll need to update the light direction
        let monkeyMaterials = this.monkey.getMaterials();
        this.time = 0;
        this.lightDirection = monkeyMaterials[0]["directionalLightDirection0"];
        // make the lights brighter
        monkeyMaterials[0]["directionalLightColor0"].alpha = 2;
        monkeyMaterials[0]["ambientLightColor"].alpha = 1.2;
        // add a fixed update where we'll change the light direction
        nc.appEvents.fixedUpdate.addCallback(this, "updateLight");
        //rotate the monkey around
        this.monkey.rotation.addMotion.x(-30, 30, .1);
        this.monkeyContainer.rotation.addMotion.y(-10, 30, .05);
        // monkey goes on the right
        this.monkeyContainer.position.x = 350;
        this.monkeyContainer.scale.swoop.all(2.7);
    }
    updateLight() {
        // keey the light rotating over time
        this.time += .02;
        this.lightDirection.x = Math.sin(this.time);
        this.lightDirection.z = Math.cos(this.time);
    }
}
CODE.runBeforeInit___begin;
if (pr.exampleList === undefined) {
    pr.exampleList = [];
}
pr.exampleList.push({ classDefinition: OBJExample, displayName: "009 OBJ", name: "OBJ" });
CODE.runBeforeInit___end;


ProjectCode/IncisorExamples/010 ObjParticles.js
------------------------------------------------------------
class OBJParticlesExample extends IncisorExample {
    constructor(parent, name) {
        // Super
        super(parent, name);
        // Description
        this.descriptionText = "OBJ files are 3D models containing geometry and material properties exported from a 3D content creation tool. GraphicAssets created from OBJ files are compatible with ParticleSystems. The ParticleSystem seen below uses the MatCap EffectNode and BlinnPhongLighting addon.";
        // Content
        this.setupParticles();
    }
    setupParticles() {
        // Create a new particle system using the ParticleSystem class. Particle systems can be defined and edited using the Particle System panel in the inspector.
        // Note: an emission time of 0 will emit particles perpetually.
        this.coinParticles = new ParticleSystem(nc.particleSystemDefs.CoinFountain, this, "Coin Particles");
        // The play function will play the system continuously without stopping.
        this.coinParticles.playbackController.play();
        // create a lighting addon.  we don't really need the reference unless we want to change the light numbers or material properties
        let addon = new BlinnPhongLighting(this.coinParticles);
        let materials = this.coinParticles.getMaterials();
        this.time = 0;
        this.lightDirection = materials[0]["directionalLightDirection0"];
        // add a fixed update where we'll change the light direction
        nc.appEvents.fixedUpdate.addCallback(this, "updateLight");
        let effectNodes = this.coinParticles.getMaterials()[0].getEffectNodes();
        effectNodes.splice(effectNodes.length - 1, 0, nc.effectNodes.MatCap);
        this.coinParticles.getMaterials()[0].matCap_texture = nc.textures.matcap;
        this.coinParticles.position.y = -650;
        materials[0]["directionalLightColor0"].swoop.each([1.05, 1, .8, 2.2]);
        materials[0]["ambientLightColor"].swoop.each([.8, .8, 1.0, .8]);
    }
    updateLight() {
        // keey the light rotating over time
        this.time += .04;
        this.lightDirection.x = -Math.sin(this.time);
        //this.lightDirection.z = -Math.abs(Math.cos(this.time));
        this.lightDirection.y = -.3;
        this.lightDirection.z = -1;
    }
}
CODE.runBeforeInit___begin;
if (pr.exampleList === undefined) {
    pr.exampleList = [];
}
pr.exampleList.push({ classDefinition: OBJParticlesExample, displayName: "010 OBJ Particles", name: "OBJ Particles" });
CODE.runBeforeInit___end;


ProjectCode/PreloadConfiguration/PreloadConfiguration.js
------------------------------------------------------------
// The 'preloadConfiguration' function below will be called before the target software is loaded and 
// can be used to customize asset loading. For example, you can custimize the code in this function
// to perform device detection, and use that information to update the
// 'projectConfiguration.assetConfiguration.assetPackageScale' value, which would result in a 
// change to which set of assets are loaded in the target software. Without customization, the 
// value of each asset configuration will be set to the values listed in the 0th element of the 
// 'supportedAssetConfigurations' of the current configuration defined in the ProjectSettings.
//
// The loading of the main Incisor resources (such as the main "..._habitat.js" file and the 
// "assetData...js" files) can be customized by manipulating the 'resourceLoadingOverride' function below.
// 
// The 'canvasPositionOverride' function below can also be changed to customize the positioning of the 
// canvas within the page. If defined, it will be called whenever the browser window is resized.
// 
// For reference, the code below will be executed within, and called by the main projectConfiguration object.




/** This function is called before the target software is loaded.
 * Customize this function to configure the project at the beginning of runtime.
 * @param {ProjectConfiguration} projectConfiguration 
 */
function preloadConfiguration(projectConfiguration)
{
    CODE.includeIf___published;
        // Preserving the drawing buffer enables several useful development features, 
        // but may cause performance issues in published software on some devices.
        projectConfiguration.preserveDrawingBuffer = false;
    CODE.includeEnd___published;
    projectConfiguration.canvasParent = document.body;
// define resource loading override function (this is optional)
    this.resourceLoadingOverride=function(filename)
    {
        if(filename.endsWith("_assetList.js")===true || filename.endsWith("_assetData.js")===true){filename = projectConfiguration.projectName+String.fromCharCode(95)+projectConfiguration.publishTimestamp+"_loadedAssets/" + filename;}
        var s=document.createElement('script'); 
        s.setAttribute('src',filename); 
        document.body.appendChild(s);
    };
// define canvas positioning function (this is optional)
    this.canvasPositionOverride=function(canvas,left,top,width,height)
    {
        canvas.style.width = width+'px';
        canvas.style.height = height+'px';
        canvas.style.left = left+'px';
        canvas.style.top = top+'px';
    };
};

ProjectCode/IncisorExampleBaseClass.js
------------------------------------------------------------
class IncisorExample extends SceneObject {
    constructor(parent, name) {
        super(parent, name);
    }
}


ProjectCode/ProjectMain.js
------------------------------------------------------------
// This is the main entry point for this Incisor® project. 
// Throughout the project, this object can be referenced as 'pr'.
class ProjectMain {
    init() {
        nc.mainCamera.adaptiveCameraMode = constants.adaptiveCameraModes.maximizeSafeZone;
        nc.useNearestPixelRenderingForAllUiItems = false;
        this.exampleViewer = new ExampleViewer(nc.mainScene, "exampleViewer");
        this.exampleViewer.init();
        nc.mainCamera.backgroundColor = new Color(.05, .05, .05, 1);
    }
}
class ExampleViewer extends SceneObject {
    constructor(parent, name) {
        // super
        super(parent, name);
        // gallery viewer construct
        this.galleryViewerConstruct = nc.constructDefs.ExampleViewerConstruct.add(this, "galleryViewerConstruct");
        this.galleryViewerConstruct.descendantsByName.CopyrightLine.string = "© " + (new Date()).getFullYear() + " Incisor®";
        CODE.includeIf___unpublished;
        this.galleryViewerConstruct.descendantsByName.PublishedProjectNote.disable();
        CODE.includeEnd___unpublished;
        // persistent state file name
        this.persistentStateFileName = "PersistentDevState.txt";
        // sort example list
        pr.exampleList.sort(function (a, b) { return (a.displayName - b.displayName); });
        // add/configure exampleSelectorDropDownMenu
        this.exampleSelector = new UiDropDownMenu(this.galleryViewerConstruct.descendantsByName.DropDownContainer);
        this.exampleSelector.displayLabel = true;
        this.exampleSelector.position.x -= 520;
        this.exampleSelector.position.y = 15;
        let textFormat = new TextFormat(nc.fontNames.ExampleFont, .1, .1, .25);
        this.exampleSelector.label.textFormat = textFormat;
        this.exampleSelector.label.string = "Select Example:";
        this.exampleSelector.mainText.textFormat = textFormat;
        this.exampleSelector.mainText.boxWidth = 900;
        this.exampleSelector.buttonBackgroundColor = new Color(.5, 0, 0, 1);
        this.exampleSelector.highlightedButtonBackgroundColor = new Color(.6, 0, 0, 1);
        this.exampleSelector.uiMenu.textFormat = textFormat;
        this.exampleSelector.uiMenu.searchBarMenuItem.leftIconScaleFactor = 6;
        this.exampleSelector.uiMenu.textBuffer = 15;
        // set selection menu options
        for (let i = 0; i < pr.exampleList.length; i++) {
            let menuItem = this.exampleSelector.uiMenu.addMenuItem(pr.exampleList[i].displayName);
        }
        this.exampleSelector.uiMenu.searchBarMenuItem.mainMenuItem.mainText.boxWidth = 600;
        this.exampleSelector.uiMenu.addMenuItemTriggerCallback(this, "selectionMenuCallback");
        // set the angles of the PerspectiveCamera
        nc.mainCamera.coreViewAngleHorizontal = 97;
        nc.mainCamera.coreViewAngleVertical = 97;
    }
    async init() {
        // index
        this.currentExampleIndex = 0;
        // add button callbacks
        this.galleryViewerConstruct.descendantsByName.ArrowRight.addPressCallback(this, "gotoNext");
        this.galleryViewerConstruct.descendantsByName.ArrowLeft.addPressCallback(this, "gotoPrevious");
        // populate current example
        this.currentExample = this.getExampleObject(this.currentExampleIndex);
        this.currentExample.parent = this.galleryViewerConstruct.descendantsByName.ExampleContainer;
        this.currentExample.enabled = true;
        this.exampleSelector.mainText.string = this.currentExample.displayName;
        this.galleryViewerConstruct.descendantsByName.InfoText.string = this.currentExample.descriptionText;
    }
    selectionMenuCallback(uiMenuItem) {
        let index = -1;
        for (let i = 0; i < pr.exampleList.length; i++) {
            if (pr.exampleList[i].displayName === uiMenuItem.name) {
                index = i;
                break;
            }
        }
        this.currentExampleIndex = index;
        // set selector string
        this.exampleSelector.mainText.string = uiMenuItem.name;
        // proceed to desired example
        this.goToExampleObject(this.getExampleObject(index), true);
    }
    gotoNext() {
        try {
            this.galleryViewerConstruct.descendantsByName.ArrowRight.position.y = -195;
            this.galleryViewerConstruct.descendantsByName.ArrowRight.position.swoop.y(-180, .1);
            this.currentExampleIndex++;
            while (this.currentExampleIndex >= pr.exampleList.length) {
                this.currentExampleIndex -= pr.exampleList.length;
            }
            // proceed to desired example
            let nextExampleObject = this.getExampleObject(this.currentExampleIndex);
            this.goToExampleObject(nextExampleObject, true);
        }
        catch (error) {
            let thing = new TextBox();
            thing.string = error.toString();
        }
    }
    gotoPrevious() {
        this.galleryViewerConstruct.descendantsByName.ArrowLeft.position.y = -195;
        this.galleryViewerConstruct.descendantsByName.ArrowLeft.position.swoop.y(-180, .1);
        this.currentExampleIndex--;
        while (this.currentExampleIndex < 0) {
            this.currentExampleIndex += pr.exampleList.length;
        }
        // proceed to desired example
        let nextExampleObject = this.getExampleObject(this.currentExampleIndex);
        this.goToExampleObject(nextExampleObject, false);
    }
    getExampleObject(index) {
        let classDefinition = pr.exampleList[index].classDefinition;
        if (pr.exampleList[index].exampleObject === undefined) {
            pr.exampleList[index].exampleObject = new classDefinition(this, pr.exampleList[index].name);
            pr.exampleList[index].exampleObject.displayName = pr.exampleList[index].displayName;
        }
        pr.exampleList[index].exampleObject.enabled = false;
        return (pr.exampleList[index].exampleObject);
    }
    goToExampleObject(exampleObject, rightToLeft) {
        if (rightToLeft === true) {
            this.galleryViewerConstruct.timelines.NextRight.playbackRate = 1;
        }
        else {
            this.galleryViewerConstruct.timelines.NextRight.playbackRate = -1;
        }
        this.galleryViewerConstruct.timelines.NextRight.playOnce();
        nc.waitThen(.25, this, "swap", exampleObject);
    }
    swap(newExampleObject) {
        this.currentExample.enabled = false;
        this.currentExample.parent = nc.mainScene;
        this.currentExample = newExampleObject;
        this.currentExample.enabled = true;
        this.currentExample.parent = this.galleryViewerConstruct.descendantsByName.ExampleContainer;
        this.galleryViewerConstruct.descendantsByName.InfoText.string = this.currentExample.descriptionText;
        this.exampleSelector.mainText.string = newExampleObject.displayName;
    }
}
// class IncisorExample extends SceneObject
// {
//     descriptionText:string;
//     displayName:string;
//     constructor(parent:SceneObject,name:string)
//     {
//         super(parent,name);
//     }
// }


Utilities/MinificationLists/DoNotMinifyLists/DoNotMinifyList.json
------------------------------------------------------------
{
	"minificationList":
    [
        "thisSymbolWillNotBeMinified",
        "thisSymbolWillAlsoNotBeMinified"
    ]
}

Utilities/MinificationLists/MinifyLists/MinifyList.json
------------------------------------------------------------
{
	"minificationList":
    [
        "thisSymbolWillBeMinified",
        "thisSymbolWillAlsoBeMinified"
    ]
}

Utilities/ProjectState.json
------------------------------------------------------------
{"docFormatVersion":0,"panelLayout":{"subPanels":[{"subPanels":[{"subPanels":[],"panelType":"Tool Tips","isColumns":true,"divisionLocation":0.5,"stateInfo":""},{"subPanels":[{"subPanels":[],"panelType":"Object","isColumns":true,"divisionLocation":0.5,"stateInfo":""},{"subPanels":[],"panelType":"Hierarchy","isColumns":true,"divisionLocation":0.5,"stateInfo":""}],"isColumns":true,"divisionLocation":0.5,"stateInfo":""}],"isColumns":false,"divisionLocation":0.12,"stateInfo":""},{"subPanels":[],"panelType":"Live View","isColumns":true,"divisionLocation":0.5,"stateInfo":""}],"isColumns":true,"divisionLocation":0.33,"stateInfo":""},"selectionState":{"sceneObject":[]},"hierarchyExpansionInfo":{"MainScene":["[[-1,\"MainScene\"],[0,\"MainCamera\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[0,\"HeaderContainer\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[1,\"DropDownContainer\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[2,\"InfoText\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[3,\"ArrowLeft\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[4,\"ArrowLeftMask\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[5,\"ArrowRight\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[6,\"ArrowRightMask\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[8,\"FrameGallery\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[11,\"CopyrightLine\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[0,\"HeaderContainer\"],[0,\"Logo\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[0,\"HeaderContainer\"],[1,\"Header\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[0,\"HeaderContainer\"],[2,\"Header2\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[0,\"HeaderContainer\"],[3,\"FrameTopMask\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[0,\"HeaderContainer\"],[4,\"FrameTop\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[1,\"DropDownContainer\"],[0,\"UiDropDownMenu\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[1,\"DropDownContainer\"],[0,\"UiDropDownMenu\"],[0,\"UiButton ButtonBackground\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[1,\"DropDownContainer\"],[0,\"UiDropDownMenu\"],[1,\"UiButton TextBox\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[1,\"DropDownContainer\"],[0,\"UiDropDownMenu\"],[3,\"Label UiText\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[1,\"T\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[2,\"e\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[3,\"x\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[4,\"t\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[6,\"A\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[7,\"s\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[8,\"s\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[9,\"e\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[10,\"m\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[11,\"b\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[12,\"l\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[13,\"y\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[14,\"!\"]]","[[-1,\"MainScene\"],[1,\"exampleViewer\"],[0,\"galleryViewerConstruct\"],[7,\"ExampleContainer\"],[0,\"TextAssembly\"],[0,\"TextAssemblyExample\"],[15,\"!\"]]","[[-1,\"MainScene\"]]"],"Construct Editor Scene: ExampleViewerConstruct":["[[-1,\"Construct Editor Scene: ExampleViewerConstruct\"],[0,\"ExampleViewerConstruct\"]]","[[-1,\"Construct Editor Scene: ExampleViewerConstruct\"],[0,\"ExampleViewerConstruct\"],[0,\"HeaderContainer\"]]","[[-1,\"Construct Editor Scene: ExampleViewerConstruct\"],[0,\"ExampleViewerConstruct\"],[5,\"DropDownContainer\"]]","[[-1,\"Construct Editor Scene: ExampleViewerConstruct\"],[0,\"ExampleViewerConstruct\"],[7,\"FrameGallery\"]]","[[-1,\"Construct Editor Scene: ExampleViewerConstruct\"]]"],"Construct Editor Scene: Incisorsaurus":["[[-1,\"Construct Editor Scene: Incisorsaurus\"],[0,\"Incisorsaurus\"]]","[[-1,\"Construct Editor Scene: Incisorsaurus\"],[0,\"Incisorsaurus\"],[2,\"Controller\"]]","[[-1,\"Construct Editor Scene: Incisorsaurus\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"]]","[[-1,\"Construct Editor Scene: Incisorsaurus\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"]]","[[-1,\"Construct Editor Scene: Incisorsaurus\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"],[0,\"Incisorsaurus_0005_UpperArm\"]]","[[-1,\"Construct Editor Scene: Incisorsaurus\"]]"],"Timeline Editor Scene: Incisorsaurus→Walk":["[[-1,\"Timeline Editor Scene: Incisorsaurus→Walk\"],[0,\"Incisorsaurus\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Walk\"]]"],"Timeline Editor Scene: Incisorsaurus→Run":["[[-1,\"Timeline Editor Scene: Incisorsaurus→Run\"],[0,\"Incisorsaurus\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Run\"],[0,\"Incisorsaurus\"],[2,\"Controller\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Run\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Run\"]]"]},"timelineSceneRepExpansionInfo":{"Timeline Editor Scene: ExampleViewerConstruct→NextRight":["[[-1,\"Timeline Editor Scene: ExampleViewerConstruct→NextRight\"],[1,\"ExampleViewerConstruct\"],[5,\"ExampleContainer\"]]"],"Timeline Editor Scene: Incisorsaurus→RunCycle":["[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[0,\"REF2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[1,\"REF1\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"],[0,\"Incisorsaurus_0005_UpperArm\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"],[0,\"Incisorsaurus_0005_UpperArm\"],[0,\"Incisorsaurus_0002_Forearm\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"],[0,\"Incisorsaurus_0005_UpperArm\"],[0,\"Incisorsaurus_0002_Forearm\"],[0,\"Incisorsaurus_0000_Finger\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"],[0,\"Incisorsaurus_0005_UpperArm\"],[0,\"Incisorsaurus_0002_Forearm\"],[1,\"Incisorsaurus_0001_Finger2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"],[0,\"Incisorsaurus_0005_UpperArm\"],[0,\"Incisorsaurus_0002_Forearm\"],[2,\"Incisorsaurus_0003_Thumb\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[0,\"Incisorsaurus_0014_LowerJaw\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[0,\"Incisorsaurus_0014_LowerJaw\"],[0,\"Incisorsaurus_0010_IncisorTooth\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[1,\"Incisorsaurus_0009_Eye\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[1,\"Incisorsaurus_0009_Eye\"],[0,\"Incisorsaurus_0033_EyeLidTop\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[1,\"Incisorsaurus_0009_Eye\"],[1,\"Incisorsaurus_0034_EyeLidBot\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[1,\"Incisorsaurus_0009_Eye\"],[2,\"Incisorsaurus_0006_Pupil\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[1,\"Incisorsaurus_0009_Eye\"],[3,\"Incisorsaurus_0008_Eyebrow\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[2,\"Incisorsaurus_0013_Eye\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[2,\"Incisorsaurus_0013_Eye\"],[0,\"Incisorsaurus_0033_EyeLidTop2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[2,\"Incisorsaurus_0013_Eye\"],[1,\"Incisorsaurus_0034_EyeLidBot2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[2,\"Incisorsaurus_0013_Eye\"],[2,\"Incisorsaurus_0012_Pupil\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[2,\"Incisorsaurus_0013_Eye\"],[3,\"Incisorsaurus_0007_Eyebrow\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[2,\"Incisorsaurus_0017_Shorts\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[2,\"Incisorsaurus_0017_Shorts\"],[0,\"Incisorsaurus_0019_LowerLeg\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[2,\"Incisorsaurus_0017_Shorts\"],[0,\"Incisorsaurus_0019_LowerLeg\"],[0,\"Incisorsaurus_0018_Sneaker\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[3,\"Incisorsaurus_0026_Shorts\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[3,\"Incisorsaurus_0026_Shorts\"],[0,\"Incisorsaurus_0028_LowerLeg\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[3,\"Incisorsaurus_0026_Shorts\"],[0,\"Incisorsaurus_0028_LowerLeg\"],[0,\"Incisorsaurus_0027_Sneaker\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"],[0,\"Incisorsaurus_0025_UpperArm\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"],[0,\"Incisorsaurus_0025_UpperArm\"],[0,\"Incisorsaurus_0023_Forearm\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"],[0,\"Incisorsaurus_0025_UpperArm\"],[0,\"Incisorsaurus_0023_Forearm\"],[0,\"Incisorsaurus_0020_Thumb\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"],[0,\"Incisorsaurus_0025_UpperArm\"],[0,\"Incisorsaurus_0023_Forearm\"],[1,\"Incisorsaurus_0021_Finger1\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"],[0,\"Incisorsaurus_0025_UpperArm\"],[0,\"Incisorsaurus_0023_Forearm\"],[2,\"Incisorsaurus_0022_Finger2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[5,\"Incisorsaurus_0029_Tail1\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[5,\"Incisorsaurus_0029_Tail1\"],[0,\"Incisorsaurus_0030_Tail2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[5,\"Incisorsaurus_0029_Tail1\"],[0,\"Incisorsaurus_0030_Tail2\"],[0,\"Incisorsaurus_0031_Tail3\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[1,\"Incisorsaurus_0032_Background\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→RunCycle\"],[0,\"Incisorsaurus\"],[3,\"Floor\"]]"],"Timeline Editor Scene: Incisorsaurus→Idle":["[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"],[0,\"Incisorsaurus_0005_UpperArm\"],[0,\"Incisorsaurus_0002_Forearm\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"],[0,\"Incisorsaurus_0005_UpperArm\"],[0,\"Incisorsaurus_0002_Forearm\"],[0,\"Incisorsaurus_0000_Finger\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"],[0,\"Incisorsaurus_0005_UpperArm\"],[0,\"Incisorsaurus_0002_Forearm\"],[1,\"Incisorsaurus_0001_Finger2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[0,\"Incisorsaurus_0004_Sleeve\"],[0,\"Incisorsaurus_0005_UpperArm\"],[0,\"Incisorsaurus_0002_Forearm\"],[2,\"Incisorsaurus_0003_Thumb\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[0,\"Incisorsaurus_0014_LowerJaw\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[0,\"Incisorsaurus_0014_LowerJaw\"],[0,\"Incisorsaurus_0010_IncisorTooth\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[1,\"Incisorsaurus_0009_Eye\"],[0,\"Incisorsaurus_0033_EyeLidTop\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[1,\"Incisorsaurus_0009_Eye\"],[1,\"Incisorsaurus_0034_EyeLidBot\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[2,\"Incisorsaurus_0013_Eye\"],[0,\"Incisorsaurus_0033_EyeLidTop2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[1,\"Incisorsaurus_0016_Neck\"],[0,\"Incisorsaurus_0011_Head\"],[2,\"Incisorsaurus_0013_Eye\"],[1,\"Incisorsaurus_0034_EyeLidBot2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[2,\"Incisorsaurus_0017_Shorts\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[2,\"Incisorsaurus_0017_Shorts\"],[0,\"Incisorsaurus_0019_LowerLeg\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[2,\"Incisorsaurus_0017_Shorts\"],[0,\"Incisorsaurus_0019_LowerLeg\"],[0,\"Incisorsaurus_0018_Sneaker\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[3,\"Incisorsaurus_0026_Shorts\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[3,\"Incisorsaurus_0026_Shorts\"],[0,\"Incisorsaurus_0028_LowerLeg\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[3,\"Incisorsaurus_0026_Shorts\"],[0,\"Incisorsaurus_0028_LowerLeg\"],[0,\"Incisorsaurus_0027_Sneaker\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"],[0,\"Incisorsaurus_0025_UpperArm\"],[0,\"Incisorsaurus_0023_Forearm\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"],[0,\"Incisorsaurus_0025_UpperArm\"],[0,\"Incisorsaurus_0023_Forearm\"],[0,\"Incisorsaurus_0020_Thumb\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"],[0,\"Incisorsaurus_0025_UpperArm\"],[0,\"Incisorsaurus_0023_Forearm\"],[1,\"Incisorsaurus_0021_Finger1\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[4,\"Incisorsaurus_0024_Sleeve\"],[0,\"Incisorsaurus_0025_UpperArm\"],[0,\"Incisorsaurus_0023_Forearm\"],[2,\"Incisorsaurus_0022_Finger2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[5,\"Incisorsaurus_0029_Tail1\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[5,\"Incisorsaurus_0029_Tail1\"],[0,\"Incisorsaurus_0030_Tail2\"]]","[[-1,\"Timeline Editor Scene: Incisorsaurus→Idle\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"],[5,\"Incisorsaurus_0029_Tail1\"],[0,\"Incisorsaurus_0030_Tail2\"],[0,\"Incisorsaurus_0031_Tail3\"]]"]},"animatedPropertyGraphEditorStateInfo":{"Timeline Editor Scene: ExampleViewerConstruct→NextRight":[["[[-1,\"Timeline Editor Scene: ExampleViewerConstruct→NextRight\"],[1,\"ExampleViewerConstruct\"]]","NextRight",0]],"Timeline Editor Scene: Incisorsaurus→RunCycle":[],"Timeline Editor Scene: Incisorsaurus→Idle":[]},"assetSelections":[],"recentPermissions":"v1,pro","publishingPopupStateInfo":{"currentConfiguration":"DevMode"}}

Utilities/ProjectTranscript.json
------------------------------------------------------------
{
	"docFormatVersion":0,
	"transcriptPhrases":{
		"Hello World":{
			"en":"Hello World",
			"es":"Hola Mundo"
		},
        "Goodbye World":{
			"en":"Goodbye World",
			"es":"Adiós Mundo"
		}
	}
}

Assets.ncData
------------------------------------------------------------
Deviations from default ncData:

- assetConfigurationFilters is {} instead of the default null.
- loadingTier is 0.25 instead of the default null.

jsconfig.json
------------------------------------------------------------
{
    "exclude": ["Publishing","Utilities/AuxiliaryPublishingSupport"]
}

ProjectSettings.json
------------------------------------------------------------
{"docFormatVersion":0,"publicProjectName":"Incisor Example Gallery JS","projectCodeName":"IncisorExampleGalleryJS","latestIncisorVersionSetUsed":"Red","requiredPermissions":"","latestIncisorVersionUsed":"2026.01.27.16.26.36","usingTypescript":false,"assetConfigurationDefinitions":{"assetPackageScale":["100","50"],"soundQuality":["stereo_115","mono_55"],"language":["en","es"]},"assetConfigurationDataOrder":["assetPackageScale","soundQuality","language"],"conditionalCodeTagDefinitions":["MyConditionalCodeTag"],"coreCanvasResolutionX":2160,"coreCanvasResolutionY":2160,"canvasTransparency":false,"mainCameraType":"perspective","maskingMode":"overlapping","preserveDrawingBuffer":true,"defaultGraphicAssetEffectNodes":["ColorMultiply"],"devModeConfiguration":"DevMode","configurations":{"DevMode":{"publishIndexFile":true,"supportedAssetConfigurations":[{"assetPackageScale":"100","soundQuality":"stereo_115","language":"en"}],"conditionalCodeTagsIncluded":["MyConditionalCodeTag"],"optionalCodeModulesExcluded":[],"minification":{"enableMinification":false,"automaticallyMinifyAllKeywords":false,"minifyPrefix":"minify_","minifySuffix":"_minify","doNotMinifyPrefix":"doNotMinify_","doNotMinifySuffix":"_doNotMinify","minifyIncisorApiKeywords":false,"minifyAssetNames":false,"substitutionAssignment":"deterministicRandom","keywordAndStringPairTreatment":"minifyBoth"},"removeComments":false,"removeWhiteSpace":false,"spriteSheetDimensionLimit":4096}},"autoClearMetaFiles":true,"limitPublishedBuildsKept":2,"enableDynamicDocumentation":true,"screenShotDestination":"ScreenShots","additionalLiveViewModes":["16x9_maximize","9x16_maximize","1920x1080","1080x1920"],"fontDefinitions":[{"fontName":"ExampleFont","kerningAdjustment":0,"lineHeight":475,"characterWidth":90,"alwaysIncludeTheseCharacters":[174],"phrasesUsingThisFont":[]},{"fontName":"SampleFont","kerningAdjustment":0,"lineHeight":82,"characterWidth":16,"alwaysIncludeTheseCharacters":[174,169],"phrasesUsingThisFont":[]},{"fontName":"CenterWinFont","kerningAdjustment":0,"lineHeight":600,"characterWidth":90,"alwaysIncludeTheseCharacters":[48,49,50,51,52,53,54,55,56,57],"phrasesUsingThisFont":[]}],"loadingTierDefinitions":[{"loadingTier":0.25,"isAutoLoaded":true,"incrementalContentProcessing":false,"assetDataFileSizeLimitKB":800,"performDuplicateRemoval":true},{"loadingTier":5,"isAutoLoaded":false,"incrementalContentProcessing":false,"assetDataFileSizeLimitKB":800,"performDuplicateRemoval":true},{"loadingTier":2,"isAutoLoaded":false,"incrementalContentProcessing":false,"assetDataFileSizeLimitKB":800,"performDuplicateRemoval":true}],"fontReduction":{"includeStandardCharactersWhenUnPublished":true,"includeStandardCharactersWhenPublished":true,"includeTranscriptCharacters":true,"limitTranscriptCharactersByLanguage":true,"limitTranscriptCharactersByPhrase":true,"standardFontCharacters":[33,34,35,36,37,38,39,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126]}}

ReleaseNotes.json
------------------------------------------------------------
{
    "2026.01.27.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Added OBJs Example",
                "description":"Example showing OBJs with the BlinnPhongLighting CustomAddOn, and the MatCap CustomAddOn."
            },
            {
                "name":"Updates Slot Template Publisher",
                "description":"Certain ts files were being left in the js build - this has been updated."
            },
            {
                "name":"Minification Settings Restored",
                "description":"Minification settings for the template have been reduced for better 'getting started' setup."
            },
            {
                "name":"Added OBJ Particle System Example",
                "description":"Example showing OBJs with the BlinnPhongLighting CustomAddOn, and the MatCap EffectNode."
            }
        ]
    },
    "2025.10.19.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Added release notes.",
                "description":"... the same notes you are currently looking at..."
            }
        ]
    }
}












----------------------------------------------------------
Section 2: IncisorSlotTemplateJS_textMap
----------------------------------------------------------


INCISOR PROJECT PLAIN TEXT MAP
============================================================
Project: Incisor Slot Template JS
Generated: 2026-11-03T17:34:40.579Z
Project Language: JavaScript

Excluded:
- AssetCache and its contents
- Publishing
- AutoSave
- IncisorAPI.js
- IncisorAPI.d.ts
- Additional file contents omitted for 1 user-specified path(s)

TABLE OF CONTENTS
============================================================
Incisor Slot Template JS
    Assets/
        CodeAssets/
            BrightnessContrast.codeAsset.js
            BulletTimeDoubleArc.codeAsset.js
            ExtremeEaseIn.codeAsset.js
            ExtremeEaseOut.codeAsset.js
            InfiniteAdd.codeAsset.js
            Sheen.codeAsset.js
            StretchBetween2D.codeAsset.js
        Dashboard/
            AutoPlayButton.png
            AutoPlayButton.png.ncData
            Circle.png
            Circle.png.ncData
            Dashboard.construct
            Dashboard.construct.ncData
            MenuButton.png
            MenuButton.png.ncData
            PanelBox.png
            PanelBox.png.ncData
            SoundButton.png
            SoundButton.png.ncData
            SoundMute.png
            SoundMute.png.ncData
            SpinButtonCenter.png
            SpinButtonCenter.png.ncData
        Fonts/
            ThemedFont/
                ThemedFont_Char{0000-8482}.png (112 files)
                ThemedFont_Char{0000-8482}.png.ncData (112 files)
            SampleFont.otf
            SampleFont.otf.ncData
            ThemedFont.ncData
        GameLayout/
            GameIntroAnimation/
                GameIntroAnimation.construct
                GameIntroAnimation.construct.ncData
            Background.png
            Background.png.ncData
            CenterWinMeterShadow.png
            CenterWinMeterShadow.png.ncData
            GameIntroAnimation.ncData
            GameLayout.construct
            GameLayout.construct.ncData
            GameTitle.png
            GameTitle.png.ncData
            InnerShadow.png
            InnerShadow.png.ncData
            ReelBackground.png
            ReelBackground.png.ncData
        LayersAndMasks/
            main.maskGroups
            main.maskGroups.ncData
            MainScene.layers
            MainScene.layers.ncData
        ParticleSystems/
            FallingStars.particleSysDef
            FallingStars.particleSysDef.ncData
            SampleParticle.png
            SampleParticle.png.ncData
            StarBurst.particleSysDef
            StarBurst.particleSysDef.ncData
            StarParticle.png
            StarParticle.png.ncData
        Sounds/
            ReelSpinSound.wav
            ReelSpinSound.wav.ncData
            ReelStop.wav
            ReelStop.wav.ncData
            SpinBegin.wav
            SpinBegin.wav.ncData
        SymbolConstructs/
            BarGrayThick_Plate.png
            BarGrayThick_Plate.png.ncData
            BarGrayThick_Text.png
            BarGrayThick_Text.png.ncData
            BarGrayThin_Plate.png
            BarGrayThin_Plate.png.ncData
            BarGrayThin_Text.png
            BarGrayThin_Text.png.ncData
            BarWhite_Plate.png
            BarWhite_Plate.png.ncData
            BarWhite_Text.png
            BarWhite_Text.png.ncData
            Bonus_Star.png
            Bonus_Star.png.ncData
            Bonus_Text.png
            Bonus_Text.png.ncData
            BonusConstruct.construct
            BonusConstruct.construct.ncData
            Major1_Fill.png
            Major1_Fill.png.ncData
            Major1_Outline.png
            Major1_Outline.png.ncData
            Major1_Shell.png
            Major1_Shell.png.ncData
            Major1Construct.construct
            Major1Construct.construct.ncData
            Major2_Fill.png
            Major2_Fill.png.ncData
            Major2_Outline.png
            Major2_Outline.png.ncData
            Major2_Shell.png
            Major2_Shell.png.ncData
            Major2Construct.construct
            Major2Construct.construct.ncData
            Major3_Fill.png
            Major3_Fill.png.ncData
            Major3_Outline.png
            Major3_Outline.png.ncData
            Major3_Shell.png
            Major3_Shell.png.ncData
            Major3Construct.construct
            Major3Construct.construct.ncData
            Minor1_PlateBottom.png
            Minor1_PlateBottom.png.ncData
            Minor1_PlateMiddle.png
            Minor1_PlateMiddle.png.ncData
            Minor1_PlateTop.png
            Minor1_PlateTop.png.ncData
            Minor1_TextBottom.png
            Minor1_TextBottom.png.ncData
            Minor1_TextMiddle.png
            Minor1_TextMiddle.png.ncData
            Minor1_TextTop.png
            Minor1_TextTop.png.ncData
            Minor1Construct.construct
            Minor1Construct.construct.ncData
            Minor2Construct.construct
            Minor2Construct.construct.ncData
            Minor3Construct.construct
            Minor3Construct.construct.ncData
            Wild_CherryLeft.png
            Wild_CherryLeft.png.ncData
            Wild_CherryRight.png
            Wild_CherryRight.png.ncData
            Wild_Leaf.png
            Wild_Leaf.png.ncData
            Wild_Text.png
            Wild_Text.png.ncData
            WildConstruct.construct
            WildConstruct.construct.ncData
        SymbolImages/
            Bonus.png
            Bonus.png.ncData
            Major1.png
            Major1.png.ncData
            Major2.png
            Major2.png.ncData
            Major3.png
            Major3.png.ncData
            Minor1.png
            Minor1.png.ncData
            Minor2.png
            Minor2.png.ncData
            Minor3.png
            Minor3.png.ncData
            Wild.png
            Wild.png.ncData
        CodeAssets.ncData
        Dashboard.ncData
        Fonts.ncData
        GameLayout.ncData
        LayersAndMasks.ncData
        ParticleSystems.ncData
        Sounds.ncData
        SymbolConstructs.ncData
        SymbolImages.ncData
    ProjectCode/
        FlowStates/
            00 GameIntro.js
            01 GameIdle.js
            02 StartGame.js
            03 SpinReels.js
            05 WinCelebration.js
        PreloadConfiguration/
            PreloadConfiguration.js
        DashboardManager.js
        GameSystemManager.js
        GameSystemReplica.js
        GrpcConnection.js
        Payline.js
        ProjectMain.js
        ReelSymbol.js
    Utilities/
        AuxiliaryPublishingSupport/
            ElectronEgmPublish/
                ElectronExtras/
                    ConnectionDefinition.proto
                ElectronMain/
                    ElectronMain.js
                    GRPC.js
                ElectronPackage/
                    package.json
                ElectronPreload/
                    ElectronPreload.js
                Example GRPC Servers/
                    NodeExample/
                        ConnectionDefinition.proto
                        GrpcServer.js
                        package.json
                    Windows Cpp Example/
                        Compiled exe/
                            abseil_dll.dll
                            cares.dll
                            connection_proto.lib
                            game_data.json
                            grpc_cpp_server.exe
                            libcrypto-3-x64.dll
                            libprotobuf.dll
                            libssl-3-x64.dll
                            re2.dll
                            zlib1.dll
                        SourceProject/
                            data/
                                game_data.json
                            proto/
                                ConnectionDefinition.proto
                            src/
                                server_main.cpp
                            CMakeLists.txt
                            README.txt
            ElectronLocalDev/
                ElectronMain/
                    ElectronMain.js
                ElectronPackage/
                    package.json
                ElectronPreload/
                    ElectronPreload.js
        MinificationLists/
            DoNotMinifyLists/
                DoNotMinifyList.json
            MinifyLists/
                MinifyList.json
        ProjectData.json
        ProjectState.json
        ProjectTranscript.json
    Assets.ncData
    jsconfig.json
    ProjectSettings.json
    ReleaseNotes.json

GROUPED REPETITIVE FILES
============================================================
Assets/Fonts/ThemedFont/ThemedFont_Char{0000-8482}.png (112 files) -> grouped repetitive non-text files (112 files)
Assets/Fonts/ThemedFont/ThemedFont_Char{0000-8482}.png.ncData (112 files) -> grouped repetitive text files (112 files)

TEXT FILE CONTENTS
============================================================
Assets/CodeAssets/BrightnessContrast.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
let brightnessContrast_def = nc.defineEffectController("brightnessContrast", "Vector2", ["brightness", "contrast"], [0, 0], nc.constants.effectControllerMixModes.addition, [[0, 1], [0, 1]], "EffectController for the BrightnessContrast EffectNode, which adjusts the brightness and contrast of the fragments (pixels) on the Material it is applied to.", ["Brightness Adjustment", "Contrast Adjustment"]);
nc.defineEffectNode("BrightnessContrast", [], "", ["uniform vec2 brightnessContrast;"], "fragment.rgb /= max(fragment.a, .001);\n\
        fragment.rgb = (fragment.rgb - vec3(.5)) * (brightnessContrast.y + 1.0) + vec3(.5);\n\
        fragment.rgb += vec3(brightnessContrast.x);\n\
        fragment.rgb *= fragment.a;", [brightnessContrast_def]);
CODE.runBeforeInit___end;


Assets/CodeAssets/BulletTimeDoubleArc.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
/** Define the tween function.
* @param {Swooper} swooper
*/
var bulletTimeDoubleArc_tweenTypeFunction = function (swooper) {
    let progress = swooper.progress;
    let params = swooper.controllers.BulletTimeDoubleArc;
    progress = (.5 * Math.pow((progress - .5) * 2, 5) + .5) * params.bulletTimeAmount + (1 - params.bulletTimeAmount) * progress;
    var oneMinus = 1 - progress;
    for (var i = 0; i < swooper.startValues.length; i++) {
        if (i === 0) {
            swooper.currentValues[i] = swooper.startValues[i] * oneMinus + swooper.endValues[i] * progress + Math.sin(progress * Math.PI) * params.x;
        }
        else if (i === 1) {
            swooper.currentValues[i] = swooper.startValues[i] * oneMinus + swooper.endValues[i] * progress + Math.sin(progress * Math.PI) * params.y;
        }
        else {
            swooper.currentValues[i] = swooper.startValues[i] * oneMinus + swooper.endValues[i] * progress;
        }
    }
};
//Define 'bulletTimeDoubleArc_tweenTypeFunction' TweenType
nc.defineTweenType("BulletTimeDoubleArc", bulletTimeDoubleArc_tweenTypeFunction, ["bulletTimeAmount", "x", "y"], [.5, 100, 100], "This TweenType in intended for use with position swoops.  It arcs the movements toward an offset position, and slows down the movement in the middle of the movement.", ["The amount to slow down the progression.  0 means no slow down, and 1 brings the progression to a standstill in the middle.", "The amound of X arc.", "The amount of Y arc."]);
CODE.runBeforeInit___end;


Assets/CodeAssets/ExtremeEaseIn.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
/** Define the tween function.
* @param {Swooper} swooper
*/
var extremeEaseIn_tweenTypeFunction = function (swooper) {
    let progress = Math.pow(Math.sin(.5 * Math.PI * swooper.progress), .3);
    for (let i = 0; i < swooper.numProperties; i++) {
        swooper.currentValues[i] = swooper.startValues[i] * (1 - progress) + swooper.endValues[i] * progress;
    }
};
//Define 'ExtremeEaseIn' TweenType
nc.defineTweenType("ExtremeEaseIn", extremeEaseIn_tweenTypeFunction, [], [], "This TweenType changes very quickly at first and slows down.", []);
CODE.runBeforeInit___end;


Assets/CodeAssets/ExtremeEaseOut.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
/** Define the tween function.
* @param {Swooper} swooper
*/
var extremeEaseOut_tweenTypeFunction = function (swooper) {
    let progress = Math.pow(1 - Math.cos(.5 * Math.PI * swooper.progress), 3.33);
    for (let i = 0; i < swooper.numProperties; i++) {
        swooper.currentValues[i] = swooper.startValues[i] * (1 - progress) + swooper.endValues[i] * progress;
    }
};
//Define 'ExtremeEaseOut' TweenType
nc.defineTweenType("ExtremeEaseOut", extremeEaseOut_tweenTypeFunction, [], [], "This TweenType changes very slowly at first and speeds up.", []);
CODE.runBeforeInit___end;


Assets/CodeAssets/InfiniteAdd.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
/** Define the motion function.
* @param {Motion} motion
*/
var infiniteAdd_motionTypeFunction = function (motion) {
    for (let i = 0; i < motion.numProperties; ++i) {
        motion.currentValues[i] = motion.lowerBounds[i] + motion.progress * (motion.upperBounds[i] - motion.lowerBounds[i]);
    }
};
// Define 'InfiniteAdd' Motion
nc.defineMotionType("InfiniteAdd", infiniteAdd_motionTypeFunction, undefined, undefined, "This MotionType adds to the value/values indefinitely.");
CODE.runBeforeInit___end;


Assets/CodeAssets/Sheen.codeAsset.js
------------------------------------------------------------
CODE.runBeforeInit___begin;
let sheen_def = nc.defineEffectController("sheen", "Vector4", ["progress", "angle", "thickness", "feather"], [0, 45, 100, 100], nc.constants.effectControllerMixModes.addition, [[0, 500], [0, 180], [0, 100], [0, 100]], "EffectController for the Sheen EffectNode, which adds a movable band of bright color to the Material it is applied to.", ["The offset of the bright band.", "The angle of the bright band.", "The thickness of the bright band.", "The fuzziness of the edges of the bright band."]);
let sheen_color_def = nc.defineEffectController("sheen_color", "Vector4", ["red", "green", "blue", "alpha"], [1, 1, 1, 1], nc.constants.effectControllerMixModes.addition, [[0, 1], [0, 1], [0, 1], [0, 1]], "EffectController for the Sheen EffectNode, which adds a movable band of bright color to the Material it is applied to.", ["The red value of the Sheen color.", "The green value of the Sheen color.", "The blue value of the Sheen color.", "The alpha value of the Sheen color."]);
let sheen_luminance_def = nc.defineEffectController("sheen_luminance", "number", [""], [1], nc.constants.effectControllerMixModes.addition, [[0, 1]], "EffectController for the Sheen EffectNode, which adds a movable band of bright color to the Material it is applied to.", "The luminance of the bright band.");
nc.defineEffectNode("Sheen", ["varying vec2 pos;"], "pos = vertex.xy;", ["varying vec2 pos;", "uniform vec4 sheen;", "uniform vec4 sheen_color;", "uniform float sheen_luminance;"], "float sheen_angle=sheen.y*3.14159/180.0;\n\
        float sheen_progress=sheen.x;\n\
        float sheen_thickness=sheen.z;\n\
        float sheen_feather=sheen.w;\n\
        vec2 sheen_axisOfTravel=vec2(cos(sheen_angle),sin(sheen_angle));\n\
        float sheen_newUV=dot(pos,sheen_axisOfTravel);\n\
        float sheen_sheenBand=smoothstep(sheen_progress-sheen_thickness*.5-sheen_feather,sheen_progress-sheen_thickness*.5,sheen_newUV)*smoothstep(sheen_progress+sheen_thickness*.5+sheen_feather,sheen_progress+max(sheen_feather, .001),sheen_newUV);\n\
        vec3 sheen_addColor = fragment.rgb+sheen_sheenBand*fragment.a*sheen_color.rgb*sheen_color.a;\n\
        vec3 sheen_normalColor = mix(fragment.rgb, fragment.a*sheen_color.rgb, sheen_color.a * sheen_sheenBand);\n\
        fragment.rgb = mix(sheen_normalColor, sheen_addColor, sheen_luminance);", [sheen_def, sheen_color_def, sheen_luminance_def]);
CODE.runBeforeInit___end;


Assets/CodeAssets/StretchBetween2D.codeAsset.js
------------------------------------------------------------
/** A CustomAddOn that will take any GraphicObject and stretch it from the middle between any two points using a GraphicExpander.
 */
class StretchBetween2D extends CustomAddOn_GraphicObject {
    constructor(owner) {
        // call the super constructor
        super(owner);
        // configure the GraphicExpander if it's not already configured
        if (this.owner.graphicExpander === undefined) {
            this.owner.configureGraphicExpander();
            this.owner.graphicExpander.expandedHeight = 0;
            this.owner.graphicExpander.expandedWidth = 0;
        }
        // initial var values
        this.internalUseGlobalCoordinates = false;
        this.internalStretchDirection = "horizontal";
        this.internalFirstPointX = 0;
        this.internalFirstPointY = 0;
        this.internalFirstPointBuffer = 0;
        this.internalSecondPointX = 0;
        this.internalSecondPointY = 0;
        this.internalSecondPointBuffer = 0;
        this.internalOneOverPi = 1 / Math.PI;
    }
    // refreshes the owner's position and rotation based on the values for the points
    refreshLayout() {
        let distanceX = (this.internalSecondPointX - this.internalFirstPointX);
        let distanceY = (this.internalSecondPointY - this.internalFirstPointY);
        let length = Math.pow(distanceX * distanceX + distanceY * distanceY, .5);
        let ratio = (1 + (-this.internalFirstPointBuffer + this.internalSecondPointBuffer) / length) * .5;
        let oneMinusRatio = (1 - ratio);
        let destX = (this.internalFirstPointX * ratio + this.internalSecondPointX * oneMinusRatio);
        let destY = (this.internalFirstPointY * ratio + this.internalSecondPointY * oneMinusRatio);
        let rotationZ = Math.atan2(distanceY, distanceX) * 180 * this.internalOneOverPi;
        if (this.internalStretchDirection === "horizontal") {
            this.owner.graphicExpander.expandedWidth = length - this.internalFirstPointBuffer - this.internalSecondPointBuffer;
            this.owner.graphicExpander.expandedHeight = 0;
        }
        else {
            this.owner.graphicExpander.expandedWidth = 0;
            this.owner.graphicExpander.expandedHeight = length - this.internalFirstPointBuffer - this.internalSecondPointBuffer;
            rotationZ += 90;
        }
        if (this.internalUseGlobalCoordinates === true) {
            this.owner.swoopGlobalPosition([destX, destY, 0], 0);
            this.owner.swoopGlobalRotation([0, 0, rotationZ], 0);
            this.owner.swoopGlobalScale([1, 1, 1], 0);
        }
        else {
            this.owner.position.x = destX;
            this.owner.position.y = destY;
            this.owner.rotation.z = rotationZ;
        }
    }
}
CODE.runBeforeInit___begin;
// Add getters/setters onto the CustomAddOn prototype, so that setting these values also triggers a refresh.
Object.defineProperty(StretchBetween2D.prototype, "useGlobalCoordinates", {
    set: function (_val) {
        this.internalUseGlobalCoordinates = _val;
        this.refreshLayout();
    },
    get: function () { return (this.internalUseGlobalCoordinates); }
});
Object.defineProperty(StretchBetween2D.prototype, "stretchDirection", {
    set: function (_val) {
        this.internalStretchDirection = _val;
        this.refreshLayout();
    },
    get: function () { return (this.internalStretchDirection); }
});
Object.defineProperty(StretchBetween2D.prototype, "firstPointX", {
    set: function (_val) {
        this.internalFirstPointX = _val;
        this.refreshLayout();
    },
    get: function () { return (this.internalFirstPointX); }
});
Object.defineProperty(StretchBetween2D.prototype, "firstPointY", {
    set: function (_val) {
        this.internalFirstPointY = _val;
        this.refreshLayout();
    },
    get: function () { return (this.internalFirstPointY); }
});
Object.defineProperty(StretchBetween2D.prototype, "firstPointBuffer", {
    set: function (_val) {
        this.internalFirstPointBuffer = _val;
        this.refreshLayout();
    },
    get: function () { return (this.internalFirstPointBuffer); }
});
Object.defineProperty(StretchBetween2D.prototype, "secondPointX", {
    set: function (_val) {
        this.internalSecondPointX = _val;
        this.refreshLayout();
    },
    get: function () { return (this.internalSecondPointX); }
});
Object.defineProperty(StretchBetween2D.prototype, "secondPointY", {
    set: function (_val) {
        this.internalSecondPointY = _val;
        this.refreshLayout();
    },
    get: function () { return (this.internalSecondPointY); }
});
Object.defineProperty(StretchBetween2D.prototype, "secondPointBuffer", {
    set: function (_val) {
        this.internalSecondPointBuffer = _val;
        this.refreshLayout();
    },
    get: function () { return (this.internalSecondPointBuffer); }
});
// register the CustomAddOn and its properties with the Incisor inspector, so that it can be added within the GUI.
nc.registerCustomAddOn(StretchBetween2D);
let stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D, "boolean", "useGlobalCoordinates");
stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D, "string", "stretchDirection");
stretchBetween2D_registeredProperty.validationList = ["horizontal", "vertical"];
stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D, "number", "firstPointX");
stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D, "number", "firstPointY");
stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D, "number", "firstPointBuffer");
stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D, "number", "secondPointX");
stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D, "number", "secondPointY");
stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D, "number", "secondPointBuffer");
CODE.runBeforeInit___end;


Assets/Dashboard/AutoPlayButton.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.resolutionScaleX is 0.6 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.6 instead of the default null.
- imageConfigurations.trimMode is "none" instead of the default null.

Assets/Dashboard/Circle.png.ncData
------------------------------------------------------------
default ncData file

Assets/Dashboard/Dashboard.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{
				"4":{},
				"5":{},
				"6":{},
				"7":{},
				"8":{},
				"9":{},
				"10":{},
				"11":{},
				"12":{},
				"13":{},
				"14":{
					"15":{},
					"16":{
						"17":{}
					},
					"18":{
						"19":{}
					}
				}
			},
			"20":{
				"21":{
					"22":{}
				}
			},
			"23":{
				"24":{},
				"25":{}
			}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"ViewArea",
				"uid":"0255217279399595",
				"scale":[21.6,43.2,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.95,
				"effectControllerValues":{"colorMultiply":[0,1,0,0.1]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{
				"i":1,
				"type":"Button",
				"name":"MenuBackgroundDimmer",
				"uid":"3692856201945776",
				"enabled":false,
				"scale":[21.6,43.2,1],
				"graphicAsset":"WhiteBox",
				"layer":"GameMenus",
				"subLayer":-0.9,
				"effectControllerValues":{"colorMultiply":[0,0,0,0.7]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"BottomBarBackground",
				"uid":"5152859927566143",
				"position":[0,-2060,0],
				"scale":[21.6,2,1],
				"graphicAsset":"WhiteBox",
				"layer":"Dashboard",
				"subLayer":-0.2,
				"effectControllerValues":{"colorMultiply":[0,0,0,0.5]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{"i":3,"name":"BottomBarContainer","uid":"6056396671095576","position":[0,-2060,0]},
			{
				"i":4,
				"type":"GraphicObject",
				"name":"BottomBarBorder",
				"uid":"1046200249065111",
				"position":[0,100,0],
				"scale":[21.6,0.049,1],
				"graphicAsset":"WhiteBox",
				"layer":"Dashboard",
				"effectControllerValues":{"colorMultiply":[0.2,0.2,0.22,1]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{
				"i":5,
				"type":"TextBox",
				"name":"BalanceLabel",
				"uid":"3062810463762450",
				"position":[-300,40,0],
				"layer":"Dashboard",
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"phraseID":"CreditMeterLabel",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.75,
					"characterScaleY":0.75,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.6352941176470588,0.6352941176470588,0.7058823529411765,1]}
					}
				]
			},
			{
				"i":6,
				"type":"TextBox",
				"name":"BalanceMeter",
				"uid":"6366022433512107",
				"position":[-300,-20,0],
				"layer":"Dashboard",
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"string":"$2,100.85",
				"textFormat":{
					"fontName":"SampleFont",
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]}
					}
				]
			},
			{
				"i":7,
				"type":"TextBox",
				"name":"BetLabel",
				"uid":"7533959443301057",
				"position":[300,40,0],
				"layer":"Dashboard",
				"phraseID":"BetMeterLabel",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.75,
					"characterScaleY":0.75,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.6352941176470588,0.6352941176470588,0.7058823529411765,1]}
					}
				]
			},
			{
				"i":8,
				"type":"TextBox",
				"name":"BetMeter",
				"uid":"3552817982372254",
				"position":[300,-20,0],
				"layer":"Dashboard",
				"string":"$1.50",
				"textFormat":{
					"fontName":"SampleFont",
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.8897692222222225,0.8897692222222225,0.9188666666666669,1]}
					}
				]
			},
			{
				"i":9,
				"type":"TextBox",
				"name":"WinMeter",
				"uid":"7770006718721982",
				"position":[0,-20,0],
				"layer":"Dashboard",
				"string":"$1.50",
				"textFormat":{
					"fontName":"SampleFont",
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.8897692222222225,0.8897692222222225,0.9188666666666669,1]}
					}
				]
			},
			{
				"i":10,
				"type":"TextBox",
				"name":"WinLabel",
				"uid":"0316236576295246",
				"position":[0,40,0],
				"layer":"Dashboard",
				"phraseID":"WinMeterLabel",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.75,
					"characterScaleY":0.75,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.6352941176470588,0.6352941176470588,0.7058823529411765,1]}
					}
				]
			},
			{
				"i":11,
				"type":"TextBox",
				"name":"BottomBarTitle",
				"uid":"1744208700345465",
				"position":[1030,0,0],
				"layer":"Dashboard",
				"phraseID":"BottomBarGameTitle",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":1.25,
					"characterScaleY":1.25,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"pivotPoint":[0.5,0],
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]}
					}
				]
			},
			{
				"i":12,
				"type":"Button",
				"name":"MenuButton",
				"uid":"2990403768905400",
				"position":[-960,0,0],
				"scale":[0.6,0.6,1],
				"graphicAsset":"MenuButton",
				"layer":"Dashboard",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","BrightnessContrast"],
						"effectControllerValues":{"colorMultiply":[0.89,0.89,0.916,1]}
					}
				]
			},
			{
				"i":13,
				"type":"Button",
				"name":"SoundButton",
				"uid":"0451180212965326",
				"position":[-800,0,0],
				"scale":[0.6,0.6,1],
				"graphicAsset":"SoundButton",
				"layer":"Dashboard",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","BrightnessContrast"],
						"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]}
					}
				]
			},
			{"i":14,"name":"AutplayContainer","uid":"7287341036502203","position":[-640,0,0]},
			{
				"i":15,
				"type":"Button",
				"name":"Autoplay Button",
				"uid":"2188549410786908",
				"scale":[0.6,0.6,1],
				"graphicAsset":"AutoPlayButton",
				"layer":"Dashboard",
				"subLayer":0.05,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","BrightnessContrast"],
						"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]}
					}
				]
			},
			{
				"i":16,
				"type":"Button",
				"name":"Autoplay Menu",
				"uid":"1431752518849777",
				"enabled":false,
				"graphicAsset":"PanelBox",
				"layer":"GameMenus",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"graphicExpander":{"symmetric":false,"expandableArea":[0,0,0,0],"expandedArea":[-115,115,-80,675]}
			},
			{
				"i":17,
				"type":"TextBox",
				"name":"BalanceLabel",
				"uid":"9717852305388767",
				"position":[0,80,0],
				"layer":"GameMenus",
				"subLayer":0.05,
				"phraseID":"AutoplayLabel",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.75,
					"characterScaleY":0.75,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.6352941176470588,0.6352941176470588,0.7058823529411765,1]}
					}
				]
			},
			{
				"i":18,
				"type":"GraphicObject",
				"name":"AutoplayCountdownBackground",
				"uid":"7311747112657510",
				"enabled":false,
				"graphicAsset":"PanelBox",
				"layer":"GameMenus",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"graphicExpander":{"symmetric":true,"expandableWidth":0,"expandableHeight":0,"expandedWidth":90,"expandedHeight":35}
			},
			{
				"i":19,
				"type":"TextBox",
				"name":"AutoplayCountdown",
				"uid":"0262139303638274",
				"layer":"GameMenus",
				"string":"10",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.75,
					"characterScaleY":0.75,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{"i":20,"name":"SpinButtonContainer","uid":"1476640098329800","position":[0,-1600,0]},
			{
				"i":21,
				"type":"Button",
				"name":"SpinButton",
				"uid":"3808583354841769",
				"scale":[1.5,1.5,1],
				"graphicAsset":"Circle",
				"layer":"Dashboard",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":22,
				"type":"GraphicObject",
				"name":"SpinButtonCenter",
				"uid":"8491280100649518",
				"scale":[0.9,0.9,1],
				"graphicAsset":"SpinButtonCenter",
				"layer":"Dashboard",
				"subLayer":0.044000000000000115,
				"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{"i":23,"name":"MainMenuContainer","uid":"7763480859850434","enabled":false},
			{
				"i":24,
				"type":"Button",
				"name":"MainMenuBackground",
				"uid":"2013930738972798",
				"graphicAsset":"PanelBox",
				"layer":"GameMenus",
				"subLayer":0.05,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[2,2,2,1]}
					}
				],
				"graphicExpander":{"symmetric":true,"expandableWidth":0,"expandableHeight":0,"expandedWidth":1800,"expandedHeight":2000}
			},
			{
				"i":25,
				"type":"TextBox",
				"name":"MainMenuLabel",
				"uid":"5021713473146068",
				"string":"Main Menu...",
				"textFormat":{
					"fontName":"SampleFont",
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			}
		]
	},
	"timelines":{
		"Layout_Mobile":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":0,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":-3140},
						{"time":-2,"value":-2060},
						{"time":-1,"value":-980}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":23.6},
						{"time":-2,"value":2}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-2,"value":-2060},
						{"time":-1,"value":-980}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6056396671095576"
				},
				{
					"keyframes":[
						{"time":1,"value":1030},
						{"time":4,"value":4270}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"keyframes":[
						{"time":1,"value":-960},
						{"time":4,"value":-4200}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"keyframes":[
						{"time":1,"value":-800},
						{"time":4,"value":-4040}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.2},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.65},
						{"time":1,"value":0.65},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.2},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.65},
						{"time":1,"value":0.65},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":0},
						{"time":-1.5,"value":0},
						{"time":-1,"value":0},
						{"time":1,"value":908.0000000000005},
						{"time":2,"value":1889}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":-1600},
						{"time":-1.5,"value":-1125},
						{"time":-1,"value":-720},
						{"time":1,"value":-720},
						{"time":2,"value":-625}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1046200249065111"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":1,"value":-640},
						{"time":4,"value":-3880}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"keyframes":[
						{"time":-2,"value":100}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7763480859850434"
				},
				{
					"keyframes":[
						{"time":-2,"value":2300},
						{"time":-1,"value":1800},
						{"time":1,"value":1800}
					],
					"propertyPath":["graphicExpander","expandedHeight"],
					"sceneObjectUid":"2013930738972798"
				},
				{
					"keyframes":[
						{"time":-1,"value":2000},
						{"time":1,"value":2000},
						{"time":2,"value":3000}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"2013930738972798"
				}
			]
		},
		"Layout_Desktop":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":0,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":-3190},
						{"time":-2,"value":-2110},
						{"time":-1,"value":-1030},
						{"time":1,"value":-1030}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":22.6},
						{"time":-2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-2,"value":-2110},
						{"time":-1,"value":-1030}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6056396671095576"
				},
				{
					"keyframes":[
						{"time":1,"value":1030},
						{"time":4,"value":4270}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"keyframes":[
						{"time":1,"value":-960},
						{"time":4,"value":-4200}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"keyframes":[
						{"time":1,"value":-800},
						{"time":4,"value":-4040}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"keyframes":[
						{"time":-2,"value":0.5},
						{"time":-1.5,"value":0.5},
						{"time":-1,"value":0.5},
						{"time":1,"value":0.5},
						{"time":2,"value":0.5}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":0.5},
						{"time":-1.5,"value":0.5},
						{"time":-1,"value":0.5},
						{"time":1,"value":0.5},
						{"time":2,"value":0.5}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":930},
						{"time":-1.5,"value":930},
						{"time":-1,"value":930},
						{"time":1,"value":930},
						{"time":2,"value":2000}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":-1900},
						{"time":-1.5,"value":-1360},
						{"time":-1,"value":-830},
						{"time":1,"value":-830},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1046200249065111"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":1,"value":-640},
						{"time":4,"value":-3880}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"keyframes":[
						{"time":-2,"value":100}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7763480859850434"
				},
				{
					"keyframes":[
						{"time":-2,"value":2300},
						{"time":-1,"value":1800},
						{"time":1,"value":1800}
					],
					"propertyPath":["graphicExpander","expandedHeight"],
					"sceneObjectUid":"2013930738972798"
				},
				{
					"keyframes":[
						{"time":-1,"value":2000},
						{"time":1,"value":2000},
						{"time":2,"value":3000}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"2013930738972798"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":50}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1046200249065111"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.67}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.67}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-2,"value":0.67}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-2,"value":0.67}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-20},
						{"time":-1.1166666666666667,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7533959443301057"
				}
			]
		},
		"Layout_EGM":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":0,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":-3190},
						{"time":-2,"value":-2110},
						{"time":-1,"value":-1030},
						{"time":1,"value":-1030}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":22.6},
						{"time":-2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-2,"value":-2110},
						{"time":-1,"value":-1030}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6056396671095576"
				},
				{
					"keyframes":[
						{"time":1,"value":1030},
						{"time":4,"value":4270}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"keyframes":[
						{"time":1,"value":-960},
						{"time":4,"value":-4200}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"keyframes":[
						{"time":1,"value":-800},
						{"time":4,"value":-4040}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"keyframes":[
						{"time":-2,"value":0.5},
						{"time":-1.5,"value":0.5},
						{"time":-1,"value":0.5},
						{"time":1,"value":0.5},
						{"time":2,"value":0.5}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":0.5},
						{"time":-1.5,"value":0.5},
						{"time":-1,"value":0.5},
						{"time":1,"value":0.5},
						{"time":2,"value":0.5}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":930},
						{"time":-1.5,"value":930},
						{"time":-1,"value":930},
						{"time":1,"value":930},
						{"time":2,"value":2000}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":-1900},
						{"time":-1.5,"value":-1360},
						{"time":-1,"value":-830},
						{"time":1,"value":-830},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1046200249065111"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":1,"value":-640},
						{"time":4,"value":-3880}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"keyframes":[
						{"time":-2,"value":100}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7763480859850434"
				},
				{
					"keyframes":[
						{"time":-2,"value":2300},
						{"time":-1,"value":1800},
						{"time":1,"value":1800}
					],
					"propertyPath":["graphicExpander","expandedHeight"],
					"sceneObjectUid":"2013930738972798"
				},
				{
					"keyframes":[
						{"time":-1,"value":2000},
						{"time":1,"value":2000},
						{"time":2,"value":3000}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"2013930738972798"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":50}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1046200249065111"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.67}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.67}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-2,"value":0.67}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-2,"value":0.67}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-20},
						{"time":-1.1166666666666667,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"type":"boolean",
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":false}
					],
					"propertyPath":["enabled"],
					"sceneObjectUid":"1476640098329800"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"Layout_Mobile"}
}

Assets/Dashboard/Dashboard.construct.ncData
------------------------------------------------------------
default ncData file

Assets/Dashboard/MenuButton.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.resolutionScaleX is 0.6 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.6 instead of the default null.
- imageConfigurations.trimMode is "none" instead of the default null.

Assets/Dashboard/PanelBox.png.ncData
------------------------------------------------------------
default ncData file

Assets/Dashboard/SoundButton.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.resolutionScaleX is 0.6 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.6 instead of the default null.
- imageConfigurations.trimMode is "none" instead of the default null.

Assets/Dashboard/SoundMute.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.resolutionScaleX is 0.6 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.6 instead of the default null.
- imageConfigurations.trimMode is "none" instead of the default null.

Assets/Dashboard/SpinButtonCenter.png.ncData
------------------------------------------------------------
default ncData file

Assets/Fonts/SampleFont.otf.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.allowAdditiveTrimBuffer is true instead of the default null.
- imageConfigurations.applyAssetPackageScaling is false instead of the default null.
- imageConfigurations.shapify is true instead of the default null.
- imageConfigurations.shapifyEdgeRange is 10 instead of the default null.
- imageConfigurations.shapifyOptimizationLevel is 0.6 instead of the default null.
- imageConfigurations.spriteSheet is "SampleFont" instead of the default null.
- imageConfigurations.trimBuffer is 10 instead of the default null.
- imageConfigurations.unitsPerPixelX is 0.2 instead of the default null.
- imageConfigurations.unitsPerPixelY is 0.2 instead of the default null.
- imageConfigurations.unitsPerPixelZ is 0.2 instead of the default null.

Assets/Fonts/ThemedFont.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/GameIntroAnimation/GameIntroAnimation.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{
				"1":{}
			},
			"2":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"GameIntroTitle",
				"uid":"9871611871543739",
				"graphicAsset":"GameTitle",
				"layer":"GameIntro",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-710.0000000000002,29.880000000000006,172.8,71.40000000000018]}
					}
				]
			},
			{
				"i":1,
				"type":"TextBox",
				"name":"PressToContinueText",
				"uid":"3967512849546244",
				"position":[0,-550,0],
				"scale":[0.3981151044451828,0.3981151044451828,0.3981151044451828],
				"phraseID":"IntroPromptButton",
				"horizontalJustification":"center",
				"boxWidth":5000,
				"boxHeight":1000,
				"scaleToFit":false,
				"textFormat":{
					"fontName":"ThemedFont",
					"lineHeightMultiplier":0.7560000000000008,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"numHorizontalGridSegments":3,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":2,
				"type":"ParticleSystem",
				"name":"GameIntroParticles",
				"uid":"9427635532718460",
				"layer":"GameIntro",
				"subLayer":-0.2,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"particleSystemDefinition":"StarBurst",
				"playbackController":{"autoplayMode":"none","initialTime":0,"playbackRate":1,"startValue":0,"endValue":1.4000000000000001},
				"materials":[
					{"effectNodes":["SampleMainTexture","StarBurstParticleSystemEffectNode","ColorMultiply"]}
				]
			}
		]
	},
	"timelines":{
		"Intro":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":15,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":0,"value":0},
						{
							"time":0.26666666666666666,
							"value":1.946827145153689,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.06515798095682436,
							"rightHandleSpan":0.22984083351821796
						},
						{
							"time":0.6666666666666666,
							"value":1.383,
							"leftHandleValue":0.06499999999999996,
							"leftHandleSpan":0.30714091235990404,
							"rightHandleValue":-0.026155806639436674,
							"rightHandleSpan":0.017776615667129236
						},
						{"time":14.966666666666667,"value":1.7013895165985877,"leftHandleValue":0,"leftHandleSpan":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9871611871543739"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{
							"time":0.2,
							"value":1.986060855112844,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.06515798095682436,
							"rightHandleSpan":0.22984083351821796
						},
						{
							"time":0.6833333333333333,
							"value":1.3699220966802816,
							"leftHandleValue":0.06499999999999996,
							"leftHandleSpan":0.30714091235990404,
							"rightHandleValue":-0.026155806639436674,
							"rightHandleSpan":0.017776615667129236
						},
						{"time":14.966666666666667,"value":1.7013895165985877,"leftHandleValue":0,"leftHandleSpan":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9871611871543739"
				},
				{
					"keyframes":[
						{"time":0.15,"value":-710.0000000000002},
						{"time":0.3,"value":715.9999999999998},
						{"time":0.31666666666666665,"value":-700},
						{"time":1.2333333333333334,"value":-700},
						{"time":1.4,"value":700}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"9871611871543739"
				},
				{
					"keyframes":[
						{"time":0.2,"value":1},
						{"time":0.26666666666666666,"value":1.6139999999999999},
						{"time":0.8333333333333334,"value":1},
						{"time":1.2666666666666666,"value":1},
						{"time":1.3333333333333333,"value":1.6139999999999999},
						{"time":4.466666666666667,"value":1}
					],
					"propertyPath":["material","0","colorMultiply","alpha"],
					"sceneObjectUid":"9871611871543739"
				},
				{
					"type":"invoke",
					"keyframes":[
						{"time":0.1}
					],
					"propertyPath":["playbackController","playOnce"],
					"sceneObjectUid":"9427635532718460"
				},
				{
					"keyframes":[
						{"time":0.35,"value":0},
						{"time":0.65,"value":0},
						{
							"time":0.8333333333333334,
							"value":0.4,
							"leftHandleValue":-0.02114655962076141,
							"leftHandleSpan":0.35172622808693166,
							"rightHandleValue":0.02255710195165208,
							"rightHandleSpan":0.04046096960579235
						},
						{"time":3.4833333333333334,"value":0.35,"leftHandleValue":0,"leftHandleSpan":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3967512849546244"
				},
				{
					"keyframes":[
						{"time":0.35,"value":0},
						{"time":0.65,"value":0},
						{
							"time":0.8666666666666667,
							"value":0.4,
							"leftHandleValue":-0.02933598754245529,
							"leftHandleSpan":0.37957648111370185,
							"rightHandleValue":0.010293532062311735,
							"rightHandleSpan":0.051764203337249876
						},
						{"time":3.4833333333333334,"value":0.35,"leftHandleValue":0,"leftHandleSpan":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3967512849546244"
				},
				{
					"type":"boolean",
					"keyframes":[
						{"time":0,"value":true}
					],
					"propertyPath":["enabled"],
					"sceneObjectUid":"9871611871543739"
				}
			]
		},
		"Outro":{
			"autoplay":false,
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":1,
			"animatedProperties":[
				{
					"sceneObject":[0],
					"sceneObjectUid":"9871611871543739",
					"propertyPath":["scale","x"],
					"keyframes":[
						{"time":0,"value":1.5},
						{
							"time":0.13333333333333333,
							"value":2,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":0.26666666666666666,"value":0}
					]
				},
				{
					"sceneObject":[0],
					"sceneObjectUid":"9871611871543739",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0,"value":1.5},
						{
							"time":0.13333333333333333,
							"value":2,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":0.26666666666666666,"value":0}
					]
				},
				{
					"type":"binary",
					"sceneObject":[0],
					"sceneObjectUid":"9871611871543739",
					"propertyPath":["enabled"],
					"keyframes":[
						{"time":0,"value":true},
						{"time":0.9,"value":false}
					]
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"Intro"}
}

Assets/GameLayout/GameIntroAnimation/GameIntroAnimation.construct.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/Background.png.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/CenterWinMeterShadow.png.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/GameIntroAnimation.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/GameLayout.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{
				"2":{}
			},
			"3":{
				"4":{},
				"5":{
					"6":{},
					"7":{}
				},
				"8":{
					"9":{},
					"10":{}
				},
				"11":{
					"12":{},
					"13":{}
				},
				"14":{
					"15":{},
					"16":{}
				},
				"17":{
					"18":{},
					"19":{}
				},
				"20":{
					"21":{}
				}
			},
			"22":{},
			"23":{},
			"24":{},
			"25":{},
			"26":{
				"27":{},
				"28":{}
			}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"ViewArea",
				"uid":"2259684172978443",
				"scale":[21.6,43.2,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.95,
				"effectControllerValues":{"fillColor":[0,1,0,0.1]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{"i":1,"name":"GameTitleContainer","uid":"9279909710684411","position":[0,1400,0],"scale":[1.5,1.5,1]},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"GameTitle",
				"uid":"6426274793272281",
				"graphicAsset":"GameTitle",
				"layer":"GameTitle",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{"i":3,"name":"ReelsContainer","uid":"7193618239035880","position":[0,-560,0]},
			{
				"i":4,
				"type":"GraphicObject",
				"name":"ReelBackground",
				"uid":"7175220269991170",
				"position":[0,-26,0],
				"graphicAsset":"ReelBackground",
				"layer":"GameBackground",
				"subLayer":0.2,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"graphicExpander":{"symmetric":true,"expandableWidth":0,"expandableHeight":0,"expandedWidth":1100,"expandedHeight":760}
			},
			{"i":5,"name":"ReelContainer0","uid":"9076020945798561","position":[-720,0,0]},
			{
				"i":6,
				"type":"GraphicObject",
				"name":"ReelMask",
				"uid":"0918370620653048",
				"scale":[3.6,12,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.01,
				"masking":{"enabled":true,"type":"mask","maskGroups":["ReelMask"]},
				"effectControllerValues":{"fillColor":[1,1,1,0.2]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":7,
				"type":"SymbolReel",
				"name":"SymbolReel0",
				"uid":"5820417336094512",
				"position":[0,450,0],
				"defaultSymbolType":"GraphicObject",
				"numMainSymbols":4,
				"spinSpeed":-0.55,
				"windupDuration":0.2,
				"initialReelData":["Major1","Major1","Major1","Minor1","Minor1","Major2"],
				"pathValues":{
					"position.y":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":300},
							{"time":0,"value":0},
							{"time":1,"value":-300},
							{"time":2,"value":-600},
							{"time":3,"value":-900},
							{"time":4,"value":-1200}
						]
					},
					"subLayer":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":-0.05},
							{"time":0,"value":0},
							{"time":1,"value":0.05},
							{"time":2,"value":0.1},
							{"time":3,"value":0.15},
							{"time":4,"value":0.2}
						]
					}
				},
				"windupCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7,"value":-0.5,"leftHandleValue":0,"leftHandleSpan":0.396,"rightHandleValue":0,"rightHandleSpan":0.55},
						{"time":1,"value":0}
					]
				},
				"bounceCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.33,"value":-0.175,"leftHandleValue":0,"leftHandleSpan":0.453,"rightHandleValue":0,"rightHandleSpan":0.583},
						{"time":0.6,"value":0},
						{"time":0.83,"value":-0.08,"leftHandleValue":0,"leftHandleSpan":0.402,"rightHandleValue":0,"rightHandleSpan":0.735},
						{"time":1,"value":0}
					]
				}
			},
			{"i":8,"name":"ReelContainer1","uid":"4791506961612279","position":[-360,0,0]},
			{
				"i":9,
				"type":"GraphicObject",
				"name":"ReelMask",
				"uid":"0784921421762356",
				"scale":[3.6,12,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.01,
				"masking":{"enabled":true,"type":"mask","maskGroups":["ReelMask"]},
				"effectControllerValues":{"fillColor":[1,1,1,0.2]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":10,
				"type":"SymbolReel",
				"name":"SymbolReel1",
				"uid":"3164920587741603",
				"position":[0,450,0],
				"defaultSymbolType":"GraphicObject",
				"numMainSymbols":4,
				"spinSpeed":-0.55,
				"windupDuration":0.24,
				"initialReelData":["Minor2","Wild","Minor3","Minor3","Major2","Major2"],
				"pathValues":{
					"position.y":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":300},
							{"time":0,"value":0},
							{"time":1,"value":-300},
							{"time":2,"value":-600},
							{"time":3,"value":-900},
							{"time":4,"value":-1200}
						]
					},
					"subLayer":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":-0.05},
							{"time":0,"value":0},
							{"time":1,"value":0.05},
							{"time":2,"value":0.1},
							{"time":3,"value":0.15},
							{"time":4,"value":0.2}
						]
					}
				},
				"windupCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7,"value":-0.5,"leftHandleValue":0,"leftHandleSpan":0.396,"rightHandleValue":0,"rightHandleSpan":0.55},
						{"time":1,"value":0}
					]
				},
				"bounceCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.33,"value":-0.175,"leftHandleValue":0,"leftHandleSpan":0.453,"rightHandleValue":0,"rightHandleSpan":0.583},
						{"time":0.6,"value":0},
						{"time":0.83,"value":-0.08,"leftHandleValue":0,"leftHandleSpan":0.402,"rightHandleValue":0,"rightHandleSpan":0.735},
						{"time":1,"value":0}
					]
				}
			},
			{"i":11,"name":"ReelContainer2","uid":"1442663436352824"},
			{
				"i":12,
				"type":"GraphicObject",
				"name":"ReelMask",
				"uid":"2453127213139897",
				"scale":[3.6,12,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.01,
				"masking":{"enabled":true,"type":"mask","maskGroups":["ReelMask"]},
				"effectControllerValues":{"fillColor":[1,1,1,0.2]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":13,
				"type":"SymbolReel",
				"name":"SymbolReel2",
				"uid":"7409518362205974",
				"position":[0,450,0],
				"defaultSymbolType":"GraphicObject",
				"numMainSymbols":4,
				"spinSpeed":-0.55,
				"windupDuration":0.28,
				"initialReelData":["Wild","Minor1","Minor1","Major3","Major3","Major3"],
				"pathValues":{
					"position.y":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":300},
							{"time":0,"value":0},
							{"time":1,"value":-300},
							{"time":2,"value":-600},
							{"time":3,"value":-900},
							{"time":4,"value":-1200}
						]
					},
					"subLayer":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":-0.05},
							{"time":0,"value":0},
							{"time":1,"value":0.05},
							{"time":2,"value":0.1},
							{"time":3,"value":0.15},
							{"time":4,"value":0.2}
						]
					}
				},
				"windupCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7,"value":-0.5,"leftHandleValue":0,"leftHandleSpan":0.396,"rightHandleValue":0,"rightHandleSpan":0.55},
						{"time":1,"value":0}
					]
				},
				"bounceCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.33,"value":-0.175,"leftHandleValue":0,"leftHandleSpan":0.453,"rightHandleValue":0,"rightHandleSpan":0.583},
						{"time":0.6,"value":0},
						{"time":0.83,"value":-0.08,"leftHandleValue":0,"leftHandleSpan":0.402,"rightHandleValue":0,"rightHandleSpan":0.735},
						{"time":1,"value":0}
					]
				}
			},
			{"i":14,"name":"ReelContainer3","uid":"1109033499726488","position":[360,0,0]},
			{
				"i":15,
				"type":"GraphicObject",
				"name":"ReelMask",
				"uid":"1273215940211608",
				"scale":[3.6,12,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.01,
				"masking":{"enabled":true,"type":"mask","maskGroups":["ReelMask"]},
				"effectControllerValues":{"fillColor":[1,1,1,0.2]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":16,
				"type":"SymbolReel",
				"name":"SymbolReel3",
				"uid":"2076341895630287",
				"position":[0,450,0],
				"defaultSymbolType":"GraphicObject",
				"numMainSymbols":4,
				"spinSpeed":-0.55,
				"windupDuration":0.32,
				"initialReelData":["Minor2","Major3","Major3","Major3","Minor3","Minor3"],
				"pathValues":{
					"position.y":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":300},
							{"time":0,"value":0},
							{"time":1,"value":-300},
							{"time":2,"value":-600},
							{"time":3,"value":-900},
							{"time":4,"value":-1200}
						]
					},
					"subLayer":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":-0.05},
							{"time":0,"value":0},
							{"time":1,"value":0.05},
							{"time":2,"value":0.1},
							{"time":3,"value":0.15},
							{"time":4,"value":0.2}
						]
					}
				},
				"windupCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7,"value":-0.5,"leftHandleValue":0,"leftHandleSpan":0.396,"rightHandleValue":0,"rightHandleSpan":0.55},
						{"time":1,"value":0}
					]
				},
				"bounceCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.33,"value":-0.175,"leftHandleValue":0,"leftHandleSpan":0.453,"rightHandleValue":0,"rightHandleSpan":0.583},
						{"time":0.6,"value":0},
						{"time":0.83,"value":-0.08,"leftHandleValue":0,"leftHandleSpan":0.402,"rightHandleValue":0,"rightHandleSpan":0.735},
						{"time":1,"value":0}
					]
				}
			},
			{"i":17,"name":"ReelContainer4","uid":"8316685187983155","position":[720,0,0]},
			{
				"i":18,
				"type":"GraphicObject",
				"name":"ReelMask",
				"uid":"6574191565655363",
				"scale":[3.6,12,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.01,
				"masking":{"enabled":true,"type":"mask","maskGroups":["ReelMask"]},
				"effectControllerValues":{"fillColor":[1,1,1,0.2]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":19,
				"type":"SymbolReel",
				"name":"SymbolReel4",
				"uid":"9538172604418735",
				"position":[0,450,0],
				"defaultSymbolType":"GraphicObject",
				"numMainSymbols":4,
				"spinSpeed":-0.55,
				"windupDuration":0.36,
				"initialReelData":["Major2","Major2","Major2","Minor3","Minor3","Bonus"],
				"pathValues":{
					"position.y":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":300},
							{"time":0,"value":0},
							{"time":1,"value":-300},
							{"time":2,"value":-600},
							{"time":3,"value":-900},
							{"time":4,"value":-1200}
						]
					},
					"subLayer":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":-0.05},
							{"time":0,"value":0},
							{"time":1,"value":0.05},
							{"time":2,"value":0.1},
							{"time":3,"value":0.15},
							{"time":4,"value":0.2}
						]
					}
				},
				"windupCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7,"value":-0.5,"leftHandleValue":0,"leftHandleSpan":0.396,"rightHandleValue":0,"rightHandleSpan":0.55},
						{"time":1,"value":0}
					]
				},
				"bounceCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.33,"value":-0.175,"leftHandleValue":0,"leftHandleSpan":0.453,"rightHandleValue":0,"rightHandleSpan":0.583},
						{"time":0.6,"value":0},
						{"time":0.83,"value":-0.08,"leftHandleValue":0,"leftHandleSpan":0.402,"rightHandleValue":0,"rightHandleSpan":0.735},
						{"time":1,"value":0}
					]
				}
			},
			{
				"i":20,
				"type":"TextBox",
				"name":"CenterWinMeter",
				"uid":"1153144534724274",
				"enabled":false,
				"subLayer":0.6,
				"string":"$100.00",
				"horizontalJustification":"center",
				"boxWidth":2000,
				"boxHeight":400,
				"textFormat":{
					"fontName":"ThemedFont",
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":21,
				"type":"GraphicObject",
				"name":"CenterWinMeterShadow",
				"uid":"4164419886904129",
				"position":[0,-39.2825401992543,0],
				"scale":[10,10,10],
				"graphicAsset":"CenterWinMeterShadow",
				"subLayer":0.5,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{"i":22,"constructDefinition":"Dashboard","type":"Construct","name":"Dashboard","uid":"6403247578121807"},
			{
				"i":23,
				"type":"Button",
				"name":"GameIntroBackground",
				"uid":"7089794052441777",
				"enabled":false,
				"scale":[100,100,1],
				"graphicAsset":"WhiteBox",
				"layer":"GameIntro",
				"subLayer":-0.5,
				"effectControllerValues":{"fillColor":[0,0,0,1]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{
				"i":24,
				"constructDefinition":"GameIntroAnimation",
				"type":"Construct",
				"name":"GameIntroAnimation",
				"uid":"0061686663830606",
				"enabled":false,
				"position":[0,250,0],
				"scale":[0.85,0.85,1]
			},
			{
				"i":25,
				"type":"GraphicObject",
				"name":"BackgroundShadow",
				"uid":"7365576968087144",
				"scale":[5.4,10.8,1],
				"graphicAsset":"InnerShadow",
				"layer":"GameBackground",
				"subLayer":0.02799999999999977,
				"effectControllerValues":{"colorMultiply":[1,1,1,0.5]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":26,
				"type":"GraphicObject",
				"name":"GameBackgroundPattern",
				"uid":"4773984937761232",
				"scale":[2,2,1],
				"graphicAsset":"Background",
				"layer":"GameBackground",
				"masking":{"enabled":false,"type":"mask","maskGroups":["MainMaskGroup"]},
				"effectControllerValues":{"colorMultiply":[0.708866666666667,0.708866666666667,0.708866666666667,1]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":27,
				"type":"ParticleSystem",
				"name":"FallingStartParticles",
				"uid":"0254323932672707",
				"position":[0,1331.9586675620262,0],
				"layer":"GameBackground",
				"frustumCulling":false,
				"masking":{"enabled":true,"maskGroups":["FallingStarMask"]},
				"particleSystemDefinition":"FallingStars",
				"playbackController":{"autoplayMode":"loop","initialTime":500,"playbackRate":1,"startValue":0,"endValue":4000},
				"materials":[
					{"effectNodes":["SampleMainTexture","FallingStarsParticleSystemEffectNode"]}
				]
			},
			{
				"i":28,
				"type":"GraphicObject",
				"name":"FallingStarMask",
				"uid":"3671157916868505",
				"graphicAsset":"Background",
				"layer":"GameBackground",
				"subLayer":-0.047999999999999945,
				"masking":{"enabled":true,"type":"mask","maskGroups":["FallingStarMask"]},
				"materials":[
					{"effectNodes":["MaskingReturn","SampleMainTexture","ColorMultiply"]}
				]
			}
		]
	},
	"timelines":{
		"BaseLayout_Mobile":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-2,"value":1400},
						{"time":-1,"value":783.0000000000015},
						{"time":1,"value":837.2507196944065},
						{"time":1.6833333333333333,"value":813.8216015403309},
						{"time":2,"value":744.427619956735}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-1,"value":0},
						{"time":1,"value":-718.2498822089738},
						{"time":1.6833333333333333,"value":-1442.7845711670052},
						{"time":2,"value":-1683.3982075134104}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-560},
						{"time":-2,"value":-560},
						{"time":-1.5,"value":-196.00000000000068},
						{"time":-1,"value":-86.00000000000114},
						{"time":1,"value":0},
						{"time":1.5,"value":-45.99999999999716},
						{"time":1.6833333333333333,"value":85.00000000000242}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":1100}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"7175220269991170"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Mobile","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":-2,"value":5.4},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4},
						{"time":2,"value":10.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"keyframes":[
						{"time":-2,"value":10.8},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Desktop","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Desktop","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":1}
					],
					"propertyPath":["timelines","Layout_Mobile","weight"],
					"sceneObjectUid":"6403247578121807"
				}
			]
		},
		"BaseLayout_Desktop":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-2,"value":1400},
						{"time":-1,"value":783.0000000000015},
						{"time":1,"value":837.2507196944065},
						{"time":1.6833333333333333,"value":813.8216015403309},
						{"time":2,"value":744.427619956735}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-1,"value":0},
						{"time":1,"value":-718.2498822089738},
						{"time":1.6833333333333333,"value":-1442.7845711670052},
						{"time":2,"value":-1683.3982075134104}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-560},
						{"time":-2,"value":-560},
						{"time":-1.5,"value":-196.00000000000068},
						{"time":-1,"value":-86.00000000000114},
						{"time":1,"value":0},
						{"time":1.5,"value":-45.99999999999716},
						{"time":1.6833333333333333,"value":85.00000000000242}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":1100}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"7175220269991170"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Mobile","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":-2,"value":5.4},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4},
						{"time":2,"value":10.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"keyframes":[
						{"time":-2,"value":10.8},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Mobile","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":1}
					],
					"propertyPath":["timelines","Layout_Desktop","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Desktop","time"],
					"sceneObjectUid":"6403247578121807"
				}
			]
		},
		"BaseLayout_EgmSingleScreen":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-2,"value":1400},
						{"time":-1,"value":783.0000000000015},
						{"time":1,"value":837.2507196944065},
						{"time":1.6833333333333333,"value":813.8216015403309},
						{"time":2,"value":744.427619956735}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-1,"value":0},
						{"time":1,"value":-718.2498822089738},
						{"time":1.6833333333333333,"value":-1442.7845711670052},
						{"time":2,"value":-1683.3982075134104}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-560},
						{"time":-2,"value":-560},
						{"time":-1.5,"value":-196.00000000000068},
						{"time":-1,"value":-86.00000000000114},
						{"time":1,"value":0},
						{"time":1.5,"value":-45.99999999999716},
						{"time":1.6833333333333333,"value":85.00000000000242}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":1100}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"7175220269991170"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Mobile","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":-2,"value":5.4},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4},
						{"time":2,"value":10.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"keyframes":[
						{"time":-2,"value":10.8},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Mobile","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Desktop","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Desktop","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_EGM","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":1}
					],
					"propertyPath":["timelines","Layout_EGM","weight"],
					"sceneObjectUid":"6403247578121807"
				}
			]
		},
		"BaseLayout_EgmDualScreen":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-4,"value":1115},
						{"time":-2,"value":1105.0000000000005},
						{"time":-1,"value":550.0000000000014},
						{"time":1,"value":550.0000000000014},
						{"time":1.6833333333333333,"value":550.0000000000014},
						{"time":2,"value":550.0000000000014}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-1,"value":0},
						{"time":1,"value":0},
						{"time":1.6833333333333333,"value":0},
						{"time":2,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":1},
						{"time":1,"value":1},
						{"time":1.6833333333333333,"value":1},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":1},
						{"time":1,"value":1},
						{"time":1.6833333333333333,"value":1},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":1,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-1050},
						{"time":-2,"value":-1040},
						{"time":-1.5,"value":-750},
						{"time":-1,"value":-490},
						{"time":1,"value":-490},
						{"time":1.5,"value":-490},
						{"time":1.6833333333333333,"value":-490},
						{"time":2,"value":-490}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":1100}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"7175220269991170"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.73},
						{"time":1,"value":0.73},
						{"time":1.5,"value":0.73},
						{"time":1.6833333333333333,"value":0.73},
						{"time":2,"value":0.73}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.73},
						{"time":1,"value":0.73},
						{"time":1.5,"value":0.73},
						{"time":1.6833333333333333,"value":0.73},
						{"time":2,"value":0.73}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Mobile","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":-2,"value":5.4},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4},
						{"time":2,"value":10.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"keyframes":[
						{"time":-2,"value":10.8},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Mobile","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Desktop","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Desktop","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_EGM","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":1}
					],
					"propertyPath":["timelines","Layout_EGM","weight"],
					"sceneObjectUid":"6403247578121807"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"BaseLayout_Mobile"}
}

Assets/GameLayout/GameLayout.construct.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/GameTitle.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.downscalingMode is "mipmapLinear" instead of the default null.

Assets/GameLayout/InnerShadow.png.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/ReelBackground.png.ncData
------------------------------------------------------------
default ncData file

Assets/LayersAndMasks/main.maskGroups.ncData
------------------------------------------------------------
default ncData file

Assets/LayersAndMasks/MainScene.layers
------------------------------------------------------------
{"layers":["GameBackground","Reels","WinningSymbols","GameTitle","Dashboard","GameIntro","GameMenus"]}

Assets/LayersAndMasks/MainScene.layers.ncData
------------------------------------------------------------
default ncData file

Assets/ParticleSystems/FallingStars.particleSysDef.ncData
------------------------------------------------------------
default ncData file

Assets/ParticleSystems/SampleParticle.png.ncData
------------------------------------------------------------
default ncData file

Assets/ParticleSystems/StarBurst.particleSysDef.ncData
------------------------------------------------------------
default ncData file

Assets/ParticleSystems/StarParticle.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.downscalingMode is "mipmapLinear" instead of the default null.

Assets/Sounds/ReelSpinSound.wav.ncData
------------------------------------------------------------
default ncData file

Assets/Sounds/ReelStop.wav.ncData
------------------------------------------------------------
default ncData file

Assets/Sounds/SpinBegin.wav.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarGrayThick_Plate.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarGrayThick_Text.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarGrayThin_Plate.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarGrayThin_Text.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarWhite_Plate.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarWhite_Text.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Bonus_Star.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Bonus_Text.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BonusConstruct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Bonus_Star",
				"uid":"4323194875749118",
				"position":[0.53,-0.93,0],
				"scale":[0.4679,0.4913,1],
				"graphicAsset":"Bonus_Star",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,192.3,85.5],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Bonus_Text",
				"uid":"6252760189555979",
				"position":[-3.29,-3.22,0],
				"scale":[0.4238,0.4319,1],
				"graphicAsset":"Bonus_Text",
				"subLayer":0.01,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,212.4,94.4],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"1809679290810033",
				"position":[0,0,1000],
				"coreViewWidth":400,
				"coreViewHeight":400,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":400,
				"constructPrecompTargetHeight":400
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":0,"value":0.53,"rightHandleValue":3.8887,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-5.361,
							"leftHandleValue":0.7538,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.8864,
							"rightHandleSpan":0.4
						},
						{
							"time":0.383333,
							"value":5.537,
							"leftHandleValue":0.7581,
							"leftHandleSpan":0.4,
							"rightHandleValue":-13.2348,
							"rightHandleSpan":0.8
						},
						{"time":0.75,"value":0.517,"leftHandleValue":1.7338,"leftHandleSpan":1},
						{"time":2,"value":0.53}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0,"value":-0.93,"rightHandleValue":-1.2185,"rightHandleSpan":0.4},
						{
							"time":0.1,
							"value":-1.108,
							"leftHandleValue":-0.6302,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.9874,
							"rightHandleSpan":0.4
						},
						{
							"time":0.283333,
							"value":-10.814,
							"leftHandleValue":0.9468,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.4736,
							"rightHandleSpan":0.4
						},
						{
							"time":0.716667,
							"value":-0.959,
							"leftHandleValue":3.7002,
							"leftHandleSpan":0.9,
							"rightHandleValue":1.2911,
							"rightHandleSpan":0.7
						},
						{"time":2,"value":-0.93,"leftHandleValue":0.1337,"leftHandleSpan":0.7}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4679,"rightHandleValue":-0.023,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.40031,
							"leftHandleValue":0.0096,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0155,
							"rightHandleSpan":0.2
						},
						{
							"time":0.283333,
							"value":0.66279,
							"leftHandleValue":0.0325,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0181,
							"rightHandleSpan":0.3
						},
						{
							"time":0.666667,
							"value":0.47725,
							"leftHandleValue":0.0788,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0129,
							"rightHandleSpan":0.1
						},
						{
							"time":0.966667,
							"value":0.44483,
							"leftHandleValue":-0.0007,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0175,
							"rightHandleSpan":1
						},
						{
							"time":1.266667,
							"value":0.60377,
							"leftHandleValue":-0.1236,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0155,
							"rightHandleSpan":0.2
						},
						{
							"time":1.383333,
							"value":0.54948,
							"leftHandleValue":0.0439,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1269,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.4679,"leftHandleValue":-0.015,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4913,"rightHandleValue":-0.0241,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.42033,
							"leftHandleValue":0.0101,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0162,
							"rightHandleSpan":0.2
						},
						{
							"time":0.283333,
							"value":0.69594,
							"leftHandleValue":0.0341,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0016,
							"rightHandleSpan":0.2
						},
						{
							"time":0.666667,
							"value":0.50112,
							"leftHandleValue":0.0854,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0136,
							"rightHandleSpan":0.1
						},
						{
							"time":0.966667,
							"value":0.46707,
							"leftHandleValue":-0.0007,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0183,
							"rightHandleSpan":1
						},
						{
							"time":1.266667,
							"value":0.63397,
							"leftHandleValue":-0.1297,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0163,
							"rightHandleSpan":0.2
						},
						{
							"time":1.383333,
							"value":0.57696,
							"leftHandleValue":0.0461,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1333,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.4913,"leftHandleValue":-0.0157,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-5.2605,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":-18.454,
							"leftHandleValue":-1.7077,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1853,
							"rightHandleSpan":0.2
						},
						{
							"time":0.083333,
							"value":3.935,
							"leftHandleValue":-10.0695,
							"leftHandleSpan":0.4,
							"rightHandleValue":97.6694,
							"rightHandleSpan":0.3
						},
						{"time":0.5,"value":372,"leftHandleValue":-79.6611,"leftHandleSpan":0.3,"rightHandleValue":8.0261,"rightHandleSpan":0.4},
						{
							"time":0.533333,
							"value":380.804,
							"leftHandleValue":0.2407,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.7307,
							"rightHandleSpan":0.4
						},
						{
							"time":0.633333,
							"value":355.601,
							"leftHandleValue":-2.0591,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.0687,
							"rightHandleSpan":0.3
						},
						{
							"time":0.983333,
							"value":360.805,
							"leftHandleValue":0.4832,
							"leftHandleSpan":1,
							"rightHandleValue":0.4889,
							"rightHandleSpan":1
						},
						{"time":1.3,"value":356,"leftHandleValue":1.2912,"leftHandleSpan":0.3,"rightHandleValue":1.6065,"rightHandleSpan":0.4},
						{
							"time":1.416667,
							"value":364.095,
							"leftHandleValue":0.8197,
							"leftHandleSpan":0.4,
							"rightHandleValue":-5.843,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":360,"leftHandleValue":-0.3582,"leftHandleSpan":1}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0,"value":-3.29,"rightHandleValue":0.7934,"rightHandleSpan":0.6},
						{
							"time":0.316667,
							"value":-5.263,
							"leftHandleValue":1.5972,
							"leftHandleSpan":0.3,
							"rightHandleValue":6.8116,
							"rightHandleSpan":0.2
						},
						{
							"time":0.666667,
							"value":-2.838,
							"leftHandleValue":-4.2644,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.9057,
							"rightHandleSpan":0.4
						},
						{
							"time":1.316667,
							"value":-5.719,
							"leftHandleValue":5.3829,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.0606,
							"rightHandleSpan":0.4
						},
						{"time":1.716667,"value":-3.472,"leftHandleValue":-0.8677,"leftHandleSpan":1},
						{"time":2,"value":-3.29}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				},
				{
					"keyframes":[
						{"time":0,"value":-3.22,"rightHandleValue":-3.2696,"rightHandleSpan":0.8},
						{
							"time":0.316667,
							"value":3.843,
							"leftHandleValue":-3.5078,
							"leftHandleSpan":0.3,
							"rightHandleValue":-4.5788,
							"rightHandleSpan":0.6
						},
						{
							"time":0.583333,
							"value":-1.439,
							"leftHandleValue":-5.5209,
							"leftHandleSpan":1,
							"rightHandleValue":-3.1196,
							"rightHandleSpan":0.4
						},
						{
							"time":1.033333,
							"value":-4.003,
							"leftHandleValue":0.4816,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.0463,
							"rightHandleSpan":0.8
						},
						{
							"time":1.283333,
							"value":2.008,
							"leftHandleValue":-1.5356,
							"leftHandleSpan":0.3,
							"rightHandleValue":-10.1659,
							"rightHandleSpan":0.3
						},
						{"time":1.8,"value":-3.197,"leftHandleValue":2.4187,"leftHandleSpan":0.7},
						{"time":2,"value":-3.22}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4238,"rightHandleValue":-0.0009,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":0.4238,
							"leftHandleValue":-0.0536,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0485,
							"rightHandleSpan":0.4
						},
						{
							"time":0.316667,
							"value":0.67791,
							"leftHandleValue":-0.0251,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0101,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.3936,
							"leftHandleValue":0.015,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0003,
							"rightHandleSpan":0.4
						},
						{
							"time":0.566667,
							"value":0.49179,
							"leftHandleValue":0.0014,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0399,
							"rightHandleSpan":0.3
						},
						{"time":1,"value":0.39607,"leftHandleValue":0.0188,"leftHandleSpan":1,"rightHandleValue":0.0026,"rightHandleSpan":0.4},
						{
							"time":1.183333,
							"value":0.42546,
							"leftHandleValue":-0.024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0356,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":0.61379,
							"leftHandleValue":0.0031,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0329,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.39637,
							"leftHandleValue":0.0007,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0135,
							"rightHandleSpan":0.4
						},
						{"time":1.65,"value":0.4238,"leftHandleValue":0.0617,"leftHandleSpan":0.9},
						{"time":2,"value":0.4238}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4319,"rightHandleValue":-0.0009,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":0.4319,
							"leftHandleValue":-0.0546,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0228,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":0.69086,
							"leftHandleValue":0.0001,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0103,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.40113,
							"leftHandleValue":0.0153,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0003,
							"rightHandleSpan":0.4
						},
						{
							"time":0.566667,
							"value":0.50119,
							"leftHandleValue":0.0014,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0406,
							"rightHandleSpan":0.3
						},
						{"time":1,"value":0.40364,"leftHandleValue":0.0192,"leftHandleSpan":1,"rightHandleValue":0.0027,"rightHandleSpan":0.4},
						{
							"time":1.183333,
							"value":0.43359,
							"leftHandleValue":-0.0245,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0363,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":0.62552,
							"leftHandleValue":0.0031,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0335,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.40395,
							"leftHandleValue":0.0007,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0332,
							"rightHandleSpan":0.5
						},
						{"time":1.65,"value":0.4319,"leftHandleValue":0.057,"leftHandleSpan":0.9},
						{"time":2,"value":0.4319}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.316667,"value":0,"rightHandleValue":0.3422,"rightHandleSpan":0.1},
						{
							"time":0.383333,
							"value":-6.543,
							"leftHandleValue":-0.5987,
							"leftHandleSpan":0.5,
							"rightHandleValue":1.3667,
							"rightHandleSpan":0.4
						},
						{
							"time":0.516667,
							"value":4.314,
							"leftHandleValue":0.3607,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.901,
							"rightHandleSpan":0.4
						},
						{
							"time":0.65,
							"value":-2.844,
							"leftHandleValue":-0.2378,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.4984,
							"rightHandleSpan":0.6
						},
						{
							"time":0.916667,
							"value":-1.236,
							"leftHandleValue":5.4774,
							"leftHandleSpan":0.9,
							"rightHandleValue":4.1934,
							"rightHandleSpan":0.6
						},
						{
							"time":1.266667,
							"value":0,
							"leftHandleValue":-1.0954,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.5026,
							"rightHandleSpan":0.3
						},
						{
							"time":1.333333,
							"value":4.778,
							"leftHandleValue":0.8875,
							"leftHandleSpan":0.6,
							"rightHandleValue":-2.1333,
							"rightHandleSpan":0.4
						},
						{
							"time":1.433333,
							"value":-3.15,
							"leftHandleValue":-1.0292,
							"leftHandleSpan":0.4,
							"rightHandleValue":10.0112,
							"rightHandleSpan":0.7
						},
						{
							"time":1.633333,
							"value":-1.369,
							"leftHandleValue":1.4133,
							"leftHandleSpan":0.6,
							"rightHandleValue":5.0772,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-1.7674,"leftHandleSpan":0.9}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				},
				{
					"keyframes":[
						{"time":0.466667,"value":-704.7,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.866667,"value":705.9,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.2,"value":-704.7,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.5,"value":705.9,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0.466667,"value":-767.8,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.866667,"value":789.5,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.2,"value":-767.8,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.5,"value":789.5,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/BonusConstruct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major1_Fill.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major1_Outline.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major1_Shell.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major1Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Major1_Shell",
				"uid":"7114710497465075",
				"position":[0.45,0.52,0],
				"scale":[0.4934,0.4934,1],
				"graphicAsset":"Major1_Shell",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Major1_Outline",
				"uid":"8426846563212233",
				"position":[-2.16,9.37,0],
				"scale":[0.4474,0.4492,1],
				"graphicAsset":"Major1_Outline",
				"subLayer":0.02,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,156.5,55.9],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"Major1_Fill",
				"uid":"2917034236671276",
				"position":[-2.18,6.59,0],
				"scale":[0.4725,0.4781,1],
				"graphicAsset":"Major1_Fill",
				"subLayer":0.01,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,148.1,52.9],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"6581741668587752",
				"position":[0,0,1000],
				"coreViewWidth":500,
				"coreViewHeight":500,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":500,
				"constructPrecompTargetHeight":500
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.45},
						{"time":0.13333333333333333,"value":1.407,"rightHandleValue":0.9937,"rightHandleSpan":0.99},
						{
							"time":0.21666666666666667,
							"value":12.023,
							"leftHandleValue":-6.5745,
							"leftHandleSpan":0.3,
							"rightHandleValue":1.9184,
							"rightHandleSpan":0.4
						},
						{
							"time":0.25,
							"value":10.925,
							"leftHandleValue":-0.736,
							"leftHandleSpan":0.4,
							"rightHandleValue":14.4002,
							"rightHandleSpan":0.7
						},
						{
							"time":0.36666666666666664,
							"value":15.455,
							"leftHandleValue":-4.8312,
							"leftHandleSpan":0.8,
							"rightHandleValue":-14.0663,
							"rightHandleSpan":0.6
						},
						{
							"time":1.25,
							"value":-14.383,
							"leftHandleValue":9.1609,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2698,
							"rightHandleSpan":0.4
						},
						{"time":1.4,"value":2.012,"leftHandleValue":2.187,"leftHandleSpan":0.6,"rightHandleValue":19.5066,"rightHandleSpan":0.4},
						{
							"time":1.4666666666666666,
							"value":-4.238,
							"leftHandleValue":1.3204,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.6051,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-2.831,
							"leftHandleValue":16.2673,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.9377,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":1.97,
							"leftHandleValue":-0.3131,
							"leftHandleSpan":0.4,
							"rightHandleValue":-10.0545,
							"rightHandleSpan":0.8
						},
						{
							"time":1.7333333333333334,
							"value":-0.647,
							"leftHandleValue":5.5423,
							"leftHandleSpan":0.9,
							"rightHandleValue":2.2003,
							"rightHandleSpan":0.1
						},
						{"time":2,"value":0.45,"leftHandleValue":-0.0308,"leftHandleSpan":0.7}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.52,"rightHandleValue":-4.2852,"rightHandleSpan":0.3},
						{
							"time":0.2,
							"value":7.108,
							"leftHandleValue":-5.5468,
							"leftHandleSpan":0.4,
							"rightHandleValue":13.691,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":10.562,
							"leftHandleValue":-11.6416,
							"leftHandleSpan":0.6,
							"rightHandleValue":3.1658,
							"rightHandleSpan":0.1
						},
						{
							"time":0.3333333333333333,
							"value":10.241,
							"leftHandleValue":-4.6685,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.6815,
							"rightHandleSpan":0.05
						},
						{
							"time":1.25,
							"value":-2.153,
							"leftHandleValue":15.6351,
							"leftHandleSpan":0.8,
							"rightHandleValue":1.7012,
							"rightHandleSpan":0.5
						},
						{
							"time":1.4,
							"value":-0.663,
							"leftHandleValue":6.7407,
							"leftHandleSpan":0.7,
							"rightHandleValue":13.5789,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":-4.802,
							"leftHandleValue":4.914,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.076,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":4.635,
							"leftHandleValue":3.6363,
							"leftHandleSpan":0.4,
							"rightHandleValue":-16.2724,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":-0.676,
							"leftHandleValue":13.5085,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.0401,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":-0.869,
							"leftHandleValue":5.8405,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.1108,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":1.098,
							"leftHandleValue":-2.7966,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.2293,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.52,"leftHandleValue":0.4866,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":0.5395,"rightHandleSpan":0.4},
						{
							"time":0.11666666666666667,
							"value":4.32,
							"leftHandleValue":-0.2111,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.8088,
							"rightHandleSpan":0.5
						},
						{
							"time":0.26666666666666666,
							"value":-32.994,
							"leftHandleValue":13.6833,
							"leftHandleSpan":0.4,
							"rightHandleValue":-8.087,
							"rightHandleSpan":0.1
						},
						{
							"time":1.2666666666666666,
							"value":-47.581,
							"leftHandleValue":-17.567,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.5886,
							"rightHandleSpan":0.4
						},
						{"time":1.45,"value":1.282,"leftHandleValue":1.417,"leftHandleSpan":0.6,"rightHandleValue":-3.296,"rightHandleSpan":0.4},
						{"time":2,"value":0,"leftHandleValue":2.1563,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4934,"rightHandleValue":-0.0324,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41446,
							"leftHandleValue":-0.0162,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0955,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.75239,
							"leftHandleValue":0.0018,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0358,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.69074,
							"leftHandleValue":-0.0136,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0408,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.76209,
							"leftHandleValue":-0.0241,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0187,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.43011,
							"leftHandleValue":-0.0047,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0212,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.55278,
							"leftHandleValue":0.0112,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0145,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.47708,
							"leftHandleValue":-0.0066,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0379,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4934,"leftHandleValue":0.0105,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4934,"rightHandleValue":-0.0324,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41446,
							"leftHandleValue":-0.0162,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0955,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.75239,
							"leftHandleValue":0.0018,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0358,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.69074,
							"leftHandleValue":-0.0136,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0408,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.76209,
							"leftHandleValue":-0.0241,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0187,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.43011,
							"leftHandleValue":-0.0047,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0212,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.55278,
							"leftHandleValue":0.0112,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0145,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.47708,
							"leftHandleValue":-0.0066,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0379,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4934,"leftHandleValue":0.0105,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.4383,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":9.975,
							"leftHandleValue":-0.0155,
							"leftHandleSpan":0.3,
							"rightHandleValue":-6.2697,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-7.645,
							"leftHandleValue":4.0732,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.5734,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":7.651,
							"leftHandleValue":-2.2661,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2313,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.161,
							"leftHandleValue":0.0168,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.2937,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.6903,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1211,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.402,
							"leftHandleValue":-0.6816,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2624,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-19.383,
							"leftHandleValue":-0.1834,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.3058,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":16.114,
							"leftHandleValue":-14.0516,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4864,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-11.089,
							"leftHandleValue":4.7516,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.9034,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.118,
							"leftHandleValue":-0.9491,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7544,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.2574,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-3.4771,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":-8.1,
							"leftHandleValue":0.8194,
							"leftHandleSpan":0.3,
							"rightHandleValue":5.3748,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2666666666666666,
							"value":7.586,
							"leftHandleValue":-7.1253,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.3395,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-8.947,
							"leftHandleValue":2.1857,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0913,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":4.247,
							"leftHandleValue":0.5918,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7415,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.8319,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-2.16,"rightHandleValue":-0.1308,"rightHandleSpan":0.3},
						{
							"time":0.2,
							"value":-4.125,
							"leftHandleValue":6.3892,
							"leftHandleSpan":0.2,
							"rightHandleValue":8.7811,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":-15.429,
							"leftHandleValue":-2.7316,
							"leftHandleSpan":0.5,
							"rightHandleValue":6.7738,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":-13.286,
							"leftHandleValue":-5.404,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.8269,
							"rightHandleSpan":0.2
						},
						{
							"time":1.2166666666666666,
							"value":4.732,
							"leftHandleValue":-2.875,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.3365,
							"rightHandleSpan":0.6
						},
						{
							"time":1.35,
							"value":-1.54,
							"leftHandleValue":1.3927,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.0149,
							"rightHandleSpan":0.99
						},
						{
							"time":1.4166666666666667,
							"value":7.494,
							"leftHandleValue":-9.2439,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.7406,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-5.867,
							"leftHandleValue":0.1576,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.814,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-6.231,
							"leftHandleValue":17.6014,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.2386,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":-1.623,
							"leftHandleValue":-0.4026,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.0718,
							"rightHandleSpan":0.8
						},
						{
							"time":1.7333333333333334,
							"value":-3.235,
							"leftHandleValue":5.872,
							"leftHandleSpan":0.8,
							"rightHandleValue":3.0976,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-2.16,"leftHandleValue":-0.2856,"leftHandleSpan":0.8}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":9.37,"rightHandleValue":-9.3454,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":17.778,
							"leftHandleValue":0.5959,
							"leftHandleSpan":0.4,
							"rightHandleValue":11.3647,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":13.661,
							"leftHandleValue":-8.8832,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.1714,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":12.768,
							"leftHandleValue":-4.7192,
							"leftHandleSpan":0.8,
							"rightHandleValue":-3.9398,
							"rightHandleSpan":0.05
						},
						{
							"time":1.25,
							"value":26.948,
							"leftHandleValue":-6.0041,
							"leftHandleSpan":0.2,
							"rightHandleValue":1.81,
							"rightHandleSpan":0.3
						},
						{
							"time":1.4,
							"value":6.798,
							"leftHandleValue":1.8145,
							"leftHandleSpan":0.5,
							"rightHandleValue":13.7627,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":3.722,
							"leftHandleValue":4.3766,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5197,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":14.431,
							"leftHandleValue":3.2635,
							"leftHandleSpan":0.4,
							"rightHandleValue":-16.0151,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":8.183,
							"leftHandleValue":14.4359,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.325,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":7.487,
							"leftHandleValue":5.8721,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.2231,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":10.146,
							"leftHandleValue":-3.1291,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.0196,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":9.37,"leftHandleValue":0.4711,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":0.4037,"rightHandleSpan":0.4},
						{
							"time":0.1,
							"value":-1.647,
							"leftHandleValue":-0.1489,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2338,
							"rightHandleSpan":0.6
						},
						{
							"time":0.26666666666666666,
							"value":39.096,
							"leftHandleValue":-14.3258,
							"leftHandleSpan":0.4,
							"rightHandleValue":7.9981,
							"rightHandleSpan":0.1
						},
						{
							"time":1.2666666666666666,
							"value":42.457,
							"leftHandleValue":22.7581,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.6616,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3833333333333333,
							"value":6.745,
							"leftHandleValue":4.7791,
							"leftHandleSpan":0.3,
							"rightHandleValue":-6.9925,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":1.237,
							"leftHandleValue":1.5628,
							"leftHandleSpan":0.4,
							"rightHandleValue":-7.1665,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":0,"leftHandleValue":2.2761,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4474,"rightHandleValue":-0.0294,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.37582,
							"leftHandleValue":-0.0147,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0866,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.68225,
							"leftHandleValue":0.0017,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0325,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.62634,
							"leftHandleValue":-0.0124,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.037,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.69104,
							"leftHandleValue":-0.0219,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0169,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39001,
							"leftHandleValue":-0.0043,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0192,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.50124,
							"leftHandleValue":0.0102,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0131,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.4326,
							"leftHandleValue":-0.006,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0274,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4474,"leftHandleValue":0.0135,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4492,"rightHandleValue":-0.0295,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.37733,
							"leftHandleValue":-0.0148,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.087,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.68499,
							"leftHandleValue":0.0017,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0326,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.62886,
							"leftHandleValue":-0.0124,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0372,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.69382,
							"leftHandleValue":-0.022,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.017,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39158,
							"leftHandleValue":-0.0043,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0193,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.50326,
							"leftHandleValue":0.0102,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0132,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.43434,
							"leftHandleValue":-0.006,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0276,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4492,"leftHandleValue":0.0135,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.4383,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":9.975,
							"leftHandleValue":-0.0155,
							"leftHandleSpan":0.3,
							"rightHandleValue":-6.2697,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-7.645,
							"leftHandleValue":4.0732,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.5734,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":7.651,
							"leftHandleValue":-2.2661,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2313,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.161,
							"leftHandleValue":0.0168,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.2937,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.6903,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1211,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.402,
							"leftHandleValue":-0.6816,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2624,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-19.383,
							"leftHandleValue":-0.1834,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.3058,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":16.114,
							"leftHandleValue":-14.0516,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4864,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-11.089,
							"leftHandleValue":4.7516,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.9034,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.118,
							"leftHandleValue":-0.9491,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7544,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.2574,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-3.4771,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":-8.1,
							"leftHandleValue":0.8194,
							"leftHandleSpan":0.3,
							"rightHandleValue":5.3748,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2666666666666666,
							"value":7.586,
							"leftHandleValue":-7.1253,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.3395,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-8.947,
							"leftHandleValue":2.1857,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0913,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":4.247,
							"leftHandleValue":0.5918,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7415,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.8319,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-2.18,"rightHandleValue":1.5668,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-1.277,
							"leftHandleValue":-0.0076,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.8129,
							"rightHandleSpan":0.4
						},
						{
							"time":0.25,
							"value":-3.503,
							"leftHandleValue":2.0648,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.056,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":-1.902,
							"leftHandleValue":5.7222,
							"leftHandleSpan":0.99,
							"rightHandleValue":3.1819,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":-1.088,
							"leftHandleValue":-1.6751,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.3573,
							"rightHandleSpan":0.8
						},
						{
							"time":1.2833333333333332,
							"value":-6.78,
							"leftHandleValue":-1.7971,
							"leftHandleSpan":0.05,
							"rightHandleValue":3.4261,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-0.113,
							"leftHandleValue":-0.4179,
							"leftHandleSpan":0.4,
							"rightHandleValue":20.136,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-6.179,
							"leftHandleValue":1.7058,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.9728,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-6.068,
							"leftHandleValue":17.1219,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.1156,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":-1.332,
							"leftHandleValue":-0.3973,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.2713,
							"rightHandleSpan":0.8
						},
						{
							"time":1.7333333333333334,
							"value":-3.26,
							"leftHandleValue":6.0865,
							"leftHandleSpan":0.8,
							"rightHandleValue":3.0194,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-2.18,"leftHandleValue":-0.3827,"leftHandleSpan":0.8}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":6.59,"rightHandleValue":-6.8383,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":15.116,
							"leftHandleValue":-6.2778,
							"leftHandleSpan":0.6,
							"rightHandleValue":13.0318,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":14.642,
							"leftHandleValue":-9.7025,
							"leftHandleSpan":0.6,
							"rightHandleValue":2.8404,
							"rightHandleSpan":0.1
						},
						{
							"time":0.3333333333333333,
							"value":14.005,
							"leftHandleValue":-4.6782,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.8291,
							"rightHandleSpan":0.05
						},
						{
							"time":1.25,
							"value":14.622,
							"leftHandleValue":-0.7748,
							"leftHandleSpan":0.9,
							"rightHandleValue":0.8272,
							"rightHandleSpan":0.4
						},
						{"time":1.4,"value":4.657,"leftHandleValue":2.735,"leftHandleSpan":0.4,"rightHandleValue":13.6451,"rightHandleSpan":0.4},
						{
							"time":1.45,
							"value":1.154,
							"leftHandleValue":4.5622,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7103,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":11.404,
							"leftHandleValue":3.4203,
							"leftHandleSpan":0.4,
							"rightHandleValue":-16.1971,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":5.354,
							"leftHandleValue":14.152,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.2279,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":4.838,
							"leftHandleValue":5.838,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.1972,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":7.316,
							"leftHandleValue":-3.0399,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.0766,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":6.59,"leftHandleValue":0.4854,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":5.0066,"rightHandleSpan":0.2},
						{
							"time":1.2666666666666666,
							"value":-2.33,
							"leftHandleValue":4.7257,
							"leftHandleSpan":0.7,
							"rightHandleValue":9.5014,
							"rightHandleSpan":0.4
						},
						{"time":1.8666666666666667,"value":0.303,"leftHandleValue":-4.5779,"leftHandleSpan":0.7},
						{"time":2,"value":0}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4725,"rightHandleValue":-0.031,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.3969,
							"leftHandleValue":-0.0155,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0915,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.72052,
							"leftHandleValue":0.0017,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0343,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.66148,
							"leftHandleValue":-0.0131,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0391,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.72981,
							"leftHandleValue":-0.0231,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0179,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.41189,
							"leftHandleValue":-0.0045,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0203,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.52936,
							"leftHandleValue":0.0108,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0139,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.45687,
							"leftHandleValue":-0.0063,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0363,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4725,"leftHandleValue":0.01,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4781,"rightHandleValue":-0.0314,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.4016,
							"leftHandleValue":-0.0157,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0926,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.72906,
							"leftHandleValue":0.0018,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0347,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.66932,
							"leftHandleValue":-0.0132,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0396,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.73846,
							"leftHandleValue":-0.0234,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0181,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.41677,
							"leftHandleValue":-0.0046,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0206,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.53563,
							"leftHandleValue":0.0109,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.014,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.46228,
							"leftHandleValue":-0.0064,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0367,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4781,"leftHandleValue":0.0101,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.4383,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":9.975,
							"leftHandleValue":-0.0155,
							"leftHandleSpan":0.3,
							"rightHandleValue":-6.2697,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-7.645,
							"leftHandleValue":4.0732,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.5734,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":7.651,
							"leftHandleValue":-2.2661,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2313,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.161,
							"leftHandleValue":0.0168,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.2937,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.6903,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1211,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.402,
							"leftHandleValue":-0.6816,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2624,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-19.383,
							"leftHandleValue":-0.1834,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.3058,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":16.114,
							"leftHandleValue":-14.0516,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4864,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-11.089,
							"leftHandleValue":4.7516,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.9034,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.118,
							"leftHandleValue":-0.9491,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7544,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.2574,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-3.4771,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":-8.1,
							"leftHandleValue":0.8194,
							"leftHandleSpan":0.3,
							"rightHandleValue":5.3748,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2666666666666666,
							"value":7.586,
							"leftHandleValue":-7.1253,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.3395,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-8.947,
							"leftHandleValue":2.1857,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0913,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":4.247,
							"leftHandleValue":0.5918,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7415,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.8319,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-705},
						{"time":1.2333333333333334,"value":691.8},
						{"time":1.4333333333333333,"value":-705},
						{"time":1.6166666666666667,"value":691.8}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-749},
						{"time":1.2333333333333334,"value":726.2},
						{"time":1.4333333333333333,"value":-749},
						{"time":1.6166666666666667,"value":726.2}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":1},
						{"time":0.11666666666666667,"value":0.8977,"rightHandleValue":-0.0576,"rightHandleSpan":0.8},
						{
							"time":0.26666666666666666,
							"value":2.0033,
							"leftHandleValue":-0.065,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0356,
							"rightHandleSpan":0.4
						},
						{"time":0.5,"value":1.25,"leftHandleValue":0.0664,"leftHandleSpan":0.4,"rightHandleValue":0.2184,"rightHandleSpan":0.5},
						{
							"time":1.0333333333333332,
							"value":1.3233,
							"leftHandleValue":1.2174,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.3153,
							"rightHandleSpan":0.6
						},
						{
							"time":1.25,
							"value":1.999,
							"leftHandleValue":-0.1669,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0145,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.9892,
							"leftHandleValue":-0.0549,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0433,
							"rightHandleSpan":0.4
						},
						{"time":1.6,"value":1.5,"leftHandleValue":-0.0349,"leftHandleSpan":0.4,"rightHandleValue":-0.134,"rightHandleSpan":0.4},
						{"time":2,"value":1,"leftHandleValue":-0.1754,"leftHandleSpan":0.8}
					],
					"propertyPath":["material","0","colorMultiply","alpha"],
					"sceneObjectUid":"8426846563212233"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Major1Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major2_Fill.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major2_Outline.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major2_Shell.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major2Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Major2_Shell",
				"uid":"0792440268599528",
				"position":[0.88,0.29,0],
				"scale":[0.4998,0.4998,1],
				"graphicAsset":"Major2_Shell",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Major2_Outline",
				"uid":"9078666617603137",
				"position":[-0.78,3.59,0],
				"scale":[0.4252,0.4287,1],
				"graphicAsset":"Major2_Outline",
				"subLayer":0.2953394666666669,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,164.6,58.8],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"Major2_Fill",
				"uid":"2159010928159013",
				"position":[-0.75,6.76,0],
				"scale":[0.4269,0.438,1],
				"graphicAsset":"Major2_Fill",
				"subLayer":0.02,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,164,58.6],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"9075793834701746",
				"position":[0,0,1000],
				"coreViewWidth":500,
				"coreViewHeight":500,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":500,
				"constructPrecompTargetHeight":500
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.88,"rightHandleValue":-3.1591,"rightHandleSpan":0.6},
						{
							"time":0.2,
							"value":-4.887,
							"leftHandleValue":8.5331,
							"leftHandleSpan":0.2,
							"rightHandleValue":8.4173,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":-20.575,
							"leftHandleValue":-4.4108,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.8781,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":-18.018,
							"leftHandleValue":-6.3839,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.3135,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":20.935,
							"leftHandleValue":-11.4401,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2839,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3833333333333333,
							"value":-1.56,
							"leftHandleValue":-0.0919,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.7511,
							"rightHandleSpan":0.8
						},
						{
							"time":1.4166666666666667,
							"value":6.962,
							"leftHandleValue":-8.0683,
							"leftHandleSpan":0.7,
							"rightHandleValue":3.0485,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-7.037,
							"leftHandleValue":-0.5583,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.3164,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-1.627,
							"leftHandleValue":14.7375,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.2877,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":4.642,
							"leftHandleValue":-0.3741,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4578,
							"rightHandleSpan":0.3
						},
						{
							"time":1.6833333333333333,
							"value":2.917,
							"leftHandleValue":-7.2411,
							"leftHandleSpan":0.7,
							"rightHandleValue":2.0587,
							"rightHandleSpan":0.2
						},
						{
							"time":1.7833333333333332,
							"value":1.937,
							"leftHandleValue":-4.0428,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.4543,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.88,"leftHandleValue":0.7619,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.29,"rightHandleValue":-3.8882,"rightHandleSpan":0.3},
						{
							"time":0.2,
							"value":6.854,
							"leftHandleValue":-6.3262,
							"leftHandleSpan":0.4,
							"rightHandleValue":15.2202,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":10.955,
							"leftHandleValue":-13.0683,
							"leftHandleSpan":0.6,
							"rightHandleValue":3.5431,
							"rightHandleSpan":0.1
						},
						{
							"time":0.3333333333333333,
							"value":10.7,
							"leftHandleValue":-5.2994,
							"leftHandleSpan":0.7,
							"rightHandleValue":-3.8706,
							"rightHandleSpan":0.1
						},
						{
							"time":1.25,
							"value":-7.375,
							"leftHandleValue":24.7578,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.9281,
							"rightHandleSpan":0.3
						},
						{
							"time":1.4,
							"value":-0.684,
							"leftHandleValue":8.3303,
							"leftHandleSpan":0.7,
							"rightHandleValue":15.1354,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":-5.353,
							"leftHandleValue":5.551,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.4108,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":4.82,
							"leftHandleValue":4.1674,
							"leftHandleSpan":0.4,
							"rightHandleValue":-18.3294,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":-1.25,
							"leftHandleValue":14.9511,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.2122,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":-1.321,
							"leftHandleValue":6.388,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.5918,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":0.903,
							"leftHandleValue":-3.108,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.3731,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.29,"leftHandleValue":0.5472,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":1.4584,"rightHandleSpan":0.4},
						{
							"time":0.16666666666666666,
							"value":0.367,
							"leftHandleValue":10.1982,
							"leftHandleSpan":0.3,
							"rightHandleValue":-11.0241,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":-39.666,
							"leftHandleValue":9.6628,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.6219,
							"rightHandleSpan":0.1
						},
						{
							"time":1.2666666666666666,
							"value":-55.417,
							"leftHandleValue":-23.6543,
							"leftHandleSpan":0.4,
							"rightHandleValue":13.5276,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":1.206,
							"leftHandleValue":1.6228,
							"leftHandleSpan":0.6,
							"rightHandleValue":-2.2997,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.7564,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4998,"rightHandleValue":-0.0328,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41983,
							"leftHandleValue":-0.0146,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0891,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.73983,
							"leftHandleValue":0.0031,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0354,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.67971,
							"leftHandleValue":-0.0131,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0402,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.74918,
							"leftHandleValue":-0.0228,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0185,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.4368,
							"leftHandleValue":-0.0077,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0231,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.55995,
							"leftHandleValue":0.0109,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0147,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.48326,
							"leftHandleValue":-0.0067,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0384,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4998,"leftHandleValue":0.0106,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4998,"rightHandleValue":-0.0328,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41983,
							"leftHandleValue":-0.0146,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0891,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.73983,
							"leftHandleValue":0.0031,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0354,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.67971,
							"leftHandleValue":-0.0131,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0402,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.74918,
							"leftHandleValue":-0.0228,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0185,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.4368,
							"leftHandleValue":-0.0077,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0231,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.55995,
							"leftHandleValue":0.0109,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0147,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.48326,
							"leftHandleValue":-0.0067,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0384,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4998,"leftHandleValue":0.0106,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":5.0724,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.401,
							"leftHandleValue":-0.0177,
							"leftHandleSpan":0.3,
							"rightHandleValue":-7.1507,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-8.737,
							"leftHandleValue":2.6052,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.6793,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":8.761,
							"leftHandleValue":0.9597,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.0846,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.202,
							"leftHandleValue":0.1773,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.4413,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.7406,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-2.1298,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":-6.503,
							"leftHandleValue":0.5865,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5784,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":22.12,
							"leftHandleValue":-0.0005,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.848,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":-18.416,
							"leftHandleValue":16.0385,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7957,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":12.651,
							"leftHandleValue":1.0968,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.7724,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":-8.151,
							"leftHandleValue":1.1577,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5015,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":3.313,
							"leftHandleValue":1.3321,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.8679,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.34,
							"leftHandleValue":-1.1471,
							"leftHandleSpan":0.3,
							"rightHandleValue":-17.6578,
							"rightHandleSpan":0.9
						},
						{
							"time":1.2666666666666666,
							"value":-10.62,
							"leftHandleValue":0.9467,
							"leftHandleSpan":0.05,
							"rightHandleValue":3.2753,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":12.525,
							"leftHandleValue":-3.06,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0557,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-6.238,
							"leftHandleValue":-0.7038,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.7632,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.4609,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-0.78,"rightHandleValue":0.0836,"rightHandleSpan":0.4},
						{
							"time":0.15,
							"value":-3.013,
							"leftHandleValue":1.4802,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.5253,
							"rightHandleSpan":0.9
						},
						{
							"time":0.23333333333333334,
							"value":10.372,
							"leftHandleValue":1.1609,
							"leftHandleSpan":0.5,
							"rightHandleValue":-3.9285,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":17.396,
							"leftHandleValue":3.3779,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.0596,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":15.725,
							"leftHandleValue":-0.7898,
							"leftHandleSpan":0.5,
							"rightHandleValue":-16.1647,
							"rightHandleSpan":0.6
						},
						{
							"time":1.2166666666666666,
							"value":-13.112,
							"leftHandleValue":3.0374,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.252,
							"rightHandleSpan":0.6
						},
						{
							"time":1.4,
							"value":-1.98,
							"leftHandleValue":4.5767,
							"leftHandleSpan":0.5,
							"rightHandleValue":21.2652,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-9.144,
							"leftHandleValue":1.0719,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.4127,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-3.124,
							"leftHandleValue":13.823,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.0247,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":3.506,
							"leftHandleValue":-0.4218,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4685,
							"rightHandleSpan":0.3
						},
						{
							"time":1.6833333333333333,
							"value":1.556,
							"leftHandleValue":-6.9631,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.9849,
							"rightHandleSpan":0.2
						},
						{
							"time":1.7833333333333332,
							"value":0.28,
							"leftHandleValue":-3.8974,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.5142,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-0.78,"leftHandleValue":0.7949,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":3.59,"rightHandleValue":-6.7768,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":7.578,
							"leftHandleValue":2.7469,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.1291,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":3.7,
							"leftHandleValue":-10.6278,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.5396,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":2.75,
							"leftHandleValue":-5.2118,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.2087,
							"rightHandleSpan":0.2
						},
						{
							"time":0.48333333333333334,
							"value":2.358,
							"leftHandleValue":0.4517,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3077,
							"rightHandleSpan":0.3
						},
						{
							"time":1.25,
							"value":21.805,
							"leftHandleValue":-3.8223,
							"leftHandleSpan":0.1,
							"rightHandleValue":2.1974,
							"rightHandleSpan":0.3
						},
						{
							"time":1.4,
							"value":1.216,
							"leftHandleValue":0.7434,
							"leftHandleSpan":0.6,
							"rightHandleValue":15.5041,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":-2.622,
							"leftHandleValue":5.2731,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.1342,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":8.266,
							"leftHandleValue":3.8621,
							"leftHandleSpan":0.4,
							"rightHandleValue":-17.8078,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":2.213,
							"leftHandleValue":15.2768,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.3382,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":1.907,
							"leftHandleValue":6.4396,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.6182,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":4.303,
							"leftHandleValue":-3.183,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.3234,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":3.59,"leftHandleValue":0.5357,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":1.3584,"rightHandleSpan":0.3},
						{
							"time":0.16666666666666666,
							"value":4.16,
							"leftHandleValue":-14.0119,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.5024,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":45.618,
							"leftHandleValue":-9.3491,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.2399,
							"rightHandleSpan":0.05
						},
						{"time":1.0666666666666667,"value":59.864,"leftHandleValue":14.3171,"leftHandleSpan":0.4},
						{"time":1.15,"value":56.548,"rightHandleValue":-10.7089,"rightHandleSpan":0.8},
						{
							"time":1.3666666666666667,
							"value":12.35,
							"leftHandleValue":46.4685,
							"leftHandleSpan":0.5,
							"rightHandleValue":-12.1939,
							"rightHandleSpan":0.1
						},
						{
							"time":1.6,
							"value":-1.816,
							"leftHandleValue":3.7291,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.4073,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":0.6863,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4252,"rightHandleValue":-0.0279,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.35717,
							"leftHandleValue":-0.0124,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0758,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.6294,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0301,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.57826,
							"leftHandleValue":-0.0111,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0342,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.63736,
							"leftHandleValue":-0.0194,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0158,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.3716,
							"leftHandleValue":-0.0065,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0196,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.47637,
							"leftHandleValue":0.0093,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0125,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.41113,
							"leftHandleValue":-0.0057,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0261,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4252,"leftHandleValue":0.0128,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4287,"rightHandleValue":-0.0281,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.36011,
							"leftHandleValue":-0.0125,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0764,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.63459,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0303,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.58302,
							"leftHandleValue":-0.0112,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0344,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.64261,
							"leftHandleValue":-0.0195,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0159,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.37466,
							"leftHandleValue":-0.0066,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0198,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.48029,
							"leftHandleValue":0.0094,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0126,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.41452,
							"leftHandleValue":-0.0058,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0263,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4287,"leftHandleValue":0.0129,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":5.0724,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.401,
							"leftHandleValue":-0.0177,
							"leftHandleSpan":0.3,
							"rightHandleValue":-7.1507,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-8.737,
							"leftHandleValue":2.6052,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.6793,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":8.761,
							"leftHandleValue":0.9597,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.0846,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.202,
							"leftHandleValue":0.1773,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.4413,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.7406,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-2.1298,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":-6.503,
							"leftHandleValue":0.5865,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5784,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":22.12,
							"leftHandleValue":-0.0005,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.848,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":-18.416,
							"leftHandleValue":16.0385,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7957,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":12.651,
							"leftHandleValue":1.0968,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.7724,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":-8.151,
							"leftHandleValue":1.1577,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5015,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":3.313,
							"leftHandleValue":1.3321,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.8679,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.34,
							"leftHandleValue":-1.1471,
							"leftHandleSpan":0.3,
							"rightHandleValue":-17.6578,
							"rightHandleSpan":0.9
						},
						{
							"time":1.2666666666666666,
							"value":-10.62,
							"leftHandleValue":0.9467,
							"leftHandleSpan":0.05,
							"rightHandleValue":3.2753,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":12.525,
							"leftHandleValue":-3.06,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0557,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-6.238,
							"leftHandleValue":-0.7038,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.7632,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.4609,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-0.75,"rightHandleValue":-0.3873,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-3.722,
							"leftHandleValue":0.3436,
							"leftHandleSpan":0.4,
							"rightHandleValue":10.8613,
							"rightHandleSpan":0.4
						},
						{
							"time":0.25,
							"value":-6.314,
							"leftHandleValue":2.4087,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.0487,
							"rightHandleSpan":0.6
						},
						{
							"time":0.3333333333333333,
							"value":-4.614,
							"leftHandleValue":5.4159,
							"leftHandleSpan":0.99,
							"rightHandleValue":3.0738,
							"rightHandleSpan":0.4
						},
						{
							"time":0.48333333333333334,
							"value":-3.343,
							"leftHandleValue":-1.2206,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.1286,
							"rightHandleSpan":0.3
						},
						{
							"time":1.25,
							"value":4.715,
							"leftHandleValue":-4.0019,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.0699,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-3.143,
							"leftHandleValue":-0.1001,
							"leftHandleSpan":0.5,
							"rightHandleValue":21.8491,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-9.569,
							"leftHandleValue":1.0333,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.5809,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-2.95,
							"leftHandleValue":13.3396,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.8963,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":3.828,
							"leftHandleValue":-0.4365,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4742,
							"rightHandleSpan":0.3
						},
						{
							"time":1.6833333333333333,
							"value":1.859,
							"leftHandleValue":-6.9288,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.968,
							"rightHandleSpan":0.2
						},
						{
							"time":1.7833333333333332,
							"value":0.416,
							"leftHandleValue":-3.7461,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.5944,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-0.75,"leftHandleValue":0.8047,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":6.76,"rightHandleValue":-6.9093,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":13.984,
							"leftHandleValue":-5.3889,
							"leftHandleSpan":0.6,
							"rightHandleValue":14.3062,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":13.587,
							"leftHandleValue":-10.9953,
							"leftHandleSpan":0.6,
							"rightHandleValue":3.1918,
							"rightHandleSpan":0.2
						},
						{
							"time":0.3333333333333333,
							"value":12.949,
							"leftHandleValue":-5.2695,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.3574,
							"rightHandleSpan":0.05
						},
						{
							"time":1.1833333333333333,
							"value":13.985,
							"leftHandleValue":-0.103,
							"leftHandleSpan":0.8,
							"rightHandleValue":2.5049,
							"rightHandleSpan":0.7
						},
						{"time":1.4,"value":4.27,"leftHandleValue":4.602,"leftHandleSpan":0.4,"rightHandleValue":15.176,"rightHandleSpan":0.4},
						{
							"time":1.45,
							"value":0.294,
							"leftHandleValue":5.1201,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.9457,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":11.715,
							"leftHandleValue":3.7122,
							"leftHandleSpan":0.4,
							"rightHandleValue":-17.6219,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":5.54,
							"leftHandleValue":15.5147,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.4444,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":4.997,
							"leftHandleValue":6.5526,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.6142,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":7.511,
							"leftHandleValue":-3.2707,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.2591,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":6.76,"leftHandleValue":0.5248,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":5.8572,"rightHandleSpan":0.3},
						{
							"time":1.25,
							"value":-3.976,
							"leftHandleValue":11.7784,
							"leftHandleSpan":0.99,
							"rightHandleValue":2.7344,
							"rightHandleSpan":0.4
						},
						{"time":1.6,"value":-1.305,"leftHandleValue":8.352,"leftHandleSpan":0.8,"rightHandleValue":0.9797,"rightHandleSpan":0.4},
						{"time":2,"value":0,"leftHandleValue":1.105,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4269,"rightHandleValue":-0.028,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.3586,
							"leftHandleValue":-0.0125,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0761,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.63192,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0302,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.58057,
							"leftHandleValue":-0.0112,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0343,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.63991,
							"leftHandleValue":-0.0194,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0158,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.37309,
							"leftHandleValue":-0.0065,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0197,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.47827,
							"leftHandleValue":0.0093,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0125,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.41278,
							"leftHandleValue":-0.0057,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0262,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4269,"leftHandleValue":0.0129,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.438,"rightHandleValue":-0.0288,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.36792,
							"leftHandleValue":-0.0128,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0781,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.64835,
							"leftHandleValue":0.0027,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.031,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.59566,
							"leftHandleValue":-0.0115,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0352,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.65655,
							"leftHandleValue":-0.0199,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0162,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.38279,
							"leftHandleValue":-0.0067,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0202,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.49071,
							"leftHandleValue":0.0096,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0129,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.42351,
							"leftHandleValue":-0.0059,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0269,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.438,"leftHandleValue":0.0132,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":5.0724,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.401,
							"leftHandleValue":-0.0177,
							"leftHandleSpan":0.3,
							"rightHandleValue":-7.1507,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-8.737,
							"leftHandleValue":2.6052,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.6793,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":8.761,
							"leftHandleValue":0.9597,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.0846,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.202,
							"leftHandleValue":0.1773,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.4413,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.7406,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-2.1298,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":-6.503,
							"leftHandleValue":0.5865,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5784,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":22.12,
							"leftHandleValue":-0.0005,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.848,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":-18.416,
							"leftHandleValue":16.0385,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7957,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":12.651,
							"leftHandleValue":1.0968,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.7724,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":-8.151,
							"leftHandleValue":1.1577,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5015,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":3.313,
							"leftHandleValue":1.3321,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.8679,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.34,
							"leftHandleValue":-1.1471,
							"leftHandleSpan":0.3,
							"rightHandleValue":-17.6578,
							"rightHandleSpan":0.9
						},
						{
							"time":1.2666666666666666,
							"value":-10.62,
							"leftHandleValue":0.9467,
							"leftHandleSpan":0.05,
							"rightHandleValue":3.2753,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":12.525,
							"leftHandleValue":-3.06,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0557,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-6.238,
							"leftHandleValue":-0.7038,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.7632,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.4609,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-783},
						{"time":1.2333333333333334,"value":763.1},
						{"time":1.4333333333333333,"value":-783},
						{"time":1.6166666666666667,"value":763.1}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-780.8},
						{"time":1.2333333333333334,"value":771.4},
						{"time":1.4333333333333333,"value":-780.8},
						{"time":1.6166666666666667,"value":771.4}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":1},
						{"time":0.11666666666666667,"value":0.8977,"rightHandleValue":-0.0576,"rightHandleSpan":0.8},
						{
							"time":0.26666666666666666,
							"value":2.0033,
							"leftHandleValue":-0.065,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0356,
							"rightHandleSpan":0.4
						},
						{"time":0.5,"value":1.25,"leftHandleValue":0.0664,"leftHandleSpan":0.4,"rightHandleValue":0.2184,"rightHandleSpan":0.5},
						{
							"time":1.0333333333333332,
							"value":1.3233,
							"leftHandleValue":1.2174,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.3153,
							"rightHandleSpan":0.6
						},
						{
							"time":1.25,
							"value":1.999,
							"leftHandleValue":-0.1669,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0145,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.9892,
							"leftHandleValue":-0.0549,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0433,
							"rightHandleSpan":0.4
						},
						{"time":1.6,"value":1.5,"leftHandleValue":-0.0349,"leftHandleSpan":0.4,"rightHandleValue":-0.134,"rightHandleSpan":0.4},
						{"time":2,"value":1,"leftHandleValue":-0.1754,"leftHandleSpan":0.8}
					],
					"propertyPath":["material","0","colorMultiply","alpha"],
					"sceneObjectUid":"9078666617603137"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Major2Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major3_Fill.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major3_Outline.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major3_Shell.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major3Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Major3_Shell",
				"uid":"9624595711777741",
				"position":[0.32,1.47,0],
				"scale":[0.43580000000000285,0.4728,1],
				"graphicAsset":"Major3_Shell",
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Major3_Outline",
				"uid":"2154728038528084",
				"position":[-0.82,10.72,0],
				"scale":[0.3831,0.3861,1],
				"graphicAsset":"Major3_Outline",
				"subLayer":0.1753394666666661,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,182.7,65.3],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"Major3_Fill",
				"uid":"1485253888539336",
				"position":[-5.35,15.98,0],
				"scale":[0.38910000000000283,0.4208,1],
				"graphicAsset":"Major3_Fill",
				"subLayer":0.02,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,179.9,64.3],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"8145384019161461",
				"position":[0,0,1000],
				"coreViewWidth":500,
				"coreViewHeight":500,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":500,
				"constructPrecompTargetHeight":500
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.32,"rightHandleValue":0.0695,"rightHandleSpan":0.4},
						{
							"time":0.13333333333333333,
							"value":0.936,
							"leftHandleValue":0.9289,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.343,
							"rightHandleSpan":0.99
						},
						{
							"time":0.21666666666666667,
							"value":16.449,
							"leftHandleValue":-9.0856,
							"leftHandleSpan":0.3,
							"rightHandleValue":3.4429,
							"rightHandleSpan":0.4
						},
						{
							"time":0.25,
							"value":17.821,
							"leftHandleValue":-1.8558,
							"leftHandleSpan":0.4,
							"rightHandleValue":19.3974,
							"rightHandleSpan":0.6
						},
						{
							"time":0.36666666666666664,
							"value":24.573,
							"leftHandleValue":-5.0413,
							"leftHandleSpan":0.8,
							"rightHandleValue":-21.2807,
							"rightHandleSpan":0.6
						},
						{
							"time":1.25,
							"value":-24.761,
							"leftHandleValue":19.7301,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.5884,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":1.966,
							"leftHandleValue":4.6644,
							"leftHandleSpan":0.6,
							"rightHandleValue":23.4794,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-5.955,
							"leftHandleValue":1.4724,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.6014,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5166666666666666,
							"value":5.427,
							"leftHandleValue":3.2931,
							"leftHandleSpan":0.4,
							"rightHandleValue":-14.8512,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":2.483,
							"leftHandleValue":-6.3193,
							"leftHandleSpan":0.6,
							"rightHandleValue":-9.5607,
							"rightHandleSpan":0.9
						},
						{
							"time":1.7,
							"value":1.299,
							"leftHandleValue":-1.8338,
							"leftHandleSpan":0.8,
							"rightHandleValue":-5.5161,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8333333333333333,
							"value":-0.026,
							"leftHandleValue":3.2465,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.2091,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.32,"leftHandleValue":-0.1825,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":1.47,"rightHandleValue":-4.2681,"rightHandleSpan":0.3},
						{
							"time":0.2,
							"value":10.416,
							"leftHandleValue":-9.0253,
							"leftHandleSpan":0.4,
							"rightHandleValue":18.1853,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":17.248,
							"leftHandleValue":-15.9469,
							"leftHandleSpan":0.7,
							"rightHandleValue":4.179,
							"rightHandleSpan":0.2
						},
						{
							"time":0.3333333333333333,
							"value":16.964,
							"leftHandleValue":-5.667,
							"leftHandleSpan":0.8,
							"rightHandleValue":-4.4738,
							"rightHandleSpan":0.05
						},
						{
							"time":1.25,
							"value":-6.041,
							"leftHandleValue":30.0161,
							"leftHandleSpan":0.9,
							"rightHandleValue":-2.2807,
							"rightHandleSpan":0.3
						},
						{
							"time":1.4,
							"value":0.421,
							"leftHandleValue":10.0109,
							"leftHandleSpan":0.7,
							"rightHandleValue":16.4721,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":-4.942,
							"leftHandleValue":6.1076,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.637,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":6.369,
							"leftHandleValue":4.5209,
							"leftHandleSpan":0.4,
							"rightHandleValue":-19.9877,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":-0.042,
							"leftHandleValue":16.3803,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.2426,
							"rightHandleSpan":0.7
						},
						{
							"time":1.6833333333333333,
							"value":-0.179,
							"leftHandleValue":6.3867,
							"leftHandleSpan":0.99,
							"rightHandleValue":5.0183,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":2.158,
							"leftHandleValue":-3.3818,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.589,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":1.47,"leftHandleValue":0.6658,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":0.7727,"rightHandleSpan":0.4},
						{
							"time":0.11666666666666667,
							"value":6.085,
							"leftHandleValue":-0.2911,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.1366,
							"rightHandleSpan":0.5
						},
						{
							"time":0.26666666666666666,
							"value":-43.928,
							"leftHandleValue":17.6387,
							"leftHandleSpan":0.4,
							"rightHandleValue":-5.793,
							"rightHandleSpan":0.05
						},
						{"time":0.9166666666666666,"value":-75.306,"leftHandleValue":-3.8141,"leftHandleSpan":0.3},
						{"time":1.0166666666666666,"value":-74.252,"rightHandleValue":6.4392,"rightHandleSpan":0.8},
						{
							"time":1.2833333333333332,
							"value":-60.638,
							"leftHandleValue":-5.424,
							"leftHandleSpan":0.05,
							"rightHandleValue":26.7466,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":1.766,
							"leftHandleValue":0.7062,
							"leftHandleSpan":0.6,
							"rightHandleValue":-3.8152,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":2.5444,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4358,"rightHandleValue":-0.0287,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.36607,
							"leftHandleValue":-0.0163,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0927,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.68889,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0327,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.63189,
							"leftHandleValue":-0.0128,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0374,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.69797,
							"leftHandleValue":-0.0232,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0169,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.37869,
							"leftHandleValue":-0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.017,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.48824,
							"leftHandleValue":0.0105,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0128,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.42138,
							"leftHandleValue":-0.0059,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0267,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4358,"leftHandleValue":0.0131,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4728,"rightHandleValue":-0.0311,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.39715,
							"leftHandleValue":-0.0177,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1006,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.74737,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0354,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.68554,
							"leftHandleValue":-0.0139,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0406,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.75722,
							"leftHandleValue":-0.0252,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0183,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.41084,
							"leftHandleValue":-0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0184,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.5297,
							"leftHandleValue":0.0114,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0139,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.45716,
							"leftHandleValue":-0.0063,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0363,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4728,"leftHandleValue":0.01,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":6.045,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":12.826,
							"leftHandleValue":0.9408,
							"leftHandleSpan":0.2,
							"rightHandleValue":-8.0445,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-9.829,
							"leftHandleValue":2.9308,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.7358,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":9.883,
							"leftHandleValue":0.9469,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.1677,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.242,
							"leftHandleValue":0.2775,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3305,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.811,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1385,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.604,
							"leftHandleValue":-0.4915,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.8944,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-24.857,
							"leftHandleValue":0.1843,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.0395,
							"rightHandleSpan":0.1
						},
						{
							"time":1.25,
							"value":20.718,
							"leftHandleValue":-18.2945,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.8259,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":-14.298,
							"leftHandleValue":-0.9156,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.899,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.183,
							"leftHandleValue":-1.3882,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2485,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.4068,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-9.5824,"rightHandleSpan":0.3},
						{
							"time":1.2666666666666666,
							"value":6.068,
							"leftHandleValue":-14.56,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.8716,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-7.157,
							"leftHandleValue":1.7486,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0745,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":3.384,
							"leftHandleValue":0.5247,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5044,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.4424,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-0.82,"rightHandleValue":-0.0314,"rightHandleSpan":0.7},
						{
							"time":0.2,
							"value":-5.93,
							"leftHandleValue":10.6721,
							"leftHandleSpan":0.2,
							"rightHandleValue":8.0441,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":-25.548,
							"leftHandleValue":-4.5101,
							"leftHandleSpan":0.4,
							"rightHandleValue":7.4841,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":-22.627,
							"leftHandleValue":-7.0947,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.4137,
							"rightHandleSpan":0.2
						},
						{
							"time":1.2333333333333334,
							"value":15.95,
							"leftHandleValue":-6.684,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.8825,
							"rightHandleSpan":0.5
						},
						{
							"time":1.3666666666666667,
							"value":-0.739,
							"leftHandleValue":0.4179,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2555,
							"rightHandleSpan":0.99
						},
						{
							"time":1.4166666666666667,
							"value":9.374,
							"leftHandleValue":-9.122,
							"leftHandleSpan":0.5,
							"rightHandleValue":3.4382,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-6.41,
							"leftHandleValue":-0.1526,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3734,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5166666666666666,
							"value":4.319,
							"leftHandleValue":3.6523,
							"leftHandleSpan":0.4,
							"rightHandleValue":-15.7251,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":0.443,
							"leftHandleValue":-6.2967,
							"leftHandleSpan":0.6,
							"rightHandleValue":-9.4184,
							"rightHandleSpan":0.9
						},
						{
							"time":1.7,
							"value":0.055,
							"leftHandleValue":-0.992,
							"leftHandleSpan":0.7,
							"rightHandleValue":-5.3204,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8333333333333333,
							"value":-0.981,
							"leftHandleValue":3.2721,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.1935,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-0.82,"leftHandleValue":-0.1092,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":10.72,"rightHandleValue":-10.755,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":19.231,
							"leftHandleValue":3.3326,
							"leftHandleSpan":0.4,
							"rightHandleValue":14.188,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":11.875,
							"leftHandleValue":-9.0007,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.1972,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":10.747,
							"leftHandleValue":-5.8641,
							"leftHandleSpan":0.8,
							"rightHandleValue":-3.179,
							"rightHandleSpan":0.6
						},
						{
							"time":0.4166666666666667,
							"value":10.269,
							"leftHandleValue":1.9328,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.3273,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":36.145,
							"leftHandleValue":-3.3575,
							"leftHandleSpan":0.05,
							"rightHandleValue":2.4786,
							"rightHandleSpan":0.3
						},
						{
							"time":1.4,
							"value":7.544,
							"leftHandleValue":0.2973,
							"leftHandleSpan":0.5,
							"rightHandleValue":16.9108,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":3.689,
							"leftHandleValue":5.4917,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.0069,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":16.481,
							"leftHandleValue":4.0196,
							"leftHandleSpan":0.4,
							"rightHandleValue":-19.4488,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":9.335,
							"leftHandleValue":17.3382,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.3963,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6333333333333333,
							"value":11.525,
							"leftHandleValue":-1.2234,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.181,
							"rightHandleSpan":0.4
						},
						{
							"time":1.7166666666666666,
							"value":11.206,
							"leftHandleValue":-6.5175,
							"leftHandleSpan":0.8,
							"rightHandleValue":-3.4466,
							"rightHandleSpan":0.5
						},
						{"time":1.8499999999999999,"value":11.152,"leftHandleValue":0.5529,"leftHandleSpan":0.99},
						{"time":2,"value":10.72}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":0.4406,"rightHandleSpan":0.4},
						{
							"time":0.1,
							"value":-2.465,
							"leftHandleValue":-0.3873,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.409,
							"rightHandleSpan":0.6
						},
						{
							"time":0.26666666666666666,
							"value":53.114,
							"leftHandleValue":-18.2068,
							"leftHandleSpan":0.4,
							"rightHandleValue":10.4668,
							"rightHandleSpan":0.1
						},
						{
							"time":1.2333333333333334,
							"value":58.645,
							"leftHandleValue":34.6649,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.2558,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":53.697,
							"leftHandleValue":5.1181,
							"leftHandleSpan":0.4,
							"rightHandleValue":-16.0527,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":3.334,
							"leftHandleValue":3.8055,
							"leftHandleSpan":0.6,
							"rightHandleValue":-5.1087,
							"rightHandleSpan":0.5
						},
						{"time":1.9,"value":0.103,"leftHandleValue":-4.574,"leftHandleSpan":0.99},
						{"time":2,"value":0}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3831,"rightHandleValue":-0.0252,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.3218,
							"leftHandleValue":-0.0143,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0815,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.60558,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0287,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.55548,
							"leftHandleValue":-0.0113,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0329,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.61356,
							"leftHandleValue":-0.0204,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0148,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.33289,
							"leftHandleValue":-0.0009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0149,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.4292,
							"leftHandleValue":0.0092,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0112,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.37042,
							"leftHandleValue":-0.0051,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0235,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.3831,"leftHandleValue":0.0115,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3861,"rightHandleValue":-0.0254,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.32432,
							"leftHandleValue":-0.0144,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0822,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.61032,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0289,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.55983,
							"leftHandleValue":-0.0113,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0331,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.61837,
							"leftHandleValue":-0.0205,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.015,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.3355,
							"leftHandleValue":-0.0009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.015,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.43256,
							"leftHandleValue":0.0093,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0113,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.37333,
							"leftHandleValue":-0.0052,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0237,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.3861,"leftHandleValue":0.0116,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":6.045,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":12.826,
							"leftHandleValue":0.9408,
							"leftHandleSpan":0.2,
							"rightHandleValue":-8.0445,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-9.829,
							"leftHandleValue":2.9308,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.7358,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":9.883,
							"leftHandleValue":0.9469,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.1677,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.242,
							"leftHandleValue":0.2775,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3305,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.811,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1385,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.604,
							"leftHandleValue":-0.4915,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.8944,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-24.857,
							"leftHandleValue":0.1843,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.0395,
							"rightHandleSpan":0.1
						},
						{
							"time":1.25,
							"value":20.718,
							"leftHandleValue":-18.2945,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.8259,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":-14.298,
							"leftHandleValue":-0.9156,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.899,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.183,
							"leftHandleValue":-1.3882,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2485,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.4068,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-9.5824,"rightHandleSpan":0.3},
						{
							"time":1.2666666666666666,
							"value":6.068,
							"leftHandleValue":-14.56,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.8716,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-7.157,
							"leftHandleValue":1.7486,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0745,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":3.384,
							"leftHandleValue":0.5247,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5044,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.4424,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-5.35,"rightHandleValue":3.3278,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-6.717,
							"leftHandleValue":1.6554,
							"leftHandleSpan":0.4,
							"rightHandleValue":11.6437,
							"rightHandleSpan":0.4
						},
						{
							"time":0.25,
							"value":-9.625,
							"leftHandleValue":2.4133,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.6489,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":-4.781,
							"leftHandleValue":2.563,
							"leftHandleSpan":0.4,
							"rightHandleValue":-6.4195,
							"rightHandleSpan":0.4
						},
						{"time":0.4,"value":-6.59,"leftHandleValue":3.6382,"leftHandleSpan":0.6,"rightHandleValue":1.6132,"rightHandleSpan":0.1},
						{
							"time":1.25,
							"value":-14.805,
							"leftHandleValue":6.206,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.2351,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-2.753,
							"leftHandleValue":-1.8641,
							"leftHandleSpan":0.6,
							"rightHandleValue":24.5533,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-10.458,
							"leftHandleValue":2.1855,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.0105,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5166666666666666,
							"value":-0.636,
							"leftHandleValue":3.8852,
							"leftHandleSpan":0.4,
							"rightHandleValue":-15.996,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":-4.489,
							"leftHandleValue":-6.5361,
							"leftHandleSpan":0.6,
							"rightHandleValue":-8.8889,
							"rightHandleSpan":0.9
						},
						{
							"time":1.7,
							"value":-4.49,
							"leftHandleValue":-1.1449,
							"leftHandleSpan":0.7,
							"rightHandleValue":-5.2874,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8333333333333333,
							"value":-5.514,
							"leftHandleValue":3.2726,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.2025,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-5.35,"leftHandleValue":-0.0466,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":15.98,"rightHandleValue":-10.9179,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":30.73,
							"leftHandleValue":-10.6505,
							"leftHandleSpan":0.6,
							"rightHandleValue":16.2417,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":29.485,
							"leftHandleValue":-11.2056,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.816,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":28.64,
							"leftHandleValue":-5.8204,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.485,
							"rightHandleSpan":0.05
						},
						{
							"time":1.0833333333333333,
							"value":29.153,
							"leftHandleValue":-0.1896,
							"leftHandleSpan":0.9,
							"rightHandleValue":0.3287,
							"rightHandleSpan":0.99
						},
						{
							"time":1.4,
							"value":13.052,
							"leftHandleValue":17.1417,
							"leftHandleSpan":0.5,
							"rightHandleValue":17.4625,
							"rightHandleSpan":0.5
						},
						{
							"time":1.45,
							"value":8.992,
							"leftHandleValue":3.4811,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7399,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":22.414,
							"leftHandleValue":3.9162,
							"leftHandleSpan":0.4,
							"rightHandleValue":-19.5576,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":14.574,
							"leftHandleValue":17.8331,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.4985,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6333333333333333,
							"value":16.546,
							"leftHandleValue":-1.1564,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.0851,
							"rightHandleSpan":0.2
						},
						{
							"time":1.7166666666666666,
							"value":16.289,
							"leftHandleValue":-6.7724,
							"leftHandleSpan":0.7,
							"rightHandleValue":-3.47,
							"rightHandleSpan":0.6
						},
						{"time":1.8499999999999999,"value":16.596,"leftHandleValue":0.9212,"leftHandleSpan":0.99},
						{"time":2,"value":15.98}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":8.762,"rightHandleSpan":0.2},
						{
							"time":1.2666666666666666,
							"value":-3.631,
							"leftHandleValue":7.0952,
							"leftHandleSpan":0.7,
							"rightHandleValue":16.2266,
							"rightHandleSpan":0.5
						},
						{"time":1.8666666666666667,"value":0.453,"leftHandleValue":-6.9656,"leftHandleSpan":0.8},
						{"time":2,"value":0}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3891,"rightHandleValue":-0.0256,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.32684,
							"leftHandleValue":-0.0145,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0828,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.61506,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0292,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.56418,
							"leftHandleValue":-0.0114,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0334,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.62317,
							"leftHandleValue":-0.0207,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0151,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.33811,
							"leftHandleValue":-0.0009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0152,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.43592,
							"leftHandleValue":0.0093,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0114,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.37623,
							"leftHandleValue":-0.0052,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0239,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.3891,"leftHandleValue":0.0117,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4208,"rightHandleValue":-0.0277,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.35347,
							"leftHandleValue":-0.0157,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0895,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.66517,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0315,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.61014,
							"leftHandleValue":-0.0124,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0361,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.67394,
							"leftHandleValue":-0.0224,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0163,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.36565,
							"leftHandleValue":-0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0164,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.47144,
							"leftHandleValue":0.0101,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0124,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.40688,
							"leftHandleValue":-0.0056,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0258,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4208,"leftHandleValue":0.0127,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":6.045,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":12.826,
							"leftHandleValue":0.9408,
							"leftHandleSpan":0.2,
							"rightHandleValue":-8.0445,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-9.829,
							"leftHandleValue":2.9308,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.7358,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":9.883,
							"leftHandleValue":0.9469,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.1677,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.242,
							"leftHandleValue":0.2775,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3305,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.811,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1385,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.604,
							"leftHandleValue":-0.4915,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.8944,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-24.857,
							"leftHandleValue":0.1843,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.0395,
							"rightHandleSpan":0.1
						},
						{
							"time":1.25,
							"value":20.718,
							"leftHandleValue":-18.2945,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.8259,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":-14.298,
							"leftHandleValue":-0.9156,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.899,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.183,
							"leftHandleValue":-1.3882,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2485,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.4068,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-9.5824,"rightHandleSpan":0.3},
						{
							"time":1.2666666666666666,
							"value":6.068,
							"leftHandleValue":-14.56,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.8716,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-7.157,
							"leftHandleValue":1.7486,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0745,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":3.384,
							"leftHandleValue":0.5247,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5044,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.4424,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-867.4},
						{"time":1.2333333333333334,"value":828.8},
						{"time":1.4333333333333333,"value":-867.4},
						{"time":1.6166666666666667,"value":828.8}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-879.7},
						{"time":1.2333333333333334,"value":843.1},
						{"time":1.4333333333333333,"value":-879.7},
						{"time":1.6166666666666667,"value":843.1}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":1},
						{"time":0.11666666666666667,"value":0.8977,"rightHandleValue":-0.0576,"rightHandleSpan":0.8},
						{
							"time":0.26666666666666666,
							"value":2.0033,
							"leftHandleValue":-0.065,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0356,
							"rightHandleSpan":0.4
						},
						{"time":0.5,"value":1.25,"leftHandleValue":0.0664,"leftHandleSpan":0.4,"rightHandleValue":0.2184,"rightHandleSpan":0.5},
						{
							"time":1.0333333333333332,
							"value":1.3233,
							"leftHandleValue":1.2174,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.3153,
							"rightHandleSpan":0.6
						},
						{
							"time":1.25,
							"value":1.999,
							"leftHandleValue":-0.1669,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0145,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.9892,
							"leftHandleValue":-0.0549,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0433,
							"rightHandleSpan":0.4
						},
						{"time":1.6,"value":1.5,"leftHandleValue":-0.0349,"leftHandleSpan":0.4,"rightHandleValue":-0.134,"rightHandleSpan":0.4},
						{"time":2,"value":1,"leftHandleValue":-0.1754,"leftHandleSpan":0.8}
					],
					"propertyPath":["material","0","colorMultiply","alpha"],
					"sceneObjectUid":"2154728038528084"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Major3Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_PlateBottom.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_PlateMiddle.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_PlateTop.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_TextBottom.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_TextMiddle.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_TextTop.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{},
			"4":{},
			"5":{},
			"6":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Minor1_PlateBottom",
				"uid":"3387500474395755",
				"position":[0.15,-86.01123723968968,0],
				"scale":[0.3886,0.3828,1],
				"graphicAsset":"Minor1_PlateBottom",
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,154.4,64.3],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Minor1_PlateMiddle",
				"uid":"1313735379907511",
				"position":[0.75,-6.62,0],
				"scale":[0.3867,0.3898,1],
				"graphicAsset":"Minor1_PlateMiddle",
				"subLayer":0.01,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,155.2,64.6],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"Minor1_PlateTop",
				"uid":"6372651676122202",
				"position":[0.37,124.73721518987342,0],
				"scale":[0.4064,0.4097,1],
				"graphicAsset":"Minor1_PlateTop",
				"subLayer":0.02,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,147.6,61.5],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"GraphicObject",
				"name":"Minor1_TextBottom",
				"uid":"9729975288200182",
				"position":[0.5,-81.47630378089146,0],
				"scale":[0.3415,0.3545,1],
				"graphicAsset":"Minor1_TextBottom",
				"subLayer":0.03,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,175.7,73.2],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":4,
				"type":"GraphicObject",
				"name":"Minor1_TextMiddle",
				"uid":"6330434839548620",
				"position":[1.02,-3.0113335125688927,0],
				"scale":[0.3846,0.4104,1],
				"graphicAsset":"Minor1_TextMiddle",
				"subLayer":0.04,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,156,65],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":5,
				"type":"GraphicObject",
				"name":"Minor1_TextTop",
				"uid":"5798682828807290",
				"position":[0.86,79.11214864867158,0],
				"scale":[0.4,0.412,1],
				"graphicAsset":"Minor1_TextTop",
				"subLayer":0.05,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,150,62.5],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":6,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"0033076661934514",
				"position":[0,0,1000],
				"coreViewWidth":400,
				"coreViewHeight":400,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":400,
				"constructPrecompTargetHeight":400
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.15},
						{"time":0.31666666666666665,"value":0.126,"rightHandleValue":-2.477,"rightHandleSpan":0.5},
						{
							"time":0.36666666666666664,
							"value":19.78,
							"leftHandleValue":-11.1407,
							"leftHandleSpan":0.8,
							"rightHandleValue":3.45,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4666666666666667,
							"value":-10.677,
							"leftHandleValue":7.2336,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.6919,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5666666666666667,
							"value":6.087,
							"leftHandleValue":-1.5967,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.9379,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6666666666666666,
							"value":-3.114,
							"leftHandleValue":0.8956,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2588,
							"rightHandleSpan":0.4
						},
						{"time":0.8333333333333334,"value":0.152,"leftHandleValue":5.4611,"leftHandleSpan":0.6},
						{"time":1.15,"value":0.131,"rightHandleValue":-0.5845,"rightHandleSpan":0.4},
						{
							"time":1.2,
							"value":6.134,
							"leftHandleValue":-0.6866,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.3891,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":-4.144,
							"leftHandleValue":-0.7824,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.6226,
							"rightHandleSpan":0.6
						},
						{
							"time":1.45,
							"value":-1.141,
							"leftHandleValue":3.8776,
							"leftHandleSpan":0.7,
							"rightHandleValue":4.415,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":0.15,"leftHandleValue":-1.7856,"leftHandleSpan":0.99}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-86.011,"rightHandleValue":-2.5171,"rightHandleSpan":0.9},
						{"time":0.6,"value":-87.477,"leftHandleValue":3.4362,"leftHandleSpan":0.6},
						{"time":0.8,"value":-87.424,"rightHandleValue":2.4009,"rightHandleSpan":0.99},
						{
							"time":1.15,
							"value":-75.641,
							"leftHandleValue":-15.606,
							"leftHandleSpan":0.2,
							"rightHandleValue":-1.1468,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1833333333333333,
							"value":-73.048,
							"leftHandleValue":1.6001,
							"leftHandleSpan":0.5,
							"rightHandleValue":-5.1894,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2666666666666666,
							"value":-109.85,
							"leftHandleValue":3.8946,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.9606,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-82.4,
							"leftHandleValue":2.2094,
							"leftHandleSpan":0.5,
							"rightHandleValue":-11.2839,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-86.011,"leftHandleValue":2.8586,"leftHandleSpan":0.7}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3886,"rightHandleValue":-0.0002,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":0.38908,
							"leftHandleValue":0.0222,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0186,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.32437,
							"leftHandleValue":-0.0226,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0531,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.5268,
							"leftHandleValue":-0.0115,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.01,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.375,
							"leftHandleValue":-0.0139,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0066,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6833333333333333,
							"value":0.41498,
							"leftHandleValue":-0.0028,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0199,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.38612,
							"leftHandleValue":0.0097,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0039,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.33938,
							"leftHandleValue":0.0102,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0138,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.47129,
							"leftHandleValue":-0.0002,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0097,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.3725,
							"leftHandleValue":0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0593,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3886,"leftHandleValue":-0.0186,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3828,"rightHandleValue":-0.0002,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":0.38327,
							"leftHandleValue":0.0219,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0183,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.31953,
							"leftHandleValue":-0.0222,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0524,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.51894,
							"leftHandleValue":-0.0113,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0099,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.3694,
							"leftHandleValue":-0.0137,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0065,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6833333333333333,
							"value":0.40879,
							"leftHandleValue":-0.0028,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0196,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.38035,
							"leftHandleValue":0.0095,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0038,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.33432,
							"leftHandleValue":0.01,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0136,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.46425,
							"leftHandleValue":-0.0002,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0096,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.36694,
							"leftHandleValue":0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0584,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3828,"leftHandleValue":-0.0184,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.31666666666666665,"value":0,"rightHandleValue":1.4221,"rightHandleSpan":0.4},
						{
							"time":0.36666666666666664,
							"value":-6.598,
							"leftHandleValue":2.997,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.0348,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4666666666666667,
							"value":3.621,
							"leftHandleValue":-0.9844,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.3698,
							"rightHandleSpan":0.5
						},
						{
							"time":0.6666666666666666,
							"value":1.091,
							"leftHandleValue":-7.1449,
							"leftHandleSpan":0.9,
							"rightHandleValue":-2.9789,
							"rightHandleSpan":0.3
						},
						{"time":1.15,"value":0,"leftHandleValue":0.8383,"leftHandleSpan":0.6,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.75},
						{"time":0.13333333333333333,"value":0.755,"rightHandleValue":-2.4569,"rightHandleSpan":0.99},
						{
							"time":0.21666666666666667,
							"value":-14.945,
							"leftHandleValue":23.7528,
							"leftHandleSpan":0.6,
							"rightHandleValue":-11.8898,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":10.991,
							"leftHandleValue":-3.2377,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.3328,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":-4.917,
							"leftHandleValue":-0.1221,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.7795,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5333333333333333,
							"value":3.883,
							"leftHandleValue":0.0895,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0884,
							"rightHandleSpan":0.3
						},
						{"time":0.7,"value":0.762,"leftHandleValue":-4.7831,"leftHandleSpan":0.7},
						{"time":2,"value":0.75}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-6.62,"rightHandleValue":0.3172,"rightHandleSpan":0.5},
						{
							"time":0.18333333333333332,
							"value":-4.888,
							"leftHandleValue":-3.3894,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1876,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":-9.396,
							"leftHandleValue":-0.0676,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.0552,
							"rightHandleSpan":0.2
						},
						{
							"time":1.1,
							"value":-6.555,
							"leftHandleValue":-1.3585,
							"leftHandleSpan":0.9,
							"rightHandleValue":2.0547,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1833333333333333,
							"value":1.9,
							"leftHandleValue":-11.196,
							"leftHandleSpan":0.5,
							"rightHandleValue":5.326,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":-13.683,
							"leftHandleValue":-1.8974,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.8605,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3666666666666667,
							"value":-3.227,
							"leftHandleValue":0.0672,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.327,
							"rightHandleSpan":0.5
						},
						{
							"time":1.5333333333333332,
							"value":-5.503,
							"leftHandleValue":-6.0391,
							"leftHandleSpan":0.9,
							"rightHandleValue":-3.377,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-6.62,"leftHandleValue":1.1408,"leftHandleSpan":0.6}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3867,"rightHandleValue":0.0188,"rightHandleSpan":0.99},
						{
							"time":0.18333333333333332,
							"value":0.31741,
							"leftHandleValue":0.0741,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0072,
							"rightHandleSpan":0.3
						},
						{
							"time":0.3,
							"value":0.4982,
							"leftHandleValue":0.0086,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0173,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.37254,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0089,
							"rightHandleSpan":0.4
						},
						{
							"time":0.65,
							"value":0.39354,
							"leftHandleValue":0.0453,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0163,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1333333333333333,
							"value":0.3526,
							"leftHandleValue":0.056,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.0724,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.46916,
							"leftHandleValue":-0.0029,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0096,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.3709,
							"leftHandleValue":0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0591,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3867,"leftHandleValue":-0.0183,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3898,"rightHandleValue":0.019,"rightHandleSpan":0.99},
						{
							"time":0.18333333333333332,
							"value":0.31996,
							"leftHandleValue":0.0747,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0073,
							"rightHandleSpan":0.3
						},
						{
							"time":0.3,
							"value":0.50219,
							"leftHandleValue":0.0087,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0175,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.37552,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.009,
							"rightHandleSpan":0.4
						},
						{
							"time":0.65,
							"value":0.39669,
							"leftHandleValue":0.0456,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0165,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1333333333333333,
							"value":0.35543,
							"leftHandleValue":0.0564,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.073,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.47292,
							"leftHandleValue":-0.0029,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0097,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.37388,
							"leftHandleValue":0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0595,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3898,"leftHandleValue":-0.0185,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.18333333333333332,"value":0,"rightHandleValue":-1.3191,"rightHandleSpan":0.2},
						{
							"time":0.23333333333333334,
							"value":6.788,
							"leftHandleValue":-0.3398,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.7046,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":-3.725,
							"leftHandleValue":1.0577,
							"leftHandleSpan":0.5,
							"rightHandleValue":5.2992,
							"rightHandleSpan":0.6
						},
						{
							"time":0.5333333333333333,
							"value":-1.122,
							"leftHandleValue":5.7625,
							"leftHandleSpan":0.9,
							"rightHandleValue":3.0318,
							"rightHandleSpan":0.2
						},
						{"time":1.15,"value":0,"leftHandleValue":-0.858,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.37},
						{"time":0.05,"value":0.303,"rightHandleValue":15.2456,"rightHandleSpan":0.3},
						{
							"time":0.1,
							"value":26.53,
							"leftHandleValue":1.9652,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.4567,
							"rightHandleSpan":0.3
						},
						{
							"time":0.2,
							"value":-14.393,
							"leftHandleValue":-5.7673,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.8163,
							"rightHandleSpan":0.4
						},
						{"time":0.3,"value":7.984,"leftHandleValue":0.582,"leftHandleSpan":0.5,"rightHandleValue":-3.0036,"rightHandleSpan":0.4},
						{
							"time":0.4,
							"value":-3.914,
							"leftHandleValue":-1.2548,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.9657,
							"rightHandleSpan":0.4
						},
						{"time":0.55,"value":0.375,"leftHandleValue":6.1358,"leftHandleSpan":0.6},
						{"time":1.1166666666666667,"value":0.357,"rightHandleValue":1.1503,"rightHandleSpan":0.9},
						{
							"time":1.2,
							"value":-8.279,
							"leftHandleValue":6.3346,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.6548,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":6.699,
							"leftHandleValue":1.1568,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.1377,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3666666666666667,
							"value":-2.83,
							"leftHandleValue":-0.9487,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.1965,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6166666666666667,
							"value":1.077,
							"leftHandleValue":-6.008,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.394,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.37,"leftHandleValue":0.2873,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":124.737,"rightHandleValue":-3.9463,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":115.126,
							"leftHandleValue":-1.4452,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.418,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":143.201,
							"leftHandleValue":-3.4969,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1986,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":122.773,
							"leftHandleValue":-1.0801,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.7897,
							"rightHandleSpan":0.5
						},
						{
							"time":0.7333333333333333,
							"value":126.574,
							"leftHandleValue":-2.6795,
							"leftHandleSpan":0.99,
							"rightHandleValue":-2.0083,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1166666666666667,
							"value":120.883,
							"leftHandleValue":5.7304,
							"leftHandleSpan":0.05,
							"rightHandleValue":-4.7728,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":109.363,
							"leftHandleValue":2.2249,
							"leftHandleSpan":0.4,
							"rightHandleValue":-5.5904,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":148.632,
							"leftHandleValue":-1.0965,
							"leftHandleSpan":0.6,
							"rightHandleValue":-13.3874,
							"rightHandleSpan":0.8
						},
						{
							"time":1.4333333333333333,
							"value":118.696,
							"leftHandleValue":-0.7425,
							"leftHandleSpan":0.3,
							"rightHandleValue":1.2916,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":129.639,
							"leftHandleValue":0.8504,
							"leftHandleSpan":0.4,
							"rightHandleValue":-8.7077,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":124.737,"leftHandleValue":0.4509,"leftHandleSpan":0.8}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4064,"rightHandleValue":-0.03,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.33332,
							"leftHandleValue":-0.0109,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0455,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":0.54557,
							"leftHandleValue":-0.0229,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0004,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.38849,
							"leftHandleValue":-0.0084,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0126,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.4119,
							"leftHandleValue":0.0447,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0067,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1166666666666667,
							"value":0.39234,
							"leftHandleValue":0.0211,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0155,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.35499,
							"leftHandleValue":0.0072,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0143,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.49331,
							"leftHandleValue":-0.0003,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0101,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39002,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0621,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.4064,"leftHandleValue":-0.0191,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4097,"rightHandleValue":-0.0302,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.33603,
							"leftHandleValue":-0.011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0459,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":0.55,
							"leftHandleValue":-0.0231,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0004,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.39165,
							"leftHandleValue":-0.0084,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0127,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.41525,
							"leftHandleValue":0.0451,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0067,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1166666666666667,
							"value":0.39553,
							"leftHandleValue":0.0212,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0156,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.35787,
							"leftHandleValue":0.0073,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0144,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.49731,
							"leftHandleValue":-0.0003,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0102,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39318,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0626,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.4097,"leftHandleValue":-0.0192,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.5},
						{"time":0.31666666666666665,"value":0.42,"rightHandleValue":-2.5159,"rightHandleSpan":0.5},
						{
							"time":0.36666666666666664,
							"value":20.662,
							"leftHandleValue":-11.6155,
							"leftHandleSpan":0.8,
							"rightHandleValue":3.8482,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4666666666666667,
							"value":-10.595,
							"leftHandleValue":7.5271,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.7283,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5666666666666667,
							"value":6.578,
							"leftHandleValue":-1.5934,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.9567,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6666666666666666,
							"value":-2.834,
							"leftHandleValue":0.9187,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2772,
							"rightHandleSpan":0.4
						},
						{"time":0.8333333333333334,"value":0.507,"leftHandleValue":5.6091,"leftHandleSpan":0.6},
						{"time":1.15,"value":0.437,"rightHandleValue":-0.5527,"rightHandleSpan":0.4},
						{
							"time":1.2,
							"value":6.173,
							"leftHandleValue":-0.6949,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.3119,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":-3.497,
							"leftHandleValue":-0.7253,
							"leftHandleSpan":0.4,
							"rightHandleValue":14.648,
							"rightHandleSpan":0.6
						},
						{
							"time":1.5333333333333332,
							"value":1.292,
							"leftHandleValue":-7.02,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.1622,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.5,"leftHandleValue":0.6517,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9729975288200182"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-81.476,"rightHandleValue":1.818,"rightHandleSpan":0.9},
						{
							"time":0.43333333333333335,
							"value":-79.575,
							"leftHandleValue":-7.7207,
							"leftHandleSpan":0.4,
							"rightHandleValue":-6.7213,
							"rightHandleSpan":0.6
						},
						{
							"time":0.8,
							"value":-82.818,
							"leftHandleValue":2.1157,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.2337,
							"rightHandleSpan":0.99
						},
						{
							"time":1.15,
							"value":-71.681,
							"leftHandleValue":-14.783,
							"leftHandleSpan":0.2,
							"rightHandleValue":-1.1753,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1833333333333333,
							"value":-68.783,
							"leftHandleValue":1.3438,
							"leftHandleSpan":0.5,
							"rightHandleValue":-4.6025,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2666666666666666,
							"value":-104.369,
							"leftHandleValue":3.9216,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.0635,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-78.024,
							"leftHandleValue":2.6,
							"leftHandleSpan":0.5,
							"rightHandleValue":-10.8935,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-81.476,"leftHandleValue":2.7859,"leftHandleSpan":0.7}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9729975288200182"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3415,"rightHandleValue":-0.0002,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":0.34192,
							"leftHandleValue":0.0195,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0163,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.28506,
							"leftHandleValue":-0.0198,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0467,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.46295,
							"leftHandleValue":-0.0101,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0088,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.32955,
							"leftHandleValue":-0.0122,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0058,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6833333333333333,
							"value":0.36468,
							"leftHandleValue":-0.0025,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0321,
							"rightHandleSpan":0.5
						},
						{
							"time":1.1,
							"value":0.33932,
							"leftHandleValue":0.0147,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0034,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.29825,
							"leftHandleValue":0.009,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0121,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.41417,
							"leftHandleValue":-0.0002,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0086,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.32735,
							"leftHandleValue":0.0009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0521,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3415,"leftHandleValue":-0.0164,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9729975288200182"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3545,"rightHandleValue":-0.0002,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":0.35494,
							"leftHandleValue":0.0203,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.017,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.29591,
							"leftHandleValue":-0.0206,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0485,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.48057,
							"leftHandleValue":-0.0105,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0091,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.34209,
							"leftHandleValue":-0.0127,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0061,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6833333333333333,
							"value":0.37857,
							"leftHandleValue":-0.0026,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0181,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.35223,
							"leftHandleValue":0.0088,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0035,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.3096,
							"leftHandleValue":0.0093,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0126,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.42993,
							"leftHandleValue":-0.0002,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0089,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.33981,
							"leftHandleValue":0.0009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0541,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3545,"leftHandleValue":-0.017,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9729975288200182"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.31666666666666665,"value":0,"rightHandleValue":1.4221,"rightHandleSpan":0.4},
						{
							"time":0.36666666666666664,
							"value":-6.598,
							"leftHandleValue":2.997,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.0348,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4666666666666667,
							"value":3.621,
							"leftHandleValue":-0.9844,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.3698,
							"rightHandleSpan":0.5
						},
						{
							"time":0.6666666666666666,
							"value":1.091,
							"leftHandleValue":-7.1449,
							"leftHandleSpan":0.9,
							"rightHandleValue":-2.9789,
							"rightHandleSpan":0.3
						},
						{"time":1.15,"value":0,"leftHandleValue":0.8383,"leftHandleSpan":0.6,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"9729975288200182"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":1.02},
						{"time":0.13333333333333333,"value":1.027,"rightHandleValue":-2.5885,"rightHandleSpan":0.99},
						{
							"time":0.21666666666666667,
							"value":-15.028,
							"leftHandleValue":24.2393,
							"leftHandleSpan":0.6,
							"rightHandleValue":-12.2863,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":11.61,
							"leftHandleValue":-3.2946,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.0994,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":-4.781,
							"leftHandleValue":1.7021,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.7934,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5333333333333333,
							"value":4.244,
							"leftHandleValue":0.0794,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0942,
							"rightHandleSpan":0.3
						},
						{"time":0.7,"value":1.036,"leftHandleValue":-4.896,"leftHandleSpan":0.7},
						{"time":2,"value":1.02}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-3.011,"rightHandleValue":0.2543,"rightHandleSpan":0.4},
						{
							"time":0.18333333333333332,
							"value":-1.926,
							"leftHandleValue":-2.181,
							"leftHandleSpan":0.4,
							"rightHandleValue":-5.9179,
							"rightHandleSpan":0.4
						},
						{"time":0.65,"value":-3.059,"leftHandleValue":1.1859,"leftHandleSpan":0.9},
						{"time":1.1,"value":-2.97,"rightHandleValue":0.8132,"rightHandleSpan":0.8},
						{
							"time":1.1666666666666667,
							"value":0.236,
							"leftHandleValue":-4.3808,
							"leftHandleSpan":0.1,
							"rightHandleValue":18.9105,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":-9.361,
							"leftHandleValue":-1.5866,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.7123,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3666666666666667,
							"value":0.448,
							"leftHandleValue":0.3372,
							"leftHandleSpan":0.4,
							"rightHandleValue":-13.386,
							"rightHandleSpan":0.7
						},
						{
							"time":1.6166666666666667,
							"value":-3.795,
							"leftHandleValue":6.3503,
							"leftHandleSpan":0.9,
							"rightHandleValue":1.5816,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-3.011,"leftHandleValue":-0.3176,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3846,"rightHandleValue":0.0187,"rightHandleSpan":0.99},
						{
							"time":0.18333333333333332,
							"value":0.31569,
							"leftHandleValue":0.0737,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0072,
							"rightHandleSpan":0.3
						},
						{
							"time":0.3,
							"value":0.49549,
							"leftHandleValue":0.0086,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0172,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.37051,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0089,
							"rightHandleSpan":0.4
						},
						{
							"time":0.65,
							"value":0.3914,
							"leftHandleValue":0.045,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0162,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1333333333333333,
							"value":0.35069,
							"leftHandleValue":0.0557,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.072,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.46661,
							"leftHandleValue":-0.0028,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0096,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.36889,
							"leftHandleValue":0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0587,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3846,"leftHandleValue":-0.0182,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4104,"rightHandleValue":0.02,"rightHandleSpan":0.99},
						{
							"time":0.18333333333333332,
							"value":0.33687,
							"leftHandleValue":0.0787,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0076,
							"rightHandleSpan":0.3
						},
						{
							"time":0.3,
							"value":0.52873,
							"leftHandleValue":0.0091,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0184,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.39537,
							"leftHandleValue":0.0028,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0094,
							"rightHandleSpan":0.4
						},
						{
							"time":0.65,
							"value":0.41765,
							"leftHandleValue":0.048,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0173,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1333333333333333,
							"value":0.37421,
							"leftHandleValue":0.0594,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.0768,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.49792,
							"leftHandleValue":-0.003,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0102,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39363,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0627,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.4104,"leftHandleValue":-0.0195,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.18333333333333332,"value":0,"rightHandleValue":-1.3191,"rightHandleSpan":0.2},
						{
							"time":0.23333333333333334,
							"value":6.788,
							"leftHandleValue":-0.3398,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.7046,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":-3.725,
							"leftHandleValue":1.0577,
							"leftHandleSpan":0.5,
							"rightHandleValue":5.2992,
							"rightHandleSpan":0.6
						},
						{
							"time":0.5333333333333333,
							"value":-1.122,
							"leftHandleValue":5.7625,
							"leftHandleSpan":0.9,
							"rightHandleValue":3.0318,
							"rightHandleSpan":0.2
						},
						{"time":1.15,"value":0,"leftHandleValue":-0.858,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.86},
						{"time":0.05,"value":0.705,"rightHandleValue":54.409,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-10.164,
							"leftHandleValue":-5.5184,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.8796,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":6.924,
							"leftHandleValue":0.3889,
							"leftHandleSpan":0.5,
							"rightHandleValue":-15.2895,
							"rightHandleSpan":0.7
						},
						{
							"time":0.5,
							"value":2.73,
							"leftHandleValue":-5.2954,
							"leftHandleSpan":0.8,
							"rightHandleValue":-3.2574,
							"rightHandleSpan":0.05
						},
						{"time":1.1,"value":0.854,"leftHandleValue":0.5101,"leftHandleSpan":0.4,"rightHandleValue":0.727,"rightHandleSpan":0.9},
						{"time":1.2,"value":-4.632,"leftHandleValue":4.751,"leftHandleSpan":0.6,"rightHandleValue":0.5163,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":5.008,
							"leftHandleValue":0.7639,
							"leftHandleSpan":0.4,
							"rightHandleValue":-14.5764,
							"rightHandleSpan":0.6
						},
						{
							"time":1.5333333333333332,
							"value":0.128,
							"leftHandleValue":6.6614,
							"leftHandleSpan":0.8,
							"rightHandleValue":2.0475,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.86,"leftHandleValue":-0.6419,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":79.112,"rightHandleValue":-5.3554,"rightHandleSpan":0.5},
						{
							"time":0.3,
							"value":79.168,
							"leftHandleValue":7.1551,
							"leftHandleSpan":0.99,
							"rightHandleValue":2.1013,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7833333333333333,
							"value":80.382,
							"leftHandleValue":-0.5568,
							"leftHandleSpan":0.5,
							"rightHandleValue":-2.5561,
							"rightHandleSpan":0.99
						},
						{
							"time":1.15,
							"value":69.51,
							"leftHandleValue":14.9576,
							"leftHandleSpan":0.2,
							"rightHandleValue":-5.6526,
							"rightHandleSpan":0.2
						},
						{
							"time":1.2333333333333334,
							"value":94.731,
							"leftHandleValue":-2.7433,
							"leftHandleSpan":0.7,
							"rightHandleValue":-14.6512,
							"rightHandleSpan":0.9
						},
						{
							"time":1.4,
							"value":77.755,
							"leftHandleValue":21.5424,
							"leftHandleSpan":0.7,
							"rightHandleValue":-9.2694,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":82.778,
							"leftHandleValue":0.4987,
							"leftHandleSpan":0.4,
							"rightHandleValue":-7.0234,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":79.112,"leftHandleValue":0.8005,"leftHandleSpan":0.8}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4,"rightHandleValue":-0.0295,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.32807,
							"leftHandleValue":-0.0107,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0448,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":0.53698,
							"leftHandleValue":-0.0225,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0004,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.38238,
							"leftHandleValue":-0.0082,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0124,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.40542,
							"leftHandleValue":0.044,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0065,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1166666666666667,
							"value":0.38617,
							"leftHandleValue":0.0207,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0152,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.34939,
							"leftHandleValue":0.0071,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0141,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.48554,
							"leftHandleValue":-0.0003,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0099,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.38387,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0611,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.4,"leftHandleValue":-0.0188,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.412,"rightHandleValue":-0.0304,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.33792,
							"leftHandleValue":-0.011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0462,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":0.55309,
							"leftHandleValue":-0.0232,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0004,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.39385,
							"leftHandleValue":-0.0085,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0128,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.41758,
							"leftHandleValue":0.0453,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0067,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1166666666666667,
							"value":0.39775,
							"leftHandleValue":0.0213,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0157,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.35988,
							"leftHandleValue":0.0073,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0145,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.50011,
							"leftHandleValue":-0.0003,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0102,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39539,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0629,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.412,"leftHandleValue":-0.0194,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":111.4},
						{"time":0.5,"value":-725.2},
						{"time":1.1666666666666667,"value":111.4},
						{"time":1.5666666666666667,"value":-725.2}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":227.2},
						{"time":0.5,"value":-622.8},
						{"time":1.1666666666666667,"value":227.2},
						{"time":1.5666666666666667,"value":-622.8}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":456.7},
						{"time":0.5,"value":-422.5},
						{"time":1.1666666666666667,"value":456.7},
						{"time":1.5666666666666667,"value":-422.5}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":449.8},
						{"time":0.5,"value":-434.2},
						{"time":1.1666666666666667,"value":449.8},
						{"time":1.5666666666666667,"value":-434.2}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":658.8},
						{"time":0.5,"value":-216.1},
						{"time":1.1666666666666667,"value":658.8},
						{"time":1.5666666666666667,"value":-216.1}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":736.4},
						{"time":0.5,"value":-259.2},
						{"time":1.1666666666666667,"value":736.4},
						{"time":1.5666666666666667,"value":-259.2}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"9729975288200182"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Minor1Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor2Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{},
			"4":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"BarWhite_Plate_1",
				"uid":"2227918058887180",
				"position":[0.5,64.94,0],
				"scale":[0.4934,0.5096,1],
				"graphicAsset":"BarWhite_Plate",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,202.7,91.2],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"BarWhite_Plate_2",
				"uid":"3340187801759898",
				"position":[0.5,-42.06,0],
				"scale":[0.4934,0.5096,1],
				"graphicAsset":"BarWhite_Plate",
				"subLayer":0.01,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,202.7,91.2],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"BarWhite_Text_1",
				"uid":"3478878384837261",
				"position":[-1.15,106.89,0],
				"scale":[0.5007,0.5047,1],
				"graphicAsset":"BarWhite_Text",
				"subLayer":0.02,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,199.7,89.9],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"GraphicObject",
				"name":"BarWhite_Text_2",
				"uid":"6751361341252427",
				"position":[-1.15,-0.11,0],
				"scale":[0.5007,0.5047,1],
				"graphicAsset":"BarWhite_Text",
				"subLayer":0.03,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,199.7,89.9],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":4,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"5061231007728378",
				"position":[0,0,1000],
				"coreViewWidth":400,
				"coreViewHeight":400,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":400,
				"constructPrecompTargetHeight":400
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":0,"value":0.5},
						{"time":0.05,"value":0.41,"rightHandleValue":54.9965,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-10.772,
							"leftHandleValue":-5.6666,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.0129,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":6.648,
							"leftHandleValue":0.3933,
							"leftHandleSpan":0.5,
							"rightHandleValue":-2.4773,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4,
							"value":-2.887,
							"leftHandleValue":-1.0403,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.0161,
							"rightHandleSpan":0.4
						},
						{"time":0.55,"value":0.507,"leftHandleValue":4.7049,"leftHandleSpan":0.5},
						{"time":1.1,"value":0.497,"rightHandleValue":1.0837,"rightHandleSpan":0.9},
						{"time":1.2,"value":-4.043,"leftHandleValue":2.303,"leftHandleSpan":0.5,"rightHandleValue":0.3531,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":3.922,
							"leftHandleValue":0.6363,
							"leftHandleSpan":0.4,
							"rightHandleValue":-11.949,
							"rightHandleSpan":0.6
						},
						{
							"time":1.533333,
							"value":-0.107,
							"leftHandleValue":6.1124,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.6633,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.5,"leftHandleValue":-0.5236,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0,"value":64.94,"rightHandleValue":-4.5094,"rightHandleSpan":0.4},
						{
							"time":0.15,
							"value":68.444,
							"leftHandleValue":-2.7951,
							"leftHandleSpan":0.5,
							"rightHandleValue":-7.0046,
							"rightHandleSpan":0.4
						},
						{
							"time":0.783333,
							"value":65.963,
							"leftHandleValue":1.9236,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.0948,
							"rightHandleSpan":1
						},
						{
							"time":1.15,
							"value":56.982,
							"leftHandleValue":12.3309,
							"leftHandleSpan":0.2,
							"rightHandleValue":-5.4414,
							"rightHandleSpan":0.2
						},
						{
							"time":1.233333,
							"value":79.354,
							"leftHandleValue":-0.0082,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.3279,
							"rightHandleSpan":0.4
						},
						{
							"time":1.316667,
							"value":73.638,
							"leftHandleValue":-1.5888,
							"leftHandleSpan":0.5,
							"rightHandleValue":1.793,
							"rightHandleSpan":0.4
						},
						{
							"time":1.433333,
							"value":60.917,
							"leftHandleValue":1.4201,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.6783,
							"rightHandleSpan":0.6
						},
						{
							"time":1.633333,
							"value":64.478,
							"leftHandleValue":6.9828,
							"leftHandleSpan":1,
							"rightHandleValue":0.6327,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":64.94,"leftHandleValue":-0.3927,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4934,"rightHandleValue":-0.0364,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.40468,
							"leftHandleValue":-0.0132,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0553,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":0.66236,
							"leftHandleValue":-0.0278,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0005,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.47166,
							"leftHandleValue":-0.0102,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0076,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.52307,
							"leftHandleValue":0.007,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0251,
							"rightHandleSpan":0.4
						},
						{
							"time":0.683333,
							"value":0.49958,
							"leftHandleValue":-0.001,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0091,
							"rightHandleSpan":1
						},
						{
							"time":1.116667,
							"value":0.47613,
							"leftHandleValue":0.0241,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.019,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.43055,
							"leftHandleValue":0.0085,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0171,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.60867,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0138,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.47304,
							"leftHandleValue":0.0023,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0526,
							"rightHandleSpan":0.6
						},
						{"time":1.716667,"value":0.49138,"leftHandleValue":0.0148,"leftHandleSpan":1},
						{"time":2,"value":0.4934}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5096,"rightHandleValue":-0.0376,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41797,
							"leftHandleValue":-0.0136,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0297,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.68411,
							"leftHandleValue":-0.0024,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0005,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.48715,
							"leftHandleValue":-0.0105,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0078,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.54025,
							"leftHandleValue":0.0073,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.023,
							"rightHandleSpan":0.4
						},
						{
							"time":0.666667,
							"value":0.51606,
							"leftHandleValue":-0.0022,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0093,
							"rightHandleSpan":1
						},
						{
							"time":1.116667,
							"value":0.49176,
							"leftHandleValue":0.0251,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0197,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.44469,
							"leftHandleValue":0.0088,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0176,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.62866,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0143,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.48857,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0019,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.52348,
							"leftHandleValue":0.0029,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0119,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.5096,"leftHandleValue":-0.0074,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5},
						{"time":0.166667,"value":0.494,"rightHandleValue":-1.2071,"rightHandleSpan":0.9},
						{
							"time":0.216667,
							"value":-5.054,
							"leftHandleValue":8.9177,
							"leftHandleSpan":0.2,
							"rightHandleValue":-41.8436,
							"rightHandleSpan":0.4
						},
						{
							"time":0.35,
							"value":12.224,
							"leftHandleValue":-2.1842,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1153,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":-5.782,
							"leftHandleValue":2.9041,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0501,
							"rightHandleSpan":0.4
						},
						{
							"time":0.55,
							"value":3.996,
							"leftHandleValue":-0.4396,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.2067,
							"rightHandleSpan":0.4
						},
						{"time":0.716667,"value":0.508,"leftHandleValue":-5.3397,"leftHandleSpan":0.6},
						{"time":1.15,"value":0.436,"rightHandleValue":5.8062,"rightHandleSpan":0.7},
						{
							"time":1.283333,
							"value":-1.54,
							"leftHandleValue":4.7777,
							"leftHandleSpan":0.8,
							"rightHandleValue":4.3636,
							"rightHandleSpan":0.5
						},
						{
							"time":1.45,
							"value":-0.143,
							"leftHandleValue":1.885,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.6234,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.5,"leftHandleValue":-0.5414,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0,"value":-42.06,"rightHandleValue":-0.3783,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-43.956,
							"leftHandleValue":3.5725,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0392,
							"rightHandleSpan":0.4
						},
						{
							"time":0.316667,
							"value":-38.942,
							"leftHandleValue":0.2043,
							"leftHandleSpan":0.4,
							"rightHandleValue":-7.4735,
							"rightHandleSpan":0.4
						},
						{"time":0.85,"value":-42.755,"leftHandleValue":2.0421,"leftHandleSpan":0.8},
						{"time":1.1,"value":-42.127,"rightHandleValue":7.2505,"rightHandleSpan":1},
						{
							"time":1.166667,
							"value":-34.741,
							"leftHandleValue":-2.9915,
							"leftHandleSpan":0.1,
							"rightHandleValue":13.6405,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":-57.449,
							"leftHandleValue":-5.0693,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.2359,
							"rightHandleSpan":0.4
						},
						{
							"time":1.383333,
							"value":-39.092,
							"leftHandleValue":-0.6846,
							"leftHandleSpan":0.5,
							"rightHandleValue":-9.3242,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":-43.277,
							"leftHandleValue":4.3566,
							"leftHandleSpan":0.6,
							"rightHandleValue":2.5178,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":-42.06,"leftHandleValue":-0.3522,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4934,"rightHandleValue":0.0007,"rightHandleSpan":0.4},
						{
							"time":0.116667,
							"value":0.50372,
							"leftHandleValue":0.0012,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0014,
							"rightHandleSpan":0.8
						},
						{
							"time":0.2,
							"value":0.40724,
							"leftHandleValue":0.0607,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0292,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":0.66616,
							"leftHandleValue":-0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0183,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.47495,
							"leftHandleValue":0.0145,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0012,
							"rightHandleSpan":0.4
						},
						{
							"time":0.666667,
							"value":0.50268,
							"leftHandleValue":0.0611,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0217,
							"rightHandleSpan":1
						},
						{
							"time":1.133333,
							"value":0.44938,
							"leftHandleValue":0.0715,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.0946,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.60833,
							"leftHandleValue":-0.0036,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0138,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.47274,
							"leftHandleValue":0.0023,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0526,
							"rightHandleSpan":0.6
						},
						{"time":1.716667,"value":0.49124,"leftHandleValue":0.0146,"leftHandleSpan":1},
						{"time":2,"value":0.4934}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5096,"rightHandleValue":0.0008,"rightHandleSpan":0.4},
						{
							"time":0.116667,
							"value":0.52026,
							"leftHandleValue":0.0012,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0014,
							"rightHandleSpan":0.8
						},
						{
							"time":0.2,
							"value":0.42061,
							"leftHandleValue":0.0627,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0302,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":0.68803,
							"leftHandleValue":-0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0189,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.49055,
							"leftHandleValue":0.015,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0013,
							"rightHandleSpan":0.4
						},
						{
							"time":0.666667,
							"value":0.51918,
							"leftHandleValue":0.0631,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0224,
							"rightHandleSpan":1
						},
						{
							"time":1.133333,
							"value":0.46414,
							"leftHandleValue":0.0738,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.0977,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.6283,
							"leftHandleValue":-0.0037,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0143,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.48826,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0019,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.52319,
							"leftHandleValue":0.0029,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0119,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.5096,"leftHandleValue":-0.0076,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.2,"value":0,"rightHandleValue":-1.4203,"rightHandleSpan":0.3},
						{
							"time":0.25,
							"value":6.733,
							"leftHandleValue":-1.1461,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0307,
							"rightHandleSpan":0.4
						},
						{
							"time":0.35,
							"value":-3.695,
							"leftHandleValue":0.4251,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.4306,
							"rightHandleSpan":0.5
						},
						{"time":0.55,"value":-1.113,"leftHandleValue":6.82,"leftHandleSpan":0.9,"rightHandleValue":2.9126,"rightHandleSpan":0.2},
						{"time":1.15,"value":0,"leftHandleValue":-0.7629,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0,"value":-1.15},
						{"time":0.05,"value":-0.943,"rightHandleValue":15.0986,"rightHandleSpan":0.3},
						{
							"time":0.1,
							"value":24.657,
							"leftHandleValue":2.1928,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.8675,
							"rightHandleSpan":0.3
						},
						{
							"time":0.2,
							"value":-16.149,
							"leftHandleValue":-5.9722,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.961,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":6.477,
							"leftHandleValue":0.5558,
							"leftHandleSpan":0.5,
							"rightHandleValue":-3.0024,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4,
							"value":-5.491,
							"leftHandleValue":-1.2255,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.9334,
							"rightHandleSpan":0.4
						},
						{"time":0.55,"value":-1.165,"leftHandleValue":6.0971,"leftHandleSpan":0.6},
						{"time":1.15,"value":-1.004,"rightHandleValue":1.5352,"rightHandleSpan":0.3},
						{
							"time":1.2,
							"value":-8.644,
							"leftHandleValue":0.2602,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.2471,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":4.037,
							"leftHandleValue":0.9485,
							"leftHandleSpan":0.4,
							"rightHandleValue":-10.7676,
							"rightHandleSpan":0.6
						},
						{
							"time":1.45,
							"value":0.475,
							"leftHandleValue":-5.9762,
							"leftHandleSpan":0.8,
							"rightHandleValue":-5.983,
							"rightHandleSpan":0.6
						},
						{"time":1.666667,"value":-1.147,"leftHandleValue":2.9772,"leftHandleSpan":0.4},
						{"time":2,"value":-1.15}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0,"value":106.89,"rightHandleValue":-3.825,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":97.572,
							"leftHandleValue":-1.3984,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.5001,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":124.76,
							"leftHandleValue":-3.1221,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.5364,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":104.95,
							"leftHandleValue":-0.9566,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.2403,
							"rightHandleSpan":0.5
						},
						{
							"time":0.733333,
							"value":108.434,
							"leftHandleValue":-3.1806,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.7581,
							"rightHandleSpan":1
						},
						{
							"time":1.116667,
							"value":103.504,
							"leftHandleValue":4.9937,
							"leftHandleSpan":0.05,
							"rightHandleValue":-8.7716,
							"rightHandleSpan":0.5
						},
						{
							"time":1.166667,
							"value":97.996,
							"leftHandleValue":-9.3522,
							"leftHandleSpan":0.2,
							"rightHandleValue":22.2766,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":129.181,
							"leftHandleValue":0.2917,
							"leftHandleSpan":0.4,
							"rightHandleValue":-15.3466,
							"rightHandleSpan":0.9
						},
						{
							"time":1.433333,
							"value":101.308,
							"leftHandleValue":3.1608,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.9068,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":111.239,
							"leftHandleValue":0.8019,
							"leftHandleSpan":0.4,
							"rightHandleValue":-7.9797,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":106.89,"leftHandleValue":0.5524,"leftHandleSpan":0.8}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5007,"rightHandleValue":-0.0369,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41067,
							"leftHandleValue":-0.0134,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0292,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.67216,
							"leftHandleValue":-0.0024,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0005,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.47864,
							"leftHandleValue":-0.0103,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0077,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.53081,
							"leftHandleValue":0.0071,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0255,
							"rightHandleSpan":0.4
						},
						{
							"time":0.683333,
							"value":0.50697,
							"leftHandleValue":-0.001,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0092,
							"rightHandleSpan":1
						},
						{
							"time":1.116667,
							"value":0.48317,
							"leftHandleValue":0.0244,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0193,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.43692,
							"leftHandleValue":0.0086,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0173,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.61768,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.014,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.48004,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0625,
							"rightHandleSpan":0.7
						},
						{"time":1.716667,"value":0.49865,"leftHandleValue":0.0091,"leftHandleSpan":1},
						{"time":2,"value":0.5007}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5047,"rightHandleValue":-0.0372,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41395,
							"leftHandleValue":-0.0135,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0294,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.67753,
							"leftHandleValue":-0.0024,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0005,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.48246,
							"leftHandleValue":-0.0104,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0077,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.53505,
							"leftHandleValue":0.0072,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0257,
							"rightHandleSpan":0.4
						},
						{
							"time":0.683333,
							"value":0.51102,
							"leftHandleValue":-0.001,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0093,
							"rightHandleSpan":1
						},
						{
							"time":1.116667,
							"value":0.48703,
							"leftHandleValue":0.0246,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0195,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.44041,
							"leftHandleValue":0.0087,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0175,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.62261,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0141,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.48388,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.063,
							"rightHandleSpan":0.7
						},
						{"time":1.716667,"value":0.50263,"leftHandleValue":0.0091,"leftHandleSpan":1},
						{"time":2,"value":0.5047}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0,"value":-1.15},
						{"time":0.2,"value":-0.949,"rightHandleValue":-0.6134,"rightHandleSpan":0.8},
						{
							"time":0.216667,
							"value":-7.552,
							"leftHandleValue":9.3548,
							"leftHandleSpan":0.6,
							"rightHandleValue":-53.4226,
							"rightHandleSpan":0.4
						},
						{
							"time":0.35,
							"value":13.583,
							"leftHandleValue":-4.3865,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.1526,
							"rightHandleSpan":0.3
						},
						{
							"time":0.45,
							"value":-8.798,
							"leftHandleValue":0.9084,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0704,
							"rightHandleSpan":0.4
						},
						{
							"time":0.55,
							"value":3.111,
							"leftHandleValue":-0.5761,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5627,
							"rightHandleSpan":0.4
						},
						{"time":0.716667,"value":-1.168,"leftHandleValue":-6.6211,"leftHandleSpan":0.6},
						{"time":2,"value":-1.15}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				},
				{
					"keyframes":[
						{"time":0,"value":-0.11,"rightHandleValue":0.4635,"rightHandleSpan":0.9},
						{
							"time":0.2,
							"value":-9.331,
							"leftHandleValue":14.4326,
							"leftHandleSpan":0.3,
							"rightHandleValue":-3.157,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":17.726,
							"leftHandleValue":2.6539,
							"leftHandleSpan":0.3,
							"rightHandleValue":-2.7963,
							"rightHandleSpan":0.4
						},
						{
							"time":0.466667,
							"value":-2.701,
							"leftHandleValue":-2.4123,
							"leftHandleSpan":0.4,
							"rightHandleValue":11.4037,
							"rightHandleSpan":0.4
						},
						{"time":0.883333,"value":-0.378,"leftHandleValue":-2.5779,"leftHandleSpan":0.8},
						{"time":1.116667,"value":-0.449,"rightHandleValue":0.4665,"rightHandleSpan":1},
						{
							"time":1.183333,
							"value":7.542,
							"leftHandleValue":-10.4106,
							"leftHandleSpan":0.6,
							"rightHandleValue":6.1999,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":-6.184,
							"leftHandleValue":-1.5132,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.5843,
							"rightHandleSpan":0.4
						},
						{
							"time":1.366667,
							"value":3.031,
							"leftHandleValue":0.493,
							"leftHandleSpan":0.4,
							"rightHandleValue":-13.4375,
							"rightHandleSpan":0.7
						},
						{
							"time":1.616667,
							"value":-1.021,
							"leftHandleValue":6.3494,
							"leftHandleSpan":0.9,
							"rightHandleValue":1.5543,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-0.11,"leftHandleValue":-0.3121,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5007,"rightHandleValue":0.0007,"rightHandleSpan":0.4},
						{
							"time":0.116667,
							"value":0.51117,
							"leftHandleValue":0.0012,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0014,
							"rightHandleSpan":0.8
						},
						{
							"time":0.2,
							"value":0.41326,
							"leftHandleValue":0.0616,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0297,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":0.67601,
							"leftHandleValue":-0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0186,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.48198,
							"leftHandleValue":0.0148,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0012,
							"rightHandleSpan":0.4
						},
						{
							"time":0.666667,
							"value":0.51011,
							"leftHandleValue":0.062,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.022,
							"rightHandleSpan":1
						},
						{
							"time":1.133333,
							"value":0.45603,
							"leftHandleValue":0.0725,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.096,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.61733,
							"leftHandleValue":-0.0036,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0141,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.47973,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0626,
							"rightHandleSpan":0.7
						},
						{"time":1.716667,"value":0.4985,"leftHandleValue":0.0088,"leftHandleSpan":1},
						{"time":2,"value":0.5007}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5047,"rightHandleValue":0.0008,"rightHandleSpan":0.4},
						{
							"time":0.116667,
							"value":0.51526,
							"leftHandleValue":0.0012,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0014,
							"rightHandleSpan":0.8
						},
						{
							"time":0.2,
							"value":0.41657,
							"leftHandleValue":0.0621,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0299,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":0.68142,
							"leftHandleValue":-0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0188,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.48583,
							"leftHandleValue":0.0149,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0013,
							"rightHandleSpan":0.4
						},
						{
							"time":0.666667,
							"value":0.51419,
							"leftHandleValue":0.0625,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0222,
							"rightHandleSpan":1
						},
						{
							"time":1.133333,
							"value":0.45968,
							"leftHandleValue":0.0731,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.0968,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.62226,
							"leftHandleValue":-0.0036,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0142,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.48356,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0631,
							"rightHandleSpan":0.7
						},
						{"time":1.716667,"value":0.50249,"leftHandleValue":0.0089,"leftHandleSpan":1},
						{"time":2,"value":0.5047}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.2,"value":0,"rightHandleValue":-1.4203,"rightHandleSpan":0.3},
						{
							"time":0.25,
							"value":6.733,
							"leftHandleValue":-1.1461,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0307,
							"rightHandleSpan":0.4
						},
						{
							"time":0.35,
							"value":-3.695,
							"leftHandleValue":0.4251,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.4306,
							"rightHandleSpan":0.5
						},
						{"time":0.55,"value":-1.113,"leftHandleValue":6.82,"leftHandleSpan":0.9,"rightHandleValue":2.9126,"rightHandleSpan":0.2},
						{"time":1.15,"value":0,"leftHandleValue":-0.7629,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				},
				{
					"keyframes":[
						{"time":0.066667,"value":-762.6,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.466667,"value":575,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-762.6,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":575,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0.066667,"value":-808.4,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.466667,"value":509.7,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-808.4,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":509.7,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0.066667,"value":-609.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.466667,"value":728.4,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-609.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":728.4,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0.066667,"value":-657.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.466667,"value":660.9,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-657.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":660.9,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Minor2Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor3Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"BarWhite_Plate",
				"uid":"3167232686563551",
				"position":[0,12.29,0],
				"scale":[0.5949,0.6148,1],
				"graphicAsset":"BarWhite_Plate",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,168.1,75.6],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"BarWhite_Text",
				"uid":"5058770658948113",
				"position":[-1.72,63.12,0],
				"scale":[0.5991,0.6039,1],
				"graphicAsset":"BarWhite_Text",
				"subLayer":0.01,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,166.9,75.1],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"3266166304940326",
				"position":[0,0,1000],
				"coreViewWidth":400,
				"coreViewHeight":400,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":400,
				"constructPrecompTargetHeight":400
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":55.8164,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-11.624,
							"leftHandleValue":-5.8533,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.2271,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":6.247,
							"leftHandleValue":0.4061,
							"leftHandleSpan":0.5,
							"rightHandleValue":-2.5113,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4,
							"value":-3.465,
							"leftHandleValue":-1.0434,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.0578,
							"rightHandleSpan":0.4
						},
						{"time":0.55,"value":0,"leftHandleValue":4.7736,"leftHandleSpan":0.5,"rightHandleValue":0.7368,"rightHandleSpan":0.7},
						{
							"time":1.283333,
							"value":0.643,
							"leftHandleValue":-2.1771,
							"leftHandleSpan":0.1,
							"rightHandleValue":-1.5207,
							"rightHandleSpan":0.1
						},
						{"time":2,"value":0,"leftHandleValue":0.4389,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0,"value":12.29,"rightHandleValue":-6.4828,"rightHandleSpan":0.5},
						{
							"time":0.15,
							"value":17.484,
							"leftHandleValue":-1.1779,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.3902,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":13.028,
							"leftHandleValue":-3.9458,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.9168,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":10.703,
							"leftHandleValue":3.5131,
							"leftHandleSpan":0.1,
							"rightHandleValue":-2.5071,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2,
							"value":22.123,
							"leftHandleValue":-1.6314,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.2928,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":9.747,
							"leftHandleValue":-0.2221,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5295,
							"rightHandleSpan":0.4
						},
						{
							"time":1.35,
							"value":16.216,
							"leftHandleValue":-1.0321,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.7818,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":9.828,
							"leftHandleValue":-0.9263,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.0926,
							"rightHandleSpan":0.6
						},
						{"time":1.666667,"value":12.256,"leftHandleValue":-4.0331,"leftHandleSpan":0.4},
						{"time":2,"value":12.29}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5949,"rightHandleValue":-0.044,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.48793,
							"leftHandleValue":-0.0213,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0436,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.8463,
							"leftHandleValue":-0.0014,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0048,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.56603,
							"leftHandleValue":-0.0094,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0065,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.63068,
							"leftHandleValue":0.0097,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0581,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.59091,
							"leftHandleValue":0.0334,
							"leftHandleSpan":1,
							"rightHandleValue":-0.0059,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.5181,
							"leftHandleValue":0.0141,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0198,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.75742,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0204,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.56923,
							"leftHandleValue":0.0053,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0006,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.6111,
							"leftHandleValue":0.0039,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0286,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.5949,"leftHandleValue":-0.0009,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0,"value":0.6148,"rightHandleValue":-0.0454,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.50425,
							"leftHandleValue":-0.022,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.045,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.87461,
							"leftHandleValue":-0.0014,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0049,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.58496,
							"leftHandleValue":-0.0097,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0067,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.65177,
							"leftHandleValue":0.01,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0601,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.61068,
							"leftHandleValue":0.0345,
							"leftHandleSpan":1,
							"rightHandleValue":-0.0061,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.53543,
							"leftHandleValue":0.0145,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0205,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.78275,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0211,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.58827,
							"leftHandleValue":0.0055,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0006,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.63155,
							"leftHandleValue":0.004,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0295,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.6148,"leftHandleValue":-0.001,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0,"value":-1.72},
						{"time":0.05,"value":-1.411,"rightHandleValue":15.6869,"rightHandleSpan":0.3},
						{
							"time":0.1,
							"value":25.732,
							"leftHandleValue":2.1152,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.6438,
							"rightHandleSpan":0.3
						},
						{
							"time":0.2,
							"value":-18.079,
							"leftHandleValue":-6.8899,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.7983,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":6.306,
							"leftHandleValue":0.6274,
							"leftHandleSpan":0.5,
							"rightHandleValue":-3.1354,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4,
							"value":-6.324,
							"leftHandleValue":-1.2645,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.0928,
							"rightHandleSpan":0.4
						},
						{"time":0.55,"value":-1.743,"leftHandleValue":6.4166,"leftHandleSpan":0.6},
						{"time":1.15,"value":-1.498,"rightHandleValue":0.7873,"rightHandleSpan":0.3},
						{
							"time":1.2,
							"value":-6.254,
							"leftHandleValue":-0.174,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1443,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":1.138,
							"leftHandleValue":0.5276,
							"leftHandleSpan":0.4,
							"rightHandleValue":-11.1724,
							"rightHandleSpan":0.6
						},
						{
							"time":1.533333,
							"value":-2.368,
							"leftHandleValue":5.67,
							"leftHandleSpan":0.8,
							"rightHandleValue":1.7034,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-1.72,"leftHandleValue":-0.4977,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				},
				{
					"keyframes":[
						{"time":0,"value":63.12,"rightHandleValue":-4.6637,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":51.77,
							"leftHandleValue":-2.2563,
							"leftHandleSpan":0.4,
							"rightHandleValue":8.8551,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":89.794,
							"leftHandleValue":-0.1793,
							"leftHandleSpan":0.3,
							"rightHandleValue":-1.2908,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":60.077,
							"leftHandleValue":-0.6983,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.2301,
							"rightHandleSpan":0.5
						},
						{"time":0.533333,"value":63.971,"leftHandleValue":5.9616,"leftHandleSpan":1},
						{"time":0.716667,"value":63.886,"rightHandleValue":-2.9959,"rightHandleSpan":1},
						{
							"time":1.15,
							"value":54.971,
							"leftHandleValue":13.6326,
							"leftHandleSpan":0.2,
							"rightHandleValue":-5.2525,
							"rightHandleSpan":0.2
						},
						{
							"time":1.233333,
							"value":78.929,
							"leftHandleValue":-1.5401,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.39,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":73.785,
							"leftHandleValue":1.3477,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.4836,
							"rightHandleSpan":0.7
						},
						{
							"time":1.433333,
							"value":58.803,
							"leftHandleValue":-0.3509,
							"leftHandleSpan":0.3,
							"rightHandleValue":5.7521,
							"rightHandleSpan":0.6
						},
						{
							"time":1.633333,
							"value":62.549,
							"leftHandleValue":6.7262,
							"leftHandleSpan":1,
							"rightHandleValue":0.6687,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":63.12,"leftHandleValue":-0.3855,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5991,"rightHandleValue":-0.0443,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.49137,
							"leftHandleValue":-0.0214,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0439,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.85228,
							"leftHandleValue":-0.0014,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0048,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.57003,
							"leftHandleValue":-0.0095,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0065,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.63513,
							"leftHandleValue":0.0097,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0585,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.59508,
							"leftHandleValue":0.0336,
							"leftHandleSpan":1,
							"rightHandleValue":-0.0059,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.52176,
							"leftHandleValue":0.0142,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.02,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.76276,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0206,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.57325,
							"leftHandleValue":0.0054,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0006,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.61542,
							"leftHandleValue":0.0039,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0288,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.5991,"leftHandleValue":-0.001,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				},
				{
					"keyframes":[
						{"time":0,"value":0.6039,"rightHandleValue":-0.0446,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.49531,
							"leftHandleValue":-0.0216,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0442,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.85911,
							"leftHandleValue":-0.0014,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0048,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.57459,
							"leftHandleValue":-0.0095,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0066,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.64022,
							"leftHandleValue":0.0098,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.059,
							"rightHandleSpan":0.3
						},
						{"time":1.1,"value":0.59985,"leftHandleValue":0.0339,"leftHandleSpan":1,"rightHandleValue":-0.006,"rightHandleSpan":0.4},
						{
							"time":1.15,
							"value":0.52594,
							"leftHandleValue":0.0143,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0201,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.76887,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0207,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.57784,
							"leftHandleValue":0.0054,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0006,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.62035,
							"leftHandleValue":0.0039,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.029,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.6039,"leftHandleValue":-0.001,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				},
				{
					"keyframes":[
						{"time":0.1,"value":-569.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.5,"value":540.1,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-569.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":540.1,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0.1,"value":-623.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.5,"value":478.4,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-623.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":478.4,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Minor3Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Wild_CherryLeft.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Wild_CherryRight.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Wild_Leaf.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Wild_Text.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/WildConstruct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{},
			"4":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Wild_CherryRight",
				"uid":"5260181590830166",
				"position":[29.62,20.11,0],
				"rotation":[0,0,13.5],
				"scale":[0.3989,0.3751,1],
				"graphicAsset":"Wild_CherryRight",
				"subLayer":0.01,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,200.6,87.7],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Wild_CherryLeft",
				"uid":"1318609139099603",
				"position":[-48.11,22.99,0],
				"rotation":[0,0,0.75],
				"scale":[0.3181,0.2925,1],
				"graphicAsset":"Wild_CherryLeft",
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,251.5,110],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"Wild_Leaf",
				"uid":"0824628194821993",
				"position":[-31.38,109.96,0],
				"rotation":[0,0,2.3],
				"scale":[0.249,0.2336,1],
				"graphicAsset":"Wild_Leaf",
				"subLayer":0.02,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,321.3,140.6],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"GraphicObject",
				"name":"Wild_Text",
				"uid":"5181909378657975",
				"position":[0.15,-74.91,0],
				"scale":[0.4063,0.4063,1],
				"graphicAsset":"Wild_Text",
				"subLayer":0.03,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,196.9,86.1],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":4,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"7877893287921742",
				"position":[0,0,1000],
				"coreViewWidth":450,
				"coreViewHeight":550,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":450,
				"constructPrecompTargetHeight":550
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":29.62,"rightHandleValue":7.1342,"rightHandleSpan":0.8},
						{
							"time":0.3833333333333333,
							"value":18.183,
							"leftHandleValue":8.6471,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.4674,
							"rightHandleSpan":0.4
						},
						{
							"time":0.55,
							"value":58.033,
							"leftHandleValue":-3.4231,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.6484,
							"rightHandleSpan":0.3
						},
						{
							"time":0.7166666666666667,
							"value":14.492,
							"leftHandleValue":-0.8105,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.0352,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9,
							"value":43.934,
							"leftHandleValue":-3.4103,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4182,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0666666666666667,
							"value":25.027,
							"leftHandleValue":2.1516,
							"leftHandleSpan":0.4,
							"rightHandleValue":16.1966,
							"rightHandleSpan":0.8
						},
						{
							"time":1.4666666666666666,
							"value":25.068,
							"leftHandleValue":5.2508,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.7609,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":29.62,"leftHandleValue":-0.7491,"leftHandleSpan":0.99}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":20.11,"rightHandleValue":-14.3071,"rightHandleSpan":0.4},
						{
							"time":0.1,
							"value":-7.594,
							"leftHandleValue":-12.6178,
							"leftHandleSpan":0.4,
							"rightHandleValue":29.9504,
							"rightHandleSpan":0.4
						},
						{
							"time":0.2833333333333333,
							"value":116.024,
							"leftHandleValue":-4.8074,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0697,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":17.193,
							"leftHandleValue":35.6725,
							"leftHandleSpan":0.5,
							"rightHandleValue":-7.101,
							"rightHandleSpan":0.3
						},
						{
							"time":0.5833333333333334,
							"value":-1.833,
							"leftHandleValue":-0.9768,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.5166,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7166666666666667,
							"value":40.464,
							"leftHandleValue":1.9218,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.026,
							"rightHandleSpan":0.3
						},
						{
							"time":0.9166666666666666,
							"value":22.642,
							"leftHandleValue":1.4232,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.3337,
							"rightHandleSpan":0.4
						},
						{
							"time":1.05,
							"value":29.354,
							"leftHandleValue":-1.6043,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.6334,
							"rightHandleSpan":0.5
						},
						{
							"time":1.1,
							"value":14.202,
							"leftHandleValue":-1.0036,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.0981,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2166666666666666,
							"value":85.214,
							"leftHandleValue":-2.1811,
							"leftHandleSpan":0.3,
							"rightHandleValue":5.2533,
							"rightHandleSpan":0.3
						},
						{
							"time":1.3833333333333333,
							"value":18.926,
							"leftHandleValue":12.1432,
							"leftHandleSpan":0.3,
							"rightHandleValue":-9.1994,
							"rightHandleSpan":0.05
						},
						{"time":2,"value":20.11,"leftHandleValue":-6.9594,"leftHandleSpan":0.9}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3989,"rightHandleValue":0.008,"rightHandleSpan":0.4},
						{
							"time":0.18333333333333332,
							"value":0.42991,
							"leftHandleValue":0.0224,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0984,
							"rightHandleSpan":0.99
						},
						{
							"time":0.5833333333333334,
							"value":0.45629,
							"leftHandleValue":-0.0092,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.0253,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7666666666666666,
							"value":0.38759,
							"leftHandleValue":-0.0367,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0995,
							"rightHandleSpan":0.7
						},
						{
							"time":1.0833333333333333,
							"value":0.46352,
							"leftHandleValue":-0.0799,
							"leftHandleSpan":0.1,
							"rightHandleValue":0.0271,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1333333333333333,
							"value":0.46206,
							"leftHandleValue":0.0115,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1054,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.40866,
							"leftHandleValue":0.0035,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0265,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3989,"leftHandleValue":-0.0014,"leftHandleSpan":0.6}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3751,"rightHandleValue":-0.0309,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":0.29778,
							"leftHandleValue":0.0052,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0088,
							"rightHandleSpan":0.4
						},
						{
							"time":0.2833333333333333,
							"value":0.48126,
							"leftHandleValue":0.0107,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0047,
							"rightHandleSpan":0.2
						},
						{
							"time":0.5166666666666666,
							"value":0.36326,
							"leftHandleValue":0.0611,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0262,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.30862,
							"leftHandleValue":-0.0048,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0249,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7333333333333333,
							"value":0.41525,
							"leftHandleValue":0.0064,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0373,
							"rightHandleSpan":0.7
						},
						{
							"time":1.05,
							"value":0.4092,
							"leftHandleValue":-0.0359,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0069,
							"rightHandleSpan":0.5
						},
						{
							"time":1.1,
							"value":0.3611,
							"leftHandleValue":0.0016,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0253,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":0.44703,
							"leftHandleValue":0.0317,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1337,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":0.3751,"leftHandleValue":0.0058,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":13.5},
						{"time":0.25,"value":13.5,"rightHandleValue":2.3209,"rightHandleSpan":0.2},
						{
							"time":0.35,
							"value":-1.939,
							"leftHandleValue":1.696,
							"leftHandleSpan":0.7,
							"rightHandleValue":2.8708,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5333333333333333,
							"value":24.79,
							"leftHandleValue":0.0173,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5134,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7166666666666667,
							"value":5.258,
							"leftHandleValue":0.4261,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.674,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9,
							"value":19.507,
							"leftHandleValue":-0.6337,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.174,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0833333333333333,
							"value":9.129,
							"leftHandleValue":0.6995,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0218,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":16.684,
							"leftHandleValue":0.618,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.4991,
							"rightHandleSpan":0.4
						},
						{"time":1.5666666666666667,"value":13.5,"leftHandleValue":-5.7201,"leftHandleSpan":0.5},
						{"time":2,"value":13.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-48.11,"rightHandleValue":-0.5378,"rightHandleSpan":0.4},
						{
							"time":0.13333333333333333,
							"value":-52.504,
							"leftHandleValue":0.6766,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.2068,
							"rightHandleSpan":0.8
						},
						{
							"time":0.3833333333333333,
							"value":-34.174,
							"leftHandleValue":-6.4044,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.8738,
							"rightHandleSpan":0.4
						},
						{
							"time":0.55,
							"value":-79.312,
							"leftHandleValue":7.4328,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.454,
							"rightHandleSpan":0.3
						},
						{
							"time":0.7166666666666667,
							"value":-30.259,
							"leftHandleValue":-0.1948,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.1991,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9166666666666666,
							"value":-64.502,
							"leftHandleValue":-2.2836,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.0799,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0666666666666667,
							"value":-44.565,
							"leftHandleValue":-1.7738,
							"leftHandleSpan":0.4,
							"rightHandleValue":-8.0696,
							"rightHandleSpan":0.3
						},
						{
							"time":1.3166666666666667,
							"value":-52.366,
							"leftHandleValue":3.2889,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.8785,
							"rightHandleSpan":0.4
						},
						{"time":1.5666666666666667,"value":-47.575,"leftHandleValue":10.5513,"leftHandleSpan":0.6},
						{"time":2,"value":-48.11}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":22.99,"rightHandleValue":-11.9545,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":-8.724,
							"leftHandleValue":-0.1321,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.1243,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":114.894,
							"leftHandleValue":11.0055,
							"leftHandleSpan":0.2,
							"rightHandleValue":-2.233,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":106.682,
							"leftHandleValue":4.2162,
							"leftHandleSpan":0.4,
							"rightHandleValue":-67.6873,
							"rightHandleSpan":0.8
						},
						{
							"time":0.5166666666666666,
							"value":33.768,
							"leftHandleValue":23.5397,
							"leftHandleSpan":0.5,
							"rightHandleValue":-10.9011,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6,
							"value":10.004,
							"leftHandleValue":-1.8646,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.5831,
							"rightHandleSpan":0.5
						},
						{
							"time":0.7833333333333333,
							"value":31.348,
							"leftHandleValue":8.6655,
							"leftHandleSpan":0.8,
							"rightHandleValue":0.4412,
							"rightHandleSpan":0.4
						},
						{
							"time":0.8833333333333333,
							"value":33.662,
							"leftHandleValue":0.3185,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7677,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0666666666666667,
							"value":26.137,
							"leftHandleValue":3.1811,
							"leftHandleSpan":0.05,
							"rightHandleValue":-5.7454,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1,
							"value":11.378,
							"leftHandleValue":-1.4505,
							"leftHandleSpan":0.4,
							"rightHandleValue":15.751,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2333333333333334,
							"value":90.979,
							"leftHandleValue":5.7574,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.658,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":17.204,
							"leftHandleValue":13.7482,
							"leftHandleSpan":0.4,
							"rightHandleValue":-10.4722,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5833333333333333,
							"value":17.477,
							"leftHandleValue":0.3735,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.6489,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":22.99,"leftHandleValue":-0.3698,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3181,"rightHandleValue":0.0064,"rightHandleSpan":0.4},
						{
							"time":0.18333333333333332,
							"value":0.34283,
							"leftHandleValue":0.0178,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0784,
							"rightHandleSpan":0.99
						},
						{
							"time":0.5833333333333334,
							"value":0.36387,
							"leftHandleValue":-0.0074,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.0202,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7666666666666666,
							"value":0.30908,
							"leftHandleValue":-0.0293,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0793,
							"rightHandleSpan":0.7
						},
						{
							"time":1.0833333333333333,
							"value":0.36963,
							"leftHandleValue":-0.0637,
							"leftHandleSpan":0.1,
							"rightHandleValue":0.0235,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1333333333333333,
							"value":0.36847,
							"leftHandleValue":0.0071,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0908,
							"rightHandleSpan":0.3
						},
						{"time":1.6166666666666667,"value":0.31404,"leftHandleValue":0.0306,"leftHandleSpan":0.99},
						{"time":2,"value":0.3181}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.2925,"rightHandleValue":-0.0241,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":0.2322,
							"leftHandleValue":0.004,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0068,
							"rightHandleSpan":0.4
						},
						{
							"time":0.2833333333333333,
							"value":0.37528,
							"leftHandleValue":0.0084,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.012,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.28327,
							"leftHandleValue":0.0546,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.0379,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6166666666666667,
							"value":0.25883,
							"leftHandleValue":-0.0366,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1486,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0166666666666666,
							"value":0.31731,
							"leftHandleValue":-0.0607,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0143,
							"rightHandleSpan":0.8
						},
						{
							"time":1.1,
							"value":0.28158,
							"leftHandleValue":0.0143,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0135,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2166666666666666,
							"value":0.3529,
							"leftHandleValue":-0.0101,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0017,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":0.28372,
							"leftHandleValue":0.0112,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0044,
							"rightHandleSpan":0.1
						},
						{"time":2,"value":0.2925,"leftHandleValue":0.0034,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.75},
						{"time":0.25,"value":0.75,"rightHandleValue":-2.5787,"rightHandleSpan":0.2},
						{
							"time":0.35,
							"value":17.904,
							"leftHandleValue":-1.8844,
							"leftHandleSpan":0.7,
							"rightHandleValue":-3.1898,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5333333333333333,
							"value":-11.794,
							"leftHandleValue":-0.0192,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.6815,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7166666666666667,
							"value":9.908,
							"leftHandleValue":-0.4735,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7489,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9,
							"value":-5.924,
							"leftHandleValue":0.7041,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1933,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0833333333333333,
							"value":5.606,
							"leftHandleValue":-0.7772,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0242,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":-2.787,
							"leftHandleValue":-0.6866,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.7768,
							"rightHandleSpan":0.4
						},
						{"time":1.5666666666666667,"value":0.75,"leftHandleValue":6.3557,"leftHandleSpan":0.5},
						{"time":2,"value":0.75}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-31.38,"rightHandleValue":-1.1334,"rightHandleSpan":0.4},
						{
							"time":0.25,
							"value":-32.443,
							"leftHandleValue":-4.0406,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.5303,
							"rightHandleSpan":0.8
						},
						{
							"time":0.26666666666666666,
							"value":-38.849,
							"leftHandleValue":9.3065,
							"leftHandleSpan":0.6,
							"rightHandleValue":-14.2888,
							"rightHandleSpan":0.3
						},
						{
							"time":0.31666666666666665,
							"value":-63.534,
							"leftHandleValue":-1.8373,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.8171,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4166666666666667,
							"value":-20.635,
							"leftHandleValue":0.5498,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.8298,
							"rightHandleSpan":0.4
						},
						{
							"time":0.48333333333333334,
							"value":-31.906,
							"leftHandleValue":1.2899,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.4508,
							"rightHandleSpan":0.5
						},
						{
							"time":0.5666666666666667,
							"value":-21.442,
							"leftHandleValue":0.9244,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.7787,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6333333333333333,
							"value":-35.376,
							"leftHandleValue":0.2493,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.1986,
							"rightHandleSpan":0.5
						},
						{
							"time":0.7666666666666666,
							"value":-30.945,
							"leftHandleValue":6.3555,
							"leftHandleSpan":0.8,
							"rightHandleValue":1.2573,
							"rightHandleSpan":0.5
						},
						{
							"time":0.9166666666666666,
							"value":-35.645,
							"leftHandleValue":1.0144,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.2966,
							"rightHandleSpan":0.9
						},
						{
							"time":1.1166666666666667,
							"value":-37.859,
							"leftHandleValue":-0.5638,
							"leftHandleSpan":0.2,
							"rightHandleValue":13.0551,
							"rightHandleSpan":0.8
						},
						{
							"time":1.2666666666666666,
							"value":-34.76,
							"leftHandleValue":5.6904,
							"leftHandleSpan":0.8,
							"rightHandleValue":2.0356,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-33.495,
							"leftHandleValue":3.3763,
							"leftHandleSpan":0.6,
							"rightHandleValue":4.6579,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":-31.38,"leftHandleValue":-0.485,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":109.96,"rightHandleValue":-19.1086,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":60.318,
							"leftHandleValue":1.0688,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.5927,
							"rightHandleSpan":0.3
						},
						{
							"time":0.25,
							"value":221.977,
							"leftHandleValue":-29.5805,
							"leftHandleSpan":0.3,
							"rightHandleValue":11.9962,
							"rightHandleSpan":0.2
						},
						{
							"time":0.31666666666666665,
							"value":208.241,
							"leftHandleValue":10.7078,
							"leftHandleSpan":0.5,
							"rightHandleValue":-14.8252,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5,
							"value":109.96,
							"leftHandleValue":89.7621,
							"leftHandleSpan":0.6,
							"rightHandleValue":-19.673,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5666666666666667,
							"value":60.977,
							"leftHandleValue":7.8533,
							"leftHandleSpan":0.4,
							"rightHandleValue":-11.5671,
							"rightHandleSpan":0.3
						},
						{
							"time":0.7,
							"value":144.406,
							"leftHandleValue":-5.5309,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3555,
							"rightHandleSpan":0.3
						},
						{
							"time":0.85,
							"value":117.376,
							"leftHandleValue":-0.7757,
							"leftHandleSpan":0.5,
							"rightHandleValue":2.3731,
							"rightHandleSpan":0.4
						},
						{
							"time":1.05,
							"value":123.418,
							"leftHandleValue":-4.2564,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.2523,
							"rightHandleSpan":0.5
						},
						{
							"time":1.1,
							"value":101.375,
							"leftHandleValue":-6.3895,
							"leftHandleSpan":0.3,
							"rightHandleValue":12.5895,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2166666666666666,
							"value":193.651,
							"leftHandleValue":0.8445,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.9074,
							"rightHandleSpan":0.3
						},
						{
							"time":1.3833333333333333,
							"value":109.425,
							"leftHandleValue":23.3123,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.5616,
							"rightHandleSpan":0.1
						},
						{
							"time":1.4666666666666666,
							"value":100.03,
							"leftHandleValue":0.0568,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.2296,
							"rightHandleSpan":0.1
						},
						{"time":2,"value":109.96,"leftHandleValue":-7.662,"leftHandleSpan":0.99}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.249,"rightHandleValue":0.0028,"rightHandleSpan":0.4},
						{
							"time":0.13333333333333333,
							"value":0.27174,
							"leftHandleValue":-0.0035,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0618,
							"rightHandleSpan":0.99
						},
						{
							"time":0.5833333333333334,
							"value":0.28483,
							"leftHandleValue":-0.0153,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.0158,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7666666666666666,
							"value":0.24194,
							"leftHandleValue":-0.0229,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0715,
							"rightHandleSpan":0.9
						},
						{
							"time":1.1,
							"value":0.29854,
							"leftHandleValue":-0.0734,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0831,
							"rightHandleSpan":0.4
						},
						{"time":1.6166666666666667,"value":0.24582,"leftHandleValue":0.023,"leftHandleSpan":0.99},
						{"time":2,"value":0.249}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.2336,"rightHandleValue":-0.0192,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":0.18545,
							"leftHandleValue":0.0032,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0055,
							"rightHandleSpan":0.4
						},
						{
							"time":0.2833333333333333,
							"value":0.29971,
							"leftHandleValue":0.0067,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0093,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.22623,
							"leftHandleValue":0.0346,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0302,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6166666666666667,
							"value":0.20671,
							"leftHandleValue":-0.0292,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1124,
							"rightHandleSpan":0.3
						},
						{
							"time":1.05,
							"value":0.25484,
							"leftHandleValue":-0.0471,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.007,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1,
							"value":0.22488,
							"leftHandleValue":0.0025,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0108,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2166666666666666,
							"value":0.28184,
							"leftHandleValue":-0.008,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0164,
							"rightHandleSpan":0.4
						},
						{"time":1.5833333333333333,"value":0.23126,"leftHandleValue":-0.0258,"leftHandleSpan":0.8},
						{"time":2,"value":0.2336}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":2.3},
						{"time":0.25,"value":2.3,"rightHandleValue":0.5341,"rightHandleSpan":0.7},
						{
							"time":0.26666666666666666,
							"value":6.078,
							"leftHandleValue":-5.7319,
							"leftHandleSpan":0.6,
							"rightHandleValue":10.6045,
							"rightHandleSpan":0.4
						},
						{
							"time":0.31666666666666665,
							"value":22.241,
							"leftHandleValue":-0.9983,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.38,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":-13.93,
							"leftHandleValue":2.9371,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7034,
							"rightHandleSpan":0.4
						},
						{
							"time":0.55,
							"value":15.406,
							"leftHandleValue":-3.9094,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.1048,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6833333333333333,
							"value":-8.523,
							"leftHandleValue":-2.1138,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.1482,
							"rightHandleSpan":0.4
						},
						{
							"time":0.8,
							"value":11.245,
							"leftHandleValue":0.401,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.6104,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9166666666666666,
							"value":-5.036,
							"leftHandleValue":0.493,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5077,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0333333333333332,
							"value":8.271,
							"leftHandleValue":-1.0805,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2588,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":-2.521,
							"leftHandleValue":1.4382,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7743,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":6.282,
							"leftHandleValue":0.7776,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.44,
							"rightHandleSpan":0.3
						},
						{"time":1.4666666666666666,"value":2.3,"leftHandleValue":-8.5759,"leftHandleSpan":0.7},
						{"time":2,"value":2.3}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.15,"rightHandleValue":-0.5454,"rightHandleSpan":0.6},
						{
							"time":0.48333333333333334,
							"value":-1.25,
							"leftHandleValue":2.7428,
							"leftHandleSpan":0.05,
							"rightHandleValue":5.0097,
							"rightHandleSpan":0.6
						},
						{
							"time":0.8666666666666667,
							"value":0.443,
							"leftHandleValue":-2.9826,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.5909,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":0.15,"leftHandleValue":0.1592,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5181909378657975"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-74.91,"rightHandleValue":-3.9316,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":-86.417,
							"leftHandleValue":-1.5091,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.5991,
							"rightHandleSpan":0.3
						},
						{
							"time":0.31666666666666665,
							"value":-8.92,
							"leftHandleValue":8.4358,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7702,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":-18.727,
							"leftHandleValue":4.9873,
							"leftHandleSpan":0.4,
							"rightHandleValue":-7.7061,
							"rightHandleSpan":0.6
						},
						{
							"time":0.5333333333333333,
							"value":-80.61,
							"leftHandleValue":17.9421,
							"leftHandleSpan":0.5,
							"rightHandleValue":-10.2504,
							"rightHandleSpan":0.5
						},
						{
							"time":0.7,
							"value":-61.685,
							"leftHandleValue":-6.7075,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.5969,
							"rightHandleSpan":0.2
						},
						{
							"time":1.0666666666666667,
							"value":-74.29,
							"leftHandleValue":-9.9613,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.0103,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1,
							"value":-76.874,
							"leftHandleValue":-1.1861,
							"leftHandleSpan":0.4,
							"rightHandleValue":8.0947,
							"rightHandleSpan":0.5
						},
						{
							"time":1.2166666666666666,
							"value":-7.614,
							"leftHandleValue":0.0959,
							"leftHandleSpan":0.2,
							"rightHandleValue":0.5342,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-15.174,
							"leftHandleValue":5.6531,
							"leftHandleSpan":0.4,
							"rightHandleValue":-47.4622,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-78.498,
							"leftHandleValue":0.3605,
							"leftHandleSpan":0.6,
							"rightHandleValue":-3.2087,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":-74.91,"leftHandleValue":-0.6575,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5181909378657975"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4063,"rightHandleValue":0.0466,"rightHandleSpan":0.7},
						{
							"time":0.2833333333333333,
							"value":0.39241,
							"leftHandleValue":0.0181,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0014,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":0.40941,
							"leftHandleValue":-0.0122,
							"leftHandleSpan":0.2,
							"rightHandleValue":0.0521,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4666666666666667,
							"value":0.61675,
							"leftHandleValue":0.0135,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0321,
							"rightHandleSpan":0.3
						},
						{
							"time":0.6,
							"value":0.41781,
							"leftHandleValue":0.0124,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0085,
							"rightHandleSpan":0.4
						},
						{
							"time":0.8166666666666667,
							"value":0.41973,
							"leftHandleValue":0.0412,
							"leftHandleSpan":0.8,
							"rightHandleValue":0.0141,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0166666666666666,
							"value":0.41444,
							"leftHandleValue":0.0187,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.014,
							"rightHandleSpan":0.7
						},
						{
							"time":1.1333333333333333,
							"value":0.46745,
							"leftHandleValue":0.0264,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.0182,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2166666666666666,
							"value":0.57487,
							"leftHandleValue":-0.007,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0201,
							"rightHandleSpan":0.4
						},
						{
							"time":1.35,
							"value":0.39149,
							"leftHandleValue":0.013,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0039,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":0.43298,
							"leftHandleValue":0.0067,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0538,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.4063,"leftHandleValue":0.0008,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5181909378657975"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4063,"rightHandleValue":-0.0339,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":0.31683,
							"leftHandleValue":0.009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0099,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.49416,
							"leftHandleValue":0.0197,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.0212,
							"rightHandleSpan":0.6
						},
						{
							"time":0.45,
							"value":0.66589,
							"leftHandleValue":-0.047,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0067,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.3059,
							"leftHandleValue":-0.0069,
							"leftHandleSpan":0.3,
							"rightHandleValue":0.0022,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7166666666666667,
							"value":0.51123,
							"leftHandleValue":0.0125,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0064,
							"rightHandleSpan":0.2
						},
						{
							"time":1.05,
							"value":0.42,
							"leftHandleValue":-0.0582,
							"leftHandleSpan":0.8,
							"rightHandleValue":0.0097,
							"rightHandleSpan":0.5
						},
						{
							"time":1.1,
							"value":0.37819,
							"leftHandleValue":-0.0026,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0495,
							"rightHandleSpan":0.7
						},
						{
							"time":1.2166666666666666,
							"value":0.68565,
							"leftHandleValue":-0.0728,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0168,
							"rightHandleSpan":0.3
						},
						{
							"time":1.3833333333333333,
							"value":0.38249,
							"leftHandleValue":-0.0154,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.0075,
							"rightHandleSpan":0.2
						},
						{"time":1.6,"value":0.40245,"leftHandleValue":0.0359,"leftHandleSpan":0.7},
						{"time":2,"value":0.4063}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5181909378657975"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.45,"value":0,"rightHandleValue":-1.3045,"rightHandleSpan":0.2},
						{
							"time":0.5166666666666666,
							"value":5.712,
							"leftHandleValue":0.7627,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.4428,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6333333333333333,
							"value":-3.765,
							"leftHandleValue":-0.4829,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.9511,
							"rightHandleSpan":0.4
						},
						{
							"time":0.75,
							"value":2.482,
							"leftHandleValue":0.3183,
							"leftHandleSpan":0.4,
							"rightHandleValue":-5.5498,
							"rightHandleSpan":0.6
						},
						{
							"time":0.9833333333333333,
							"value":1.079,
							"leftHandleValue":-3.4967,
							"leftHandleSpan":0.7,
							"rightHandleValue":-3.4963,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":1.1345,"leftHandleSpan":0.99}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"5181909378657975"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.5,"value":-950.1},
						{"time":0.8666666666666667,"value":1061.8},
						{"time":1.2333333333333334,"value":-950.1},
						{"time":1.5,"value":1061.8}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.5,"value":-890.4},
						{"time":0.8666666666666667,"value":714.1},
						{"time":1.2333333333333334,"value":-890.4},
						{"time":1.5,"value":714.1}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.5,"value":-1508.3},
						{"time":0.8666666666666667,"value":1062},
						{"time":1.2333333333333334,"value":-1508.3},
						{"time":1.5,"value":1062}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.5,"value":-657.5},
						{"time":0.8666666666666667,"value":917.7},
						{"time":1.2333333333333334,"value":-657.5},
						{"time":1.5,"value":917.7}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"5181909378657975"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/WildConstruct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Bonus.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Major1.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Major2.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Major3.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Minor1.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Minor2.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Minor3.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Wild.png.ncData
------------------------------------------------------------
default ncData file

Assets/CodeAssets.ncData
------------------------------------------------------------
default ncData file

Assets/Dashboard.ncData
------------------------------------------------------------
default ncData file

Assets/Fonts.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout.ncData
------------------------------------------------------------
default ncData file

Assets/LayersAndMasks.ncData
------------------------------------------------------------
default ncData file

Assets/ParticleSystems.ncData
------------------------------------------------------------
default ncData file

Assets/Sounds.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages.ncData
------------------------------------------------------------
default ncData file

ProjectCode/FlowStates/00 GameIntro.js
------------------------------------------------------------
class GameIntro extends FlowState {
    constructor() {
        super();
        this.userTouchedScreen = false;
        this.addElement(0, "startGameIntro");
        this.addPause(1, "waitForUserToTouchScreen");
        this.addElement(1.05, "playIntroOutro");
        // this.addElement(3,"fadeIntroBackground")
    }
    startGameIntro() {
        pr.gameLayout.descendantsByName.GameIntroBackground.addReleaseCallback(this, "userTouchedScreenCallback");
        pr.gameLayout.descendantsByName.GameIntroAnimation.enable();
        pr.gameLayout.descendantsByName.GameIntroAnimation.timelines.Intro.playOnce();
    }
    userTouchedScreenCallback() {
        this.userTouchedScreen = true;
        pr.gameLayout.descendantsByName.GameIntroAnimation.timelines.Outro.playOnceAndTakeWeight(.15, undefined, pr.gameLayout.descendantsByName.GameIntroAnimation.timelines.Outro, pr.gameLayout.descendantsByName.GameIntroAnimation, "disable");
        pr.gameLayout.descendantsByName.GameIntroBackground.removeReleaseCallback(this, "userTouchedScreenCallback");
        pr.gameLayout.descendantsByName.GameIntroBackground.buttonActive = false;
        pr.adjustGameLayout();
    }
    waitForUserToTouchScreen() {
        return (this.userTouchedScreen);
    }
    playIntroOutro() {
        pr.gameLayout.descendantsByName.GameIntroBackground.colorMultiply.swoop.alpha(0, .75, undefined, pr.gameLayout.descendantsByName.GameIntroBackground, "disable");
        nc.flows.MainGameFlow.GameIdle.setToCurrentState();
    }
}


ProjectCode/FlowStates/01 GameIdle.js
------------------------------------------------------------
class GameIdle extends FlowState {
    constructor() {
        super();
        this.addElement(0, "startIdle");
    }
    startIdle() {
    }
}


ProjectCode/FlowStates/02 StartGame.js
------------------------------------------------------------
class StartGame extends FlowState {
    constructor() {
        super();
        this.addElement(0, "startGame");
    }
    async startGame() {
        // update the balance and clear the win meter
        pr.dashboard.descendantsByName.WinMeter.string = "";
        if (gameSystemManager.currentGameOutcome !== undefined) {
            let balanceString = gameSystemManager.formatCurrency(gameSystemManager.currentGameOutcome.balanceAfter);
            pr.dashboard.descendantsByName.BalanceMeter.string = balanceString;
        }
        // start a new game if the local info in the gameSystemManager indicates that's possible
        if (gameSystemManager.attemptBet(pr, "processNewGameOutcome") === true) {
            nc.flows.MainGameFlow.SpinReels.setToCurrentState(true);
            gameSystemManager.gameStarted();
        }
        else {
            console.log("GameOutcome could not be requested.");
            nc.flows.MainGameFlow.GameIdle.setToCurrentState();
        }
        // reset items that may have been in progress when the game started
        pr.payline.colorMultiply.swoop.alpha(0, .5);
    }
}


ProjectCode/FlowStates/03 SpinReels.js
------------------------------------------------------------
class SpinReels extends FlowState {
    constructor() {
        super();
        this.addElement(0, "startSpin", undefined);
        this.addElement(.05, "startReelSpinSound");
        for (let i = 0; i < pr.symbolReels.length; i++) {
            this.addElement(.01 + .05 * i, "spinReel", i);
        }
        this.addPause(1.5, "waitForGameOutcome");
        for (let i = 0; i < pr.symbolReels.length; i++) {
            this.addElement(1.51 + .2 * i, "stopReel", i, "offset");
        }
    }
    startSpin() {
        nc.sounds.SpinBegin.playOnce();
        this.allReelsHaveStarted = false;
        nc.appEvents.fixedUpdate.addCallback(this, "fixedUpdate");
        pr.dashboard.descendantsByName.SpinButtonCenter.rotation.swoop.z(0, 0);
        pr.dashboard.descendantsByName.SpinButtonCenter.rotation.swoop.z(-360, .75, nc.tweenTypes.ExtremeEaseIn);
    }
    startReelSpinSound() {
        nc.sounds.ReelSpinSound.play();
    }
    fixedUpdate() {
        if (this.allReelsHaveStarted === true) {
            // benchmark 1: all reels are done with full speed motion (each has reached at least 'bounce') - pause the spin sound
            // benchmark 2: all reels are done with all motion (each is 'stopped') - move to the next FlowState
            let allReelsDoneSpinning = true;
            let allReelsAreStopped = true;
            for (let i = 0; i < pr.symbolReels.length; i++) {
                let reelState = pr.symbolReels[i].reelState;
                if (reelState !== "stopped") {
                    allReelsAreStopped = false;
                    // a reel in its 'bounce' state is done spinning, but it can't begin another spin until it is fully 'stopped'
                    if (reelState !== "bounce") {
                        allReelsDoneSpinning = false;
                        break;
                    }
                }
            }
            if (allReelsDoneSpinning === true && nc.sounds.ReelSpinSound.playbackState === "playing") {
                nc.sounds.ReelSpinSound.pause();
            }
            if (allReelsAreStopped === true) {
                nc.appEvents.fixedUpdate.removeCallback(this, "fixedUpdate");
                nc.flows.MainGameFlow.WinCelebration.setToCurrentState();
            }
        }
    }
    spinReel(reelIdx) {
        pr.symbolReels[reelIdx].beginSpin();
        if (reelIdx === pr.symbolReels.length - 1) {
            this.allReelsHaveStarted = true;
        }
    }
    waitForGameOutcome() {
        if (gameSystemManager.currentGameOutcome !== undefined) {
            return (true);
        }
    }
    stopReel(reelIdx) {
        // a reel that was slammed (or has otherwise already stopped) no longer needs a stop request, and 'beginStop' is only valid while it is still spinning
        let reelState = pr.symbolReels[reelIdx].reelState;
        if (reelState === "windup" || reelState === "spinFree") {
            pr.symbolReels[reelIdx].beginStop(true);
        }
    }
}


ProjectCode/FlowStates/05 WinCelebration.js
------------------------------------------------------------
class WinCelebration extends FlowState {
    constructor() {
        super();
        this.centerWinMeter = pr.gameLayout.descendantsByName.CenterWinMeter;
        this.winRollupAmount = 0;
        this.animatedSymbols = [];
        this.addElement(0, "startWinCelebration");
        this.addElement(.2, "highlightWin");
        // each win is shown long enough for the 2 second SymbolAnimation to play (it starts at .2)
        this.addElement(2.3, "unhighlightWinSymbols");
        this.addElement(2.4, "goToNextWin");
    }
    updateCenterWinMeterValue() {
        let meterString = gameSystemManager.formatCurrency(this.winRollupAmount);
        this.centerWinMeter.string = meterString;
        pr.dashboard.descendantsByName.WinMeter.string = meterString;
    }
    winRollupComplete() {
        this.winRollupAmount = gameSystemManager.currentGameOutcome.totalWin;
        nc.swoopValue(this, "winRollupAmount", gameSystemManager.currentGameOutcome.totalWin, 0);
        this.updateCenterWinMeterValue();
        this.centerWinMeter.colorMultiply.swoop.alpha(0, 1.5, nc.tweenTypes.ExtremeEaseOut, this.centerWinMeter, "disable");
        gameSystemManager.gameEnded();
    }
    startWinCelebration() {
        if (gameSystemManager.currentGameOutcome.totalWin === 0) {
            nc.flows.MainGameFlow.GameIdle.setToCurrentState(true);
            gameSystemManager.gameEnded();
            return;
        }
        this.winHighlightIndex = 0;
        this.winRollupAmount = 0;
        this.centerWinMeter.enable();
        this.centerWinMeter.colorMultiply.alpha = 1;
        this.centerWinMeter.string = "";
        this.centerWinMeter.scale.swoop.all(0, 0);
        this.centerWinMeter.position.swoop.y(-100, 0);
        this.centerWinMeter.position.swoop.y(200, 8, nc.tweenTypes.ExtremeEaseIn);
        pr.gameLayout.descendantsByName.CenterWinMeterShadow.enabled = true;
        pr.gameLayout.descendantsByName.CenterWinMeterShadow.colorMultiply.alpha = 0;
        let shadowAlpha = 0;
        let rollupTime = 0;
        let winMultiplier = gameSystemManager.currentGameOutcome.totalWin / gameSystemManager.currentGameOutcome.bet;
        if (winMultiplier <= 1) {
            this.centerWinMeter.scale.swoop.all(.5, .1);
            rollupTime = .25;
            shadowAlpha = .4;
        }
        else if (winMultiplier <= 5) {
            this.centerWinMeter.scale.swoop.all(.65, .1);
            rollupTime = .5;
            shadowAlpha = .5;
        }
        else if (winMultiplier <= 15) {
            this.centerWinMeter.scale.swoop.all(.75, .1);
            rollupTime = 1.25;
            shadowAlpha = .6;
        }
        else if (winMultiplier <= 25) {
            this.centerWinMeter.scale.swoop.all(.85, .1);
            rollupTime = 2;
            shadowAlpha = .7;
        }
        else {
            this.centerWinMeter.scale.swoop.all(1, .1);
            rollupTime = 4;
            shadowAlpha = .8;
        }
        pr.gameLayout.descendantsByName.CenterWinMeterShadow.colorMultiply.swoop.alpha(shadowAlpha, 3, nc.tweenTypes.ExtremeEaseIn);
        nc.swoopValue(this, "winRollupAmount", gameSystemManager.currentGameOutcome.totalWin, rollupTime, undefined, this, "winRollupComplete", undefined, undefined, undefined, this, "updateCenterWinMeterValue");
    }
    highlightWin() {
        let symbol;
        if (this.winHighlightIndex < gameSystemManager.currentGameOutcome.wins.length) {
            pr.gameLayout.descendantsByName.ReelBackground.brightnessContrast.swoop.brightness(-.1, .5);
            pr.gameLayout.descendantsByName.GameBackgroundPattern.brightnessContrast.swoop.brightness(-.15, .55);
            let winDescription = gameSystemManager.currentGameOutcome.wins[this.winHighlightIndex];
            if (winDescription.winType === "line") {
                pr.payline.displayPayline(winDescription.line, .35, .1);
            }
            else {
                pr.payline.colorMultiply.alpha = 0;
            }
            for (let i = 0; i < pr.symbolReels.length; i++) {
                for (let j = 0; j < pr.symbolReels[i].numMainSymbols; j++) {
                    let isSymbolWinning = false;
                    for (let k = 0; k < winDescription.winningSymbols.length; k++) {
                        if (winDescription.winningSymbols[k][0] === i && winDescription.winningSymbols[k][1] === j) {
                            isSymbolWinning = true;
                            break;
                        }
                    }
                    symbol = pr.symbolReels[i].getSymbol(j);
                    if (isSymbolWinning === true) {
                        symbol.brightnessContrast.swoop.brightness(.1, 1, nc.tweenTypes.ExtremeEaseIn);
                        symbol.layer = nc.layers.WinningSymbols;
                        // symbols with a SymbolAnimation Construct (e.g. 'Major1Construct' for 'Major1') show its Precomp while the animation plays
                        let constructDef = nc.constructDefs[symbol.graphicAsset.name + "Construct"];
                        if (constructDef !== undefined) {
                            // symbols of the same type share one Precomp, so the Timeline only needs starting once (zero fades keep the keyframed motion intact)
                            let timeline = constructDef.precomp.constructInstance.timelines.SymbolAnimation;
                            if (timeline.playbackState !== constants.playbackStates.playing) {
                                timeline.playOnceAndTakeWeight(0, 0, undefined, this, "restoreWinSymbols");
                            }
                            this.animatedSymbols.push({ symbol: symbol, graphicAsset: symbol.graphicAsset, timeline: timeline });
                            // keep the symbol's EffectNodes (including its BrightnessContrast) and values, or it can no longer be dimmed
                            symbol.setGraphicAsset(constructDef.precomp.graphicAsset, true);
                            // the animation overshoots the symbol's bounds, so the ReelMask must not clip it while it plays
                            symbol.masking.enabled = false;
                        }
                    }
                    else {
                        symbol.brightnessContrast.swoop.brightness(-.3, 1, nc.tweenTypes.ExtremeEaseIn);
                        symbol.layer = nc.layers.Reels;
                    }
                }
            }
        }
        else {
            pr.payline.colorMultiply.swoop.alpha(0, .7);
            pr.gameLayout.descendantsByName.ReelBackground.brightnessContrast.swoop.brightness(0, .25);
            pr.gameLayout.descendantsByName.GameBackgroundPattern.brightnessContrast.swoop.brightness(0, .35);
        }
        this.winHighlightIndex++;
        this.winHighlightIndex = this.winHighlightIndex % (gameSystemManager.currentGameOutcome.wins.length + 1);
    }
    unhighlightWinSymbols() {
        this.restoreWinSymbols();
        for (let i = 0; i < pr.symbolReels.length; i++) {
            for (let j = 0; j < pr.symbolReels[i].numMainSymbols; j++) {
                pr.symbolReels[i].getSymbol(j).brightnessContrast.swoop.brightness(0, 1, nc.tweenTypes.Ease);
            }
        }
    }
    goToNextWin() {
        this.setTime(.1, true);
    }
    // puts every symbol that is showing a SymbolAnimation Precomp back to its image (runs when the animation completes, and as part of the cleanup)
    restoreWinSymbols() {
        let animatedSymbols = this.animatedSymbols;
        this.animatedSymbols = [];
        for (let i = 0; i < animatedSymbols.length; i++) {
            animatedSymbols[i].symbol.setGraphicAsset(animatedSymbols[i].graphicAsset, true);
            animatedSymbols[i].symbol.masking.enabled = true;
            animatedSymbols[i].timeline.stop();
        }
    }
    cleanUpWinCelebration() {
        // (unhighlightWinSymbols restores the symbol images as well)
        this.unhighlightWinSymbols();
        // catch-all: whatever state an interrupted win cycle left the symbols in, every symbol is masked by the reel again
        for (let i = 0; i < pr.symbolReels.length; i++) {
            for (let j = 0; j < pr.symbolReels[i].numMainSymbols; j++) {
                pr.symbolReels[i].getSymbol(j).masking.enabled = true;
            }
        }
        pr.gameLayout.descendantsByName.ReelBackground.brightnessContrast.swoop.brightness(0, .25);
        pr.gameLayout.descendantsByName.GameBackgroundPattern.brightnessContrast.swoop.brightness(0, .35);
    }
}


ProjectCode/PreloadConfiguration/PreloadConfiguration.js
------------------------------------------------------------
async function preloadConfiguration(projectConfiguration) {
    CODE.includeIf___published;
    // Preserving the drawing buffer enables several useful development features, 
    // but may cause performance issues in published software on some devices.
    projectConfiguration.preserveDrawingBuffer = false;
    CODE.includeEnd___published;
    projectConfiguration.canvasParent = document.body;
    // define resource loading override function (this is optional)
    this.resourceLoadingOverride = function (filename) {
        if (filename.endsWith("_assetList.js") === true || filename.endsWith("_assetData.js") === true) {
            filename = projectConfiguration.projectName + String.fromCharCode(95) + projectConfiguration.publishTimestamp + "_loadedAssets/" + filename;
        }
        var s = document.createElement('script');
        s.setAttribute('src', filename);
        document.body.appendChild(s);
    };
    // define canvas positioning function (this is optional)
    this.canvasPositionOverride = function (canvas, left, top, width, height) {
        canvas.style.width = width + 'px';
        canvas.style.height = height + 'px';
        canvas.style.left = left + 'px';
        canvas.style.top = top + 'px';
    };
}
;


ProjectCode/DashboardManager.js
------------------------------------------------------------
class DashboardManager {
    constructor() {
        // initial values
        this.autoplaySpinsRemaining = 0;
        // create shortcuts to key items
        this.dashboard = pr.gameLayout.descendantsByName.Dashboard;
        this.spinButton = this.dashboard.descendantsByName.SpinButton;
        this.soundButton = this.dashboard.descendantsByName.SoundButton;
        this.autoplayButton = this.dashboard.descendantsByName["Autoplay Button"];
        this.menuButton = this.dashboard.descendantsByName.MenuButton;
        this.mainMenuContainer = this.dashboard.descendantsByName.MainMenuContainer;
        this.mainMenuBackground = this.dashboard.descendantsByName.MainMenuBackground;
        this.menuBackgroundDimmer = this.dashboard.descendantsByName.MenuBackgroundDimmer;
        this.autoplayMenu = this.dashboard.descendantsByName["Autoplay Menu"];
        // make the gamelayout view area invisible
        this.dashboard.descendantsByName.ViewArea.enabled = false;
        // add button callbacks
        this.spinButton.addReleaseCallback(this, "spinButtonReleaseCallback");
        this.soundButton.addReleaseCallback(this, "soundButtonReleaseCallback");
        this.autoplayButton.addReleaseCallback(this, "autoplayButtonReleaseCallback");
        this.menuButton.addReleaseCallback(this, "menuButtonReleaseCallback");
        // populate autoplay options
        this.populateAutoplayOptions();
        // set up autoplay rotation motion
        this.autoplayRotationMotion = this.dashboard.descendantsByName["Autoplay Button"].rotation.addMotion.z(100, -100, 1, nc.motionTypes.InfiniteAdd);
        this.autoplayRotationMotion.influence = 0;
        // create the WaitThen responsible for starting autoplay
        this.autoplayStartDelay = new WaitThen("autoplayStartDelay");
    }
    populateAutoplayOptions() {
        if (gameSystemManager.autoplayOptions !== undefined && gameSystemManager.autoplayOptions.length > 0) {
            this.autoplayOptionButtons = [];
            this.autoplayMenu.graphicExpander.expandedAreaTop = 175 + 175 * gameSystemManager.autoplayOptions.length;
            for (let i = 0; i < gameSystemManager.autoplayOptions.length; i++) {
                let newButton = new TextBox(this.autoplayMenu, "Autoplay Option Button");
                let numSpins = gameSystemManager.autoplayOptions[i];
                newButton.string = nc.getPhrase(nc.phraseIDs.AutoplaySelection, { nSpins: numSpins });
                newButton["numSpins"] = numSpins;
                newButton.position.y = 225 + 175 * i;
                newButton.buttonActive = true;
                newButton.horizontalJustification = constants.justifications.center;
                newButton.textFormat.lineHeightMultiplier = .8;
                newButton.colorMultiply.red = .89;
                newButton.colorMultiply.green = .89;
                newButton.colorMultiply.blue = .92;
                newButton.addReleaseCallback(this, "autoplayOptionButtonCallback", newButton);
            }
        }
        else {
            this.autoplayButton.disable();
        }
    }
    spinButtonReleaseCallback() {
        // bounce the spin button when released
        this.spinButton.position.y = -25;
        this.spinButton.position.swoop.y(0, .1);
        this.spinButton.scale.swoop.all(1.35, 0);
        this.spinButton.scale.swoop.all(1.5, .15);
        // trigger the mainPlayer input function
        pr.mainPlayerInput();
    }
    menuButtonReleaseCallback() {
        if (this.mainMenuContainer.enabled === false) {
            this.showMainMenu();
        }
        else {
            this.hideMainMenu();
        }
    }
    showMainMenu() {
        let container = this.dashboard.descendantsByName.MainMenuContainer;
        container.enabled = true;
        this.dashboard.descendantsByName.MenuBackgroundDimmer.enabled = true;
        container.scale.swoop.y(0, 0);
        container.scale.swoop.y(1, .07, nc.tweenTypes.ExtremeEaseIn);
        this.menuBackgroundDimmer.addReleaseCallback(this, "hideMainMenu");
    }
    hideMainMenu() {
        this.dashboard.descendantsByName.MainMenuContainer.enabled = false;
        this.dashboard.descendantsByName.MenuBackgroundDimmer.enabled = false;
        this.menuBackgroundDimmer.removeReleaseCallback(this, "hideMainMenu");
    }
    processGameStarted() {
        // dim the menu button
        this.dashboard.descendantsByName.MenuButton.buttonActive = false;
        this.dashboard.descendantsByName.MenuButton.brightnessContrast.brightness = -.5;
        // dim the autoplay button
        if (this.autoplaySpinsRemaining === 0) {
            this.autoplayButton.buttonActive = false;
            this.autoplayButton.brightnessContrast.brightness = -.5;
        }
    }
    processGameEnded() {
        // undim the menu button
        this.dashboard.descendantsByName.MenuButton.buttonActive = true;
        this.dashboard.descendantsByName.MenuButton.brightnessContrast.brightness = 0;
        // undim the autoplay button
        this.autoplayButton.buttonActive = true;
        this.autoplayButton.brightnessContrast.brightness = 0;
    }
    autoplayButtonReleaseCallback() {
        if (this.autoplaySpinsRemaining === 0) {
            if (!this.autoplayMenu.enabled) {
                this.showAutoplayMenu();
            }
            else {
                this.hideAutoplayMenu();
            }
        }
        else {
            this.stopAutoplay();
        }
    }
    showAutoplayMenu() {
        this.menuBackgroundDimmer.enabled = true;
        this.autoplayMenu.enabled = true;
        this.autoplayButton.layer = nc.layers.GameMenus;
        this.autoplayMenu.scale.swoop.y(0, 0);
        this.autoplayMenu.scale.swoop.y(1, .07, nc.tweenTypes.ExtremeEaseIn);
        this.menuBackgroundDimmer.addReleaseCallback(this, "hideAutoplayMenu");
    }
    hideAutoplayMenu() {
        this.menuBackgroundDimmer.enabled = false;
        this.autoplayMenu.enabled = false;
        this.autoplayButton.layer = nc.layers.Dashboard;
        this.menuBackgroundDimmer.removeReleaseCallback(this, "hideAutoplayMenu");
    }
    autoplayOptionButtonCallback(event, camera, button) {
        this.startAutoplay(button["numSpins"]);
        this.hideAutoplayMenu();
    }
    startAutoplay(numSpins) {
        this.autoplaySpinsRemaining = numSpins;
        this.autoplayRotationMotion.influence = 1;
        this.dashboard.descendantsByName.AutoplayCountdownBackground.enabled = true;
        this.dashboard.descendantsByName.AutoplayCountdown.string = this.autoplaySpinsRemaining.toString();
        this.autoplayIfApplicable();
    }
    stopAutoplay() {
        this.autoplayStartDelay.stop(false);
        this.autoplaySpinsRemaining = 0;
        this.autoplayRotationMotion.influence = 0;
        this.autoplayButton.rotation.z = 0;
        this.dashboard.descendantsByName.AutoplayCountdownBackground.enabled = false;
        if (gameSystemManager.gameInProgress === true) {
            this.autoplayButton.buttonActive = false;
            this.autoplayButton.brightnessContrast.brightness = -.5;
        }
    }
    autoplayIfApplicable() {
        if (this.autoplaySpinsRemaining > 0) {
            this.autoplayStartDelay.activate(.5, pr, "mainPlayerInput");
        }
    }
    decrementAutoplay() {
        this.autoplayStartDelay.stop(false);
        if (this.autoplaySpinsRemaining > 0) {
            if (this.autoplaySpinsRemaining === 1) {
                pr.dashboardManager.stopAutoplay();
            }
            else {
                // decrement the autoplay spins and update the autoplay countdown
                this.autoplaySpinsRemaining--;
                pr.dashboard.descendantsByName.AutoplayCountdown.string = this.autoplaySpinsRemaining.toString();
            }
        }
    }
    soundButtonReleaseCallback() {
        if (pr.dashboard.descendantsByName.SoundButton.graphicAsset === nc.graphicAssets.SoundButton) {
            // toggle to muted  
            pr.dashboard.descendantsByName.SoundButton.graphicAsset = nc.graphicAssets.SoundMute;
            nc.volumeControls.MainVolumeControl.volume = 0;
        }
        else {
            // toggle to sound on  
            pr.dashboard.descendantsByName.SoundButton.graphicAsset = nc.graphicAssets.SoundButton;
            nc.volumeControls.MainVolumeControl.volume = 1;
        }
    }
}


ProjectCode/GameSystemManager.js
------------------------------------------------------------
class GameSystemManager {
    async init() {
        // initial values
        this.gameInProgress = false;
        // if in LocalDev...
        CODE.includeIf___LocalDev;
        this.gameSystemReplica = new GameSystemReplica();
        CODE.includeEnd___LocalDev;
        // if in EgmPublish...
        CODE.includeIf___EgmPublish;
        this.grpcConnection = new GrpcConnection();
        await this.grpcConnection.init();
        CODE.includeEnd___EgmPublish;
    }
    async fetchGameSystemInfo(processPreloadGameSystemInfoCallbackOwner, processPreloadGameSystemInfoCallbackName) {
        let gameSystemInfoFromExternalSource;
        let initialGameLogicDataFromExternalSource;
        // if in LocalDev...
        CODE.includeIf___LocalDev;
        // fetch game system info from 'external' source...
        gameSystemInfoFromExternalSource = await this.gameSystemReplica.getPostloadInfo();
        // populate local properties from fetched data
        this.unitBet = gameSystemInfoFromExternalSource["unitBet"];
        this.currentBet = gameSystemInfoFromExternalSource["currentBet"];
        this.currentBalance = gameSystemInfoFromExternalSource["currentBalance"];
        this.availableBets = gameSystemInfoFromExternalSource["availableBets"];
        this.autoplayOptions = gameSystemInfoFromExternalSource["autoplayOptions"];
        // fetch inital game logic data from 'external' source...
        initialGameLogicDataFromExternalSource = await this.gameSystemReplica.getInitialLogicData();
        // populate local properties from fetched data
        this.initialGameLogicData = new InitialGameLogicData();
        this.initialGameLogicData.initialSymbolWindow = initialGameLogicDataFromExternalSource["initialSymbolWindow"];
        this.initialGameLogicData.reelData = initialGameLogicDataFromExternalSource["reelData"];
        this.initialGameLogicData.paylines = initialGameLogicDataFromExternalSource["paylines"];
        CODE.includeEnd___LocalDev;
        // if in WebPublish
        CODE.includeIf___WebPublish;
        CODE.includeEnd___WebPublish;
        // if in EgmPublish
        CODE.includeIf___EgmPublish;
        gameSystemInfoFromExternalSource = await this.grpcConnection.makeRequestToRemoteProcess({ type: "getPostLoadInfo" });
        if (gameSystemInfoFromExternalSource !== undefined) {
            // populate local properties from fetched data
            this.unitBet = gameSystemInfoFromExternalSource["unitBet"];
            this.currentBet = gameSystemInfoFromExternalSource["currentBet"];
            this.currentBalance = gameSystemInfoFromExternalSource["currentBalance"];
            this.availableBets = gameSystemInfoFromExternalSource["availableBets"];
            this.autoplayOptions = gameSystemInfoFromExternalSource["autoplayOptions"];
        }
        // fetch inital game logic data from 'external' source...
        initialGameLogicDataFromExternalSource = await this.grpcConnection.makeRequestToRemoteProcess({ type: "getInitialLogicData" });
        if (gameSystemInfoFromExternalSource !== undefined) {
            // populate local properties from fetched data
            this.initialGameLogicData = new InitialGameLogicData();
            this.initialGameLogicData.initialSymbolWindow = initialGameLogicDataFromExternalSource["initialSymbolWindow"];
            this.initialGameLogicData.reelData = initialGameLogicDataFromExternalSource["reelData"];
            this.initialGameLogicData.paylines = initialGameLogicDataFromExternalSource["paylines"];
        }
        CODE.includeEnd___EgmPublish;
        // perform 'processPreloadGameSystemInfo' callback
        if (processPreloadGameSystemInfoCallbackOwner !== undefined && processPreloadGameSystemInfoCallbackName !== undefined) {
            processPreloadGameSystemInfoCallbackOwner[processPreloadGameSystemInfoCallbackName]();
        }
    }
    attemptBet(processNewGameOutcomeCallbackOwner, processNewGameOutcomeCallbackName) {
        if (this.currentBalance >= this.currentBet) {
            // clear the current game outcome
            this.currentGameOutcome = undefined;
            // first, update the balance based on what we think we know locally
            this.currentBalance -= this.currentBet;
            // informing the external system of an attempted bet - this is intentially not awaited so that this function can immediately return "true", which allows the reels to begin spinning.
            this.requestBetFromExternalSystem(processNewGameOutcomeCallbackOwner, processNewGameOutcomeCallbackName);
            return (true);
        }
        else {
            return (false);
        }
    }
    async requestBetFromExternalSystem(processNewGameOutcomeCallbackOwner, processNewGameOutcomeCallbackName) {
        let gameOutcomeFromExternalSource;
        // assemble bet request
        let betRequest = new BetRequest();
        betRequest.betAmount = this.currentBet;
        // if in LocalDev...
        CODE.includeIf___LocalDev;
        // get game outcome from 'external' source...
        gameOutcomeFromExternalSource = await this.gameSystemReplica.getGameOutcome(betRequest);
        // map external gameOutcome properties to the gameOutcome object
        this.currentGameOutcome = new GameOutcome();
        this.currentGameOutcome.bet = gameOutcomeFromExternalSource.bet;
        this.currentGameOutcome.reelStops = gameOutcomeFromExternalSource.reelStops;
        this.currentGameOutcome.wins = gameOutcomeFromExternalSource.wins;
        this.currentGameOutcome.totalWin = gameOutcomeFromExternalSource.totalWin;
        this.currentGameOutcome.balanceBefore = gameOutcomeFromExternalSource.balanceBefore;
        this.currentGameOutcome.balanceAfter = gameOutcomeFromExternalSource.balanceAfter;
        // update current balance
        this.currentBalance = this.currentGameOutcome.balanceAfter;
        CODE.includeEnd___LocalDev;
        // if in WebPublish
        CODE.includeIf___WebPublish;
        // contact webAPI for gameOutcome...
        CODE.includeEnd___WebPublish;
        // if in EgmPublish
        CODE.includeIf___EgmPublish;
        // get game outcome from source...
        gameOutcomeFromExternalSource = await this.grpcConnection.makeRequestToRemoteProcess({ type: "getGameOutcome", payload: betRequest });
        // map external gameOutcome properties to the gameOutcome object
        this.currentGameOutcome = new GameOutcome();
        this.currentGameOutcome.bet = gameOutcomeFromExternalSource.bet;
        this.currentGameOutcome.reelStops = gameOutcomeFromExternalSource.reelStops;
        this.currentGameOutcome.wins = gameOutcomeFromExternalSource.wins;
        this.currentGameOutcome.totalWin = gameOutcomeFromExternalSource.totalWin;
        this.currentGameOutcome.balanceBefore = gameOutcomeFromExternalSource.balanceBefore;
        this.currentGameOutcome.balanceAfter = gameOutcomeFromExternalSource.balanceAfter;
        // update current balance
        this.currentBalance = this.currentGameOutcome.balanceAfter;
        CODE.includeEnd___EgmPublish;
        // perform 'processNewGameOutcome' callback
        if (processNewGameOutcomeCallbackOwner !== undefined && processNewGameOutcomeCallbackName !== undefined) {
            processNewGameOutcomeCallbackOwner[processNewGameOutcomeCallbackName]();
        }
    }
    gameStarted() {
        this.gameInProgress = true;
        pr.dashboardManager.processGameStarted();
        pr.dashboardManager.decrementAutoplay();
    }
    gameEnded() {
        this.gameInProgress = false;
        pr.dashboardManager.processGameEnded();
        pr.dashboardManager.autoplayIfApplicable();
    }
    formatCurrency(val) {
        const formattedValue = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(val);
        return (formattedValue);
    }
}
class InitialGameLogicData {
}
class GameOutcome {
    constructor() {
        this.bet = null;
        this.reelStops = null;
        this.wins = null;
        this.totalWin = null;
        this.balanceBefore = null;
        this.balanceAfter = null;
    }
}
class BetRequest {
    constructor() {
        this.betAmount = null;
    }
}
class WinDescription {
    constructor() {
        this.winType = null;
        this.line = null;
        this.winAmount = null;
        this.winningSymbols = null;
        this.featureFlags = null;
    }
}


ProjectCode/GameSystemReplica.js
------------------------------------------------------------
class GameSystemReplica {
    constructor() {
        this.unitBet = 0.25;
        this.currentBet = 1.5;
        this.availableBets = [0.25, 0.50, 0.75, 1.00, 1.50, 2.50, 3.00, 5.00, 7.50, 10.00, 15.00, 20.00, 25.00, 50.00, 75.00, 100.00];
        this.currentBalance = 1000.0;
        this.autoplayOptions = [25, 50, 100, 500];
        this.populateBulkData();
    }
    async simulateServerResponseTime(base, variation) {
        let simulatedServerResponseTime = base + Math.floor(variation * Math.random());
        await new Promise(resolve => setTimeout(resolve, simulatedServerResponseTime));
    }
    async getPostloadInfo() {
        await this.simulateServerResponseTime(25, 50);
        let info = {};
        info["unitBet"] = this.unitBet;
        info["currentBet"] = this.currentBet;
        info["currentBalance"] = this.currentBalance;
        info["availableBets"] = this.availableBets;
        info["autoplayOptions"] = this.autoplayOptions;
        return (info);
    }
    async getInitialLogicData() {
        // simulate server response time...
        await this.simulateServerResponseTime(50, 150);
        //create initial gameData
        let initialGameData = {};
        initialGameData["reelData"] = this.reelData;
        initialGameData["availableBets"] = this.availableBets;
        initialGameData["initialSymbolWindow"] = this.initialSymbolWindow;
        initialGameData["currentBet"] = this.currentBet;
        initialGameData["unitBet"] = this.unitBet;
        initialGameData["currentBalance"] = this.currentBalance;
        initialGameData["paylines"] = this.paylines;
        return (initialGameData);
    }
    async getGameOutcome(betRequest) {
        // simulate server response time...
        await this.simulateServerResponseTime(100, 300);
        // create new gameOutcome
        let gameOutcome = this.outcomes[Math.floor((this.outcomes.length) * Math.random())];
        gameOutcome["bet"] = betRequest.betAmount;
        gameOutcome["balanceBefore"] = this.currentBalance;
        this.currentBalance -= betRequest.betAmount;
        this.currentBalance += gameOutcome["totalWin"];
        gameOutcome["balanceAfter"] = this.currentBalance;
        return (gameOutcome);
    }
    populateBulkData() {
        this.initialSymbolWindow = [
            ["Major1", "Minor1", "Wild", "Minor2", "Major2", "Major2"],
            ["Major2", "Minor3", "Bonus", "Minor1", "Major3", "Major3"],
            ["Minor1", "Major3", "Major3", "Minor2", "Major1", "Major1"],
            ["Major2", "Major2", "Minor3", "Bonus", "Minor1", "Major3"],
            ["Major1", "Major1", "Minor1", "Wild", "Minor2", "Major2"]
        ];
        this.reelData = [
            ["Major1", "Major1", "Major1", "Minor1", "Minor1", "Major2", "Major2", "Major2", "Minor3", "Minor3", "Bonus", "Minor1", "Minor1", "Wild", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Minor1", "Minor1", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor1", "Minor1", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor1", "Minor1", "Wild", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Minor1", "Minor1", "Minor3", "Minor3", "Wild", "Minor2", "Minor2", "Bonus", "Minor1", "Minor1", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Wild", "Minor2", "Minor2", "Bonus", "Minor1", "Minor1", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Minor3", "Minor3", "Wild", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor3", "Minor3", "Wild", "Minor2", "Minor2", "Minor1", "Minor1", "Major2", "Major2", "Major2", "Minor3", "Minor3", "Major1", "Major1", "Major1", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor3", "Minor3", "Wild", "Minor2", "Minor2", "Minor1", "Minor1", "Major2", "Major2", "Major2", "Minor3", "Minor3", "Wild", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Major2", "Major2", "Major2", "Minor3", "Minor3"], ["Minor2", "Wild", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor1", "Minor1", "Wild", "Minor2", "Minor2", "Major2", "Major2", "Major2", "Minor3", "Minor3", "Major1", "Major1", "Major1", "Minor2", "Minor2", "Wild", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Wild", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Major1", "Major1", "Major1", "Minor1", "Minor1", "Bonus", "Minor2", "Minor2", "Major2", "Major2", "Major2", "Minor3", "Minor3", "Major1", "Major1", "Major1", "Minor2", "Minor2", "Wild", "Minor3", "Minor3", "Major1", "Major1", "Major1", "Minor2", "Minor2", "Bonus", "Minor1", "Minor1", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Major3", "Major3", "Major3", "Major1", "Major1", "Major1", "Minor1", "Minor1", "Wild", "Minor2", "Minor2", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor1", "Minor1", "Bonus", "Minor2", "Minor2", "Wild", "Minor1", "Minor1", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Major1", "Major1", "Major1", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Wild", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Major3", "Major3", "Major3"], ["Wild", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor1", "Minor1", "Wild", "Minor2", "Minor2", "Minor3", "Minor3", "Bonus", "Minor1", "Minor1", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Major1", "Major1", "Major1", "Minor1", "Minor1", "Major2", "Major2", "Major2", "Minor3", "Minor3", "Wild", "Minor1", "Minor1", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Bonus", "Minor1", "Minor1", "Minor2", "Minor2", "Wild", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor1", "Minor1", "Wild", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Minor1", "Minor1", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Minor1", "Minor1", "Minor3", "Minor3", "Wild", "Minor2", "Minor2", "Major3", "Major3", "Major3", "Minor1", "Minor1", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Wild", "Minor2", "Minor2", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Bonus", "Minor3", "Minor3", "Wild", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor3", "Minor3"], ["Minor2", "Major3", "Major3", "Major3", "Minor3", "Minor3", "Major1", "Major1", "Major1", "Minor2", "Minor2", "Wild", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Wild", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Major3", "Major3", "Major3", "Minor1", "Minor1", "Wild", "Minor2", "Minor2", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Major1", "Major1", "Major1", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Major1", "Major1", "Major1", "Wild", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Bonus", "Minor3", "Minor3", "Major1", "Major1", "Major1", "Minor1", "Minor1", "Wild", "Minor2", "Minor2", "Major2", "Major2", "Major2", "Minor1", "Minor1", "Bonus", "Minor2", "Minor2", "Major3", "Major3", "Major3", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Minor1", "Minor1", "Wild", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Bonus", "Minor3", "Minor3", "Wild", "Minor2", "Minor2", "Major1", "Major1", "Major1", "Minor1", "Minor1", "Wild", "Minor2", "Minor2", "Major1", "Major1", "Major1", "Minor1", "Minor1", "Major2", "Major2", "Major2"], ["Major2", "Major2", "Major2", "Minor3", "Minor3", "Bonus", "Minor1", "Minor1", "Major3", "Major3", "Major3", "Minor2", "Minor2", "Wild", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor1", "Minor1", "Minor2", "Minor2", "Bonus", "Minor3", "Minor3", "Major2", "Major2", "Major2", "Minor1", "Minor1", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor1", "Minor1", "Wild", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor1", "Minor1", "Wild", "Minor2", "Minor2", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Minor1", "Minor1", "Major2", "Major2", "Major2", "Minor2", "Minor2", "Minor3", "Minor3", "Major3", "Major3", "Major3", "Minor1", "Minor1", "Minor2", "Minor2", "Major2", "Major2", "Major2", "Minor3", "Minor3", "Major1", "Major1", "Major1", "Minor1", "Minor1", "Minor2", "Minor2", "Major2", "Major2", "Major2", "Minor3", "Minor3", "Minor1", "Minor1", "Wild", "Minor2", "Minor2", "Major2", "Major2", "Major2", "Minor3", "Minor3", "Wild", "Minor1", "Minor1", "Major2", "Major2", "Major2", "Minor3", "Minor3", "Major1", "Major1", "Major1", "Minor2", "Minor2", "Wild", "Minor1", "Minor1", "Bonus", "Minor3", "Minor3", "Wild", "Minor1", "Minor1", "Major1", "Major1", "Major1", "Minor3", "Minor3", "Wild", "Minor1", "Minor1"]
        ];
        this.paylines = [
            [0, 0, 0, 0, 0],
            [1, 1, 1, 1, 1],
            [2, 2, 2, 2, 2],
            [3, 3, 3, 3, 3],
            [0, 1, 1, 1, 0],
            [1, 2, 2, 2, 1],
            [2, 3, 3, 3, 2],
            [1, 0, 0, 0, 1],
            [2, 1, 1, 1, 2],
            [3, 2, 2, 2, 3],
            [0, 1, 0, 1, 0],
            [1, 2, 1, 2, 1],
            [2, 3, 2, 3, 2],
            [1, 0, 1, 0, 1],
            [2, 1, 2, 1, 2],
            [3, 2, 3, 2, 3],
            [0, 0, 1, 0, 0],
            [1, 1, 2, 1, 1],
            [2, 2, 3, 2, 2],
            [1, 1, 0, 1, 1],
            [2, 2, 1, 2, 2],
            [3, 3, 2, 3, 3]
        ];
        this.outcomes = [
            { "reelStops": [98, 53, 101, 61, 98], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [35, 12, 25, 44, 115], "totalWin": 0, "wins": [] },
            { "reelStops": [23, 53, 103, 26, 18], "totalWin": 0, "wins": [] },
            { "reelStops": [64, 40, 55, 83, 29], "totalWin": 0, "wins": [] },
            { "reelStops": [43, 22, 72, 65, 123], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2], [4, 2]], "line": 18, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [55, 99, 95, 61, 115], "totalWin": 0, "wins": [] },
            { "reelStops": [55, 39, 23, 17, 78], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [41, 27, 102, 1, 76], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [90, 46, 7, 116, 48], "totalWin": 4.2, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [54, 0, 58, 22, 80], "totalWin": 2.88, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1], [3, 1]], "line": 1, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [112, 19, 66, 46, 39], "totalWin": 0, "wins": [] },
            { "reelStops": [52, 49, 113, 79, 92], "totalWin": 0, "wins": [] },
            { "reelStops": [128, 28, 17, 111, 109], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 109, 37, 61, 29], "totalWin": 4.44, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [128, 66, 116, 21, 48], "totalWin": 0, "wins": [] },
            { "reelStops": [11, 120, 47, 119, 67], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [84, 85, 127, 81, 65], "totalWin": 2.28, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [5, 80, 53, 47, 48], "totalWin": 2.16, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [49, 29, 35, 30, 89], "totalWin": 0, "wins": [] },
            { "reelStops": [72, 107, 69, 45, 67], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 21, 82, 119, 85], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [43, 43, 65, 40, 58], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [98, 28, 72, 106, 64], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [72, 125, 104, 77, 74], "totalWin": 0, "wins": [] },
            { "reelStops": [25, 66, 75, 16, 51], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [97, 66, 42, 4, 91], "totalWin": 0, "wins": [] },
            { "reelStops": [25, 46, 31, 32, 92], "totalWin": 0, "wins": [] },
            { "reelStops": [107, 122, 19, 2, 49], "totalWin": 0, "wins": [] },
            { "reelStops": [77, 125, 129, 113, 72], "totalWin": 4.68, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [103, 111, 112, 110, 31], "totalWin": 0, "wins": [] },
            { "reelStops": [74, 65, 6, 82, 108], "totalWin": 0, "wins": [] },
            { "reelStops": [24, 24, 77, 91, 118], "totalWin": 0, "wins": [] },
            { "reelStops": [15, 81, 22, 100, 83], "totalWin": 0, "wins": [] },
            { "reelStops": [67, 110, 37, 37, 49], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 66, 114, 8, 19], "totalWin": 0, "wins": [] },
            { "reelStops": [70, 43, 2, 87, 70], "totalWin": 0, "wins": [] },
            { "reelStops": [44, 90, 128, 7, 30], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [116, 24, 22, 3, 109], "totalWin": 0, "wins": [] },
            { "reelStops": [53, 109, 47, 9, 56], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2], [4, 2]], "line": 18, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [2, 126, 41, 67, 32], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [66, 64, 47, 76, 118], "totalWin": 24, "wins": [{ "winningSymbols": [[0, 3], [1, 0], [2, 2]], "winType": "scatter", "winAmount": 24, "featureFlags": ["bonus"] }], "bonusWin": 24 },
            { "reelStops": [23, 38, 69, 74, 10], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [1, 53, 53, 97, 113], "totalWin": 4.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0], [4, 0]], "line": 16, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0]], "line": 13, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [122, 46, 35, 46, 41], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [53, 109, 30, 91, 62], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [91, 74, 20, 95, 127], "totalWin": 0, "wins": [] },
            { "reelStops": [11, 57, 8, 107, 59], "totalWin": 0, "wins": [] },
            { "reelStops": [44, 13, 121, 87, 115], "totalWin": 1.5, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [62, 67, 82, 13, 90], "totalWin": 0, "wins": [] },
            { "reelStops": [126, 5, 92, 18, 21], "totalWin": 0, "wins": [] },
            { "reelStops": [84, 70, 36, 42, 3], "totalWin": 0, "wins": [] },
            { "reelStops": [58, 115, 72, 31, 5], "totalWin": 0, "wins": [] },
            { "reelStops": [128, 30, 76, 52, 103], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [29, 82, 65, 56, 80], "totalWin": 0, "wins": [] },
            { "reelStops": [83, 5, 58, 0, 93], "totalWin": 0, "wins": [] },
            { "reelStops": [10, 3, 65, 103, 74], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [23, 71, 4, 13, 62], "totalWin": 0, "wins": [] },
            { "reelStops": [60, 5, 19, 96, 63], "totalWin": 0, "wins": [] },
            { "reelStops": [31, 1, 110, 87, 106], "totalWin": 0, "wins": [] },
            { "reelStops": [124, 4, 59, 72, 9], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 3], [3, 2]], "line": 15, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2]], "line": 18, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [128, 62, 72, 11, 62], "totalWin": 0, "wins": [] },
            { "reelStops": [51, 119, 99, 66, 22], "totalWin": 0, "wins": [] },
            { "reelStops": [80, 61, 29, 118, 10], "totalWin": 0, "wins": [] },
            { "reelStops": [23, 79, 25, 89, 94], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 63, 101, 62, 60], "totalWin": 0, "wins": [] },
            { "reelStops": [2, 87, 107, 59, 48], "totalWin": 0, "wins": [] },
            { "reelStops": [50, 46, 71, 81, 41], "totalWin": 0, "wins": [] },
            { "reelStops": [4, 15, 105, 79, 50], "totalWin": 0, "wins": [] },
            { "reelStops": [19, 64, 30, 4, 12], "totalWin": 0, "wins": [] },
            { "reelStops": [92, 95, 75, 114, 105], "totalWin": 6, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2], [3, 2]], "line": 2, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2]], "line": 18, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [76, 88, 83, 76, 55], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [111, 91, 55, 61, 114], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [10, 9, 85, 7, 18], "totalWin": 4.08, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2], [3, 2], [4, 3]], "line": 9, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3], [3, 2], [4, 3]], "line": 15, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [76, 82, 129, 95, 59], "totalWin": 3.72, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [43, 86, 125, 116, 37], "totalWin": 7.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], "line": 0, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0], [4, 0]], "line": 16, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [90, 3, 17, 90, 3], "totalWin": 0, "wins": [] },
            { "reelStops": [58, 0, 28, 84, 25], "totalWin": 0, "wins": [] },
            { "reelStops": [80, 74, 15, 121, 30], "totalWin": 0, "wins": [] },
            { "reelStops": [7, 3, 42, 15, 13], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 122, 30, 107, 117], "totalWin": 0, "wins": [] },
            { "reelStops": [2, 92, 63, 17, 70], "totalWin": 0, "wins": [] },
            { "reelStops": [97, 59, 68, 15, 113], "totalWin": 0, "wins": [] },
            { "reelStops": [71, 82, 122, 47, 28], "totalWin": 0, "wins": [] },
            { "reelStops": [55, 7, 92, 111, 31], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [33, 126, 61, 80, 88], "totalWin": 3.12, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [50, 109, 105, 94, 37], "totalWin": 2.76, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [62, 70, 91, 1, 78], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 54, 53, 55, 31], "totalWin": 10.56, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2], [4, 1]], "line": 11, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2], [4, 2]], "line": 20, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3], [4, 3]], "line": 3, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3], [4, 3]], "line": 21, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [93, 126, 2, 53, 22], "totalWin": 0, "wins": [] },
            { "reelStops": [13, 29, 106, 83, 14], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [64, 106, 29, 91, 33], "totalWin": 0, "wins": [] },
            { "reelStops": [23, 94, 90, 110, 28], "totalWin": 0, "wins": [] },
            { "reelStops": [44, 49, 20, 23, 63], "totalWin": 0, "wins": [] },
            { "reelStops": [40, 109, 13, 72, 82], "totalWin": 2.28, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2], [3, 2]], "line": 9, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3], [3, 2]], "line": 15, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [99, 102, 36, 28, 40], "totalWin": 0, "wins": [] },
            { "reelStops": [65, 37, 59, 101, 84], "totalWin": 0, "wins": [] },
            { "reelStops": [108, 2, 54, 44, 41], "totalWin": 0, "wins": [] },
            { "reelStops": [129, 116, 63, 43, 34], "totalWin": 0, "wins": [] },
            { "reelStops": [119, 81, 67, 97, 96], "totalWin": 0, "wins": [] },
            { "reelStops": [1, 23, 35, 40, 19], "totalWin": 0, "wins": [] },
            { "reelStops": [57, 82, 94, 124, 34], "totalWin": 0, "wins": [] },
            { "reelStops": [89, 74, 57, 88, 63], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 29, 54, 118, 36], "totalWin": 3.36, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [92, 1, 22, 39, 60], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [98, 91, 84, 59, 44], "totalWin": 2.52, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [120, 125, 75, 96, 43], "totalWin": 0, "wins": [] },
            { "reelStops": [57, 73, 96, 63, 107], "totalWin": 0, "wins": [] },
            { "reelStops": [10, 105, 71, 4, 28], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [91, 19, 39, 7, 95], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [45, 123, 72, 88, 28], "totalWin": 0, "wins": [] },
            { "reelStops": [29, 36, 117, 101, 100], "totalWin": 0, "wins": [] },
            { "reelStops": [50, 27, 66, 16, 28], "totalWin": 0, "wins": [] },
            { "reelStops": [21, 28, 100, 24, 81], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [31, 92, 3, 28, 31], "totalWin": 0, "wins": [] },
            { "reelStops": [111, 99, 32, 68, 33], "totalWin": 0, "wins": [] },
            { "reelStops": [125, 33, 62, 63, 18], "totalWin": 0, "wins": [] },
            { "reelStops": [58, 3, 129, 51, 23], "totalWin": 0, "wins": [] },
            { "reelStops": [114, 84, 85, 9, 73], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [129, 62, 28, 43, 60], "totalWin": 0, "wins": [] },
            { "reelStops": [57, 92, 77, 104, 26], "totalWin": 0, "wins": [] },
            { "reelStops": [22, 102, 2, 68, 36], "totalWin": 0, "wins": [] },
            { "reelStops": [14, 25, 33, 54, 72], "totalWin": 0, "wins": [] },
            { "reelStops": [67, 12, 40, 4, 107], "totalWin": 0, "wins": [] },
            { "reelStops": [47, 13, 4, 55, 19], "totalWin": 0, "wins": [] },
            { "reelStops": [77, 17, 86, 7, 26], "totalWin": 0.9, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [114, 102, 106, 79, 96], "totalWin": 0, "wins": [] },
            { "reelStops": [83, 119, 116, 81, 75], "totalWin": 0, "wins": [] },
            { "reelStops": [100, 27, 42, 79, 46], "totalWin": 0, "wins": [] },
            { "reelStops": [116, 65, 77, 92, 79], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [56, 26, 2, 118, 11], "totalWin": 0, "wins": [] },
            { "reelStops": [30, 119, 52, 116, 108], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [62, 123, 120, 83, 69], "totalWin": 0, "wins": [] },
            { "reelStops": [122, 121, 8, 7, 15], "totalWin": 0, "wins": [] },
            { "reelStops": [110, 86, 59, 90, 13], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [8, 80, 129, 78, 15], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [110, 100, 110, 32, 10], "totalWin": 0, "wins": [] },
            { "reelStops": [31, 52, 29, 25, 75], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [44, 124, 71, 14, 23], "totalWin": 0, "wins": [] },
            { "reelStops": [126, 107, 40, 36, 17], "totalWin": 0, "wins": [] },
            { "reelStops": [116, 42, 17, 44, 15], "totalWin": 0, "wins": [] },
            { "reelStops": [70, 123, 79, 45, 57], "totalWin": 0, "wins": [] },
            { "reelStops": [69, 75, 63, 124, 64], "totalWin": 0, "wins": [] },
            { "reelStops": [77, 17, 80, 80, 71], "totalWin": 0, "wins": [] },
            { "reelStops": [46, 114, 90, 1, 118], "totalWin": 0, "wins": [] },
            { "reelStops": [31, 103, 27, 29, 47], "totalWin": 0, "wins": [] },
            { "reelStops": [2, 63, 97, 87, 48], "totalWin": 1.44, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [61, 51, 74, 79, 51], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [4, 28, 82, 78, 30], "totalWin": 0, "wins": [] },
            { "reelStops": [98, 33, 16, 105, 30], "totalWin": 0, "wins": [] },
            { "reelStops": [16, 90, 124, 60, 32], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [73, 6, 33, 103, 105], "totalWin": 0, "wins": [] },
            { "reelStops": [28, 24, 14, 49, 116], "totalWin": 0, "wins": [] },
            { "reelStops": [129, 65, 121, 95, 73], "totalWin": 0, "wins": [] },
            { "reelStops": [105, 24, 40, 50, 58], "totalWin": 4.32, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [48, 85, 42, 108, 8], "totalWin": 0, "wins": [] },
            { "reelStops": [122, 75, 90, 89, 71], "totalWin": 0, "wins": [] },
            { "reelStops": [56, 23, 105, 85, 37], "totalWin": 0, "wins": [] },
            { "reelStops": [108, 108, 88, 73, 67], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [108, 87, 40, 110, 124], "totalWin": 3.36, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [105, 125, 76, 76, 117], "totalWin": 6, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3], [4, 2]], "line": 6, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3], [4, 2]], "line": 12, "winType": "line", "winAmount": 3, "featureFlags": [] }] },
            { "reelStops": [89, 4, 102, 99, 92], "totalWin": 0, "wins": [] },
            { "reelStops": [79, 21, 95, 48, 41], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [59, 79, 43, 2, 66], "totalWin": 3.12, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [87, 24, 89, 45, 115], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [49, 117, 51, 15, 40], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [110, 114, 3, 74, 80], "totalWin": 0, "wins": [] },
            { "reelStops": [67, 8, 78, 7, 24], "totalWin": 1.38, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [107, 99, 103, 74, 9], "totalWin": 0, "wins": [] },
            { "reelStops": [54, 12, 91, 96, 55], "totalWin": 0, "wins": [] },
            { "reelStops": [116, 31, 2, 115, 28], "totalWin": 4.8, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0], [4, 1]], "line": 7, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1], [4, 1]], "line": 19, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [18, 112, 25, 32, 124], "totalWin": 0, "wins": [] },
            { "reelStops": [51, 53, 61, 124, 85], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [5, 45, 105, 31, 5], "totalWin": 0, "wins": [] },
            { "reelStops": [15, 45, 100, 92, 93], "totalWin": 0, "wins": [] },
            { "reelStops": [15, 14, 97, 27, 89], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [54, 109, 44, 73, 110], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [49, 45, 45, 51, 3], "totalWin": 0, "wins": [] },
            { "reelStops": [100, 84, 110, 121, 69], "totalWin": 0, "wins": [] },
            { "reelStops": [40, 21, 24, 48, 65], "totalWin": 0, "wins": [] },
            { "reelStops": [68, 12, 44, 114, 84], "totalWin": 0, "wins": [] },
            { "reelStops": [108, 56, 18, 53, 103], "totalWin": 0, "wins": [] },
            { "reelStops": [24, 38, 127, 58, 19], "totalWin": 0, "wins": [] },
            { "reelStops": [82, 66, 110, 10, 58], "totalWin": 0, "wins": [] },
            { "reelStops": [109, 48, 102, 116, 63], "totalWin": 0, "wins": [] },
            { "reelStops": [118, 103, 79, 10, 48], "totalWin": 0, "wins": [] },
            { "reelStops": [100, 12, 1, 121, 40], "totalWin": 0, "wins": [] },
            { "reelStops": [110, 61, 56, 124, 21], "totalWin": 0, "wins": [] },
            { "reelStops": [36, 110, 125, 106, 58], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [7, 93, 109, 53, 86], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [33, 51, 70, 102, 67], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [54, 11, 109, 14, 44], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [74, 1, 56, 89, 125], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [79, 111, 121, 73, 16], "totalWin": 4.08, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0]], "line": 13, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0]], "line": 16, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [32, 126, 19, 121, 9], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [63, 92, 17, 35, 41], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [56, 21, 69, 23, 92], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [37, 21, 29, 89, 57], "totalWin": 0, "wins": [] },
            { "reelStops": [66, 43, 125, 35, 86], "totalWin": 0, "wins": [] },
            { "reelStops": [31, 21, 119, 17, 71], "totalWin": 0, "wins": [] },
            { "reelStops": [94, 39, 48, 53, 111], "totalWin": 0, "wins": [] },
            { "reelStops": [19, 109, 49, 32, 21], "totalWin": 1.44, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [107, 12, 49, 125, 103], "totalWin": 0, "wins": [] },
            { "reelStops": [43, 123, 84, 114, 91], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [63, 3, 30, 106, 71], "totalWin": 0, "wins": [] },
            { "reelStops": [95, 76, 7, 95, 42], "totalWin": 0, "wins": [] },
            { "reelStops": [96, 66, 80, 43, 11], "totalWin": 0, "wins": [] },
            { "reelStops": [86, 64, 6, 71, 39], "totalWin": 0, "wins": [] },
            { "reelStops": [69, 114, 41, 64, 54], "totalWin": 0, "wins": [] },
            { "reelStops": [120, 101, 63, 86, 48], "totalWin": 0, "wins": [] },
            { "reelStops": [57, 118, 27, 43, 119], "totalWin": 0, "wins": [] },
            { "reelStops": [58, 93, 74, 91, 108], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 41, 100, 95, 84], "totalWin": 0, "wins": [] },
            { "reelStops": [129, 62, 2, 123, 6], "totalWin": 0, "wins": [] },
            { "reelStops": [85, 111, 109, 41, 26], "totalWin": 0, "wins": [] },
            { "reelStops": [77, 73, 106, 52, 96], "totalWin": 0, "wins": [] },
            { "reelStops": [60, 101, 98, 82, 4], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [124, 90, 54, 67, 50], "totalWin": 1.68, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [55, 37, 6, 50, 83], "totalWin": 0, "wins": [] },
            { "reelStops": [74, 70, 106, 90, 5], "totalWin": 0, "wins": [] },
            { "reelStops": [96, 32, 93, 98, 120], "totalWin": 0, "wins": [] },
            { "reelStops": [43, 120, 53, 61, 126], "totalWin": 4.56, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [88, 95, 62, 1, 50], "totalWin": 0, "wins": [] },
            { "reelStops": [72, 89, 13, 104, 44], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [34, 67, 87, 60, 27], "totalWin": 0, "wins": [] },
            { "reelStops": [41, 61, 127, 78, 76], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [90, 16, 39, 106, 38], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 120, 129, 97, 85], "totalWin": 4.5, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0]], "line": 13, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0]], "line": 16, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [74, 41, 54, 104, 115], "totalWin": 15, "wins": [{ "winningSymbols": [[1, 2], [3, 1], [4, 1]], "winType": "scatter", "winAmount": 15, "featureFlags": ["bonus"] }], "bonusWin": 15 },
            { "reelStops": [127, 61, 24, 63, 94], "totalWin": 0, "wins": [] },
            { "reelStops": [67, 75, 88, 115, 66], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 40, 62, 100, 70], "totalWin": 0, "wins": [] },
            { "reelStops": [36, 8, 93, 36, 67], "totalWin": 0, "wins": [] },
            { "reelStops": [73, 87, 72, 14, 115], "totalWin": 0, "wins": [] },
            { "reelStops": [28, 21, 62, 117, 59], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [17, 123, 93, 126, 13], "totalWin": 0, "wins": [] },
            { "reelStops": [20, 93, 116, 59, 97], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [128, 121, 62, 121, 10], "totalWin": 3.36, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [127, 0, 18, 70, 19], "totalWin": 0, "wins": [] },
            { "reelStops": [65, 14, 78, 104, 127], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [121, 69, 99, 21, 66], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [116, 31, 65, 73, 124], "totalWin": 0, "wins": [] },
            { "reelStops": [51, 16, 128, 115, 80], "totalWin": 0, "wins": [] },
            { "reelStops": [14, 90, 102, 76, 51], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [29, 26, 3, 21, 89], "totalWin": 0, "wins": [] },
            { "reelStops": [70, 102, 112, 122, 5], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [6, 78, 107, 66, 115], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2], [4, 2]], "line": 20, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [32, 42, 82, 118, 52], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [96, 70, 55, 122, 104], "totalWin": 0, "wins": [] },
            { "reelStops": [30, 61, 4, 100, 124], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 78, 64, 56, 99], "totalWin": 6, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2], [4, 1]], "line": 5, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2], [4, 1]], "line": 11, "winType": "line", "winAmount": 3, "featureFlags": [] }] },
            { "reelStops": [94, 14, 14, 39, 20], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [111, 95, 126, 65, 39], "totalWin": 0, "wins": [] },
            { "reelStops": [44, 91, 62, 20, 28], "totalWin": 3.36, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 3], [3, 2]], "line": 15, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2]], "line": 18, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [98, 14, 61, 3, 10], "totalWin": 0, "wins": [] },
            { "reelStops": [127, 90, 9, 64, 104], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 90, 24, 42, 128], "totalWin": 0, "wins": [] },
            { "reelStops": [21, 58, 90, 97, 8], "totalWin": 0, "wins": [] },
            { "reelStops": [36, 116, 63, 100, 74], "totalWin": 0, "wins": [] },
            { "reelStops": [10, 86, 77, 60, 51], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 14, 59, 14, 61], "totalWin": 2.16, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [57, 18, 77, 43, 48], "totalWin": 0, "wins": [] },
            { "reelStops": [16, 70, 23, 117, 78], "totalWin": 0, "wins": [] },
            { "reelStops": [4, 67, 54, 64, 113], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [62, 96, 30, 1, 117], "totalWin": 0, "wins": [] },
            { "reelStops": [44, 40, 8, 11, 104], "totalWin": 0, "wins": [] },
            { "reelStops": [51, 16, 22, 102, 41], "totalWin": 0, "wins": [] },
            { "reelStops": [24, 25, 30, 32, 79], "totalWin": 0, "wins": [] },
            { "reelStops": [12, 21, 4, 109, 54], "totalWin": 6.48, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [35, 73, 41, 104, 91], "totalWin": 0, "wins": [] },
            { "reelStops": [108, 106, 39, 3, 5], "totalWin": 0, "wins": [] },
            { "reelStops": [70, 5, 33, 15, 103], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [51, 19, 73, 119, 100], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [129, 80, 57, 75, 20], "totalWin": 0, "wins": [] },
            { "reelStops": [93, 112, 51, 32, 129], "totalWin": 0, "wins": [] },
            { "reelStops": [58, 108, 98, 116, 47], "totalWin": 0, "wins": [] },
            { "reelStops": [73, 10, 4, 36, 34], "totalWin": 0, "wins": [] },
            { "reelStops": [75, 9, 33, 53, 69], "totalWin": 0, "wins": [] },
            { "reelStops": [53, 8, 129, 23, 22], "totalWin": 4.5, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [28, 8, 22, 4, 32], "totalWin": 0, "wins": [] },
            { "reelStops": [8, 6, 26, 81, 68], "totalWin": 0, "wins": [] },
            { "reelStops": [55, 88, 109, 42, 26], "totalWin": 0, "wins": [] },
            { "reelStops": [7, 80, 72, 59, 100], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [36, 54, 23, 114, 31], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [117, 104, 11, 92, 112], "totalWin": 6.48, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [113, 92, 9, 88, 65], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [7, 1, 68, 58, 60], "totalWin": 0, "wins": [] },
            { "reelStops": [79, 28, 116, 96, 5], "totalWin": 1.38, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [9, 8, 63, 56, 58], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [35, 45, 65, 123, 104], "totalWin": 0, "wins": [] },
            { "reelStops": [31, 85, 124, 61, 63], "totalWin": 0, "wins": [] },
            { "reelStops": [101, 4, 103, 117, 52], "totalWin": 0, "wins": [] },
            { "reelStops": [81, 118, 73, 18, 36], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 41, 0, 76, 29], "totalWin": 0, "wins": [] },
            { "reelStops": [114, 54, 36, 67, 68], "totalWin": 2.52, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [42, 6, 111, 11, 16], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0]], "line": 7, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [4, 125, 83, 77, 99], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [34, 31, 52, 53, 62], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 36, 116, 93, 87], "totalWin": 0, "wins": [] },
            { "reelStops": [42, 37, 84, 105, 77], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [21, 18, 17, 12, 4], "totalWin": 0, "wins": [] },
            { "reelStops": [124, 61, 19, 69, 83], "totalWin": 0, "wins": [] },
            { "reelStops": [78, 51, 41, 5, 71], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [127, 76, 53, 88, 70], "totalWin": 0, "wins": [] },
            { "reelStops": [39, 99, 30, 37, 47], "totalWin": 0, "wins": [] },
            { "reelStops": [107, 97, 58, 59, 7], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [41, 59, 28, 52, 115], "totalWin": 1.08, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [82, 88, 20, 20, 16], "totalWin": 0, "wins": [] },
            { "reelStops": [3, 40, 107, 92, 50], "totalWin": 0, "wins": [] },
            { "reelStops": [19, 76, 89, 93, 103], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3], [3, 2]], "line": 15, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2]], "line": 18, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [84, 100, 34, 106, 126], "totalWin": 0, "wins": [] },
            { "reelStops": [93, 63, 7, 96, 79], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 5, 2, 81, 27], "totalWin": 0, "wins": [] },
            { "reelStops": [125, 124, 85, 121, 129], "totalWin": 0, "wins": [] },
            { "reelStops": [59, 23, 80, 28, 55], "totalWin": 0, "wins": [] },
            { "reelStops": [56, 75, 44, 113, 44], "totalWin": 0, "wins": [] },
            { "reelStops": [0, 110, 106, 86, 2], "totalWin": 0, "wins": [] },
            { "reelStops": [0, 31, 100, 76, 109], "totalWin": 0, "wins": [] },
            { "reelStops": [88, 47, 79, 61, 103], "totalWin": 0, "wins": [] },
            { "reelStops": [16, 108, 52, 29, 1], "totalWin": 2.58, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [74, 43, 113, 123, 112], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 79, 6, 35, 16], "totalWin": 1.08, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [105, 73, 21, 51, 36], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [58, 48, 29, 41, 12], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [39, 26, 125, 100, 55], "totalWin": 5.4, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [59, 1, 38, 83, 119], "totalWin": 0, "wins": [] },
            { "reelStops": [99, 43, 120, 25, 15], "totalWin": 0, "wins": [] },
            { "reelStops": [118, 3, 18, 48, 2], "totalWin": 0, "wins": [] },
            { "reelStops": [92, 70, 95, 1, 47], "totalWin": 0, "wins": [] },
            { "reelStops": [17, 32, 94, 88, 27], "totalWin": 0, "wins": [] },
            { "reelStops": [83, 64, 105, 108, 64], "totalWin": 0, "wins": [] },
            { "reelStops": [67, 47, 100, 36, 106], "totalWin": 0, "wins": [] },
            { "reelStops": [35, 84, 13, 27, 108], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [119, 121, 35, 21, 106], "totalWin": 0, "wins": [] },
            { "reelStops": [99, 91, 38, 44, 52], "totalWin": 1.56, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [104, 62, 27, 9, 53], "totalWin": 0, "wins": [] },
            { "reelStops": [31, 18, 74, 106, 24], "totalWin": 0, "wins": [] },
            { "reelStops": [44, 55, 107, 0, 23], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [121, 92, 91, 95, 29], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [112, 13, 63, 24, 37], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [63, 96, 30, 10, 37], "totalWin": 0, "wins": [] },
            { "reelStops": [20, 29, 84, 114, 99], "totalWin": 7.68, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2], [3, 2], [4, 2]], "line": 2, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2], [4, 1]], "line": 5, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2], [3, 1], [4, 2]], "line": 14, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2], [3, 1], [4, 1]], "line": 17, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [51, 28, 128, 13, 4], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [79, 61, 64, 63, 7], "totalWin": 0, "wins": [] },
            { "reelStops": [120, 98, 101, 71, 30], "totalWin": 0, "wins": [] },
            { "reelStops": [123, 37, 50, 12, 93], "totalWin": 0, "wins": [] },
            { "reelStops": [79, 75, 41, 31, 69], "totalWin": 2.28, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [32, 54, 71, 77, 73], "totalWin": 4.2, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [110, 10, 16, 118, 56], "totalWin": 0, "wins": [] },
            { "reelStops": [78, 88, 114, 37, 20], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 27, 35, 121, 50], "totalWin": 0, "wins": [] },
            { "reelStops": [42, 13, 75, 86, 35], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [92, 59, 106, 106, 93], "totalWin": 0, "wins": [] },
            { "reelStops": [124, 27, 103, 79, 89], "totalWin": 0, "wins": [] },
            { "reelStops": [69, 24, 22, 51, 113], "totalWin": 0, "wins": [] },
            { "reelStops": [21, 94, 66, 34, 71], "totalWin": 0, "wins": [] },
            { "reelStops": [53, 101, 28, 36, 42], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [19, 51, 86, 105, 127], "totalWin": 0, "wins": [] },
            { "reelStops": [129, 106, 58, 69, 55], "totalWin": 0, "wins": [] },
            { "reelStops": [70, 70, 128, 32, 54], "totalWin": 0, "wins": [] },
            { "reelStops": [87, 34, 1, 3, 125], "totalWin": 0, "wins": [] },
            { "reelStops": [11, 92, 49, 55, 123], "totalWin": 5.22, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [9, 69, 0, 114, 82], "totalWin": 0, "wins": [] },
            { "reelStops": [30, 10, 27, 110, 112], "totalWin": 0, "wins": [] },
            { "reelStops": [47, 96, 100, 122, 24], "totalWin": 0, "wins": [] },
            { "reelStops": [85, 82, 91, 59, 129], "totalWin": 0, "wins": [] },
            { "reelStops": [117, 113, 60, 8, 27], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [9, 89, 119, 79, 94], "totalWin": 22, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 3]], "winType": "scatter", "winAmount": 22, "featureFlags": ["bonus"] }], "bonusWin": 22 },
            { "reelStops": [87, 78, 109, 0, 23], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [34, 45, 68, 102, 100], "totalWin": 0, "wins": [] },
            { "reelStops": [74, 15, 128, 110, 0], "totalWin": 0, "wins": [] },
            { "reelStops": [127, 87, 42, 112, 114], "totalWin": 0, "wins": [] },
            { "reelStops": [10, 57, 53, 65, 42], "totalWin": 0, "wins": [] },
            { "reelStops": [62, 61, 80, 88, 52], "totalWin": 0, "wins": [] },
            { "reelStops": [5, 122, 98, 74, 92], "totalWin": 0, "wins": [] },
            { "reelStops": [62, 85, 33, 105, 21], "totalWin": 0, "wins": [] },
            { "reelStops": [118, 30, 115, 68, 40], "totalWin": 0, "wins": [] },
            { "reelStops": [30, 125, 60, 56, 59], "totalWin": 1.5, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [98, 61, 58, 15, 115], "totalWin": 0, "wins": [] },
            { "reelStops": [60, 111, 70, 44, 40], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [33, 60, 69, 84, 42], "totalWin": 0, "wins": [] },
            { "reelStops": [118, 97, 82, 59, 121], "totalWin": 0, "wins": [] },
            { "reelStops": [8, 32, 20, 48, 67], "totalWin": 0, "wins": [] },
            { "reelStops": [39, 75, 69, 38, 129], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [58, 45, 39, 25, 121], "totalWin": 0, "wins": [] },
            { "reelStops": [56, 117, 68, 75, 111], "totalWin": 14.4, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], "line": 0, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1], [3, 1], [4, 1]], "line": 1, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1], [4, 0]], "line": 4, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0], [4, 1]], "line": 7, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1], [4, 0]], "line": 10, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0], [4, 1]], "line": 13, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0], [4, 0]], "line": 16, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1], [4, 1]], "line": 19, "winType": "line", "winAmount": 1.8, "featureFlags": [] }] },
            { "reelStops": [61, 121, 63, 23, 68], "totalWin": 0, "wins": [] },
            { "reelStops": [67, 9, 110, 85, 121], "totalWin": 0, "wins": [] },
            { "reelStops": [125, 123, 117, 123, 81], "totalWin": 0, "wins": [] },
            { "reelStops": [1, 77, 119, 75, 3], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [50, 108, 39, 95, 63], "totalWin": 1.86, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [84, 95, 76, 60, 126], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [96, 115, 75, 91, 26], "totalWin": 0, "wins": [] },
            { "reelStops": [59, 100, 44, 1, 17], "totalWin": 4.2, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [51, 5, 4, 11, 78], "totalWin": 0, "wins": [] },
            { "reelStops": [91, 7, 17, 114, 99], "totalWin": 0, "wins": [] },
            { "reelStops": [12, 66, 99, 80, 90], "totalWin": 4.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], "line": 0, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0], [4, 1]], "line": 7, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [103, 19, 81, 33, 22], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [83, 89, 105, 51, 76], "totalWin": 0, "wins": [] },
            { "reelStops": [120, 30, 40, 44, 42], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [91, 102, 32, 78, 13], "totalWin": 0, "wins": [] },
            { "reelStops": [122, 103, 26, 123, 79], "totalWin": 0, "wins": [] },
            { "reelStops": [19, 18, 32, 48, 64], "totalWin": 0, "wins": [] },
            { "reelStops": [85, 99, 71, 43, 25], "totalWin": 6, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2], [3, 2]], "line": 2, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2]], "line": 18, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [114, 121, 92, 81, 90], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 62, 115, 13, 106], "totalWin": 0, "wins": [] },
            { "reelStops": [18, 122, 16, 25, 2], "totalWin": 0, "wins": [] },
            { "reelStops": [27, 108, 24, 20, 33], "totalWin": 4.8, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [41, 65, 108, 99, 4], "totalWin": 6, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2], [3, 2]], "line": 2, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2]], "line": 18, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [47, 124, 24, 30, 61], "totalWin": 0, "wins": [] },
            { "reelStops": [74, 51, 90, 19, 45], "totalWin": 0, "wins": [] },
            { "reelStops": [81, 111, 74, 59, 59], "totalWin": 0, "wins": [] },
            { "reelStops": [109, 99, 61, 33, 109], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0]], "line": 16, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [67, 79, 0, 89, 85], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [35, 49, 59, 65, 25], "totalWin": 0, "wins": [] },
            { "reelStops": [7, 57, 72, 99, 114], "totalWin": 0, "wins": [] },
            { "reelStops": [19, 72, 23, 99, 65], "totalWin": 0, "wins": [] },
            { "reelStops": [108, 77, 85, 74, 114], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [68, 107, 88, 13, 113], "totalWin": 0, "wins": [] },
            { "reelStops": [41, 72, 29, 72, 118], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [49, 48, 42, 14, 46], "totalWin": 0, "wins": [] },
            { "reelStops": [52, 8, 108, 103, 90], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [22, 16, 73, 65, 34], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [125, 30, 10, 27, 57], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [23, 19, 50, 78, 129], "totalWin": 0, "wins": [] },
            { "reelStops": [123, 87, 27, 38, 98], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 48, 7, 30, 37], "totalWin": 0, "wins": [] },
            { "reelStops": [9, 64, 40, 1, 97], "totalWin": 3.36, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [122, 123, 18, 99, 37], "totalWin": 0, "wins": [] },
            { "reelStops": [122, 33, 15, 112, 101], "totalWin": 0, "wins": [] },
            { "reelStops": [24, 77, 112, 36, 103], "totalWin": 0, "wins": [] },
            { "reelStops": [106, 14, 103, 123, 48], "totalWin": 0, "wins": [] },
            { "reelStops": [24, 85, 97, 19, 55], "totalWin": 0, "wins": [] },
            { "reelStops": [92, 38, 26, 49, 128], "totalWin": 0, "wins": [] },
            { "reelStops": [19, 41, 3, 5, 125], "totalWin": 0, "wins": [] },
            { "reelStops": [44, 52, 129, 71, 50], "totalWin": 0, "wins": [] },
            { "reelStops": [37, 110, 44, 29, 65], "totalWin": 0, "wins": [] },
            { "reelStops": [51, 47, 106, 23, 2], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [16, 32, 25, 46, 57], "totalWin": 0, "wins": [] },
            { "reelStops": [75, 50, 3, 39, 119], "totalWin": 0, "wins": [] },
            { "reelStops": [48, 55, 38, 43, 122], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [54, 60, 21, 87, 24], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [40, 32, 75, 13, 124], "totalWin": 0, "wins": [] },
            { "reelStops": [33, 24, 108, 84, 97], "totalWin": 0, "wins": [] },
            { "reelStops": [6, 99, 52, 98, 70], "totalWin": 0, "wins": [] },
            { "reelStops": [86, 4, 106, 101, 22], "totalWin": 0, "wins": [] },
            { "reelStops": [104, 22, 128, 68, 53], "totalWin": 7.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0]], "line": 7, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0]], "line": 13, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [119, 54, 35, 91, 85], "totalWin": 0, "wins": [] },
            { "reelStops": [101, 101, 123, 96, 30], "totalWin": 0, "wins": [] },
            { "reelStops": [10, 96, 84, 73, 34], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [32, 30, 12, 77, 3], "totalWin": 2.52, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [55, 32, 127, 55, 23], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [15, 50, 78, 22, 44], "totalWin": 0, "wins": [] },
            { "reelStops": [50, 85, 101, 93, 37], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3], [4, 2]], "line": 12, "winType": "line", "winAmount": 1.8, "featureFlags": [] }] },
            { "reelStops": [6, 47, 5, 118, 120], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [49, 49, 48, 30, 107], "totalWin": 0, "wins": [] },
            { "reelStops": [53, 18, 110, 20, 61], "totalWin": 0, "wins": [] },
            { "reelStops": [121, 65, 109, 10, 76], "totalWin": 0, "wins": [] },
            { "reelStops": [80, 0, 65, 83, 63], "totalWin": 0, "wins": [] },
            { "reelStops": [54, 99, 113, 7, 34], "totalWin": 0, "wins": [] },
            { "reelStops": [104, 12, 115, 74, 114], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 126, 115, 104, 129], "totalWin": 0, "wins": [] },
            { "reelStops": [28, 69, 126, 35, 114], "totalWin": 0, "wins": [] },
            { "reelStops": [35, 10, 62, 48, 11], "totalWin": 0, "wins": [] },
            { "reelStops": [117, 33, 99, 25, 85], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [79, 10, 103, 60, 109], "totalWin": 0, "wins": [] },
            { "reelStops": [101, 96, 63, 96, 115], "totalWin": 0, "wins": [] },
            { "reelStops": [33, 87, 5, 2, 74], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 19, 5, 126, 97], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [71, 52, 74, 97, 24], "totalWin": 0, "wins": [] },
            { "reelStops": [29, 68, 114, 11, 95], "totalWin": 0, "wins": [] },
            { "reelStops": [64, 28, 112, 21, 102], "totalWin": 1.68, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [56, 96, 101, 122, 47], "totalWin": 0, "wins": [] },
            { "reelStops": [3, 17, 16, 76, 129], "totalWin": 0, "wins": [] },
            { "reelStops": [106, 79, 79, 124, 73], "totalWin": 9.12, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1], [4, 1]], "line": 19, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [46, 11, 66, 65, 83], "totalWin": 4.2, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [101, 72, 15, 79, 49], "totalWin": 0, "wins": [] },
            { "reelStops": [42, 45, 123, 122, 123], "totalWin": 0, "wins": [] },
            { "reelStops": [105, 2, 15, 2, 62], "totalWin": 3.36, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [66, 4, 87, 112, 42], "totalWin": 0, "wins": [] },
            { "reelStops": [92, 123, 11, 42, 107], "totalWin": 0, "wins": [] },
            { "reelStops": [66, 4, 78, 100, 106], "totalWin": 4.8, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0]], "line": 0, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0]], "line": 16, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [27, 26, 125, 104, 45], "totalWin": 0, "wins": [] },
            { "reelStops": [69, 47, 116, 30, 111], "totalWin": 0, "wins": [] },
            { "reelStops": [125, 82, 52, 5, 115], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [47, 68, 111, 88, 3], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [58, 86, 15, 3, 11], "totalWin": 0, "wins": [] },
            { "reelStops": [6, 108, 31, 33, 89], "totalWin": 0, "wins": [] },
            { "reelStops": [86, 41, 75, 77, 54], "totalWin": 0, "wins": [] },
            { "reelStops": [13, 126, 65, 67, 123], "totalWin": 0, "wins": [] },
            { "reelStops": [23, 7, 122, 111, 35], "totalWin": 0, "wins": [] },
            { "reelStops": [44, 76, 125, 3, 58], "totalWin": 0, "wins": [] },
            { "reelStops": [64, 40, 112, 65, 84], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [17, 6, 129, 12, 43], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 42, 118, 6, 23], "totalWin": 23, "wins": [{ "winningSymbols": [[1, 1], [2, 1], [4, 0]], "winType": "scatter", "winAmount": 23, "featureFlags": ["bonus"] }], "bonusWin": 23 },
            { "reelStops": [43, 39, 78, 81, 92], "totalWin": 0, "wins": [] },
            { "reelStops": [57, 112, 14, 10, 41], "totalWin": 0, "wins": [] },
            { "reelStops": [11, 34, 109, 120, 106], "totalWin": 0, "wins": [] },
            { "reelStops": [66, 70, 53, 53, 25], "totalWin": 8.1, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0]], "line": 0, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1], [3, 1]], "line": 1, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0]], "line": 7, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0]], "line": 13, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0]], "line": 16, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [67, 55, 84, 69, 81], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [60, 123, 3, 64, 36], "totalWin": 0, "wins": [] },
            { "reelStops": [73, 114, 42, 84, 71], "totalWin": 0, "wins": [] },
            { "reelStops": [100, 25, 126, 89, 88], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [103, 7, 56, 18, 125], "totalWin": 0, "wins": [] },
            { "reelStops": [116, 41, 54, 122, 56], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0], [4, 1]], "line": 7, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1], [4, 1]], "line": 19, "winType": "line", "winAmount": 1.8, "featureFlags": [] }] },
            { "reelStops": [19, 97, 63, 117, 112], "totalWin": 0, "wins": [] },
            { "reelStops": [83, 41, 64, 11, 5], "totalWin": 0, "wins": [] },
            { "reelStops": [77, 46, 117, 32, 63], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [37, 15, 77, 12, 57], "totalWin": 0, "wins": [] },
            { "reelStops": [115, 5, 86, 45, 105], "totalWin": 0, "wins": [] },
            { "reelStops": [70, 57, 58, 114, 122], "totalWin": 0, "wins": [] },
            { "reelStops": [118, 81, 98, 30, 104], "totalWin": 0, "wins": [] },
            { "reelStops": [10, 70, 27, 53, 87], "totalWin": 0, "wins": [] },
            { "reelStops": [5, 57, 11, 9, 19], "totalWin": 0, "wins": [] },
            { "reelStops": [66, 70, 109, 35, 106], "totalWin": 0, "wins": [] },
            { "reelStops": [71, 48, 63, 57, 112], "totalWin": 0, "wins": [] },
            { "reelStops": [52, 109, 86, 54, 122], "totalWin": 1.08, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [69, 30, 0, 98, 92], "totalWin": 5.28, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [101, 93, 18, 70, 4], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [90, 41, 45, 83, 33], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 25, 45, 99, 67], "totalWin": 0, "wins": [] },
            { "reelStops": [36, 81, 82, 43, 84], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [47, 42, 52, 116, 75], "totalWin": 3.66, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2], [3, 2]], "line": 2, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2], [3, 2]], "line": 9, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [66, 51, 69, 65, 83], "totalWin": 0, "wins": [] },
            { "reelStops": [56, 125, 39, 46, 68], "totalWin": 2.28, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [124, 35, 94, 58, 103], "totalWin": 0, "wins": [] },
            { "reelStops": [78, 35, 51, 72, 84], "totalWin": 2.76, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [10, 97, 82, 97, 60], "totalWin": 0, "wins": [] },
            { "reelStops": [37, 49, 0, 33, 105], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [54, 100, 57, 106, 57], "totalWin": 0, "wins": [] },
            { "reelStops": [49, 97, 48, 107, 66], "totalWin": 0, "wins": [] },
            { "reelStops": [1, 82, 19, 105, 26], "totalWin": 0, "wins": [] },
            { "reelStops": [86, 49, 45, 85, 108], "totalWin": 1.08, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [61, 63, 39, 91, 19], "totalWin": 0, "wins": [] },
            { "reelStops": [66, 113, 123, 43, 64], "totalWin": 0, "wins": [] },
            { "reelStops": [122, 33, 105, 84, 122], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [83, 23, 66, 77, 78], "totalWin": 0, "wins": [] },
            { "reelStops": [20, 13, 106, 42, 17], "totalWin": 0, "wins": [] },
            { "reelStops": [110, 35, 27, 37, 33], "totalWin": 0, "wins": [] },
            { "reelStops": [94, 124, 61, 43, 32], "totalWin": 0, "wins": [] },
            { "reelStops": [119, 15, 2, 108, 128], "totalWin": 0, "wins": [] },
            { "reelStops": [68, 3, 60, 119, 11], "totalWin": 0, "wins": [] },
            { "reelStops": [31, 78, 7, 90, 92], "totalWin": 0, "wins": [] },
            { "reelStops": [101, 102, 95, 63, 74], "totalWin": 0, "wins": [] },
            { "reelStops": [92, 74, 8, 30, 75], "totalWin": 0, "wins": [] },
            { "reelStops": [51, 58, 54, 116, 96], "totalWin": 0, "wins": [] },
            { "reelStops": [76, 124, 103, 18, 89], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [81, 74, 83, 112, 27], "totalWin": 0, "wins": [] },
            { "reelStops": [44, 117, 51, 17, 30], "totalWin": 0, "wins": [] },
            { "reelStops": [82, 28, 64, 16, 49], "totalWin": 0, "wins": [] },
            { "reelStops": [128, 112, 35, 102, 39], "totalWin": 0, "wins": [] },
            { "reelStops": [100, 121, 62, 9, 22], "totalWin": 0, "wins": [] },
            { "reelStops": [62, 44, 14, 72, 7], "totalWin": 0, "wins": [] },
            { "reelStops": [59, 13, 80, 37, 1], "totalWin": 0, "wins": [] },
            { "reelStops": [2, 93, 129, 53, 92], "totalWin": 5.4, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [55, 100, 96, 93, 26], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [104, 5, 9, 54, 42], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [94, 85, 30, 123, 122], "totalWin": 0, "wins": [] },
            { "reelStops": [73, 1, 7, 56, 19], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [59, 121, 82, 67, 79], "totalWin": 0, "wins": [] },
            { "reelStops": [75, 15, 56, 47, 113], "totalWin": 0, "wins": [] },
            { "reelStops": [39, 6, 63, 60, 82], "totalWin": 0, "wins": [] },
            { "reelStops": [103, 17, 10, 31, 116], "totalWin": 0, "wins": [] },
            { "reelStops": [23, 6, 57, 124, 74], "totalWin": 0, "wins": [] },
            { "reelStops": [102, 35, 101, 22, 122], "totalWin": 0, "wins": [] },
            { "reelStops": [100, 89, 35, 50, 90], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [74, 24, 112, 83, 81], "totalWin": 0, "wins": [] },
            { "reelStops": [72, 114, 80, 15, 12], "totalWin": 0, "wins": [] },
            { "reelStops": [117, 29, 14, 82, 22], "totalWin": 4.56, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1], [4, 0]], "line": 4, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1], [4, 0]], "line": 10, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [60, 54, 5, 79, 51], "totalWin": 0, "wins": [] },
            { "reelStops": [93, 80, 4, 96, 104], "totalWin": 7.2, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3], [4, 3]], "line": 3, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3], [4, 2]], "line": 6, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3], [4, 2]], "line": 12, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3], [4, 3]], "line": 21, "winType": "line", "winAmount": 1.8, "featureFlags": [] }] },
            { "reelStops": [49, 70, 123, 25, 37], "totalWin": 0, "wins": [] },
            { "reelStops": [16, 71, 72, 32, 114], "totalWin": 0, "wins": [] },
            { "reelStops": [49, 97, 77, 102, 125], "totalWin": 0, "wins": [] },
            { "reelStops": [13, 5, 86, 62, 29], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [70, 122, 21, 90, 21], "totalWin": 0, "wins": [] },
            { "reelStops": [3, 82, 85, 116, 79], "totalWin": 0, "wins": [] },
            { "reelStops": [98, 94, 112, 13, 92], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [59, 24, 0, 13, 87], "totalWin": 0, "wins": [] },
            { "reelStops": [52, 111, 101, 88, 39], "totalWin": 1.08, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [121, 124, 70, 113, 81], "totalWin": 0, "wins": [] },
            { "reelStops": [64, 49, 119, 121, 27], "totalWin": 4.56, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [23, 41, 50, 7, 2], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 39, 77, 82, 16], "totalWin": 0, "wins": [] },
            { "reelStops": [127, 119, 49, 3, 25], "totalWin": 0, "wins": [] },
            { "reelStops": [23, 44, 29, 85, 64], "totalWin": 0, "wins": [] },
            { "reelStops": [92, 117, 9, 30, 128], "totalWin": 0, "wins": [] },
            { "reelStops": [55, 77, 117, 27, 115], "totalWin": 6, "wins": [{ "winningSymbols": [[0, 3], [2, 2], [4, 1]], "winType": "scatter", "winAmount": 6, "featureFlags": ["bonus"] }], "bonusWin": 6 },
            { "reelStops": [14, 0, 75, 51, 44], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [7, 29, 16, 76, 22], "totalWin": 20.44, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [2, 2], [4, 1]], "winType": "scatter", "winAmount": 19, "featureFlags": ["bonus"] }], "bonusWin": 19 },
            { "reelStops": [77, 93, 77, 11, 10], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [32, 106, 25, 117, 126], "totalWin": 0, "wins": [] },
            { "reelStops": [93, 60, 15, 0, 66], "totalWin": 0, "wins": [] },
            { "reelStops": [66, 47, 37, 23, 50], "totalWin": 4.8, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0]], "line": 0, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0]], "line": 16, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [39, 45, 18, 80, 42], "totalWin": 0, "wins": [] },
            { "reelStops": [45, 88, 110, 111, 25], "totalWin": 0, "wins": [] },
            { "reelStops": [9, 40, 36, 69, 64], "totalWin": 0, "wins": [] },
            { "reelStops": [111, 106, 76, 72, 45], "totalWin": 0, "wins": [] },
            { "reelStops": [87, 110, 24, 26, 64], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [2, 93, 76, 17, 81], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [106, 40, 84, 111, 89], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [62, 55, 105, 14, 66], "totalWin": 4.32, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [91, 56, 16, 28, 39], "totalWin": 0, "wins": [] },
            { "reelStops": [53, 125, 76, 66, 35], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [94, 73, 34, 40, 112], "totalWin": 0, "wins": [] },
            { "reelStops": [76, 76, 47, 47, 105], "totalWin": 1.38, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 3], [3, 2]], "line": 15, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [92, 107, 99, 97, 10], "totalWin": 0, "wins": [] },
            { "reelStops": [111, 17, 14, 100, 77], "totalWin": 0, "wins": [] },
            { "reelStops": [31, 7, 11, 90, 114], "totalWin": 6.48, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [105, 86, 2, 27, 112], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2], [3, 1]], "line": 14, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [56, 85, 14, 110, 67], "totalWin": 0, "wins": [] },
            { "reelStops": [43, 65, 116, 17, 129], "totalWin": 0, "wins": [] },
            { "reelStops": [21, 89, 68, 118, 90], "totalWin": 0, "wins": [] },
            { "reelStops": [101, 93, 57, 21, 56], "totalWin": 0, "wins": [] },
            { "reelStops": [33, 123, 91, 16, 42], "totalWin": 0, "wins": [] },
            { "reelStops": [5, 75, 23, 74, 52], "totalWin": 0, "wins": [] },
            { "reelStops": [82, 65, 30, 60, 21], "totalWin": 0, "wins": [] },
            { "reelStops": [0, 108, 19, 115, 48], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [91, 76, 81, 112, 93], "totalWin": 0, "wins": [] },
            { "reelStops": [32, 124, 10, 21, 71], "totalWin": 0, "wins": [] },
            { "reelStops": [121, 41, 102, 10, 7], "totalWin": 0, "wins": [] },
            { "reelStops": [0, 98, 116, 59, 72], "totalWin": 0, "wins": [] },
            { "reelStops": [90, 17, 77, 78, 106], "totalWin": 0, "wins": [] },
            { "reelStops": [38, 94, 18, 10, 92], "totalWin": 0, "wins": [] },
            { "reelStops": [101, 55, 39, 87, 32], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [126, 28, 55, 94, 125], "totalWin": 1.08, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [55, 22, 109, 85, 77], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [69, 81, 112, 33, 72], "totalWin": 0, "wins": [] },
            { "reelStops": [87, 85, 17, 75, 8], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [70, 86, 125, 75, 26], "totalWin": 0, "wins": [] },
            { "reelStops": [36, 89, 31, 21, 112], "totalWin": 0, "wins": [] },
            { "reelStops": [46, 40, 35, 0, 88], "totalWin": 0, "wins": [] },
            { "reelStops": [43, 8, 68, 100, 109], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [93, 96, 84, 16, 97], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [56, 63, 79, 16, 122], "totalWin": 2.34, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [9, 26, 73, 75, 37], "totalWin": 0, "wins": [] },
            { "reelStops": [89, 15, 129, 24, 11], "totalWin": 0, "wins": [] },
            { "reelStops": [67, 81, 101, 77, 128], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [3, 69, 38, 108, 54], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 120, 87, 40, 44], "totalWin": 0, "wins": [] },
            { "reelStops": [76, 43, 91, 74, 84], "totalWin": 0, "wins": [] },
            { "reelStops": [117, 48, 90, 100, 35], "totalWin": 0, "wins": [] },
            { "reelStops": [77, 55, 27, 122, 17], "totalWin": 1.08, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [59, 63, 62, 61, 110], "totalWin": 0, "wins": [] },
            { "reelStops": [29, 39, 74, 74, 60], "totalWin": 0, "wins": [] },
            { "reelStops": [129, 106, 18, 43, 116], "totalWin": 0, "wins": [] },
            { "reelStops": [60, 39, 7, 24, 44], "totalWin": 0, "wins": [] },
            { "reelStops": [119, 60, 79, 25, 3], "totalWin": 0, "wins": [] },
            { "reelStops": [35, 60, 38, 85, 74], "totalWin": 0, "wins": [] },
            { "reelStops": [75, 116, 19, 41, 79], "totalWin": 0, "wins": [] },
            { "reelStops": [76, 73, 20, 93, 110], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [72, 76, 54, 95, 128], "totalWin": 0, "wins": [] },
            { "reelStops": [21, 72, 62, 68, 19], "totalWin": 0, "wins": [] },
            { "reelStops": [49, 71, 91, 41, 95], "totalWin": 0, "wins": [] },
            { "reelStops": [17, 30, 28, 88, 89], "totalWin": 0, "wins": [] },
            { "reelStops": [123, 34, 19, 62, 50], "totalWin": 0, "wins": [] },
            { "reelStops": [81, 57, 103, 42, 25], "totalWin": 0, "wins": [] },
            { "reelStops": [13, 65, 26, 46, 75], "totalWin": 0, "wins": [] },
            { "reelStops": [54, 7, 71, 58, 129], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0]], "line": 7, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [103, 28, 125, 83, 123], "totalWin": 3.36, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [128, 97, 28, 21, 69], "totalWin": 0, "wins": [] },
            { "reelStops": [74, 102, 63, 108, 122], "totalWin": 0, "wins": [] },
            { "reelStops": [100, 117, 98, 92, 113], "totalWin": 0, "wins": [] },
            { "reelStops": [87, 120, 106, 90, 101], "totalWin": 0, "wins": [] },
            { "reelStops": [39, 56, 0, 17, 115], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [77, 112, 122, 13, 24], "totalWin": 6.96, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], "line": 0, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0], [4, 1]], "line": 7, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2]], "line": 18, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [25, 2, 116, 107, 107], "totalWin": 0, "wins": [] },
            { "reelStops": [3, 14, 73, 120, 122], "totalWin": 0, "wins": [] },
            { "reelStops": [56, 87, 34, 45, 13], "totalWin": 0, "wins": [] },
            { "reelStops": [35, 79, 48, 3, 69], "totalWin": 0.9, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [100, 69, 92, 54, 59], "totalWin": 0, "wins": [] },
            { "reelStops": [9, 67, 26, 20, 93], "totalWin": 0, "wins": [] },
            { "reelStops": [35, 90, 80, 77, 102], "totalWin": 0, "wins": [] },
            { "reelStops": [11, 121, 86, 95, 45], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [19, 58, 111, 3, 25], "totalWin": 0, "wins": [] },
            { "reelStops": [79, 107, 70, 105, 88], "totalWin": 0, "wins": [] },
            { "reelStops": [70, 107, 3, 26, 82], "totalWin": 0, "wins": [] },
            { "reelStops": [40, 38, 77, 92, 33], "totalWin": 0, "wins": [] },
            { "reelStops": [92, 117, 114, 99, 107], "totalWin": 0, "wins": [] },
            { "reelStops": [5, 104, 78, 121, 67], "totalWin": 0, "wins": [] },
            { "reelStops": [41, 26, 91, 45, 123], "totalWin": 0, "wins": [] },
            { "reelStops": [63, 110, 111, 69, 31], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 95, 89, 83, 70], "totalWin": 0, "wins": [] },
            { "reelStops": [90, 15, 129, 55, 89], "totalWin": 0, "wins": [] },
            { "reelStops": [39, 122, 72, 107, 115], "totalWin": 0, "wins": [] },
            { "reelStops": [40, 74, 59, 96, 48], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [50, 95, 70, 83, 27], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [3, 92, 111, 55, 0], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [92, 109, 86, 107, 13], "totalWin": 0, "wins": [] },
            { "reelStops": [105, 99, 76, 31, 37], "totalWin": 0, "wins": [] },
            { "reelStops": [85, 76, 48, 53, 52], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [13, 33, 108, 8, 126], "totalWin": 0, "wins": [] },
            { "reelStops": [23, 125, 88, 22, 34], "totalWin": 0, "wins": [] },
            { "reelStops": [111, 108, 63, 38, 93], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [67, 50, 19, 126, 83], "totalWin": 0, "wins": [] },
            { "reelStops": [115, 100, 17, 77, 75], "totalWin": 0, "wins": [] },
            { "reelStops": [121, 22, 23, 24, 86], "totalWin": 0, "wins": [] },
            { "reelStops": [44, 13, 8, 22, 105], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2], [3, 1]], "line": 14, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [41, 79, 43, 10, 38], "totalWin": 6.06, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1], [4, 1]], "line": 19, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2], [3, 1]], "line": 14, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [120, 81, 26, 12, 89], "totalWin": 0, "wins": [] },
            { "reelStops": [126, 108, 47, 88, 40], "totalWin": 0, "wins": [] },
            { "reelStops": [58, 57, 31, 105, 42], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [12, 15, 21, 55, 93], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [54, 6, 20, 90, 102], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [127, 91, 17, 0, 114], "totalWin": 0, "wins": [] },
            { "reelStops": [35, 71, 53, 107, 100], "totalWin": 0, "wins": [] },
            { "reelStops": [45, 75, 21, 47, 30], "totalWin": 0, "wins": [] },
            { "reelStops": [51, 1, 101, 68, 110], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [55, 101, 28, 111, 107], "totalWin": 0, "wins": [] },
            { "reelStops": [57, 103, 14, 98, 121], "totalWin": 0, "wins": [] },
            { "reelStops": [12, 56, 52, 47, 16], "totalWin": 4.32, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [76, 53, 93, 124, 15], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [50, 51, 36, 113, 43], "totalWin": 0, "wins": [] },
            { "reelStops": [74, 73, 63, 35, 51], "totalWin": 0, "wins": [] },
            { "reelStops": [76, 86, 125, 89, 127], "totalWin": 0, "wins": [] },
            { "reelStops": [9, 57, 101, 14, 92], "totalWin": 0, "wins": [] },
            { "reelStops": [93, 91, 16, 36, 80], "totalWin": 0.9, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [80, 44, 58, 61, 116], "totalWin": 0, "wins": [] },
            { "reelStops": [63, 61, 29, 35, 38], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 100, 117, 75, 20], "totalWin": 0, "wins": [] },
            { "reelStops": [42, 114, 62, 88, 115], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [72, 39, 93, 68, 86], "totalWin": 0, "wins": [] },
            { "reelStops": [121, 119, 19, 19, 94], "totalWin": 0, "wins": [] },
            { "reelStops": [85, 14, 40, 104, 43], "totalWin": 4.2, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [81, 33, 78, 83, 117], "totalWin": 0, "wins": [] },
            { "reelStops": [126, 60, 63, 93, 5], "totalWin": 0, "wins": [] },
            { "reelStops": [43, 55, 27, 116, 116], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [29, 87, 124, 54, 53], "totalWin": 0, "wins": [] },
            { "reelStops": [91, 83, 73, 107, 71], "totalWin": 0, "wins": [] },
            { "reelStops": [99, 12, 117, 12, 108], "totalWin": 0, "wins": [] },
            { "reelStops": [31, 70, 110, 92, 115], "totalWin": 0, "wins": [] },
            { "reelStops": [129, 107, 117, 111, 47], "totalWin": 0, "wins": [] },
            { "reelStops": [45, 77, 82, 96, 0], "totalWin": 0, "wins": [] },
            { "reelStops": [110, 98, 22, 1, 80], "totalWin": 0, "wins": [] },
            { "reelStops": [54, 122, 110, 27, 25], "totalWin": 0, "wins": [] },
            { "reelStops": [72, 87, 21, 31, 81], "totalWin": 0, "wins": [] },
            { "reelStops": [78, 83, 58, 29, 4], "totalWin": 0, "wins": [] },
            { "reelStops": [6, 6, 61, 93, 19], "totalWin": 3.12, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [12, 74, 101, 0, 103], "totalWin": 0, "wins": [] },
            { "reelStops": [5, 45, 88, 5, 100], "totalWin": 0, "wins": [] },
            { "reelStops": [21, 59, 26, 14, 28], "totalWin": 0, "wins": [] },
            { "reelStops": [81, 103, 22, 71, 117], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 101, 110, 76, 0], "totalWin": 0, "wins": [] },
            { "reelStops": [3, 55, 26, 6, 125], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [19, 0, 83, 9, 80], "totalWin": 0, "wins": [] },
            { "reelStops": [47, 43, 82, 76, 105], "totalWin": 0, "wins": [] },
            { "reelStops": [42, 109, 77, 124, 66], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [42, 11, 25, 34, 7], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [71, 49, 109, 29, 0], "totalWin": 0, "wins": [] },
            { "reelStops": [40, 74, 102, 14, 50], "totalWin": 0, "wins": [] },
            { "reelStops": [29, 16, 119, 13, 48], "totalWin": 0, "wins": [] },
            { "reelStops": [94, 82, 102, 57, 14], "totalWin": 0, "wins": [] },
            { "reelStops": [18, 113, 57, 52, 125], "totalWin": 0, "wins": [] },
            { "reelStops": [48, 79, 93, 118, 28], "totalWin": 0, "wins": [] },
            { "reelStops": [92, 41, 18, 23, 29], "totalWin": 0, "wins": [] },
            { "reelStops": [104, 45, 72, 99, 95], "totalWin": 0, "wins": [] },
            { "reelStops": [88, 38, 93, 100, 27], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 106, 94, 100, 14], "totalWin": 0, "wins": [] },
            { "reelStops": [29, 12, 19, 96, 6], "totalWin": 0, "wins": [] },
            { "reelStops": [24, 42, 105, 111, 90], "totalWin": 0, "wins": [] },
            { "reelStops": [23, 51, 64, 21, 119], "totalWin": 0, "wins": [] },
            { "reelStops": [58, 111, 82, 16, 57], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [36, 13, 25, 78, 116], "totalWin": 0, "wins": [] },
            { "reelStops": [99, 2, 59, 3, 13], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 21, 16, 85, 122], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [105, 93, 119, 117, 7], "totalWin": 2.04, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [27, 90, 101, 6, 38], "totalWin": 0, "wins": [] },
            { "reelStops": [15, 31, 0, 84, 45], "totalWin": 4.8, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3], [3, 2]], "line": 15, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2]], "line": 18, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [5, 56, 16, 32, 129], "totalWin": 0, "wins": [] },
            { "reelStops": [112, 112, 41, 49, 46], "totalWin": 0, "wins": [] },
            { "reelStops": [28, 75, 44, 116, 45], "totalWin": 0, "wins": [] },
            { "reelStops": [4, 115, 67, 7, 107], "totalWin": 0, "wins": [] },
            { "reelStops": [80, 91, 119, 11, 9], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [83, 63, 106, 122, 71], "totalWin": 0, "wins": [] },
            { "reelStops": [71, 64, 24, 68, 13], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [7, 18, 10, 91, 95], "totalWin": 0, "wins": [] },
            { "reelStops": [18, 10, 124, 59, 126], "totalWin": 0, "wins": [] },
            { "reelStops": [7, 114, 119, 40, 83], "totalWin": 0, "wins": [] },
            { "reelStops": [89, 111, 119, 0, 118], "totalWin": 0, "wins": [] },
            { "reelStops": [86, 18, 43, 6, 79], "totalWin": 9, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1], [3, 1], [4, 1]], "line": 1, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0], [4, 1]], "line": 13, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2], [3, 1], [4, 1]], "line": 17, "winType": "line", "winAmount": 3, "featureFlags": [] }] },
            { "reelStops": [70, 72, 114, 25, 22], "totalWin": 0, "wins": [] },
            { "reelStops": [124, 90, 113, 65, 38], "totalWin": 0, "wins": [] },
            { "reelStops": [40, 42, 64, 115, 29], "totalWin": 0, "wins": [] },
            { "reelStops": [65, 81, 123, 8, 67], "totalWin": 0, "wins": [] },
            { "reelStops": [86, 123, 13, 57, 39], "totalWin": 2.16, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [67, 54, 92, 69, 83], "totalWin": 0, "wins": [] },
            { "reelStops": [59, 23, 57, 79, 6], "totalWin": 0, "wins": [] },
            { "reelStops": [57, 86, 11, 98, 62], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [46, 97, 98, 116, 107], "totalWin": 6.96, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0]], "line": 13, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0]], "line": 16, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2], [3, 2]], "line": 9, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3], [3, 2]], "line": 15, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [28, 79, 108, 117, 56], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [24, 82, 107, 58, 71], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [36, 40, 101, 78, 45], "totalWin": 0, "wins": [] },
            { "reelStops": [56, 76, 75, 6, 62], "totalWin": 0, "wins": [] },
            { "reelStops": [97, 112, 96, 18, 33], "totalWin": 0, "wins": [] },
            { "reelStops": [31, 59, 104, 59, 50], "totalWin": 0, "wins": [] },
            { "reelStops": [21, 75, 74, 86, 105], "totalWin": 0, "wins": [] },
            { "reelStops": [94, 0, 10, 121, 121], "totalWin": 1.56, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [129, 57, 124, 52, 66], "totalWin": 0, "wins": [] },
            { "reelStops": [53, 8, 122, 53, 107], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [123, 58, 127, 88, 99], "totalWin": 0, "wins": [] },
            { "reelStops": [82, 75, 87, 37, 57], "totalWin": 0, "wins": [] },
            { "reelStops": [125, 45, 80, 28, 104], "totalWin": 0, "wins": [] },
            { "reelStops": [21, 111, 87, 92, 60], "totalWin": 0, "wins": [] },
            { "reelStops": [85, 73, 74, 106, 56], "totalWin": 0, "wins": [] },
            { "reelStops": [38, 54, 59, 4, 128], "totalWin": 1.56, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [14, 113, 74, 120, 104], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [37, 71, 57, 62, 98], "totalWin": 0, "wins": [] },
            { "reelStops": [92, 81, 95, 100, 108], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [10, 78, 113, 54, 92], "totalWin": 2.16, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [53, 72, 109, 108, 63], "totalWin": 0, "wins": [] },
            { "reelStops": [117, 33, 53, 121, 37], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [75, 112, 109, 119, 57], "totalWin": 0, "wins": [] },
            { "reelStops": [75, 22, 58, 30, 78], "totalWin": 0, "wins": [] },
            { "reelStops": [22, 108, 1, 78, 90], "totalWin": 0, "wins": [] },
            { "reelStops": [107, 50, 0, 1, 77], "totalWin": 1.08, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [104, 124, 95, 108, 126], "totalWin": 0, "wins": [] },
            { "reelStops": [29, 82, 65, 109, 36], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 48, 62, 106, 99], "totalWin": 0.9, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2], [3, 2]], "line": 9, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [7, 122, 18, 109, 119], "totalWin": 0, "wins": [] },
            { "reelStops": [84, 80, 70, 108, 111], "totalWin": 0, "wins": [] },
            { "reelStops": [35, 59, 2, 96, 105], "totalWin": 0, "wins": [] },
            { "reelStops": [65, 102, 74, 47, 111], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0]], "line": 7, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [113, 24, 57, 0, 22], "totalWin": 0, "wins": [] },
            { "reelStops": [62, 20, 25, 20, 1], "totalWin": 0, "wins": [] },
            { "reelStops": [65, 40, 88, 118, 38], "totalWin": 0, "wins": [] },
            { "reelStops": [60, 10, 43, 22, 30], "totalWin": 0, "wins": [] },
            { "reelStops": [78, 81, 29, 1, 113], "totalWin": 1.92, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [11, 72, 17, 93, 91], "totalWin": 0, "wins": [] },
            { "reelStops": [5, 9, 61, 44, 121], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [60, 30, 43, 59, 104], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0]], "line": 0, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [27, 121, 79, 56, 41], "totalWin": 0, "wins": [] },
            { "reelStops": [58, 96, 32, 12, 52], "totalWin": 0, "wins": [] },
            { "reelStops": [42, 69, 38, 124, 126], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0], [4, 1]], "line": 7, "winType": "line", "winAmount": 3, "featureFlags": [] }] },
            { "reelStops": [82, 48, 50, 84, 72], "totalWin": 0, "wins": [] },
            { "reelStops": [77, 50, 112, 101, 116], "totalWin": 0, "wins": [] },
            { "reelStops": [129, 58, 35, 28, 72], "totalWin": 0, "wins": [] },
            { "reelStops": [105, 75, 94, 52, 22], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [104, 10, 57, 6, 22], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [104, 88, 60, 114, 51], "totalWin": 0.9, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [52, 85, 85, 2, 44], "totalWin": 0, "wins": [] },
            { "reelStops": [77, 13, 111, 40, 36], "totalWin": 0, "wins": [] },
            { "reelStops": [27, 85, 83, 59, 15], "totalWin": 0, "wins": [] },
            { "reelStops": [49, 23, 0, 11, 85], "totalWin": 0, "wins": [] },
            { "reelStops": [76, 99, 123, 58, 12], "totalWin": 0, "wins": [] },
            { "reelStops": [53, 28, 37, 111, 0], "totalWin": 2.04, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [19, 39, 122, 76, 108], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [69, 78, 103, 80, 107], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0]], "line": 7, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [6, 19, 107, 54, 95], "totalWin": 0, "wins": [] },
            { "reelStops": [24, 8, 89, 110, 74], "totalWin": 0, "wins": [] },
            { "reelStops": [16, 84, 128, 37, 2], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [45, 2, 70, 68, 16], "totalWin": 0, "wins": [] },
            { "reelStops": [47, 105, 86, 4, 74], "totalWin": 0, "wins": [] },
            { "reelStops": [89, 126, 32, 114, 49], "totalWin": 2.7, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2], [3, 2]], "line": 2, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3], [3, 2]], "line": 18, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [89, 58, 87, 33, 24], "totalWin": 0, "wins": [] },
            { "reelStops": [74, 50, 28, 67, 77], "totalWin": 0, "wins": [] },
            { "reelStops": [103, 54, 60, 59, 91], "totalWin": 6.84, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2], [4, 1]], "line": 5, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [126, 85, 2, 23, 63], "totalWin": 0, "wins": [] },
            { "reelStops": [113, 68, 34, 65, 25], "totalWin": 0.6, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [71, 0, 23, 99, 36], "totalWin": 0, "wins": [] },
            { "reelStops": [120, 106, 27, 30, 69], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3], [4, 3]], "line": 3, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3], [4, 3]], "line": 21, "winType": "line", "winAmount": 1.8, "featureFlags": [] }] },
            { "reelStops": [7, 117, 46, 120, 76], "totalWin": 0, "wins": [] },
            { "reelStops": [23, 1, 128, 51, 37], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [100, 126, 8, 80, 77], "totalWin": 0, "wins": [] },
            { "reelStops": [69, 80, 110, 73, 8], "totalWin": 0, "wins": [] },
            { "reelStops": [55, 44, 80, 75, 45], "totalWin": 8.1, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0]], "line": 0, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1], [3, 1]], "line": 1, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0]], "line": 7, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0]], "line": 13, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0]], "line": 16, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [95, 85, 46, 12, 57], "totalWin": 0, "wins": [] },
            { "reelStops": [115, 35, 96, 55, 96], "totalWin": 1.68, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [75, 99, 87, 13, 125], "totalWin": 3.84, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [71, 92, 92, 71, 72], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [7, 92, 127, 97, 44], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1], [3, 1]], "line": 1, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2], [3, 1]], "line": 14, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2], [3, 1]], "line": 17, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [42, 35, 4, 95, 91], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [37, 110, 38, 56, 50], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [114, 3, 63, 56, 114], "totalWin": 4.56, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2], [3, 2]], "line": 9, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3], [3, 2]], "line": 15, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [95, 4, 125, 36, 53], "totalWin": 0, "wins": [] },
            { "reelStops": [43, 83, 5, 17, 99], "totalWin": 3.36, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [13, 46, 30, 98, 90], "totalWin": 0, "wins": [] },
            { "reelStops": [14, 122, 9, 58, 120], "totalWin": 0, "wins": [] },
            { "reelStops": [34, 26, 7, 1, 36], "totalWin": 0, "wins": [] },
            { "reelStops": [110, 84, 106, 4, 91], "totalWin": 0, "wins": [] },
            { "reelStops": [70, 27, 87, 122, 77], "totalWin": 0, "wins": [] },
            { "reelStops": [110, 4, 94, 98, 42], "totalWin": 0, "wins": [] },
            { "reelStops": [46, 95, 73, 4, 70], "totalWin": 0, "wins": [] },
            { "reelStops": [7, 99, 4, 16, 30], "totalWin": 0, "wins": [] },
            { "reelStops": [63, 83, 20, 111, 96], "totalWin": 0, "wins": [] },
            { "reelStops": [117, 24, 34, 54, 77], "totalWin": 0, "wins": [] },
            { "reelStops": [6, 30, 23, 104, 76], "totalWin": 0, "wins": [] },
            { "reelStops": [21, 37, 27, 87, 89], "totalWin": 0, "wins": [] },
            { "reelStops": [6, 14, 7, 76, 65], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [87, 111, 77, 30, 24], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [1, 87, 38, 126, 104], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [0, 113, 100, 82, 29], "totalWin": 0, "wins": [] },
            { "reelStops": [79, 92, 35, 54, 102], "totalWin": 1.56, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [62, 74, 78, 28, 63], "totalWin": 0, "wins": [] },
            { "reelStops": [65, 123, 48, 79, 90], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [67, 92, 101, 38, 45], "totalWin": 2.88, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [21, 115, 94, 103, 16], "totalWin": 0, "wins": [] },
            { "reelStops": [66, 14, 72, 13, 49], "totalWin": 0, "wins": [] },
            { "reelStops": [121, 121, 104, 33, 25], "totalWin": 0, "wins": [] },
            { "reelStops": [4, 113, 76, 11, 83], "totalWin": 0, "wins": [] },
            { "reelStops": [24, 51, 21, 54, 65], "totalWin": 10.8, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1], [3, 1]], "line": 1, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2], [3, 1]], "line": 17, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [91, 74, 61, 106, 118], "totalWin": 0, "wins": [] },
            { "reelStops": [96, 33, 45, 113, 25], "totalWin": 0, "wins": [] },
            { "reelStops": [50, 122, 65, 92, 47], "totalWin": 0, "wins": [] },
            { "reelStops": [17, 56, 77, 108, 84], "totalWin": 0, "wins": [] },
            { "reelStops": [120, 83, 117, 42, 30], "totalWin": 0, "wins": [] },
            { "reelStops": [70, 101, 65, 101, 83], "totalWin": 0, "wins": [] },
            { "reelStops": [81, 39, 32, 76, 84], "totalWin": 0, "wins": [] },
            { "reelStops": [38, 26, 48, 47, 113], "totalWin": 0, "wins": [] },
            { "reelStops": [51, 73, 40, 66, 64], "totalWin": 0, "wins": [] },
            { "reelStops": [67, 83, 126, 3, 15], "totalWin": 0, "wins": [] },
            { "reelStops": [46, 96, 124, 45, 47], "totalWin": 0, "wins": [] },
            { "reelStops": [48, 105, 76, 18, 84], "totalWin": 0, "wins": [] },
            { "reelStops": [36, 114, 85, 71, 58], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [86, 56, 8, 98, 84], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [9, 48, 52, 109, 39], "totalWin": 0, "wins": [] },
            { "reelStops": [121, 33, 45, 33, 56], "totalWin": 0, "wins": [] },
            { "reelStops": [59, 72, 91, 105, 70], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [63, 81, 6, 4, 9], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [110, 118, 50, 0, 85], "totalWin": 0, "wins": [] },
            { "reelStops": [63, 80, 71, 116, 25], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0]], "line": 16, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [5, 48, 67, 18, 106], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0]], "line": 0, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0]], "line": 7, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [11, 17, 36, 4, 99], "totalWin": 0, "wins": [] },
            { "reelStops": [0, 48, 66, 3, 6], "totalWin": 0, "wins": [] },
            { "reelStops": [26, 18, 21, 102, 87], "totalWin": 0, "wins": [] },
            { "reelStops": [33, 83, 119, 118, 117], "totalWin": 0, "wins": [] },
            { "reelStops": [118, 23, 1, 79, 37], "totalWin": 4.8, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [22, 57, 15, 3, 31], "totalWin": 0, "wins": [] },
            { "reelStops": [90, 33, 15, 3, 128], "totalWin": 0, "wins": [] },
            { "reelStops": [15, 3, 101, 57, 91], "totalWin": 0, "wins": [] },
            { "reelStops": [126, 121, 10, 33, 26], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [124, 123, 43, 116, 108], "totalWin": 0, "wins": [] },
            { "reelStops": [42, 17, 27, 55, 79], "totalWin": 0, "wins": [] },
            { "reelStops": [25, 36, 14, 17, 68], "totalWin": 0, "wins": [] },
            { "reelStops": [119, 4, 82, 27, 40], "totalWin": 0, "wins": [] },
            { "reelStops": [2, 44, 23, 31, 114], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [129, 13, 14, 11, 70], "totalWin": 0, "wins": [] },
            { "reelStops": [85, 87, 32, 84, 12], "totalWin": 1.44, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [109, 69, 68, 106, 11], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [62, 24, 8, 71, 88], "totalWin": 0, "wins": [] },
            { "reelStops": [17, 22, 41, 3, 7], "totalWin": 4.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0], [4, 1]], "line": 7, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0]], "line": 0, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [75, 29, 123, 37, 114], "totalWin": 0, "wins": [] },
            { "reelStops": [125, 121, 4, 85, 17], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [86, 82, 108, 3, 37], "totalWin": 1.8, "wins": [{ "winningSymbols": [[0, 0], [1, 1], [2, 0], [3, 1]], "line": 10, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0], [3, 1]], "line": 19, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [125, 119, 120, 120, 0], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [123, 15, 48, 43, 4], "totalWin": 0, "wins": [] },
            { "reelStops": [81, 100, 55, 97, 129], "totalWin": 0, "wins": [] },
            { "reelStops": [112, 67, 30, 79, 91], "totalWin": 0, "wins": [] },
            { "reelStops": [95, 96, 66, 114, 79], "totalWin": 0, "wins": [] },
            { "reelStops": [121, 40, 30, 30, 92], "totalWin": 0, "wins": [] },
            { "reelStops": [13, 108, 93, 111, 28], "totalWin": 0, "wins": [] },
            { "reelStops": [22, 83, 86, 10, 105], "totalWin": 0, "wins": [] },
            { "reelStops": [111, 58, 118, 37, 104], "totalWin": 0, "wins": [] },
            { "reelStops": [55, 64, 23, 68, 103], "totalWin": 0, "wins": [] },
            { "reelStops": [98, 48, 23, 124, 125], "totalWin": 0, "wins": [] },
            { "reelStops": [78, 96, 108, 92, 45], "totalWin": 3.6, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0]], "line": 13, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1]], "line": 11, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [92, 30, 104, 105, 128], "totalWin": 0, "wins": [] },
            { "reelStops": [23, 49, 25, 67, 33], "totalWin": 0, "wins": [] },
            { "reelStops": [45, 91, 24, 58, 5], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [91, 82, 51, 68, 22], "totalWin": 0, "wins": [] },
            { "reelStops": [61, 46, 109, 29, 38], "totalWin": 0, "wins": [] },
            { "reelStops": [77, 104, 42, 77, 22], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [36, 97, 11, 76, 96], "totalWin": 0, "wins": [] },
            { "reelStops": [24, 82, 54, 125, 109], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1]], "line": 20, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [79, 4, 49, 37, 3], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [105, 19, 2, 63, 118], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [49, 88, 104, 112, 98], "totalWin": 0, "wins": [] },
            { "reelStops": [12, 107, 119, 35, 28], "totalWin": 0, "wins": [] },
            { "reelStops": [80, 22, 111, 106, 109], "totalWin": 2.16, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [84, 36, 52, 21, 67], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [93, 33, 118, 94, 36], "totalWin": 0, "wins": [] },
            { "reelStops": [86, 125, 113, 58, 43], "totalWin": 4.2, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0], [4, 1]], "line": 13, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [53, 68, 65, 10, 84], "totalWin": 7.92, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1], [4, 2]], "line": 8, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2], [3, 1], [4, 2]], "line": 14, "winType": "line", "winAmount": 3, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [79, 120, 117, 102, 50], "totalWin": 0, "wins": [] },
            { "reelStops": [106, 76, 55, 70, 59], "totalWin": 0, "wins": [] },
            { "reelStops": [18, 113, 10, 43, 126], "totalWin": 0, "wins": [] },
            { "reelStops": [36, 55, 53, 10, 5], "totalWin": 5.7, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 1], [3, 1]], "line": 1, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1], [3, 1]], "line": 4, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2], [3, 2]], "line": 5, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 1], [3, 2]], "line": 11, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2], [3, 1]], "line": 17, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [84, 18, 1, 91, 9], "totalWin": 0, "wins": [] },
            { "reelStops": [74, 13, 48, 7, 0], "totalWin": 0, "wins": [] },
            { "reelStops": [15, 20, 22, 123, 66], "totalWin": 0, "wins": [] },
            { "reelStops": [3, 118, 38, 20, 26], "totalWin": 0, "wins": [] },
            { "reelStops": [62, 1, 46, 37, 18], "totalWin": 6.9, "wins": [{ "winningSymbols": [[0, 0], [1, 0], [2, 0], [3, 0]], "line": 0, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 0], [3, 0]], "line": 7, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2], [3, 2]], "line": 2, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2], [3, 2]], "line": 9, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2], [3, 1]], "line": 14, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 1], [3, 2]], "line": 20, "winType": "line", "winAmount": 0.9, "featureFlags": [] }] },
            { "reelStops": [61, 47, 37, 94, 68], "totalWin": 2.76, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [55, 37, 115, 33, 76], "totalWin": 0, "wins": [] },
            { "reelStops": [8, 83, 74, 34, 91], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 0], [2, 1]], "line": 13, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1]], "line": 16, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 2]], "line": 17, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [110, 54, 128, 52, 25], "totalWin": 1.68, "wins": [{ "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 2], [2, 2]], "line": 5, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [123, 95, 55, 19, 113], "totalWin": 7.8, "wins": [{ "winningSymbols": [[0, 3], [1, 3], [2, 3], [3, 3]], "line": 3, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3]], "line": 6, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2], [3, 3]], "line": 12, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2], [3, 3]], "line": 21, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 2]], "line": 14, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [37, 47, 6, 92, 54], "totalWin": 0, "wins": [] },
            { "reelStops": [124, 90, 120, 114, 100], "totalWin": 1.2, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [52, 22, 67, 78, 70], "totalWin": 0, "wins": [] },
            { "reelStops": [76, 20, 58, 92, 20], "totalWin": 0.96, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [96, 36, 7, 20, 18], "totalWin": 0, "wins": [] },
            { "reelStops": [10, 55, 113, 100, 73], "totalWin": 0.48, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [122, 117, 109, 108, 77], "totalWin": 0, "wins": [] },
            { "reelStops": [47, 111, 25, 19, 69], "totalWin": 2.4, "wins": [{ "winningSymbols": [[0, 1], [1, 0], [2, 1], [3, 0]], "line": 13, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 0], [2, 1], [3, 0]], "line": 16, "winType": "line", "winAmount": 1.2, "featureFlags": [] }] },
            { "reelStops": [115, 102, 32, 118, 57], "totalWin": 5.04, "wins": [{ "winningSymbols": [[0, 2], [1, 1], [2, 1], [3, 1]], "line": 8, "winType": "line", "winAmount": 1.2, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 2]], "line": 2, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 3]], "line": 3, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 3]], "line": 6, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 2]], "line": 9, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 3], [2, 2]], "line": 12, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 3], [2, 2]], "line": 21, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [23, 21, 32, 105, 61], "totalWin": 3, "wins": [{ "winningSymbols": [[0, 1], [1, 1], [2, 1]], "line": 1, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 1]], "line": 4, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 1], [2, 1]], "line": 8, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 0], [1, 1], [2, 0]], "line": 10, "winType": "line", "winAmount": 0.6, "featureFlags": [] }, { "winningSymbols": [[0, 1], [1, 1], [2, 0]], "line": 19, "winType": "line", "winAmount": 0.6, "featureFlags": [] }] },
            { "reelStops": [124, 109, 93, 58, 6], "totalWin": 0, "wins": [] },
            { "reelStops": [68, 23, 119, 68, 15], "totalWin": 0, "wins": [] },
            { "reelStops": [63, 113, 82, 97, 55], "totalWin": 0, "wins": [] },
            { "reelStops": [76, 109, 49, 113, 86], "totalWin": 1.38, "wins": [{ "winningSymbols": [[0, 3], [1, 2], [2, 2], [3, 2]], "line": 9, "winType": "line", "winAmount": 0.9, "featureFlags": [] }, { "winningSymbols": [[0, 3], [1, 2], [2, 3]], "line": 15, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] },
            { "reelStops": [53, 102, 8, 77, 111], "totalWin": 2.28, "wins": [{ "winningSymbols": [[0, 2], [1, 3], [2, 3], [3, 3], [4, 2]], "line": 6, "winType": "line", "winAmount": 1.8, "featureFlags": [] }, { "winningSymbols": [[0, 2], [1, 2], [2, 3]], "line": 18, "winType": "line", "winAmount": 0.48, "featureFlags": [] }] }
        ];
    }
}


ProjectCode/GrpcConnection.js
------------------------------------------------------------
CODE.includeIf___EgmPublish;
class GrpcConnection {
    constructor() { }
    async init() {
        await this.beginHandlingRequestsFromRemoteProcess();
    }
    // call this with 'await' to make a request of the associated remote process and wait for the response
    async makeRequestToRemoteProcess(request) {
        let response = await window["GrpcService"].requestAndResponse(JSON.stringify(request));
        if (response.type === "error") {
            console.log("Error performing GRPC requestAndResponse: " + JSON.stringify(response.value));
        }
        else if (response.type === "data") {
            return JSON.parse(response.value.message);
        }
    }
    // this method (which is automatically invoked upon 'init'), opens the connection with the associated remote process, enabling it to trigger the 'handleRequestFromRemoteProcess' method below.
    async beginHandlingRequestsFromRemoteProcess() {
        let resultStringified = await window["GrpcService"].createTwoWayStream();
        let result = JSON.parse(resultStringified);
        window["GrpcService"].setResponseCallback((event) => this.handleRequestFromRemoteProcess(event));
        return (result);
    }
    // populate this method with the functionality to react to any requests that could come from the associated remote process
    handleRequestFromRemoteProcess(event) {
        if (event === undefined) {
            console.log("undefined response event");
        }
        else {
            if (event.type === "data") {
                if (event.value.message === "spin") {
                    pr.mainPlayerInput();
                }
            }
            else if (event.type === "error") {
                console.log("Unknown error occured: " + event.value.code);
            }
            else if (event.type === "status") {
                if (event.value.code === 14) {
                    console.log("Input server unavailable: " + event.value.details);
                }
                else {
                    console.log("Unknown status change occured");
                }
            }
            else if (event.type === "end") {
                console.log("End occured");
            }
            else {
                console.log("Unknown event type:" + event.type);
            }
        }
    }
}
CODE.includeEnd___EgmPublish;


ProjectCode/Payline.js
------------------------------------------------------------
/** Dynamic payline object that generates a series of line segments (GraphicObjects with the 'StretchBetween' CustomAddOns),
 * that are dynamically stretched to span between symbol positions to form the given payline.
 */
class Payline extends SceneObject {
    constructor(parent, name) {
        super(parent, name);
        this.paylineSegments = [];
        this.stretchBetweenAddOns = [];
        this.paylineData = gameSystemManager.initialGameLogicData.paylines;
        // create the payline segments
        for (let i = 0; i <= pr.symbolReels.length; i++) {
            let newPaylineSegment = new GraphicObject(nc.graphicAssets.SampleParticle, this, "PaylineSegment" + i);
            // set the layer and sub-layer of the payline
            newPaylineSegment.layer = nc.layers.Reels;
            newPaylineSegment.subLayer = .5;
            // change the blending mode to 'add'
            newPaylineSegment.materialMaster.blending = constants.blendingModes.add;
            // add the 'StretchBetween' CustomAddOn
            let newStretchBetweenAddOn = new StretchBetween2D(newPaylineSegment);
            newStretchBetweenAddOn.firstPointBuffer = 5;
            newStretchBetweenAddOn.secondPointBuffer = 5;
            this.stretchBetweenAddOns.push(newStretchBetweenAddOn);
        }
        this.displayPayline(0, 0, 0);
        this.enabled = false;
    }
    displayPayline(paylineNumber, motionDuration, fadeDuration) {
        if (motionDuration === undefined) {
            motionDuration = 0;
        }
        this.enabled = true;
        this.colorMultiply.swoop.alpha(0, 0);
        this.colorMultiply.swoop.alpha(1, fadeDuration);
        let globalSymbolPositions = [];
        // first get global position
        for (let i = 0; i < pr.symbolReels.length; i++) {
            let symbol = pr.symbolReels[i].getSymbol(this.paylineData[paylineNumber][i]);
            globalSymbolPositions.push(symbol.getGlobalPosition());
        }
        // left line tab
        let posx = globalSymbolPositions[0].x;
        let posy = globalSymbolPositions[0].y;
        let tweenType = nc.tweenTypes.ExtremeEaseIn;
        let addOn = this.stretchBetweenAddOns[0];
        nc.swoopValue(addOn, "firstPointX", posx - 250, motionDuration, tweenType);
        nc.swoopValue(addOn, "firstPointY", posy, motionDuration, tweenType);
        nc.swoopValue(addOn, "secondPointX", posx, motionDuration, tweenType);
        nc.swoopValue(addOn, "secondPointY", posy, motionDuration, tweenType);
        // right line tab
        let idx = pr.symbolReels.length - 1;
        posx = globalSymbolPositions[idx].x;
        posy = globalSymbolPositions[idx].y;
        addOn = this.stretchBetweenAddOns[idx + 1];
        nc.swoopValue(addOn, "firstPointX", posx + 250, motionDuration, tweenType);
        nc.swoopValue(addOn, "firstPointY", posy, motionDuration, tweenType);
        nc.swoopValue(addOn, "secondPointX", posx, motionDuration, tweenType);
        nc.swoopValue(addOn, "secondPointY", posy, motionDuration, tweenType);
        // position all of the segments between the symbols
        for (let i = 0; i < pr.symbolReels.length - 1; i++) {
            addOn = this.stretchBetweenAddOns[i + 1];
            nc.swoopValue(addOn, "firstPointX", globalSymbolPositions[i].x, motionDuration, tweenType);
            nc.swoopValue(addOn, "firstPointY", globalSymbolPositions[i].y, motionDuration, tweenType);
            nc.swoopValue(addOn, "secondPointX", globalSymbolPositions[i + 1].x, motionDuration, tweenType);
            nc.swoopValue(addOn, "secondPointY", globalSymbolPositions[i + 1].y, motionDuration, tweenType);
        }
    }
}


ProjectCode/ProjectMain.js
------------------------------------------------------------
// This is the main entry point for this Incisor® project. 
// Throughout the project, this object can be referenced as 'pr'.
var gameSystemManager;
class ProjectMain {
    async init() {
        // create a shortcut to the gameSystemManager
        gameSystemManager = new GameSystemManager();
        await gameSystemManager.init();
        await gameSystemManager.fetchGameSystemInfo();
        // put the main camera into 'maximizeSafeZone' mode
        nc.mainCamera.adaptiveCameraMode = constants.adaptiveCameraModes.maximizeSafeZone;
        // setup main GameLayout Construct
        this.gameLayout = nc.constructDefs.GameLayout.add(nc.mainScene, "GameLayout");
        // create shortcut to Dashboard
        this.dashboard = this.gameLayout.descendantsByName.Dashboard;
        // make the gamelayout view area invisible
        this.gameLayout.descendantsByName.ViewArea.enabled = false;
        // enable game intro brackground immediately, and add press callback
        this.gameLayout.descendantsByName.GameIntroBackground.enable();
        // add callback for keyDown 
        nc.appEvents.keyDown.addCallback(this, "keyDownCallback");
        // create canvas resize callback to adjust the aspect ratio of the GameLayout Construct
        nc.appEvents.canvasResize.addCallback(this, "adjustGameLayout");
        this.adjustGameLayout();
        // create instance of DashboardManager
        this.dashboardManager = new DashboardManager();
        // set bet and balance
        this.dashboard.descendantsByName.BetMeter.string = gameSystemManager.formatCurrency(gameSystemManager.currentBet);
        this.dashboard.descendantsByName.BalanceMeter.string = gameSystemManager.formatCurrency(gameSystemManager.currentBalance);
        // the SymbolReels are laid out within the GameLayout Construct, so they are collected rather than created here
        this.symbolReels = [];
        for (let i = 0; i < gameSystemManager.initialGameLogicData.reelData.length; i++) {
            let symbolReel = this.gameLayout.descendantsByName["SymbolReel" + i];
            // supply the symbol class, which replaces the stand-in symbols the reel was laid out with
            symbolReel.symbolClassDefinition = ReelSymbol;
            // the game system supplies a full reel strip, so the reel does not assemble its data as it spins
            symbolReel.assembleReelDataOnTheFly = false;
            symbolReel.setReelData(gameSystemManager.initialGameLogicData.reelData[i]);
            symbolReel.addReelStateChangeCallback(this, "reelStateChangeCallback", i);
            this.symbolReels.push(symbolReel);
        }
        // create Payline
        this.payline = new Payline(nc.mainScene, "Payline");
        // create main game FlowController
        nc.defineFlowController("MainGameFlow");
        nc.flows.MainGameFlow.addFlowState(GameIntro);
        nc.flows.MainGameFlow.addFlowState(GameIdle);
        nc.flows.MainGameFlow.addFlowState(StartGame);
        nc.flows.MainGameFlow.addFlowState(SpinReels);
        nc.flows.MainGameFlow.addFlowState(WinCelebration);
        nc.flows.MainGameFlow.GameIntro.setToCurrentState(true);
    }
    adjustGameLayout() {
        // acquire aspect ratio
        let canvasResolution = nc.getCanvasPixelResolution();
        let aspectRatio = canvasResolution.x / canvasResolution.y;
        // set GameLayout construct's time based on aspect ratio
        let timeValue = aspectRatio;
        if (aspectRatio <= 1) {
            timeValue = -1 / aspectRatio;
        }
        this.gameLayout.timelines.BaseLayout_Desktop.time = timeValue;
        this.gameLayout.timelines.BaseLayout_EgmDualScreen.time = timeValue;
        this.gameLayout.timelines.BaseLayout_EgmSingleScreen.time = timeValue;
        this.gameLayout.timelines.BaseLayout_Mobile.time = timeValue;
        // determine which layout to use
        let isEGM = false;
        CODE.includeIf___EgmPublish;
        isEGM = true;
        CODE.includeEnd___EgmPublish;
        let isDualScreen = false;
        CODE.includeIf___isDualScreen;
        isDualScreen = true;
        CODE.includeEnd___isDualScreen;
        if (!isEGM) {
            if (nc.cursorMode === "touch") {
                this.gameLayout.timelines.BaseLayout_Mobile.takeWeight(0);
            }
            else {
                this.gameLayout.timelines.BaseLayout_Desktop.takeWeight(0);
            }
        }
        else {
            if (isDualScreen) {
                this.gameLayout.timelines.BaseLayout_EgmDualScreen.takeWeight(0);
            }
            else {
                this.gameLayout.timelines.BaseLayout_EgmSingleScreen.takeWeight(0);
            }
        }
    }
    keyDownCallback(event) {
        if (event.key === " ") {
            this.mainPlayerInput();
        }
    }
    mainPlayerInput() {
        // if in GameIdle, move to StartGame FlowState
        if (nc.flows.MainGameFlow.currentFlowState.name === "GameIdle") {
            nc.flows.MainGameFlow.StartGame.setToCurrentState(true);
        }
        // if in SpinReels, and if the conditions are met, slam the reels
        if (nc.flows.MainGameFlow.currentFlowState.name === "SpinReels") {
            // slam the reels if the game outcome has been populated 
            if (gameSystemManager.currentGameOutcome !== undefined && nc.flows.MainGameFlow.SpinReels.allReelsHaveStarted === true) {
                for (let i = 0; i < pr.symbolReels.length; i++) {
                    pr.symbolReels[i].slam();
                }
            }
        }
        // if in WinCelebration, slam the win meter if it's rolling, otherwise move to StartGame FlowState
        if (nc.flows.MainGameFlow.currentFlowState.name === "WinCelebration") {
            // slam the win meters if needed
            if (nc.flows.MainGameFlow.WinCelebration.winRollupAmount !== gameSystemManager.currentGameOutcome.totalWin) {
                nc.flows.MainGameFlow.WinCelebration.winRollupComplete();
            }
            // move to StartGame FlowState
            else {
                nc.flows.MainGameFlow.WinCelebration.cleanUpWinCelebration();
                nc.flows.MainGameFlow.StartGame.setToCurrentState(true);
            }
        }
    }
    processNewGameOutcome() {
        // inform the symbol reels of their target stops
        for (let i = 0; i < pr.symbolReels.length; i++) {
            pr.symbolReels[i].setTarget(gameSystemManager.currentGameOutcome.reelStops[i]);
        }
        // sync the balance meter 
        let newBalanceString = gameSystemManager.formatCurrency(gameSystemManager.currentBalance);
        pr.gameLayout.descendantsByName.Dashboard.descendantsByName.BalanceMeter.string = newBalanceString;
    }
    reelStateChangeCallback(newState, oldState, reelIndex) {
        if (newState === "bounce") {
            nc.sounds.ReelStop.playOnce();
        }
    }
}


ProjectCode/ReelSymbol.js
------------------------------------------------------------
/** The symbol class for the SymbolReels laid out in the GameLayout Construct. A SymbolReel constructs one of these
 * for every position on its reel path, and calls 'setSymbol' whenever the symbol a given object represents changes.
 * The class is handed to each reel in code, through 'SymbolReel.symbolClassDefinition'.
 */
class ReelSymbol extends GraphicObject {
    constructor(parent, name) {
        // a SymbolReel constructs its symbols with a parent and a name only, so the graphic arrives through 'setSymbol'
        super(undefined, parent, name);
        // make the symbol 'masked' by the ReelMask masking group
        this.masking.makeMasked(nc.maskGroups.ReelMask, false);
        this.layer = nc.layers.Reels;
        // give the symbol a BrightnessContrast EffectNode for easy 'dimming'
        this.setEffectNodes([nc.effectNodes.SampleMainTexture, nc.effectNodes.ColorMultiply, nc.effectNodes.BrightnessContrast]);
    }
    // called by the owning SymbolReel whenever the symbol this object represents changes
    setSymbol(symbol) {
        // a reel position with no data, or a symbol naming no GraphicAsset, falls back to the WhiteBox so the reel stays visible
        let graphicAsset;
        if (symbol !== undefined) {
            graphicAsset = nc.graphicAssets[symbol];
        }
        if (graphicAsset === undefined) {
            graphicAsset = nc.graphicAssets.WhiteBox;
        }
        this.setGraphicAsset(graphicAsset, true, false);
    }
}


Utilities/AuxiliaryPublishingSupport/ElectronEgmPublish/ElectronMain/ElectronMain.js
------------------------------------------------------------
// a new set of parameters is populated based on the given 'auxiliaryPublishingPackage' as defined in the Incisor ProjectSettings
var incisorBrowserWindowParameters = IncisorBrowserParameters; // these are populated by Incisor from the associated auxiliaryPublishingPackages

const { app, BrowserWindow} = require('electron');
const path = require('path');
const url = require('url');
var win;

function createWindow() 
{
    incisorBrowserWindowParameters.webPreferences.preload = path.join(__dirname, 'preload.js');
    incisorBrowserWindowParameters.show = false;

    // the window is created
    win = new BrowserWindow(incisorBrowserWindowParameters);
    win.setAlwaysOnTop(incisorBrowserWindowParameters.alwaysOnTop, incisorBrowserWindowParameters.level);
    win.setVisibleOnAllWorkspaces(incisorBrowserWindowParameters.visibleOnAllWorkspaces); 
    

    // load the page created
    win.loadURL
    (
        url.format
        (
            {
                pathname: path.join(__dirname, 'index.html'),
                protocol: 'file',
                slashes: true
            }
        )
    );

    // window positioning
    var windowPositioning = function () 
    {
        const bp = incisorBrowserWindowParameters;

        win.show();
        // win.setMenuBarVisibility(false); - this may be needed by some implementation of linux

        // set capabilities first
        win.setResizable(true);
        win.setMovable(true);
        win.setFullScreenable(true);

        // bounds only if not entering any fullscreen-like mode
        const wantsFullscreen = !!bp.postDelayFullscreen;
        const wantsKiosk = !!bp.postDelayKiosk;
        const wantsSimple = !!bp.postDelaySimpleFullscreen && process.platform === "darwin";

        if (!wantsFullscreen && !wantsKiosk && !wantsSimple) 
        {
            win.setBounds({ x: bp.postDelayX, y: bp.postDelayY, width: bp.postDelayWidth, height: bp.postDelayHeight });
        }

        // only call the mode we want
        if (wantsKiosk) {win.setKiosk(true);} 
        else if (wantsSimple) {win.setSimpleFullScreen(true);} 
        else if (wantsFullscreen) 
        {
            win.setFullScreen(true);
            // setImmediate(() => win.setFullScreen(true));
        } 
        else 
        {
            // optionally ensure we aren't in any mode
            win.setFullScreen(false);
            if (process.platform === "darwin") win.setSimpleFullScreen(false);
            win.setKiosk(false);
        }

        // now apply final locks
        win.setFullScreenable(bp.postDelayFullscreenable);
        win.setResizable(bp.postDelayResizable);
        win.setMovable(bp.postDelayMovable);
        win.setMenuBarVisibility(bp.postDelayMenuBarVisible);
        win.setAutoHideMenuBar(bp.postDelayAutoHideMenuBar);
    };

    // function called when window is ready to show
    var readyToShowFunction = function()
    {
        setTimeout(windowPositioning, incisorBrowserWindowParameters.windowPositionDelay, [win,incisorBrowserWindowParameters] );
    };
    win.once('ready-to-show',readyToShowFunction);

    // set win to null on close
    win.on('closed', ()=>{win = null;});
}

app.on('ready', createWindow);

app.on('window-all-closed', () => {app.quit();});

app.on('activate', () => { if (win === null) {createWindow();}});


// a simple example of a context (right click) menu.
if(incisorBrowserWindowParameters.enableContextMenu===true)
{
    const {Menu} = require('electron');
    const contextMenu = Menu.buildFromTemplate([
            { label: 'Inspect Element', click() { win.webContents.openDevTools(); } },
            { label: 'Reload', click() { win.reload(); } },
            { type: 'separator' },
            { label: 'Close', click() { win.close(); } }
        ]);

    function registerContextMenu()
    {
        if (win) { win.webContents.on('context-menu', (e, params) => { contextMenu.popup({ window: win }); }); }
    }

    app.on('ready', registerContextMenu);
}





Utilities/AuxiliaryPublishingSupport/ElectronEgmPublish/ElectronMain/GRPC.js
------------------------------------------------------------
const { ipcMain } = require('electron');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
let service;
let twoWayStream;


ipcMain.handle('GrpcService.requestAndResponse', async (event, args) => {
    let promise = new Promise((resolve, reject) => {
        service.requestAndResponse(args,
            (err, response) => {
                if (err)
                {
                    return reject({value: err, type: "error"});
                }
                resolve({value: response, type: "data"});
            }
        );
    });
    try
    {
        let response = await promise;
        return response;
    }
    catch (error)
    {
        return error;
    }
});


ipcMain.handle('GrpcService.createTwoWayStream', async (event, args) => {
    twoWayStream = service.createTwoWayStream(args,
        (err, response) => {}
    );
    try
    {
        twoWayStream.on('data', async value => {
            win.webContents.send("GrpcService.message", {value:value, type:'data'});
        });
        twoWayStream.on('error', async value => {
            win.webContents.send("GrpcService.message", {value:value, type:'error'});
        });
        twoWayStream.on('status', async value => {
            win.webContents.send("GrpcService.message", {value:value, type:'status'});
        });
        twoWayStream.on('end', async value => {
            win.webContents.send("GrpcService.message", {value:value, type:'end'});
        });
        return true;
    }
    catch (error)
    {
        return error;
    }
});


function createGrpcClient()
{
    let loadParams = {
        keepCase: true,
        longs: String,
        enums: String,
        defaults: true,
        oneofs: true,
    };
    const grpcConnectionPackageDefinitionString = protoLoader.loadSync(path.join(__dirname,'ConnectionDefinition.proto'), loadParams);
    const grpcConnectionPackageDefinition = grpc.loadPackageDefinition(grpcConnectionPackageDefinitionString);
    service = new grpcConnectionPackageDefinition.grpcConnection.GrpcService(
        'localhost:50051',
        grpc.credentials.createInsecure()
    );
}
app.on('ready', createGrpcClient);



Utilities/AuxiliaryPublishingSupport/ElectronEgmPublish/ElectronPackage/package.json
------------------------------------------------------------
{
    "name": "IncisorSlotTemplateTS",
    "productName": "Incisor Slot Template TS",
    "version": "1.0.0",
    "description": "Incisor Slot Template TS",
    "author": 
    {
        "name": "Incisor Slot Template TS",
        "email": "dev@example.com"
    },
    "main": "main.js",
    "devDependencies": 
    {
        "electron": "33.0.2",
        "electron-builder": "25.1.8"
    },
    "dependencies": 
    {
        "@grpc/grpc-js": "^1.14.3",
        "@grpc/proto-loader": "^0.8.0"
    },
    "build": 
    {
        "appId": "com.example.IncisorSlotTemplateTS",
        "productName": "IncisorSlotTemplateTS",
        "files": 
        [
            "./**/*",
            "main.js",
            "!publish/"
        ],
        "linux": 
        {
            "target": 
            [
                "AppImage",
                "deb"
            ],
            "category": "Game",
            "maintainer": "IncisorSlotTemplateTS <dev@example.com>"
        },
        "mac":
        {
            "target": ["dmg"]
        },
        "win": 
        {
            "target": ["nsis"]
        }
    }
}

Utilities/AuxiliaryPublishingSupport/ElectronEgmPublish/ElectronPreload/ElectronPreload.js
------------------------------------------------------------
// This preload.js file runs in Electron's renderer process before the web page loads and is 
// used as a secure bridge between the UI and Electron/Node functionality. It is the 
// recommended place to expose a small, controlled API to the renderer (for example via 
// contextBridge) and to set up safe IPC communication with the main process while keeping 
// nodeIntegration disabled and contextIsolation enabled for better security. Only 
// functionality that the renderer truly needs should be exposed here, and it should be done 
// in a way that avoids giving the page direct access to full Node or Electron internals.


const { contextBridge, ipcRenderer, ipcMain } = require('electron');
contextBridge.exposeInMainWorld('GrpcService', {
    createTwoWayStream: async () => { return ipcRenderer.invoke('GrpcService.createTwoWayStream', {}); },
    requestAndResponse: async (message) => { return ipcRenderer.invoke('GrpcService.requestAndResponse', { message }); },
    setResponseCallback: (callback) => ipcRenderer.on('GrpcService.message', (event, ...args) => callback(...args))
});


Utilities/AuxiliaryPublishingSupport/ElectronLocalDev/ElectronMain/ElectronMain.js
------------------------------------------------------------
// a new set of parameters is populated based on the given 'auxiliaryPublishingPackage' as defined in the Incisor ProjectSettings
var incisorBrowserWindowParameters = IncisorBrowserParameters; // these are populated by Incisor from the associated auxiliaryPublishingPackages

const { app, BrowserWindow} = require('electron');
const path = require('path');
const url = require('url');
var win;

function createWindow() 
{
    incisorBrowserWindowParameters.webPreferences.preload = path.join(__dirname, 'preload.js');
    incisorBrowserWindowParameters.show = false;

    // the window is created
    win = new BrowserWindow(incisorBrowserWindowParameters);
    win.setAlwaysOnTop(incisorBrowserWindowParameters.alwaysOnTop, incisorBrowserWindowParameters.level);
    win.setVisibleOnAllWorkspaces(incisorBrowserWindowParameters.visibleOnAllWorkspaces); 
    

    // load the page created
    win.loadURL
    (
        url.format
        (
            {
                pathname: path.join(__dirname, 'index.html'),
                protocol: 'file',
                slashes: true
            }
        )
    );

    // window positioning
    var windowPositioning = function () 
    {
        const bp = incisorBrowserWindowParameters;

        win.show();
        // win.setMenuBarVisibility(false); - this may be needed by some implementation of linux

        // set capabilities first
        win.setResizable(true);
        win.setMovable(true);
        win.setFullScreenable(true);

        // bounds only if not entering any fullscreen-like mode
        const wantsFullscreen = !!bp.postDelayFullscreen;
        const wantsKiosk = !!bp.postDelayKiosk;
        const wantsSimple = !!bp.postDelaySimpleFullscreen && process.platform === "darwin";

        if (!wantsFullscreen && !wantsKiosk && !wantsSimple) 
        {
            win.setBounds({ x: bp.postDelayX, y: bp.postDelayY, width: bp.postDelayWidth, height: bp.postDelayHeight });
        }

        // only call the mode we want
        if (wantsKiosk) {win.setKiosk(true);} 
        else if (wantsSimple) {win.setSimpleFullScreen(true);} 
        else if (wantsFullscreen) 
        {
            win.setFullScreen(true);
            // setImmediate(() => win.setFullScreen(true));
        } 
        else 
        {
            // optionally ensure we aren't in any mode
            win.setFullScreen(false);
            if (process.platform === "darwin") win.setSimpleFullScreen(false);
            win.setKiosk(false);
        }

        // now apply final locks
        win.setFullScreenable(bp.postDelayFullscreenable);
        win.setResizable(bp.postDelayResizable);
        win.setMovable(bp.postDelayMovable);
        win.setMenuBarVisibility(bp.postDelayMenuBarVisible);
        win.setAutoHideMenuBar(bp.postDelayAutoHideMenuBar);
    };

    // function called when window is ready to show
    var readyToShowFunction = function()
    {
        setTimeout(windowPositioning, incisorBrowserWindowParameters.windowPositionDelay, [win,incisorBrowserWindowParameters] );
    };
    win.once('ready-to-show',readyToShowFunction);

    // set win to null on close
    win.on('closed', ()=>{win = null;});
}

app.on('ready', createWindow);

app.on('window-all-closed', () => {app.quit();});

app.on('activate', () => { if (win === null) {createWindow();}});


// a simple example of a context (right click) menu.
if(incisorBrowserWindowParameters.enableContextMenu===true)
{
    const {Menu} = require('electron');
    const contextMenu = Menu.buildFromTemplate([
            { label: 'Inspect Element', click() { win.webContents.openDevTools(); } },
            { label: 'Reload', click() { win.reload(); } },
            { type: 'separator' },
            { label: 'Close', click() { win.close(); } }
        ]);

    function registerContextMenu()
    {
        if (win) { win.webContents.on('context-menu', (e, params) => { contextMenu.popup({ window: win }); }); }
    }

    app.on('ready', registerContextMenu);
}





Utilities/AuxiliaryPublishingSupport/ElectronLocalDev/ElectronPackage/package.json
------------------------------------------------------------
{
    "name": "__PROJECT_CODE_NAME__",
    "productName": "__PROJECT_NAME__",
    "version": "1.0.0",
    "description": "Description for __PROJECT_NAME__",
    "author": 
    {
        "name": "__PROJECT_NAME__",
        "email": "dev@example.com"
    },
    "main": "main.js",
    "devDependencies": 
    {
        "electron": "33.0.2",
        "electron-builder": "^25.1.8"
    },
    "build": 
    {
        "appId": "com.example.__PROJECT_CODE_NAME__",
        "productName": "__PROJECT_CODE_NAME__",
        "files": 
        [
            "./**/*",
            "main.js",
            "!publish/"
        ],
        "linux": 
        {
            "target": 
            [
                "AppImage",
                "deb"
            ],
            "category": "Game",
            "maintainer": "__PROJECT_CODE_NAME__ <dev@example.com>"
        },
        "mac":
        {
            "target": ["dmg"]
        },
        "win": 
        {
            "target": ["nsis"]
        }
    }
}

Utilities/AuxiliaryPublishingSupport/ElectronLocalDev/ElectronPreload/ElectronPreload.js
------------------------------------------------------------
// This preload.js file runs in Electron's renderer process before the web page loads and is 
// used as a secure bridge between the UI and Electron/Node functionality. It is the 
// recommended place to expose a small, controlled API to the renderer (for example via 
// contextBridge) and to set up safe IPC communication with the main process while keeping 
// nodeIntegration disabled and contextIsolation enabled for better security. Only 
// functionality that the renderer truly needs should be exposed here, and it should be done 
// in a way that avoids giving the page direct access to full Node or Electron internals.

// Example uses of context bridge:
// const { contextBridge } = require('electron');
// contextBridge.exposeInMainWorld('preloadObjectExposedOnMainWindow', {"note":"This object has been added to the main window from within the Electron 'preload' context."});
// contextBridge.exposeInMainWorld('preloadFunctionExposedOnMainWindow',  async () => { console.log("This is a preload function made accessable within the main window runtime.");});

Utilities/MinificationLists/DoNotMinifyLists/DoNotMinifyList.json
------------------------------------------------------------
{
	"minificationList":
    [
        "thisSymbolWillNotBeMinified",
        "thisSymbolWillAlsoNotBeMinified"
    ]
}

Utilities/MinificationLists/MinifyLists/MinifyList.json
------------------------------------------------------------
{
	"minificationList":
    [
        "thisSymbolWillBeMinified",
        "thisSymbolWillAlsoBeMinified"
    ]
}

Utilities/ProjectData.json
------------------------------------------------------------
{
	"docFormatVersion":1,
	"dataObjects":[
		{
			"type":"rowData",
			"name":"SymbolHierarchy",
			"id":"7XazMZnZuBaMDdubaieR",
			"tags":[],
			"tables":[
				{
					"name":"mainData",
					"isRowData":true,
					"data":[
						["AMajor1","Major1","Wild",""],
						["AMajor2","Major2","Wild",""],
						["AMajor3","Major3","Wild",""],
						["AMinor1","Minor1","Wild",""],
						["AMinor2","Minor2","Wild",""],
						["AMinor3","Minor3","Wild",""],
						["","","",""]
					]
				}
			]
		},
		{
			"type":"slotReels",
			"name":"Reels",
			"id":"OTGh4TvQi2TyxVcxytI5",
			"tags":[],
			"tables":[
				{
					"name":"distribution",
					"isRowData":false,
					"data":[
						["Symbols","Major1","Major2","Major3","Minor1","Minor2","Minor3","Wild","Bonus","","","","","","",""],
						["Reel0","3","9","3","9","3","9","2","3","","","","","","",""],
						["Reel1","9","3","9","3","9","3","2","0","","","","","","",""],
						["Reel2","3","9","3","9","3","9","2","2","","","","","","",""],
						["Reel3","9","3","9","3","9","3","2","0","","","","","","",""],
						["Reel4","3","9","3","9","3","9","2","1","","","","","","",""]
					]
				},
				{
					"name":"reels",
					"data":[
						[
							"Reel0",
							"Minor1",
							"Major1",
							"Major1",
							"Major1",
							"Minor1",
							"Bonus",
							"Minor3",
							"Bonus",
							"Minor1",
							"Major3",
							"Major3",
							"Major3",
							"Minor3",
							"Minor1",
							"Minor2",
							"Bonus",
							"Minor3",
							"Minor1",
							"Minor3",
							"Minor1",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor3",
							"Minor1",
							"Minor2",
							"Minor1",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor3",
							"Minor1",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor2",
							"Wild",
							"Wild"
						],
						[
							"Reel1",
							"Minor2",
							"Major3",
							"Major3",
							"Major3",
							"Minor3",
							"Major3",
							"Major3",
							"Major3",
							"Minor1",
							"Minor2",
							"Major1",
							"Major1",
							"Major1",
							"Minor2",
							"Minor1",
							"Minor2",
							"Wild",
							"Wild",
							"Minor1",
							"Minor2",
							"Major3",
							"Major3",
							"Major3",
							"Minor2",
							"Major2",
							"Major2",
							"Major2",
							"Minor2",
							"Major1",
							"Major1",
							"Major1",
							"Minor2",
							"Minor3",
							"Major1",
							"Major1",
							"Major1",
							"Minor2",
							"Minor3",
							"",
							"",
							""
						],
						[
							"Reel2",
							"Bonus",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor1",
							"Major1",
							"Major1",
							"Major1",
							"Minor1",
							"Major2",
							"Major2",
							"Major2",
							"Minor3",
							"Minor1",
							"Major2",
							"Major2",
							"Major2",
							"Minor1",
							"Minor3",
							"Wild",
							"Wild",
							"Minor2",
							"Minor1",
							"Major3",
							"Major3",
							"Major3",
							"Minor1",
							"Minor3",
							"Minor1",
							"Bonus",
							"Minor3",
							"Minor1",
							"Minor3",
							"Minor2",
							"Minor3",
							"Minor2",
							"Minor3",
							"Minor1",
							"Minor3",
							""
						],
						[
							"Reel3",
							"Minor2",
							"Minor1",
							"Minor2",
							"Minor1",
							"Wild",
							"Wild",
							"Minor1",
							"Minor3",
							"Minor2",
							"Major3",
							"Major3",
							"Major3",
							"Minor2",
							"Major3",
							"Major3",
							"Major3",
							"Minor2",
							"Minor3",
							"Major1",
							"Major1",
							"Major1",
							"Minor2",
							"Major3",
							"Major3",
							"Major3",
							"Minor2",
							"Major1",
							"Major1",
							"Major1",
							"Minor2",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor2",
							"Major1",
							"Major1",
							"Major1",
							"",
							"",
							""
						],
						[
							"Reel4",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor1",
							"Minor2",
							"Major1",
							"Major1",
							"Major1",
							"Minor3",
							"Minor1",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor3",
							"Minor1",
							"Minor2",
							"Minor1",
							"Minor3",
							"Minor1",
							"Minor2",
							"Wild",
							"Wild",
							"Minor1",
							"Minor3",
							"Major3",
							"Major3",
							"Major3",
							"Minor1",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor3",
							"Minor1",
							"Minor3",
							"Bonus",
							"Minor1",
							"",
							""
						]
					]
				}
			],
			"numReels":5,
			"selfRepelBuffer":1,
			"selfRepelWeight":1,
			"symbolColors":{
				"Major1":{"x":1,"y":0,"z":0},
				"Major2":{"x":1,"y":0,"z":0},
				"Major3":{"x":1,"y":0,"z":0},
				"Wild":{"x":1,"y":0.8532000000000016,"z":0},
				"Bonus":{"x":0.6066666666666667,"y":0.6066666666666667,"z":1}
			},
			"symbolSeparationRules":[
				{
					"symbols":["Major1","Major2","Major3","Wild","Bonus"],
					"reels":["Reel0","Reel1","Reel2","Reel3","Reel4"],
					"bufferSize":1,
					"weight":1
				}
			],
			"symbolStacking":[
				{"symbols":["Major1","Major2","Major3"],"reels":["Reel0","Reel1","Reel2","Reel3","Reel4"],"stackHeight":3},
				{"symbols":["Wild"],"reels":["Reel0","Reel1","Reel2","Reel3","Reel4"],"stackHeight":2}
			],
			"reelsToGenerate":["Reel0","Reel1","Reel2","Reel3","Reel4"]
		},
		{
			"type":"rowData",
			"name":"Pays",
			"id":"Yzzh4Ji4shHwV678tWKN",
			"tags":[],
			"tables":[
				{
					"name":"mainData",
					"isRowData":true,
					"data":[
						["","3 oak","4 oak","5 oak",""],
						["AMajor1","10","25","100",""],
						["AMajor2","10","25","100",""],
						["AMajor3","10","25","100",""],
						["AMinor1","5","15","50",""],
						["AMinor2","5","15","50",""],
						["AMinor3","5","15","50",""],
						["","","","",""]
					]
				}
			]
		},
		{
			"type":"slotPaylines",
			"name":"Paylines",
			"id":"9bNSJwWxdVHc8HdHCzas",
			"tags":[],
			"tables":[
				{
					"name":"paylines",
					"isRowData":true,
					"data":[
						["Payline","Col0","Col1","Col2","Col3","Col4"],
						["payline 0","0","0","0","0","0"],
						["payline 1","0","0","1","0","0"],
						["payline 2","0","0","1","2","2"],
						["payline 3","0","1","0","1","0"],
						["payline 4","0","1","1","1","0"],
						["payline 5","0","1","1","1","2"],
						["payline 6","0","1","2","1","0"],
						["payline 7","1","0","0","0","1"],
						["payline 8","1","0","1","0","1"],
						["payline 9","1","0","1","2","1"],
						["payline 10","1","1","0","1","1"],
						["payline 11","1","1","1","1","1"],
						["payline 12","1","1","2","1","1"],
						["payline 13","1","1","2","3","3"],
						["payline 14","1","2","1","0","1"],
						["payline 15","1","2","1","2","1"],
						["payline 16","1","2","2","2","1"],
						["payline 17","1","2","2","2","3"],
						["payline 18","1","2","3","2","1"],
						["payline 19","2","1","0","1","2"],
						["payline 20","2","1","1","1","0"],
						["payline 21","2","1","1","1","2"],
						["payline 22","2","1","2","1","2"],
						["payline 23","2","1","2","3","2"],
						["payline 24","2","2","1","0","0"],
						["payline 25","2","2","1","2","2"],
						["payline 26","2","2","2","2","2"],
						["payline 27","2","2","3","2","2"],
						["payline 28","2","3","2","1","2"],
						["payline 29","2","3","2","3","2"],
						["payline 30","2","3","3","3","2"],
						["payline 31","3","2","1","2","3"],
						["payline 32","3","2","2","2","1"],
						["payline 33","3","2","2","2","3"],
						["payline 34","3","2","3","2","3"],
						["payline 35","3","3","2","1","1"],
						["payline 36","3","3","2","3","3"],
						["payline 37","3","3","3","3","3"],
						["payline 38","1","1","2","2","2"],
						["payline 39","2","2","1","1","1"]
					]
				},
				{"name":"columnHeights","data":[["Col0","4"],["Col1","4"],["Col2","4"],["Col3","4"],["Col4","4"]]},
				{"name":"columnTopOffsets","data":[["Col0","0"],["Col1","0"],["Col2","0"],["Col3","0"],["Col4","0"]]},
				{"name":"maxLineJump","data":[["Col 0-1","1"],["Col 1-2","1"],["Col 2-3","1"],["Col 3-4","1"]]}
			],
			"numColumns":5,
			"includedSymmetries":["symmetricFlipped","symmetric"]
		}
	],
	"exportSettings":[]
}

Utilities/ProjectState.json
------------------------------------------------------------
{
	"docFormatVersion":0,
	"panelLayout":{
		"subPanels":[
			{
				"subPanels":[
					{
						"subPanels":[
							{"subPanels":[],"panelType":"Object","isColumns":true,"divisionLocation":0.5,"stateInfo":""},
							{"subPanels":[],"panelType":"Hierarchy","isColumns":true,"divisionLocation":0.5,"stateInfo":""}
						],
						"isColumns":false,
						"divisionLocation":0.47747821956596986,
						"stateInfo":""
					},
					{"subPanels":[],"panelType":"Flows","isColumns":true,"divisionLocation":0.5,"stateInfo":""}
				],
				"isColumns":true,
				"divisionLocation":0.47510167727385966,
				"stateInfo":""
			},
			{
				"subPanels":[
					{
						"subPanels":[
							{"subPanels":[],"panelType":"Live View","isColumns":true,"divisionLocation":0.5,"stateInfo":"{}"},
							{
								"subPanels":[],
								"panelType":"Construct",
								"isColumns":true,
								"divisionLocation":0.5,
								"stateInfo":"{\"targetConstructName\":\"Major1Construct\",\"targetViewMode\":\"Editor Mode\",\"targetConstructState\":\"SymbolAnimation\"}"
							}
						],
						"isColumns":true,
						"divisionLocation":0.6774325620451619,
						"stateInfo":""
					},
					{
						"subPanels":[],
						"panelType":"Timeline",
						"isColumns":true,
						"divisionLocation":0.5,
						"stateInfo":"{\"graphModeRows\":{\"Minor1Construct\":{\"SymbolAnimation\":{\"3387500474395755|position.x\":true}}},\"currentTime\":{\"Minor1Construct\":{\"SymbolAnimation\":1.4666666666666444},\"Major1Construct\":{\"SymbolAnimation\":0},\"Major2Construct\":{\"SymbolAnimation\":0.04999999999999179},\"WildConstruct\":{\"SymbolAnimation\":0.5666666666666326},\"Major3Construct\":{\"SymbolAnimation\":0.13974387467482913},\"GameLayout\":{\"BaseLayout_Desktop\":1.4833333333333334,\"BaseLayout_Mobile\":0.6333333333333333,\"BaseLayout_EgmSingleScreen\":0.26666666666666666,\"BaseLayout_EgmDualScreen\":-0.16666666666666666},\"Dashboard\":{\"Layout_Desktop\":-1.5,\"Layout_EGM\":-0.95}},\"scroll\":{\"Dashboard\":{\"Layout_Desktop\":0.09329517767952111,\"Layout_EGM\":0.9497036102650089},\"GameLayout\":{\"BaseLayout_Mobile\":1,\"BaseLayout_Desktop\":1,\"BaseLayout_EgmSingleScreen\":1}},\"constructName\":\"Major1Construct\",\"timelineName\":\"SymbolAnimation\",\"timeView\":{\"Major1Construct\":{\"SymbolAnimation\":{\"left\":-0.1,\"right\":2.1}}}}"
					}
				],
				"isColumns":false,
				"divisionLocation":0.6558493049272016,
				"stateInfo":""
			}
		],
		"isColumns":true,
		"divisionLocation":0.31882927090997254,
		"stateInfo":""
	},
	"selectionState":{"sceneObject":["[[-1,\"Timeline Editor Scene: Major1Construct→SymbolAnimation\"],[0,\"Major1Construct\"]]"]},
	"hierarchyExpansionInfo":{
		"Construct Editor Scene: GameLayout":[
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[1,\"Construct Editor Camera\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[0,\"ViewArea\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[6,\"BackgroundShadow\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[7,\"GameBackgroundPattern\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[0,\"ReelBackground\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[2,\"ReelContainer1\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[5,\"ReelContainer4\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[1,\"BottomBarBackground\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[3,\"SpinButtonContainer\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[1,\"ReelContainer0\"],[0,\"ReelMask\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[2,\"ReelContainer1\"],[0,\"ReelMask\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[3,\"ReelContainer2\"],[0,\"ReelMask\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[4,\"ReelContainer3\"],[0,\"ReelMask\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[5,\"ReelContainer4\"],[0,\"ReelMask\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[0,\"BalanceLabel\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[1,\"BalanceMeter\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[2,\"BetLabel\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[3,\"BetMeter\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[4,\"WinMeter\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[5,\"WinLabel\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[6,\"BottomBarTitle\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[7,\"MenuButton\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[8,\"SoundButton\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[3,\"SpinButtonContainer\"],[0,\"SpinButton\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"]]"
		],
		"Timeline Editor Scene: Dashboard→Layout_Mobile":[
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[10,\"AutplayContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"]]"
		],
		"Construct Editor Scene: Dashboard":[
			"[[-1,\"Construct Editor Scene: Dashboard\"],[1,\"Construct Editor Camera\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[0,\"ViewArea\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[2,\"BottomBarBackground\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[1,\"BalanceLabel\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[2,\"BalanceMeter\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[3,\"BetLabel\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[4,\"BetMeter\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[5,\"WinMeter\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[6,\"WinLabel\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[7,\"BottomBarTitle\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[8,\"MenuButton\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[9,\"SoundButton\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[4,\"SpinButtonContainer\"],[0,\"SpinButton\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[4,\"SpinButtonContainer\"],[0,\"SpinButton\"],[0,\"SpinButtonCenter\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"]]"
		],
		"Construct Editor Scene: GameIntroAnimation":[
			"[[-1,\"Construct Editor Scene: GameIntroAnimation\"],[0,\"GameIntroAnimation\"]]",
			"[[-1,\"Construct Editor Scene: GameIntroAnimation\"],[0,\"GameIntroAnimation\"],[0,\"GameIntroTitle\"]]",
			"[[-1,\"Construct Editor Scene: GameIntroAnimation\"]]"
		],
		"Timeline Editor Scene: GameLayout→BaseLayout_Mobile":[
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"]]"
		],
		"MainScene":[
			"[[-1,\"MainScene\"],[1,\"GameLayout\"]]",
			"[[-1,\"MainScene\"],[1,\"GameLayout\"],[1,\"GameTitleContainer\"]]",
			"[[-1,\"MainScene\"],[1,\"GameLayout\"],[2,\"ReelsContainer\"]]",
			"[[-1,\"MainScene\"]]"
		],
		"Construct Editor Scene: PaylineConstruct":[
			"[[-1,\"Construct Editor Scene: PaylineConstruct\"],[0,\"PaylineConstruct\"]]",
			"[[-1,\"Construct Editor Scene: PaylineConstruct\"]]"
		],
		"Construct Editor Scene: Major1Construct":[
			"[[-1,\"Construct Editor Scene: Major1Construct\"],[0,\"Major1Construct\"]]",
			"[[-1,\"Construct Editor Scene: Major1Construct\"]]"
		],
		"Construct Editor Scene: Major2Construct":[
			"[[-1,\"Construct Editor Scene: Major2Construct\"],[0,\"Major2Construct\"]]",
			"[[-1,\"Construct Editor Scene: Major2Construct\"]]"
		],
		"Construct Editor Scene: Minor3Construct":[
			"[[-1,\"Construct Editor Scene: Minor3Construct\"],[0,\"Minor3Construct\"]]",
			"[[-1,\"Construct Editor Scene: Minor3Construct\"]]"
		],
		"Construct Editor Scene: Major3Construct":[
			"[[-1,\"Construct Editor Scene: Major3Construct\"],[0,\"Major3Construct\"]]",
			"[[-1,\"Construct Editor Scene: Major3Construct\"]]"
		]
	},
	"timelineSceneRepExpansionInfo":{
		"Timeline Editor Scene: GameLayout→BaseLayout":[
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout\"],[1,\"GameLayout\"],[0,\"ViewArea\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout\"],[1,\"GameLayout\"],[1,\"GameTitleContainer\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout\"],[1,\"GameLayout\"],[2,\"ReelsContainer\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout\"],[1,\"GameLayout\"],[2,\"ReelsContainer\"],[1,\"ReelBackground\"]]"
		],
		"Timeline Editor Scene: GameLayout→BaseLayout_Mobile":[
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[0,\"ViewArea\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[1,\"GameTitleContainer\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[0,\"ReelBackground\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[3,\"Dashboard\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[6,\"BackgroundShadow\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[7,\"GameBackgroundPattern\"]]"
		],
		"Timeline Editor Scene: Dashboard→Layout_Mobile":[
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[0,\"ViewArea\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[1,\"MenuBackgroundDimmer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[2,\"BottomBarBackground\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[0,\"BottomBarBorder\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[1,\"BalanceLabel\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[2,\"BalanceMeter\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[3,\"BetLabel\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[4,\"BetMeter\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[5,\"WinMeter\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[6,\"WinLabel\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[7,\"BottomBarTitle\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[8,\"MenuButton\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[9,\"SoundButton\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[10,\"AutplayContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[10,\"AutplayContainer\"],[0,\"Autoplay Button\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[10,\"AutplayContainer\"],[1,\"Autoplay Menu\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[4,\"SpinButtonContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[4,\"SpinButtonContainer\"],[0,\"SpinButton\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[4,\"SpinButtonContainer\"],[0,\"SpinButton\"],[0,\"SpinButtonCenter\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[5,\"MainMenuContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[5,\"MainMenuContainer\"],[0,\"MainMenuBackground\"]]"
		],
		"Timeline Editor Scene: GameIntroAnimation→Intro":[
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Intro\"],[0,\"GameIntroAnimation\"],[0,\"GameIntroTitle\"]]",
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Intro\"],[0,\"GameIntroAnimation\"],[0,\"GameIntroTitle\"],[0,\"PressToContinueText\"]]",
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Intro\"],[0,\"GameIntroAnimation\"],[1,\"GameIntroParticles\"]]"
		],
		"Timeline Editor Scene: GameIntroAnimation→Outro":[
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Outro\"],[0,\"GameIntroAnimation\"],[0,\"GameIntroTitle\"]]",
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Outro\"],[0,\"GameIntroAnimation\"],[0,\"GameIntroTitle\"],[0,\"PressToContinueText\"]]",
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Outro\"],[0,\"GameIntroAnimation\"],[1,\"GameIntroParticles\"]]"
		]
	},
	"animatedPropertyGraphEditorStateInfo":{
		"Timeline Editor Scene: GameLayout→BaseLayout":[],
		"Timeline Editor Scene: GameLayout→BaseLayout_Mobile":[],
		"Timeline Editor Scene: Dashboard→Layout_Mobile":[],
		"Timeline Editor Scene: GameIntroAnimation→Intro":[
			["[[-1,\"Timeline Editor Scene: GameIntroAnimation→Intro\"],[0,\"GameIntroAnimation\"]]","Intro",0],
			["[[-1,\"Timeline Editor Scene: GameIntroAnimation→Intro\"],[0,\"GameIntroAnimation\"]]","Intro",1]
		],
		"Timeline Editor Scene: GameIntroAnimation→Outro":[]
	},
	"assetSelections":[],
	"helloThere":false,
	"spineImportHistory":[],
	"recentPermissions":"v1,pro",
	"publishingPopupStateInfo":{"currentConfiguration":"EgmDualScreenPublish","hostPublishedProject":true}
}

Utilities/ProjectTranscript.json
------------------------------------------------------------
{
	"docFormatVersion":0,
	"transcriptPhrases":{
		"CreditMeterLabel":{"en":"BALANCE","es":"CRÉDITO"},
		"WinMeterLabel":{"en":"WIN","es":"GANANCIA"},
		"BetMeterLabel":{"en":"BET","es":"APUESTA"},
		"BottomBarGameTitle":{"en":"INCISOR 7s™","es":"INCISOR 7s™"},
		"IntroPromptButton":{"en":"PRESS TO CONTINUE","es":"PRESIONE PARA CONTINUAR"},
		"AutoplaySelection":{"en":"{value:nSpins}\nSPINS","es":"{value:nSpins}\nTIRADAS"},
		"AutoplayLabel":{"en":"AUTOPLAY","es":"AUTOJUGAR"}
	}
}

Assets.ncData
------------------------------------------------------------
Deviations from default ncData:

- allowDuplicateRemoval is true instead of the default null.
- assetConfigurationFilters is {} instead of the default null.
- fontFamily is "" instead of the default null.
- imageConfigurations.allowAdditiveTrimBuffer is false instead of the default null.
- imageConfigurations.alphaThreshold is 0.015 instead of the default null.
- imageConfigurations.applyAssetPackageScaling is true instead of the default null.
- imageConfigurations.compression is "paletted" instead of the default null.
- imageConfigurations.downscalingMode is "linear" instead of the default null.
- imageConfigurations.imageScalingAffectsHugging is false instead of the default null.
- imageConfigurations.mirroring is "none" instead of the default null.
- imageConfigurations.pivotPointOffsetX is 0 instead of the default null.
- imageConfigurations.pivotPointOffsetY is 0 instead of the default null.
- imageConfigurations.pivotPointOffsetZ is 0 instead of the default null.
- imageConfigurations.premultiplyAlpha is true instead of the default null.
- imageConfigurations.resolutionScaleX is 1 instead of the default null.
- imageConfigurations.resolutionScaleY is 1 instead of the default null.
- imageConfigurations.shapify is false instead of the default null.
- imageConfigurations.shapifyEdgeRange is 10 instead of the default null.
- imageConfigurations.shapifyOptimizationLevel is 0.85 instead of the default null.
- imageConfigurations.spriteSheet is "" instead of the default null.
- imageConfigurations.spriteSheetDimensionLimit is 2048 instead of the default null.
- imageConfigurations.spriteSheetPlacementBuffer is 2 instead of the default null.
- imageConfigurations.trimBuffer is 2 instead of the default null.
- imageConfigurations.trimMode is "hugged" instead of the default null.
- imageConfigurations.unitsPerPixelX is 1 instead of the default null.
- imageConfigurations.unitsPerPixelY is 1 instead of the default null.
- imageConfigurations.unitsPerPixelZ is 1 instead of the default null.
- imageConfigurations.upscalingMode is "linear" instead of the default null.
- imageConfigurations.wrapModeH is "clamp" instead of the default null.
- imageConfigurations.wrapModeV is "clamp" instead of the default null.
- includeWhenBuilt is true instead of the default null.
- loadingTier is 100 instead of the default null.
- typeFontScale is 5 instead of the default null.

jsconfig.json
------------------------------------------------------------
{
    "exclude": ["Publishing","Utilities/AuxiliaryPublishingSupport"]
}

ProjectSettings.json
------------------------------------------------------------
{"docFormatVersion":0,"publicProjectName":"Incisor Slot Template JS","projectCodeName":"IncisorSlotTemplateJS","latestIncisorVersionSetUsed":"Crimson","latestIncisorVersionUsed":"2026.10.15.09.15.36","requiredPermissions":"proGaming","usingTypescript":false,"assetConfigurationDefinitions":{"assetPackageScale":["100","50"],"soundQuality":["stereo_115","mono_55"],"language":["en","es"]},"assetConfigurationDataOrder":["assetPackageScale","soundQuality","language"],"conditionalCodeTagDefinitions":["LocalDev","WebPublish","EgmPublish","isDualScreen"],"coreCanvasResolutionX":2160,"coreCanvasResolutionY":2160,"canvasTransparency":false,"mainCameraType":"orthographic","maskingMode":"overlapping","defaultTimelineTimeSnap":0.02,"preserveDrawingBuffer":true,"defaultGraphicAssetEffectNodes":["ColorMultiply"],"devModeConfiguration":"LocalDev","configurations":{"LocalDev":{"publishIndexFile":true,"supportedAssetConfigurations":[{"assetPackageScale":"100","soundQuality":"stereo_115","language":"en"}],"conditionalCodeTagsIncluded":["LocalDev"],"optionalCodeModulesExcluded":[],"minification":{"enableMinification":false,"automaticallyMinifyAllKeywords":false,"minifyPrefix":"minify_","minifySuffix":"_minify","doNotMinifyPrefix":"doNotMinify_","doNotMinifySuffix":"_doNotMinify","minifyIncisorApiKeywords":false,"minifyAssetNames":false,"substitutionAssignment":"deterministicRandom","keywordAndStringPairTreatment":"minifyBoth"},"removeComments":false,"removeWhiteSpace":false,"spriteSheetDimensionLimit":4096,"auxiliaryPublishingPackages":[]},"EgmSingleScreenPublish":{"publishIndexFile":true,"supportedAssetConfigurations":[{"assetPackageScale":"100","soundQuality":"stereo_115","language":"en"}],"conditionalCodeTagsIncluded":["EgmPublish"],"optionalCodeModulesExcluded":[],"minification":{"enableMinification":false,"automaticallyMinifyAllKeywords":true,"minifyPrefix":"minify_","minifySuffix":"_minify","doNotMinifyPrefix":"doNotMinify_","doNotMinifySuffix":"_doNotMinify","minifyIncisorApiKeywords":false,"minifyAssetNames":false,"substitutionAssignment":"deterministicRandom","keywordAndStringPairTreatment":"minifyBoth"},"removeComments":false,"removeWhiteSpace":false,"spriteSheetDimensionLimit":4096,"auxiliaryPublishingPackages":["ElectronEgmPublish"]},"EgmDualScreenPublish":{"publishIndexFile":true,"supportedAssetConfigurations":[{"assetPackageScale":"100","soundQuality":"stereo_115","language":"en"}],"conditionalCodeTagsIncluded":["EgmPublish","isDualScreen"],"optionalCodeModulesExcluded":[],"minification":{"enableMinification":false,"automaticallyMinifyAllKeywords":true,"minifyPrefix":"minify_","minifySuffix":"_minify","doNotMinifyPrefix":"doNotMinify_","doNotMinifySuffix":"_doNotMinify","minifyIncisorApiKeywords":false,"minifyAssetNames":false,"substitutionAssignment":"deterministicRandom","keywordAndStringPairTreatment":"minifyBoth"},"removeComments":false,"removeWhiteSpace":false,"spriteSheetDimensionLimit":4096,"auxiliaryPublishingPackages":["ElectronEgmPublish"]}},"auxiliaryPublishingPackageDefinitions":{"electron":{"ElectronLocalDev":{"os":"--win --x64","width":800,"height":800,"x":0,"y":0,"windowPositionDelay":0,"center":false,"minWidth":0,"minHeight":0,"maxWidth":0,"maxHeight":0,"resizable":true,"movable":true,"minimizable":true,"maximizable":true,"closable":true,"focusable":true,"level":"normal","fullscreen":false,"fullscreenable":true,"simpleFullscreen":false,"skipTaskbar":false,"kiosk":false,"icon":"","frame":true,"menuBarVisible":false,"autoHideMenuBar":true,"transparent":false,"type":"normal","backgroundColor":"#FFF","hasShadow":true,"opacity":1,"visualEffectState":"followWindow","darkTheme":false,"vibrancy":"default","zoomToPageWidth":false,"enableContextMenu":false,"incisorFileIoLayer":true,"allowUniversalFileIO":false,"webPreferences":{"nodeIntegration":false,"contextIsolation":true,"enableRemoteModule":false,"preload":"","sandbox":false,"devTools":true,"zoomFactor":1,"javascript":true,"webSecurity":true,"allowRunningInsecureContent":false,"experimentalFeatures":false,"backgroundThrottling":true,"webviewTag":false,"nativeWindowOpen":false,"scrollBounce":false,"offscreen":false,"plugins":false,"webaudio":false,"disableDialogs":false}},"ElectronEgmPublish":{"os":"--win --x64","width":800,"height":800,"x":0,"y":0,"windowPositionDelay":0,"center":false,"minWidth":0,"minHeight":0,"maxWidth":0,"maxHeight":0,"resizable":true,"movable":true,"minimizable":true,"maximizable":true,"closable":true,"focusable":true,"level":"normal","fullscreen":false,"fullscreenable":true,"simpleFullscreen":false,"skipTaskbar":false,"kiosk":false,"icon":"","frame":true,"menuBarVisible":true,"autoHideMenuBar":false,"transparent":false,"type":"normal","backgroundColor":"#FFF","hasShadow":true,"opacity":1,"visualEffectState":"followWindow","darkTheme":false,"vibrancy":"default","zoomToPageWidth":false,"enableContextMenu":true,"incisorFileIoLayer":true,"allowUniversalFileIO":false,"webPreferences":{"nodeIntegration":false,"contextIsolation":true,"enableRemoteModule":false,"preload":"","sandbox":false,"devTools":true,"zoomFactor":1,"javascript":true,"webSecurity":true,"allowRunningInsecureContent":false,"experimentalFeatures":false,"backgroundThrottling":true,"webviewTag":false,"nativeWindowOpen":false,"scrollBounce":false,"offscreen":false,"plugins":false,"webaudio":false,"disableDialogs":false}}}},"autoClearMetaFiles":true,"limitPublishedBuildsKept":0,"enableDynamicDocumentation":true,"screenShotDestination":"ScreenShots","additionalLiveViewModes":["16x9_maximize","9x16_maximize","1920x1080","1080x1920"],"fontDefinitions":[{"fontName":"ThemedFont","kerningAdjustment":0,"lineHeight":600,"characterWidth":90,"alwaysIncludeTheseCharacters":[],"phrasesUsingThisFont":["IntroPromptButton"]},{"fontName":"SampleFont","kerningAdjustment":0,"lineHeight":72,"characterWidth":12,"alwaysIncludeTheseCharacters":[],"phrasesUsingThisFont":["CreditMeterLabel","WinMeterLabel","New Phrase 1","AutoplaySelection","AutoplayLabel"]}],"loadingTierDefinitions":[{"loadingTier":100,"isAutoLoaded":true,"incrementalContentProcessing":false,"assetDataFileSizeLimitKB":800,"performDuplicateRemoval":true}],"fontReduction":{"includeStandardCharactersWhenUnPublished":true,"includeStandardCharactersWhenPublished":true,"includeTranscriptCharacters":true,"limitTranscriptCharactersByLanguage":true,"limitTranscriptCharactersByPhrase":true,"standardFontCharacters":[33,34,35,36,37,38,39,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,8482]}}

ReleaseNotes.json
------------------------------------------------------------
{
    "2026.10.14.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Symbol Constructs added for animation",
                "description":"Each symbol now has a Construct in 'Assets/SymbolConstructs' that recreates its image from separate parts, with a Precomp Camera so it generates a Precomp. The reels still display the symbol images."
            },
            {
                "name":"SymbolAnimation Timelines",
                "description":"Each symbol Construct has a two second 'SymbolAnimation' Timeline, authored with 'bezier' interpolation and Keyframe handles so each property needs only a few Keyframes."
            },
            {
                "name":"Winning symbols play their SymbolAnimation",
                "description":"During a win, WinCelebration swaps each winning symbol to its Construct's Precomp GraphicAsset while the animation plays, then restores the image when it completes and during cleanup. The old win scaling was removed."
            },
            {
                "name":"Symbol masking is turned off while animating",
                "description":"Animating symbols are no longer clipped by the ReelMask. Masking is restored with the symbol image, and the win cleanup re-enables it on every symbol."
            },
            {
                "name":"Fixed some reels not spinning when spins were requested in rapid succession",
                "description":"SpinReels now waits for every reel to be 'stopped' rather than 'bounce', so a new spin can't begin while a reel is still bouncing and ignoring 'beginSpin'."
            }
        ]
    },
    "2026.08.12.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Reels upgraded from SlotReel to SymbolReel",
                "description":"The five reels are now SymbolReels rather than SlotReels. A SymbolReel drives any property of its symbols from a KeyframedValue sampled along the reel path, so the symbol spacing and the reverse shingled sub-layering are authored as curves rather than written in code, and the windup and bounce motion are curves owned by the reel rather than tween functions."
            },
            {
                "name":"The reels are laid out in the GameLayout Construct",
                "description":"Each ReelContainer now holds its own SymbolReel, with its symbol counts, spin speed, windup duration, symbol path and starting symbols all authored in the Construct and editable in the Incisor inspector. ProjectMain collects the reels from the Construct and hands each one its symbol class and its reel strip, rather than building them from scratch."
            },
            {
                "name":"SlotReelSymbol codeAsset replaced by the ReelSymbol class",
                "description":"The symbol class is now an ordinary project class in 'TypescriptProjectCode/ReelSymbol.ts', supplied to each reel through 'SymbolReel.symbolClassDefinition'. It is no longer a CustomObject registered with the Incisor inspector, since a SymbolReel owns and builds its own symbols."
            },
            {
                "name":"The reels are fed a full reel strip",
                "description":"The reels now take their reel strips from the game system through 'setReelData' with 'assembleReelDataOnTheFly' turned off, which is the arrangement that matches a game system supplying stop indices."
            }
        ]
    },
    "2026.03.03.00.00.00":
    {
        "changeList":
        [
            {
                "name":"GRPC Refactored to be Agnostic",
                "description":"For simpler integrations with external systems, now the GRPC just sends any messages between the project and outside GRPC processes generically, with the details of the messaging stored inside of the messages themselves. This way, the GRPC protocol does not need to be edited each time a new type of message is needed, instead the message handling can just be extended directly in each context."
            }
        ]
    },
    "2026.02.07.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Added support auxiliary publishing packages",
                "description":"Added two electron publishing packages to the ProjectSettings.json"
            },
            {
                "name":"Added conditional code to support GRPC server interactions within the EgmPublish configuraiton",
                "description":"Now, initial game info and game outcomes are pulled from a GRPC server when the game is published in the 'EgmPublish' configuration."
            },
            {
                "name":"Added Sample GRPC servers to the auxiliary publishing support directories",
                "description":"These servers, when runnning, will supply the published game (using the 'EgmPublish' config), with it's initial game info and game outcomes."
            }
        ]
    },
    "2026.01.27.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Updates Slot Template Publisher",
                "description":"Certain ts files were being left in the js build - this has been updated."
            },
            {
                "name":"Stray Project Extension Removed",
                "description":"Extra menu that was accidently added has been removed."
            },
            {
                "name":"Minification Settings Restored",
                "description":"Minification settings for the template have been reduced for better 'getting started' setup."
            }
        ]
    },
    "2025.10.23.00.00.00":
    {
        "changeList":
        [
            {
                "name":"The GameLogicManager has become the GameSystemManager",
                "description":"It is now the manager for not just game logic, but also game configurations etc..."
            },
            {
                "name":"Autoplay Functionality Added",
                "description":"Button, menu, options driven by the GameSystemManager, and the actual functionality for autoplay have all been added."
            },
            {
                "name":"Main Menu Stub Added",
                "description":"Now you can press the button to see a main menu stub."
            }
        ]
    },
    "2025.10.19.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Translated 'PRESS TO CONTINUE'",
                "description":"Now using the transcript..."
            }
        ]
    },
    "2025.10.15.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Updated GameLogicManager/LocalGameServiceStub Interface",
                "description":"In order to provide a better example of how the GameLogicManager communicates with externally fetched items."
            },
            {
                "name":"Changed the SlotReels to use CustomObjects instead of CustomAddons",
                "description":"By request to make a cleaner and less verbose implementation."
            }
        ]
    },
    "2025.09.30.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Added Initial Translations.",
                "description":"For basic dashboard items."
            }
        ]
    },
    "2025.09.29.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Added the Payline class and implementation.",
                "description":"Using the 'StretchBetween2d' CustomAddOn..."
            }
        ]
    }
}












----------------------------------------------------------
Section 3: IncisorSlotTemplateTS_textMap
----------------------------------------------------------


INCISOR PROJECT PLAIN TEXT MAP
============================================================
Project: Incisor Slot Template TS
Generated: 2026-11-03T17:34:38.727Z
Project Language: TypeScript

Excluded:
- AssetCache and its contents
- Publishing
- AutoSave
- IncisorAPI.js
- IncisorAPI.d.ts
- ProjectCode file contents omitted because ProjectSettings.usingTypescript is true
- Additional file contents omitted for 1 user-specified path(s)

TABLE OF CONTENTS
============================================================
Incisor Slot Template TS
    Assets/
        CodeAssets/
            BrightnessContrast.codeAsset.ts
            BulletTimeDoubleArc.codeAsset.ts
            ExtremeEaseIn.codeAsset.ts
            ExtremeEaseOut.codeAsset.ts
            InfiniteAdd.codeAsset.ts
            Sheen.codeAsset.ts
            StretchBetween2D.codeAsset.ts
        Dashboard/
            AutoPlayButton.png
            AutoPlayButton.png.ncData
            Circle.png
            Circle.png.ncData
            Dashboard.construct
            Dashboard.construct.ncData
            MenuButton.png
            MenuButton.png.ncData
            PanelBox.png
            PanelBox.png.ncData
            SoundButton.png
            SoundButton.png.ncData
            SoundMute.png
            SoundMute.png.ncData
            SpinButtonCenter.png
            SpinButtonCenter.png.ncData
        Fonts/
            ThemedFont/
                ThemedFont_Char{0000-8482}.png (112 files)
                ThemedFont_Char{0000-8482}.png.ncData (112 files)
            SampleFont.otf
            SampleFont.otf.ncData
            ThemedFont.ncData
        GameLayout/
            GameIntroAnimation/
                GameIntroAnimation.construct
                GameIntroAnimation.construct.ncData
            Background.png
            Background.png.ncData
            CenterWinMeterShadow.png
            CenterWinMeterShadow.png.ncData
            GameIntroAnimation.ncData
            GameLayout.construct
            GameLayout.construct.ncData
            GameTitle.png
            GameTitle.png.ncData
            InnerShadow.png
            InnerShadow.png.ncData
            ReelBackground.png
            ReelBackground.png.ncData
        LayersAndMasks/
            main.maskGroups
            main.maskGroups.ncData
            MainScene.layers
            MainScene.layers.ncData
        ParticleSystems/
            FallingStars.particleSysDef
            FallingStars.particleSysDef.ncData
            SampleParticle.png
            SampleParticle.png.ncData
            StarBurst.particleSysDef
            StarBurst.particleSysDef.ncData
            StarParticle.png
            StarParticle.png.ncData
        Sounds/
            ReelSpinSound.wav
            ReelSpinSound.wav.ncData
            ReelStop.wav
            ReelStop.wav.ncData
            SpinBegin.wav
            SpinBegin.wav.ncData
        SymbolConstructs/
            BarGrayThick_Plate.png
            BarGrayThick_Plate.png.ncData
            BarGrayThick_Text.png
            BarGrayThick_Text.png.ncData
            BarGrayThin_Plate.png
            BarGrayThin_Plate.png.ncData
            BarGrayThin_Text.png
            BarGrayThin_Text.png.ncData
            BarWhite_Plate.png
            BarWhite_Plate.png.ncData
            BarWhite_Text.png
            BarWhite_Text.png.ncData
            Bonus_Star.png
            Bonus_Star.png.ncData
            Bonus_Text.png
            Bonus_Text.png.ncData
            BonusConstruct.construct
            BonusConstruct.construct.ncData
            Major1_Fill.png
            Major1_Fill.png.ncData
            Major1_Outline.png
            Major1_Outline.png.ncData
            Major1_Shell.png
            Major1_Shell.png.ncData
            Major1Construct.construct
            Major1Construct.construct.ncData
            Major2_Fill.png
            Major2_Fill.png.ncData
            Major2_Outline.png
            Major2_Outline.png.ncData
            Major2_Shell.png
            Major2_Shell.png.ncData
            Major2Construct.construct
            Major2Construct.construct.ncData
            Major3_Fill.png
            Major3_Fill.png.ncData
            Major3_Outline.png
            Major3_Outline.png.ncData
            Major3_Shell.png
            Major3_Shell.png.ncData
            Major3Construct.construct
            Major3Construct.construct.ncData
            Minor1_PlateBottom.png
            Minor1_PlateBottom.png.ncData
            Minor1_PlateMiddle.png
            Minor1_PlateMiddle.png.ncData
            Minor1_PlateTop.png
            Minor1_PlateTop.png.ncData
            Minor1_TextBottom.png
            Minor1_TextBottom.png.ncData
            Minor1_TextMiddle.png
            Minor1_TextMiddle.png.ncData
            Minor1_TextTop.png
            Minor1_TextTop.png.ncData
            Minor1Construct.construct
            Minor1Construct.construct.ncData
            Minor2Construct.construct
            Minor2Construct.construct.ncData
            Minor3Construct.construct
            Minor3Construct.construct.ncData
            Wild_CherryLeft.png
            Wild_CherryLeft.png.ncData
            Wild_CherryRight.png
            Wild_CherryRight.png.ncData
            Wild_Leaf.png
            Wild_Leaf.png.ncData
            Wild_Text.png
            Wild_Text.png.ncData
            WildConstruct.construct
            WildConstruct.construct.ncData
        SymbolImages/
            Bonus.png
            Bonus.png.ncData
            Major1.png
            Major1.png.ncData
            Major2.png
            Major2.png.ncData
            Major3.png
            Major3.png.ncData
            Minor1.png
            Minor1.png.ncData
            Minor2.png
            Minor2.png.ncData
            Minor3.png
            Minor3.png.ncData
            Wild.png
            Wild.png.ncData
        CodeAssets.ncData
        Dashboard.ncData
        Fonts.ncData
        GameLayout.ncData
        LayersAndMasks.ncData
        ParticleSystems.ncData
        Sounds.ncData
        SymbolConstructs.ncData
        SymbolImages.ncData
    ProjectCode/
        TypescriptGeneratedJS/
            Assets/
                CodeAssets/
                    BrightnessContrast.codeAsset.js
                    BulletTimeDoubleArc.codeAsset.js
                    ExtremeEaseIn.codeAsset.js
                    ExtremeEaseOut.codeAsset.js
                    InfiniteAdd.codeAsset.js
                    Sheen.codeAsset.js
                    StretchBetween2D.codeAsset.js
            TypescriptProjectCode/
                FlowStates/
                    00 GameIntro.js
                    01 GameIdle.js
                    02 StartGame.js
                    03 SpinReels.js
                    05 WinCelebration.js
                PreloadConfiguration/
                    PreloadConfiguration.js
                DashboardManager.js
                GameSystemManager.js
                GameSystemReplica.js
                GrpcConnection.js
                Payline.js
                ProjectMain.js
                ReelSymbol.js
    TypescriptProjectCode/
        FlowStates/
            00 GameIntro.ts
            01 GameIdle.ts
            02 StartGame.ts
            03 SpinReels.ts
            05 WinCelebration.ts
        PreloadConfiguration/
            PreloadConfiguration.ts
        DashboardManager.ts
        GameSystemManager.ts
        GameSystemReplica.ts
        GrpcConnection.ts
        Payline.ts
        ProjectMain.ts
        ReelSymbol.ts
    Utilities/
        AuxiliaryPublishingSupport/
            ElectronEgmPublish/
                ElectronExtras/
                    ConnectionDefinition.proto
                ElectronMain/
                    ElectronMain.js
                    GRPC.js
                ElectronPackage/
                    package.json
                ElectronPreload/
                    ElectronPreload.js
                Example GRPC Servers/
                    NodeExample/
                        ConnectionDefinition.proto
                        GrpcServer.js
                        package.json
                    Windows Cpp Example/
                        Compiled exe/
                            abseil_dll.dll
                            cares.dll
                            connection_proto.lib
                            game_data.json
                            grpc_cpp_server.exe
                            libcrypto-3-x64.dll
                            libprotobuf.dll
                            libssl-3-x64.dll
                            re2.dll
                            zlib1.dll
                        SourceProject/
                            data/
                                game_data.json
                            proto/
                                ConnectionDefinition.proto
                            src/
                                server_main.cpp
                            CMakeLists.txt
                            README.txt
            ElectronLocalDev/
                ElectronMain/
                    ElectronMain.js
                ElectronPackage/
                    package.json
                ElectronPreload/
                    ElectronPreload.js
        MinificationLists/
            DoNotMinifyLists/
                DoNotMinifyList.json
            MinifyLists/
                MinifyList.json
        ProjectData.json
        ProjectState.json
        ProjectTranscript.json
    Assets.ncData
    ProjectSettings.json
    ReleaseNotes.json
    tsconfig.json

GROUPED REPETITIVE FILES
============================================================
Assets/Fonts/ThemedFont/ThemedFont_Char{0000-8482}.png (112 files) -> grouped repetitive non-text files (112 files)
Assets/Fonts/ThemedFont/ThemedFont_Char{0000-8482}.png.ncData (112 files) -> grouped repetitive text files (112 files)

TEXT FILE CONTENTS
============================================================
Assets/CodeAssets/BrightnessContrast.codeAsset.ts
------------------------------------------------------------
CODE.runBeforeInit___begin;
    let brightnessContrast_def = nc.defineEffectController("brightnessContrast", "Vector2", ["brightness", "contrast"], [0, 0], nc.constants.effectControllerMixModes.addition, [[0, 1], [0, 1]], "EffectController for the BrightnessContrast EffectNode, which adjusts the brightness and contrast of the fragments (pixels) on the Material it is applied to.", ["Brightness Adjustment", "Contrast Adjustment"]);
    nc.defineEffectNode("BrightnessContrast",
        [],
        "",
        ["uniform vec2 brightnessContrast;"],
        "fragment.rgb /= max(fragment.a, .001);\n\
        fragment.rgb = (fragment.rgb - vec3(.5)) * (brightnessContrast.y + 1.0) + vec3(.5);\n\
        fragment.rgb += vec3(brightnessContrast.x);\n\
        fragment.rgb *= fragment.a;",
        [brightnessContrast_def]
    );
CODE.runBeforeInit___end;

Assets/CodeAssets/BulletTimeDoubleArc.codeAsset.ts
------------------------------------------------------------
CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper 
    */
    var bulletTimeDoubleArc_tweenTypeFunction = function(swooper)
    {
        let progress = swooper.progress;
        let params = swooper.controllers.BulletTimeDoubleArc;
        progress = (.5*Math.pow((progress-.5)*2,5)+.5)*params.bulletTimeAmount+(1-params.bulletTimeAmount)*progress;
        var oneMinus = 1-progress;
        for(var i=0; i<swooper.startValues.length; i++)
        {
            if(i===0)       {swooper.currentValues[i] = swooper.startValues[i]*oneMinus+swooper.endValues[i]*progress+Math.sin(progress*Math.PI)*params.x;}
            else if(i===1)  {swooper.currentValues[i] = swooper.startValues[i]*oneMinus+swooper.endValues[i]*progress+Math.sin(progress*Math.PI)*params.y;}
            else{swooper.currentValues[i] = swooper.startValues[i]*oneMinus+swooper.endValues[i]*progress;}
        }
    };

    //Define 'bulletTimeDoubleArc_tweenTypeFunction' TweenType
    nc.defineTweenType(
        "BulletTimeDoubleArc",
        bulletTimeDoubleArc_tweenTypeFunction,
        ["bulletTimeAmount", "x", "y"],
        [.5, 100, 100],
        "This TweenType in intended for use with position swoops.  It arcs the movements toward an offset position, and slows down the movement in the middle of the movement.",
        ["The amount to slow down the progression.  0 means no slow down, and 1 brings the progression to a standstill in the middle.", "The amound of X arc.", "The amount of Y arc."]
    );
CODE.runBeforeInit___end;


Assets/CodeAssets/ExtremeEaseIn.codeAsset.ts
------------------------------------------------------------
CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper 
    */
    var extremeEaseIn_tweenTypeFunction = function(swooper)
    {
        let progress = Math.pow(Math.sin(.5*Math.PI*swooper.progress),.3);
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

    //Define 'ExtremeEaseIn' TweenType
    nc.defineTweenType(
        "ExtremeEaseIn",
        extremeEaseIn_tweenTypeFunction,
        [],
        [],
        "This TweenType changes very quickly at first and slows down.",
        []
    );
CODE.runBeforeInit___end;


Assets/CodeAssets/ExtremeEaseOut.codeAsset.ts
------------------------------------------------------------
CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper 
    */
    var extremeEaseOut_tweenTypeFunction = function(swooper)
    {
        let progress = Math.pow(1-Math.cos(.5*Math.PI*swooper.progress),3.33);
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

    //Define 'ExtremeEaseOut' TweenType
    nc.defineTweenType(
        "ExtremeEaseOut",
        extremeEaseOut_tweenTypeFunction,
        [],
        [],
        "This TweenType changes very slowly at first and speeds up.",
        []
    );
CODE.runBeforeInit___end;


Assets/CodeAssets/InfiniteAdd.codeAsset.ts
------------------------------------------------------------
CODE.runBeforeInit___begin;
    /** Define the motion function.
    * @param {Motion} motion
    */
    var infiniteAdd_motionTypeFunction = function(motion)
    {
        for (let i = 0; i < motion.numProperties; ++i)
        {
            motion.currentValues[i] = motion.lowerBounds[i] + motion.progress * (motion.upperBounds[i] - motion.lowerBounds[i] );
        }
    };

    // Define 'InfiniteAdd' Motion
    nc.defineMotionType(
        "InfiniteAdd",
        infiniteAdd_motionTypeFunction,
        undefined,
        undefined,
        "This MotionType adds to the value/values indefinitely."
    );
CODE.runBeforeInit___end;

Assets/CodeAssets/Sheen.codeAsset.ts
------------------------------------------------------------
CODE.runBeforeInit___begin;
    let sheen_def = nc.defineEffectController("sheen","Vector4",["progress","angle","thickness","feather"],[0,45,100,100],nc.constants.effectControllerMixModes.addition,[[0,500],[0,180],[0,100],[0,100]],"EffectController for the Sheen EffectNode, which adds a movable band of bright color to the Material it is applied to.",["The offset of the bright band.","The angle of the bright band.","The thickness of the bright band.","The fuzziness of the edges of the bright band."]);
    let sheen_color_def = nc.defineEffectController("sheen_color","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the Sheen EffectNode, which adds a movable band of bright color to the Material it is applied to.",["The red value of the Sheen color.","The green value of the Sheen color.","The blue value of the Sheen color.","The alpha value of the Sheen color."]);
    let sheen_luminance_def = nc.defineEffectController("sheen_luminance","number",[""],[1],nc.constants.effectControllerMixModes.addition,[[0,1]],"EffectController for the Sheen EffectNode, which adds a movable band of bright color to the Material it is applied to.","The luminance of the bright band.");
    nc.defineEffectNode("Sheen",
        ["varying vec2 pos;"],
        "pos = vertex.xy;",
        ["varying vec2 pos;", "uniform vec4 sheen;","uniform vec4 sheen_color;", "uniform float sheen_luminance;"],
        "float sheen_angle=sheen.y*3.14159/180.0;\n\
        float sheen_progress=sheen.x;\n\
        float sheen_thickness=sheen.z;\n\
        float sheen_feather=sheen.w;\n\
        vec2 sheen_axisOfTravel=vec2(cos(sheen_angle),sin(sheen_angle));\n\
        float sheen_newUV=dot(pos,sheen_axisOfTravel);\n\
        float sheen_sheenBand=smoothstep(sheen_progress-sheen_thickness*.5-sheen_feather,sheen_progress-sheen_thickness*.5,sheen_newUV)*smoothstep(sheen_progress+sheen_thickness*.5+sheen_feather,sheen_progress+max(sheen_feather, .001),sheen_newUV);\n\
        vec3 sheen_addColor = fragment.rgb+sheen_sheenBand*fragment.a*sheen_color.rgb*sheen_color.a;\n\
        vec3 sheen_normalColor = mix(fragment.rgb, fragment.a*sheen_color.rgb, sheen_color.a * sheen_sheenBand);\n\
        fragment.rgb = mix(sheen_normalColor, sheen_addColor, sheen_luminance);",
        [sheen_def,sheen_color_def,sheen_luminance_def]
    );
CODE.runBeforeInit___end;

Assets/CodeAssets/StretchBetween2D.codeAsset.ts
------------------------------------------------------------
/** A CustomAddOn that will take any GraphicObject and stretch it from the middle between any two points using a GraphicExpander.
 */
class StretchBetween2D extends CustomAddOn_GraphicObject
{
    
    internalUseGlobalCoordinates:boolean;
    internalStretchDirection:string;
    internalFirstPointX:number;
    internalFirstPointY:number;
    internalFirstPointBuffer:number;
    internalSecondPointX:number;
    internalSecondPointY:number;
    internalSecondPointBuffer:number;
    internalOneOverPi:number;
    useGlobalCoordinates:boolean;
    stretchDirection:string;
    firstPointX:number;
    firstPointY:number;
    firstPointBuffer:number;
    secondPointX:number;
    secondPointY:number;
    secondPointBuffer:number;
    


    constructor(owner)
    {
        // call the super constructor
        super(owner);

        // configure the GraphicExpander if it's not already configured
        if(this.owner.graphicExpander===undefined)
        {
            this.owner.configureGraphicExpander();
            this.owner.graphicExpander.expandedHeight = 0;
            this.owner.graphicExpander.expandedWidth = 0;
        }

        // initial var values
        this.internalUseGlobalCoordinates = false;
        this.internalStretchDirection = "horizontal";
        this.internalFirstPointX = 0;
        this.internalFirstPointY = 0;
        this.internalFirstPointBuffer = 0;
        this.internalSecondPointX = 0;
        this.internalSecondPointY = 0;
        this.internalSecondPointBuffer = 0;
        this.internalOneOverPi = 1/Math.PI;
    }


    // refreshes the owner's position and rotation based on the values for the points
    refreshLayout()
    {
        let distanceX = (this.internalSecondPointX-this.internalFirstPointX);
        let distanceY = (this.internalSecondPointY-this.internalFirstPointY);
        let length = Math.pow( distanceX*distanceX + distanceY*distanceY ,.5);
        let ratio = (1+(-this.internalFirstPointBuffer+this.internalSecondPointBuffer)/length)*.5;
        let oneMinusRatio = (1-ratio);
        let destX = (this.internalFirstPointX*ratio+this.internalSecondPointX*oneMinusRatio);
        let destY = (this.internalFirstPointY*ratio+this.internalSecondPointY*oneMinusRatio);
        let rotationZ = Math.atan2(distanceY,distanceX)*180*this.internalOneOverPi;
        if(this.internalStretchDirection==="horizontal")
        {
            this.owner.graphicExpander.expandedWidth = length-this.internalFirstPointBuffer-this.internalSecondPointBuffer;
            this.owner.graphicExpander.expandedHeight = 0;
        }
        else
        {
            this.owner.graphicExpander.expandedWidth = 0;
            this.owner.graphicExpander.expandedHeight = length-this.internalFirstPointBuffer-this.internalSecondPointBuffer;
            rotationZ+=90;
        }
        if(this.internalUseGlobalCoordinates===true)
        {
            this.owner.swoopGlobalPosition([destX,destY,0],0);
            this.owner.swoopGlobalRotation([0,0,rotationZ],0);
            this.owner.swoopGlobalScale([1,1,1],0);
        }
        else
        {
            this.owner.position.x = destX;
            this.owner.position.y = destY;
            this.owner.rotation.z = rotationZ;
        }
    }
}


CODE.runBeforeInit___begin;
// Add getters/setters onto the CustomAddOn prototype, so that setting these values also triggers a refresh.
    Object.defineProperty(StretchBetween2D.prototype,"useGlobalCoordinates",{
        set:function(_val)
        {
            this.internalUseGlobalCoordinates = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalUseGlobalCoordinates);}
    });
    Object.defineProperty(StretchBetween2D.prototype,"stretchDirection",{
        set:function(_val)
        {
            this.internalStretchDirection = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalStretchDirection);}
    });
    Object.defineProperty(StretchBetween2D.prototype,"firstPointX",{
        set:function(_val)
        {
            this.internalFirstPointX = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalFirstPointX);}
    });
    Object.defineProperty(StretchBetween2D.prototype,"firstPointY",{
        set:function(_val)
        {
            this.internalFirstPointY = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalFirstPointY);}
    });
    Object.defineProperty(StretchBetween2D.prototype,"firstPointBuffer",{
        set:function(_val)
        {
            this.internalFirstPointBuffer = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalFirstPointBuffer);}
    });
    Object.defineProperty(StretchBetween2D.prototype,"secondPointX",{
        set:function(_val)
        {
            this.internalSecondPointX = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalSecondPointX);}
    });
    Object.defineProperty(StretchBetween2D.prototype,"secondPointY",{
        set:function(_val)
        {
            this.internalSecondPointY = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalSecondPointY);}
    });
    Object.defineProperty(StretchBetween2D.prototype,"secondPointBuffer",{
        set:function(_val)
        {
            this.internalSecondPointBuffer = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalSecondPointBuffer);}
    });

    // register the CustomAddOn and its properties with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomAddOn(StretchBetween2D);
    let stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D,"boolean","useGlobalCoordinates");
    stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D,"string","stretchDirection");
    stretchBetween2D_registeredProperty.validationList = ["horizontal","vertical"];
    stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D,"number","firstPointX");
    stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D,"number","firstPointY");
    stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D,"number","firstPointBuffer");
    stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D,"number","secondPointX");
    stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D,"number","secondPointY");
    stretchBetween2D_registeredProperty = nc.registerCustomAddOnProperty(StretchBetween2D,"number","secondPointBuffer");
CODE.runBeforeInit___end;


Assets/Dashboard/AutoPlayButton.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.resolutionScaleX is 0.6 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.6 instead of the default null.
- imageConfigurations.trimMode is "none" instead of the default null.

Assets/Dashboard/Circle.png.ncData
------------------------------------------------------------
default ncData file

Assets/Dashboard/Dashboard.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{
				"4":{},
				"5":{},
				"6":{},
				"7":{},
				"8":{},
				"9":{},
				"10":{},
				"11":{},
				"12":{},
				"13":{},
				"14":{
					"15":{},
					"16":{
						"17":{}
					},
					"18":{
						"19":{}
					}
				}
			},
			"20":{
				"21":{
					"22":{}
				}
			},
			"23":{
				"24":{},
				"25":{}
			}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"ViewArea",
				"uid":"0255217279399595",
				"scale":[21.6,43.2,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.95,
				"effectControllerValues":{"colorMultiply":[0,1,0,0.1]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{
				"i":1,
				"type":"Button",
				"name":"MenuBackgroundDimmer",
				"uid":"3692856201945776",
				"enabled":false,
				"scale":[21.6,43.2,1],
				"graphicAsset":"WhiteBox",
				"layer":"GameMenus",
				"subLayer":-0.9,
				"effectControllerValues":{"colorMultiply":[0,0,0,0.7]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"BottomBarBackground",
				"uid":"5152859927566143",
				"position":[0,-2060,0],
				"scale":[21.6,2,1],
				"graphicAsset":"WhiteBox",
				"layer":"Dashboard",
				"subLayer":-0.2,
				"effectControllerValues":{"colorMultiply":[0,0,0,0.5]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{"i":3,"name":"BottomBarContainer","uid":"6056396671095576","position":[0,-2060,0]},
			{
				"i":4,
				"type":"GraphicObject",
				"name":"BottomBarBorder",
				"uid":"1046200249065111",
				"position":[0,100,0],
				"scale":[21.6,0.049,1],
				"graphicAsset":"WhiteBox",
				"layer":"Dashboard",
				"effectControllerValues":{"colorMultiply":[0.2,0.2,0.22,1]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{
				"i":5,
				"type":"TextBox",
				"name":"BalanceLabel",
				"uid":"3062810463762450",
				"position":[-300,40,0],
				"layer":"Dashboard",
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"phraseID":"CreditMeterLabel",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.75,
					"characterScaleY":0.75,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.6352941176470588,0.6352941176470588,0.7058823529411765,1]}
					}
				]
			},
			{
				"i":6,
				"type":"TextBox",
				"name":"BalanceMeter",
				"uid":"6366022433512107",
				"position":[-300,-20,0],
				"layer":"Dashboard",
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"string":"$2,100.85",
				"textFormat":{
					"fontName":"SampleFont",
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]}
					}
				]
			},
			{
				"i":7,
				"type":"TextBox",
				"name":"BetLabel",
				"uid":"7533959443301057",
				"position":[300,40,0],
				"layer":"Dashboard",
				"phraseID":"BetMeterLabel",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.75,
					"characterScaleY":0.75,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.6352941176470588,0.6352941176470588,0.7058823529411765,1]}
					}
				]
			},
			{
				"i":8,
				"type":"TextBox",
				"name":"BetMeter",
				"uid":"3552817982372254",
				"position":[300,-20,0],
				"layer":"Dashboard",
				"string":"$1.50",
				"textFormat":{
					"fontName":"SampleFont",
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.8897692222222225,0.8897692222222225,0.9188666666666669,1]}
					}
				]
			},
			{
				"i":9,
				"type":"TextBox",
				"name":"WinMeter",
				"uid":"7770006718721982",
				"position":[0,-20,0],
				"layer":"Dashboard",
				"string":"$1.50",
				"textFormat":{
					"fontName":"SampleFont",
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.8897692222222225,0.8897692222222225,0.9188666666666669,1]}
					}
				]
			},
			{
				"i":10,
				"type":"TextBox",
				"name":"WinLabel",
				"uid":"0316236576295246",
				"position":[0,40,0],
				"layer":"Dashboard",
				"phraseID":"WinMeterLabel",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.75,
					"characterScaleY":0.75,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.6352941176470588,0.6352941176470588,0.7058823529411765,1]}
					}
				]
			},
			{
				"i":11,
				"type":"TextBox",
				"name":"BottomBarTitle",
				"uid":"1744208700345465",
				"position":[1030,0,0],
				"layer":"Dashboard",
				"phraseID":"BottomBarGameTitle",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":1.25,
					"characterScaleY":1.25,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"pivotPoint":[0.5,0],
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]}
					}
				]
			},
			{
				"i":12,
				"type":"Button",
				"name":"MenuButton",
				"uid":"2990403768905400",
				"position":[-960,0,0],
				"scale":[0.6,0.6,1],
				"graphicAsset":"MenuButton",
				"layer":"Dashboard",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","BrightnessContrast"],
						"effectControllerValues":{"colorMultiply":[0.89,0.89,0.916,1]}
					}
				]
			},
			{
				"i":13,
				"type":"Button",
				"name":"SoundButton",
				"uid":"0451180212965326",
				"position":[-800,0,0],
				"scale":[0.6,0.6,1],
				"graphicAsset":"SoundButton",
				"layer":"Dashboard",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","BrightnessContrast"],
						"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]}
					}
				]
			},
			{"i":14,"name":"AutplayContainer","uid":"7287341036502203","position":[-640,0,0]},
			{
				"i":15,
				"type":"Button",
				"name":"Autoplay Button",
				"uid":"2188549410786908",
				"scale":[0.6,0.6,1],
				"graphicAsset":"AutoPlayButton",
				"layer":"Dashboard",
				"subLayer":0.05,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","BrightnessContrast"],
						"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]}
					}
				]
			},
			{
				"i":16,
				"type":"Button",
				"name":"Autoplay Menu",
				"uid":"1431752518849777",
				"enabled":false,
				"graphicAsset":"PanelBox",
				"layer":"GameMenus",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"graphicExpander":{"symmetric":false,"expandableArea":[0,0,0,0],"expandedArea":[-115,115,-80,675]}
			},
			{
				"i":17,
				"type":"TextBox",
				"name":"BalanceLabel",
				"uid":"9717852305388767",
				"position":[0,80,0],
				"layer":"GameMenus",
				"subLayer":0.05,
				"phraseID":"AutoplayLabel",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.75,
					"characterScaleY":0.75,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[0.6352941176470588,0.6352941176470588,0.7058823529411765,1]}
					}
				]
			},
			{
				"i":18,
				"type":"GraphicObject",
				"name":"AutoplayCountdownBackground",
				"uid":"7311747112657510",
				"enabled":false,
				"graphicAsset":"PanelBox",
				"layer":"GameMenus",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"graphicExpander":{"symmetric":true,"expandableWidth":0,"expandableHeight":0,"expandedWidth":90,"expandedHeight":35}
			},
			{
				"i":19,
				"type":"TextBox",
				"name":"AutoplayCountdown",
				"uid":"0262139303638274",
				"layer":"GameMenus",
				"string":"10",
				"textFormat":{
					"fontName":"SampleFont",
					"characterScaleX":0.75,
					"characterScaleY":0.75,
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{"i":20,"name":"SpinButtonContainer","uid":"1476640098329800","position":[0,-1600,0]},
			{
				"i":21,
				"type":"Button",
				"name":"SpinButton",
				"uid":"3808583354841769",
				"scale":[1.5,1.5,1],
				"graphicAsset":"Circle",
				"layer":"Dashboard",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":22,
				"type":"GraphicObject",
				"name":"SpinButtonCenter",
				"uid":"8491280100649518",
				"scale":[0.9,0.9,1],
				"graphicAsset":"SpinButtonCenter",
				"layer":"Dashboard",
				"subLayer":0.044000000000000115,
				"effectControllerValues":{"colorMultiply":[0.8901960784313725,0.8901960784313725,0.9176470588235294,1]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{"i":23,"name":"MainMenuContainer","uid":"7763480859850434","enabled":false},
			{
				"i":24,
				"type":"Button",
				"name":"MainMenuBackground",
				"uid":"2013930738972798",
				"graphicAsset":"PanelBox",
				"layer":"GameMenus",
				"subLayer":0.05,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{"colorMultiply":[2,2,2,1]}
					}
				],
				"graphicExpander":{"symmetric":true,"expandableWidth":0,"expandableHeight":0,"expandedWidth":1800,"expandedHeight":2000}
			},
			{
				"i":25,
				"type":"TextBox",
				"name":"MainMenuLabel",
				"uid":"5021713473146068",
				"string":"Main Menu...",
				"textFormat":{
					"fontName":"SampleFont",
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","Shapify","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			}
		]
	},
	"timelines":{
		"Layout_Mobile":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":0,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":-3140},
						{"time":-2,"value":-2060},
						{"time":-1,"value":-980}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":23.6},
						{"time":-2,"value":2}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-2,"value":-2060},
						{"time":-1,"value":-980}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6056396671095576"
				},
				{
					"keyframes":[
						{"time":1,"value":1030},
						{"time":4,"value":4270}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"keyframes":[
						{"time":1,"value":-960},
						{"time":4,"value":-4200}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"keyframes":[
						{"time":1,"value":-800},
						{"time":4,"value":-4040}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.2},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.65},
						{"time":1,"value":0.65},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.2},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.65},
						{"time":1,"value":0.65},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":0},
						{"time":-1.5,"value":0},
						{"time":-1,"value":0},
						{"time":1,"value":908.0000000000005},
						{"time":2,"value":1889}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":-1600},
						{"time":-1.5,"value":-1125},
						{"time":-1,"value":-720},
						{"time":1,"value":-720},
						{"time":2,"value":-625}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1046200249065111"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":1,"value":-640},
						{"time":4,"value":-3880}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"keyframes":[
						{"time":-2,"value":100}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7763480859850434"
				},
				{
					"keyframes":[
						{"time":-2,"value":2300},
						{"time":-1,"value":1800},
						{"time":1,"value":1800}
					],
					"propertyPath":["graphicExpander","expandedHeight"],
					"sceneObjectUid":"2013930738972798"
				},
				{
					"keyframes":[
						{"time":-1,"value":2000},
						{"time":1,"value":2000},
						{"time":2,"value":3000}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"2013930738972798"
				}
			]
		},
		"Layout_Desktop":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":0,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":-3190},
						{"time":-2,"value":-2110},
						{"time":-1,"value":-1030},
						{"time":1,"value":-1030}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":22.6},
						{"time":-2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-2,"value":-2110},
						{"time":-1,"value":-1030}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6056396671095576"
				},
				{
					"keyframes":[
						{"time":1,"value":1030},
						{"time":4,"value":4270}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"keyframes":[
						{"time":1,"value":-960},
						{"time":4,"value":-4200}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"keyframes":[
						{"time":1,"value":-800},
						{"time":4,"value":-4040}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"keyframes":[
						{"time":-2,"value":0.5},
						{"time":-1.5,"value":0.5},
						{"time":-1,"value":0.5},
						{"time":1,"value":0.5},
						{"time":2,"value":0.5}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":0.5},
						{"time":-1.5,"value":0.5},
						{"time":-1,"value":0.5},
						{"time":1,"value":0.5},
						{"time":2,"value":0.5}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":930},
						{"time":-1.5,"value":930},
						{"time":-1,"value":930},
						{"time":1,"value":930},
						{"time":2,"value":2000}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":-1900},
						{"time":-1.5,"value":-1360},
						{"time":-1,"value":-830},
						{"time":1,"value":-830},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1046200249065111"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":1,"value":-640},
						{"time":4,"value":-3880}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"keyframes":[
						{"time":-2,"value":100}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7763480859850434"
				},
				{
					"keyframes":[
						{"time":-2,"value":2300},
						{"time":-1,"value":1800},
						{"time":1,"value":1800}
					],
					"propertyPath":["graphicExpander","expandedHeight"],
					"sceneObjectUid":"2013930738972798"
				},
				{
					"keyframes":[
						{"time":-1,"value":2000},
						{"time":1,"value":2000},
						{"time":2,"value":3000}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"2013930738972798"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":50}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1046200249065111"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.67}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.67}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-2,"value":0.67}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-2,"value":0.67}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-20},
						{"time":-1.1166666666666667,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7533959443301057"
				}
			]
		},
		"Layout_EGM":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0255217279399595"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":0,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":-3190},
						{"time":-2,"value":-2110},
						{"time":-1,"value":-1030},
						{"time":1,"value":-1030}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-4,"value":22.6},
						{"time":-2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5152859927566143"
				},
				{
					"keyframes":[
						{"time":-2,"value":-2110},
						{"time":-1,"value":-1030}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6056396671095576"
				},
				{
					"keyframes":[
						{"time":1,"value":1030},
						{"time":4,"value":4270}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"keyframes":[
						{"time":1,"value":-300},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"keyframes":[
						{"time":1,"value":-960},
						{"time":4,"value":-4200}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"keyframes":[
						{"time":1,"value":-800},
						{"time":4,"value":-4040}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"keyframes":[
						{"time":1,"value":300},
						{"time":2,"value":830}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"keyframes":[
						{"time":-2,"value":0.5},
						{"time":-1.5,"value":0.5},
						{"time":-1,"value":0.5},
						{"time":1,"value":0.5},
						{"time":2,"value":0.5}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":0.5},
						{"time":-1.5,"value":0.5},
						{"time":-1,"value":0.5},
						{"time":1,"value":0.5},
						{"time":2,"value":0.5}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":930},
						{"time":-1.5,"value":930},
						{"time":-1,"value":930},
						{"time":1,"value":930},
						{"time":2,"value":2000}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":-2,"value":-1900},
						{"time":-1.5,"value":-1360},
						{"time":-1,"value":-830},
						{"time":1,"value":-830},
						{"time":2,"value":-830}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1476640098329800"
				},
				{
					"keyframes":[
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1046200249065111"
				},
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3692856201945776"
				},
				{
					"keyframes":[
						{"time":1,"value":-640},
						{"time":4,"value":-3880}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"keyframes":[
						{"time":-2,"value":100}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7763480859850434"
				},
				{
					"keyframes":[
						{"time":-2,"value":2300},
						{"time":-1,"value":1800},
						{"time":1,"value":1800}
					],
					"propertyPath":["graphicExpander","expandedHeight"],
					"sceneObjectUid":"2013930738972798"
				},
				{
					"keyframes":[
						{"time":-1,"value":2000},
						{"time":1,"value":2000},
						{"time":2,"value":3000}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"2013930738972798"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":50}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1046200249065111"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2990403768905400"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0451180212965326"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.67}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.67}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7287341036502203"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-2,"value":0.67}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-2,"value":0.67}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1744208700345465"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3062810463762450"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-20},
						{"time":-1.1166666666666667,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"6366022433512107"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7770006718721982"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0316236576295246"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-15}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3552817982372254"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":25}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0.8}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7533959443301057"
				},
				{
					"type":"boolean",
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":false}
					],
					"propertyPath":["enabled"],
					"sceneObjectUid":"1476640098329800"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"Layout_Mobile"}
}

Assets/Dashboard/Dashboard.construct.ncData
------------------------------------------------------------
default ncData file

Assets/Dashboard/MenuButton.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.resolutionScaleX is 0.6 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.6 instead of the default null.
- imageConfigurations.trimMode is "none" instead of the default null.

Assets/Dashboard/PanelBox.png.ncData
------------------------------------------------------------
default ncData file

Assets/Dashboard/SoundButton.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.resolutionScaleX is 0.6 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.6 instead of the default null.
- imageConfigurations.trimMode is "none" instead of the default null.

Assets/Dashboard/SoundMute.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.resolutionScaleX is 0.6 instead of the default null.
- imageConfigurations.resolutionScaleY is 0.6 instead of the default null.
- imageConfigurations.trimMode is "none" instead of the default null.

Assets/Dashboard/SpinButtonCenter.png.ncData
------------------------------------------------------------
default ncData file

Assets/Fonts/SampleFont.otf.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.allowAdditiveTrimBuffer is true instead of the default null.
- imageConfigurations.applyAssetPackageScaling is false instead of the default null.
- imageConfigurations.shapify is true instead of the default null.
- imageConfigurations.shapifyEdgeRange is 10 instead of the default null.
- imageConfigurations.shapifyOptimizationLevel is 0.6 instead of the default null.
- imageConfigurations.spriteSheet is "SampleFont" instead of the default null.
- imageConfigurations.trimBuffer is 10 instead of the default null.
- imageConfigurations.unitsPerPixelX is 0.2 instead of the default null.
- imageConfigurations.unitsPerPixelY is 0.2 instead of the default null.
- imageConfigurations.unitsPerPixelZ is 0.2 instead of the default null.

Assets/Fonts/ThemedFont.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/GameIntroAnimation/GameIntroAnimation.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{
				"1":{}
			},
			"2":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"GameIntroTitle",
				"uid":"9871611871543739",
				"graphicAsset":"GameTitle",
				"layer":"GameIntro",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-710.0000000000002,29.880000000000006,172.8,71.40000000000018]}
					}
				]
			},
			{
				"i":1,
				"type":"TextBox",
				"name":"PressToContinueText",
				"uid":"3967512849546244",
				"position":[0,-550,0],
				"scale":[0.3981151044451828,0.3981151044451828,0.3981151044451828],
				"phraseID":"IntroPromptButton",
				"horizontalJustification":"center",
				"boxWidth":5000,
				"boxHeight":1000,
				"scaleToFit":false,
				"textFormat":{
					"fontName":"ThemedFont",
					"lineHeightMultiplier":0.7560000000000008,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"numHorizontalGridSegments":3,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":2,
				"type":"ParticleSystem",
				"name":"GameIntroParticles",
				"uid":"9427635532718460",
				"layer":"GameIntro",
				"subLayer":-0.2,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"particleSystemDefinition":"StarBurst",
				"playbackController":{"autoplayMode":"none","initialTime":0,"playbackRate":1,"startValue":0,"endValue":1.4000000000000001},
				"materials":[
					{"effectNodes":["SampleMainTexture","StarBurstParticleSystemEffectNode","ColorMultiply"]}
				]
			}
		]
	},
	"timelines":{
		"Intro":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":15,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":0,"value":0},
						{
							"time":0.26666666666666666,
							"value":1.946827145153689,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.06515798095682436,
							"rightHandleSpan":0.22984083351821796
						},
						{
							"time":0.6666666666666666,
							"value":1.383,
							"leftHandleValue":0.06499999999999996,
							"leftHandleSpan":0.30714091235990404,
							"rightHandleValue":-0.026155806639436674,
							"rightHandleSpan":0.017776615667129236
						},
						{"time":14.966666666666667,"value":1.7013895165985877,"leftHandleValue":0,"leftHandleSpan":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9871611871543739"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{
							"time":0.2,
							"value":1.986060855112844,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.06515798095682436,
							"rightHandleSpan":0.22984083351821796
						},
						{
							"time":0.6833333333333333,
							"value":1.3699220966802816,
							"leftHandleValue":0.06499999999999996,
							"leftHandleSpan":0.30714091235990404,
							"rightHandleValue":-0.026155806639436674,
							"rightHandleSpan":0.017776615667129236
						},
						{"time":14.966666666666667,"value":1.7013895165985877,"leftHandleValue":0,"leftHandleSpan":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9871611871543739"
				},
				{
					"keyframes":[
						{"time":0.15,"value":-710.0000000000002},
						{"time":0.3,"value":715.9999999999998},
						{"time":0.31666666666666665,"value":-700},
						{"time":1.2333333333333334,"value":-700},
						{"time":1.4,"value":700}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"9871611871543739"
				},
				{
					"keyframes":[
						{"time":0.2,"value":1},
						{"time":0.26666666666666666,"value":1.6139999999999999},
						{"time":0.8333333333333334,"value":1},
						{"time":1.2666666666666666,"value":1},
						{"time":1.3333333333333333,"value":1.6139999999999999},
						{"time":4.466666666666667,"value":1}
					],
					"propertyPath":["material","0","colorMultiply","alpha"],
					"sceneObjectUid":"9871611871543739"
				},
				{
					"type":"invoke",
					"keyframes":[
						{"time":0.1}
					],
					"propertyPath":["playbackController","playOnce"],
					"sceneObjectUid":"9427635532718460"
				},
				{
					"keyframes":[
						{"time":0.35,"value":0},
						{"time":0.65,"value":0},
						{
							"time":0.8333333333333334,
							"value":0.4,
							"leftHandleValue":-0.02114655962076141,
							"leftHandleSpan":0.35172622808693166,
							"rightHandleValue":0.02255710195165208,
							"rightHandleSpan":0.04046096960579235
						},
						{"time":3.4833333333333334,"value":0.35,"leftHandleValue":0,"leftHandleSpan":0.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3967512849546244"
				},
				{
					"keyframes":[
						{"time":0.35,"value":0},
						{"time":0.65,"value":0},
						{
							"time":0.8666666666666667,
							"value":0.4,
							"leftHandleValue":-0.02933598754245529,
							"leftHandleSpan":0.37957648111370185,
							"rightHandleValue":0.010293532062311735,
							"rightHandleSpan":0.051764203337249876
						},
						{"time":3.4833333333333334,"value":0.35,"leftHandleValue":0,"leftHandleSpan":0.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3967512849546244"
				},
				{
					"type":"boolean",
					"keyframes":[
						{"time":0,"value":true}
					],
					"propertyPath":["enabled"],
					"sceneObjectUid":"9871611871543739"
				}
			]
		},
		"Outro":{
			"autoplay":false,
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":1,
			"animatedProperties":[
				{
					"sceneObject":[0],
					"sceneObjectUid":"9871611871543739",
					"propertyPath":["scale","x"],
					"keyframes":[
						{"time":0,"value":1.5},
						{
							"time":0.13333333333333333,
							"value":2,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":0.26666666666666666,"value":0}
					]
				},
				{
					"sceneObject":[0],
					"sceneObjectUid":"9871611871543739",
					"propertyPath":["scale","y"],
					"keyframes":[
						{"time":0,"value":1.5},
						{
							"time":0.13333333333333333,
							"value":2,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":0,
							"rightHandleSpan":0.4
						},
						{"time":0.26666666666666666,"value":0}
					]
				},
				{
					"type":"binary",
					"sceneObject":[0],
					"sceneObjectUid":"9871611871543739",
					"propertyPath":["enabled"],
					"keyframes":[
						{"time":0,"value":true},
						{"time":0.9,"value":false}
					]
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"Intro"}
}

Assets/GameLayout/GameIntroAnimation/GameIntroAnimation.construct.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/Background.png.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/CenterWinMeterShadow.png.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/GameIntroAnimation.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/GameLayout.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{
				"2":{}
			},
			"3":{
				"4":{},
				"5":{
					"6":{},
					"7":{}
				},
				"8":{
					"9":{},
					"10":{}
				},
				"11":{
					"12":{},
					"13":{}
				},
				"14":{
					"15":{},
					"16":{}
				},
				"17":{
					"18":{},
					"19":{}
				},
				"20":{
					"21":{}
				}
			},
			"22":{},
			"23":{},
			"24":{},
			"25":{},
			"26":{
				"27":{},
				"28":{}
			}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"ViewArea",
				"uid":"2259684172978443",
				"scale":[21.6,43.2,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.95,
				"effectControllerValues":{"fillColor":[0,1,0,0.1]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{"i":1,"name":"GameTitleContainer","uid":"9279909710684411","position":[0,1400,0],"scale":[1.5,1.5,1]},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"GameTitle",
				"uid":"6426274793272281",
				"graphicAsset":"GameTitle",
				"layer":"GameTitle",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{"i":3,"name":"ReelsContainer","uid":"7193618239035880","position":[0,-560,0]},
			{
				"i":4,
				"type":"GraphicObject",
				"name":"ReelBackground",
				"uid":"7175220269991170",
				"position":[0,-26,0],
				"graphicAsset":"ReelBackground",
				"layer":"GameBackground",
				"subLayer":0.2,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				],
				"graphicExpander":{"symmetric":true,"expandableWidth":0,"expandableHeight":0,"expandedWidth":1100,"expandedHeight":760}
			},
			{"i":5,"name":"ReelContainer0","uid":"9076020945798561","position":[-720,0,0]},
			{
				"i":6,
				"type":"GraphicObject",
				"name":"ReelMask",
				"uid":"0918370620653048",
				"scale":[3.6,12,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.01,
				"masking":{"enabled":true,"type":"mask","maskGroups":["ReelMask"]},
				"effectControllerValues":{"fillColor":[1,1,1,0.2]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":7,
				"type":"SymbolReel",
				"name":"SymbolReel0",
				"uid":"5820417336094512",
				"position":[0,450,0],
				"defaultSymbolType":"GraphicObject",
				"numMainSymbols":4,
				"spinSpeed":-0.55,
				"windupDuration":0.2,
				"initialReelData":["Major1","Major1","Major1","Minor1","Minor1","Major2"],
				"pathValues":{
					"position.y":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":300},
							{"time":0,"value":0},
							{"time":1,"value":-300},
							{"time":2,"value":-600},
							{"time":3,"value":-900},
							{"time":4,"value":-1200}
						]
					},
					"subLayer":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":-0.05},
							{"time":0,"value":0},
							{"time":1,"value":0.05},
							{"time":2,"value":0.1},
							{"time":3,"value":0.15},
							{"time":4,"value":0.2}
						]
					}
				},
				"windupCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7,"value":-0.5,"leftHandleValue":0,"leftHandleSpan":0.396,"rightHandleValue":0,"rightHandleSpan":0.55},
						{"time":1,"value":0}
					]
				},
				"bounceCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.33,"value":-0.175,"leftHandleValue":0,"leftHandleSpan":0.453,"rightHandleValue":0,"rightHandleSpan":0.583},
						{"time":0.6,"value":0},
						{"time":0.83,"value":-0.08,"leftHandleValue":0,"leftHandleSpan":0.402,"rightHandleValue":0,"rightHandleSpan":0.735},
						{"time":1,"value":0}
					]
				}
			},
			{"i":8,"name":"ReelContainer1","uid":"4791506961612279","position":[-360,0,0]},
			{
				"i":9,
				"type":"GraphicObject",
				"name":"ReelMask",
				"uid":"0784921421762356",
				"scale":[3.6,12,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.01,
				"masking":{"enabled":true,"type":"mask","maskGroups":["ReelMask"]},
				"effectControllerValues":{"fillColor":[1,1,1,0.2]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":10,
				"type":"SymbolReel",
				"name":"SymbolReel1",
				"uid":"3164920587741603",
				"position":[0,450,0],
				"defaultSymbolType":"GraphicObject",
				"numMainSymbols":4,
				"spinSpeed":-0.55,
				"windupDuration":0.24,
				"initialReelData":["Minor2","Wild","Minor3","Minor3","Major2","Major2"],
				"pathValues":{
					"position.y":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":300},
							{"time":0,"value":0},
							{"time":1,"value":-300},
							{"time":2,"value":-600},
							{"time":3,"value":-900},
							{"time":4,"value":-1200}
						]
					},
					"subLayer":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":-0.05},
							{"time":0,"value":0},
							{"time":1,"value":0.05},
							{"time":2,"value":0.1},
							{"time":3,"value":0.15},
							{"time":4,"value":0.2}
						]
					}
				},
				"windupCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7,"value":-0.5,"leftHandleValue":0,"leftHandleSpan":0.396,"rightHandleValue":0,"rightHandleSpan":0.55},
						{"time":1,"value":0}
					]
				},
				"bounceCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.33,"value":-0.175,"leftHandleValue":0,"leftHandleSpan":0.453,"rightHandleValue":0,"rightHandleSpan":0.583},
						{"time":0.6,"value":0},
						{"time":0.83,"value":-0.08,"leftHandleValue":0,"leftHandleSpan":0.402,"rightHandleValue":0,"rightHandleSpan":0.735},
						{"time":1,"value":0}
					]
				}
			},
			{"i":11,"name":"ReelContainer2","uid":"1442663436352824"},
			{
				"i":12,
				"type":"GraphicObject",
				"name":"ReelMask",
				"uid":"2453127213139897",
				"scale":[3.6,12,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.01,
				"masking":{"enabled":true,"type":"mask","maskGroups":["ReelMask"]},
				"effectControllerValues":{"fillColor":[1,1,1,0.2]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":13,
				"type":"SymbolReel",
				"name":"SymbolReel2",
				"uid":"7409518362205974",
				"position":[0,450,0],
				"defaultSymbolType":"GraphicObject",
				"numMainSymbols":4,
				"spinSpeed":-0.55,
				"windupDuration":0.28,
				"initialReelData":["Wild","Minor1","Minor1","Major3","Major3","Major3"],
				"pathValues":{
					"position.y":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":300},
							{"time":0,"value":0},
							{"time":1,"value":-300},
							{"time":2,"value":-600},
							{"time":3,"value":-900},
							{"time":4,"value":-1200}
						]
					},
					"subLayer":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":-0.05},
							{"time":0,"value":0},
							{"time":1,"value":0.05},
							{"time":2,"value":0.1},
							{"time":3,"value":0.15},
							{"time":4,"value":0.2}
						]
					}
				},
				"windupCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7,"value":-0.5,"leftHandleValue":0,"leftHandleSpan":0.396,"rightHandleValue":0,"rightHandleSpan":0.55},
						{"time":1,"value":0}
					]
				},
				"bounceCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.33,"value":-0.175,"leftHandleValue":0,"leftHandleSpan":0.453,"rightHandleValue":0,"rightHandleSpan":0.583},
						{"time":0.6,"value":0},
						{"time":0.83,"value":-0.08,"leftHandleValue":0,"leftHandleSpan":0.402,"rightHandleValue":0,"rightHandleSpan":0.735},
						{"time":1,"value":0}
					]
				}
			},
			{"i":14,"name":"ReelContainer3","uid":"1109033499726488","position":[360,0,0]},
			{
				"i":15,
				"type":"GraphicObject",
				"name":"ReelMask",
				"uid":"1273215940211608",
				"scale":[3.6,12,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.01,
				"masking":{"enabled":true,"type":"mask","maskGroups":["ReelMask"]},
				"effectControllerValues":{"fillColor":[1,1,1,0.2]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":16,
				"type":"SymbolReel",
				"name":"SymbolReel3",
				"uid":"2076341895630287",
				"position":[0,450,0],
				"defaultSymbolType":"GraphicObject",
				"numMainSymbols":4,
				"spinSpeed":-0.55,
				"windupDuration":0.32,
				"initialReelData":["Minor2","Major3","Major3","Major3","Minor3","Minor3"],
				"pathValues":{
					"position.y":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":300},
							{"time":0,"value":0},
							{"time":1,"value":-300},
							{"time":2,"value":-600},
							{"time":3,"value":-900},
							{"time":4,"value":-1200}
						]
					},
					"subLayer":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":-0.05},
							{"time":0,"value":0},
							{"time":1,"value":0.05},
							{"time":2,"value":0.1},
							{"time":3,"value":0.15},
							{"time":4,"value":0.2}
						]
					}
				},
				"windupCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7,"value":-0.5,"leftHandleValue":0,"leftHandleSpan":0.396,"rightHandleValue":0,"rightHandleSpan":0.55},
						{"time":1,"value":0}
					]
				},
				"bounceCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.33,"value":-0.175,"leftHandleValue":0,"leftHandleSpan":0.453,"rightHandleValue":0,"rightHandleSpan":0.583},
						{"time":0.6,"value":0},
						{"time":0.83,"value":-0.08,"leftHandleValue":0,"leftHandleSpan":0.402,"rightHandleValue":0,"rightHandleSpan":0.735},
						{"time":1,"value":0}
					]
				}
			},
			{"i":17,"name":"ReelContainer4","uid":"8316685187983155","position":[720,0,0]},
			{
				"i":18,
				"type":"GraphicObject",
				"name":"ReelMask",
				"uid":"6574191565655363",
				"scale":[3.6,12,1],
				"graphicAsset":"WhiteBox",
				"subLayer":0.01,
				"masking":{"enabled":true,"type":"mask","maskGroups":["ReelMask"]},
				"effectControllerValues":{"fillColor":[1,1,1,0.2]},
				"materials":[
					{"effectNodes":["MaskingReturn","FillColor","ColorMultiply"]}
				]
			},
			{
				"i":19,
				"type":"SymbolReel",
				"name":"SymbolReel4",
				"uid":"9538172604418735",
				"position":[0,450,0],
				"defaultSymbolType":"GraphicObject",
				"numMainSymbols":4,
				"spinSpeed":-0.55,
				"windupDuration":0.36,
				"initialReelData":["Major2","Major2","Major2","Minor3","Minor3","Bonus"],
				"pathValues":{
					"position.y":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":300},
							{"time":0,"value":0},
							{"time":1,"value":-300},
							{"time":2,"value":-600},
							{"time":3,"value":-900},
							{"time":4,"value":-1200}
						]
					},
					"subLayer":{
						"valueSnap":0.001,
						"continueLeft":"extrapolate",
						"continueRight":"extrapolate",
						"keyframes":[
							{"time":-1,"value":-0.05},
							{"time":0,"value":0},
							{"time":1,"value":0.05},
							{"time":2,"value":0.1},
							{"time":3,"value":0.15},
							{"time":4,"value":0.2}
						]
					}
				},
				"windupCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.7,"value":-0.5,"leftHandleValue":0,"leftHandleSpan":0.396,"rightHandleValue":0,"rightHandleSpan":0.55},
						{"time":1,"value":0}
					]
				},
				"bounceCurve":{
					"valueSnap":0.001,
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.33,"value":-0.175,"leftHandleValue":0,"leftHandleSpan":0.453,"rightHandleValue":0,"rightHandleSpan":0.583},
						{"time":0.6,"value":0},
						{"time":0.83,"value":-0.08,"leftHandleValue":0,"leftHandleSpan":0.402,"rightHandleValue":0,"rightHandleSpan":0.735},
						{"time":1,"value":0}
					]
				}
			},
			{
				"i":20,
				"type":"TextBox",
				"name":"CenterWinMeter",
				"uid":"1153144534724274",
				"enabled":false,
				"subLayer":0.6,
				"string":"$100.00",
				"horizontalJustification":"center",
				"boxWidth":2000,
				"boxHeight":400,
				"textFormat":{
					"fontName":"ThemedFont",
					"lineHeightMultiplier":1,
					"characterMaterial":{
						"effectNodes":["SampleMainTexture","ColorMultiply"],
						"effectControllerValues":{}
					}
				},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":21,
				"type":"GraphicObject",
				"name":"CenterWinMeterShadow",
				"uid":"4164419886904129",
				"position":[0,-39.2825401992543,0],
				"scale":[10,10,10],
				"graphicAsset":"CenterWinMeterShadow",
				"subLayer":0.5,
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{"i":22,"constructDefinition":"Dashboard","type":"Construct","name":"Dashboard","uid":"6403247578121807"},
			{
				"i":23,
				"type":"Button",
				"name":"GameIntroBackground",
				"uid":"7089794052441777",
				"enabled":false,
				"scale":[100,100,1],
				"graphicAsset":"WhiteBox",
				"layer":"GameIntro",
				"subLayer":-0.5,
				"effectControllerValues":{"fillColor":[0,0,0,1]},
				"materials":[
					{"effectNodes":["FillColor","ColorMultiply"]}
				]
			},
			{
				"i":24,
				"constructDefinition":"GameIntroAnimation",
				"type":"Construct",
				"name":"GameIntroAnimation",
				"uid":"0061686663830606",
				"enabled":false,
				"position":[0,250,0],
				"scale":[0.85,0.85,1]
			},
			{
				"i":25,
				"type":"GraphicObject",
				"name":"BackgroundShadow",
				"uid":"7365576968087144",
				"scale":[5.4,10.8,1],
				"graphicAsset":"InnerShadow",
				"layer":"GameBackground",
				"subLayer":0.02799999999999977,
				"effectControllerValues":{"colorMultiply":[1,1,1,0.5]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":26,
				"type":"GraphicObject",
				"name":"GameBackgroundPattern",
				"uid":"4773984937761232",
				"scale":[2,2,1],
				"graphicAsset":"Background",
				"layer":"GameBackground",
				"masking":{"enabled":false,"type":"mask","maskGroups":["MainMaskGroup"]},
				"effectControllerValues":{"colorMultiply":[0.708866666666667,0.708866666666667,0.708866666666667,1]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":27,
				"type":"ParticleSystem",
				"name":"FallingStartParticles",
				"uid":"0254323932672707",
				"position":[0,1331.9586675620262,0],
				"layer":"GameBackground",
				"frustumCulling":false,
				"masking":{"enabled":true,"maskGroups":["FallingStarMask"]},
				"particleSystemDefinition":"FallingStars",
				"playbackController":{"autoplayMode":"loop","initialTime":500,"playbackRate":1,"startValue":0,"endValue":4000},
				"materials":[
					{"effectNodes":["SampleMainTexture","FallingStarsParticleSystemEffectNode"]}
				]
			},
			{
				"i":28,
				"type":"GraphicObject",
				"name":"FallingStarMask",
				"uid":"3671157916868505",
				"graphicAsset":"Background",
				"layer":"GameBackground",
				"subLayer":-0.047999999999999945,
				"masking":{"enabled":true,"type":"mask","maskGroups":["FallingStarMask"]},
				"materials":[
					{"effectNodes":["MaskingReturn","SampleMainTexture","ColorMultiply"]}
				]
			}
		]
	},
	"timelines":{
		"BaseLayout_Mobile":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-2,"value":1400},
						{"time":-1,"value":783.0000000000015},
						{"time":1,"value":837.2507196944065},
						{"time":1.6833333333333333,"value":813.8216015403309},
						{"time":2,"value":744.427619956735}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-1,"value":0},
						{"time":1,"value":-718.2498822089738},
						{"time":1.6833333333333333,"value":-1442.7845711670052},
						{"time":2,"value":-1683.3982075134104}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-560},
						{"time":-2,"value":-560},
						{"time":-1.5,"value":-196.00000000000068},
						{"time":-1,"value":-86.00000000000114},
						{"time":1,"value":0},
						{"time":1.5,"value":-45.99999999999716},
						{"time":1.6833333333333333,"value":85.00000000000242}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":1100}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"7175220269991170"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Mobile","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":-2,"value":5.4},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4},
						{"time":2,"value":10.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"keyframes":[
						{"time":-2,"value":10.8},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Desktop","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Desktop","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":1}
					],
					"propertyPath":["timelines","Layout_Mobile","weight"],
					"sceneObjectUid":"6403247578121807"
				}
			]
		},
		"BaseLayout_Desktop":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-2,"value":1400},
						{"time":-1,"value":783.0000000000015},
						{"time":1,"value":837.2507196944065},
						{"time":1.6833333333333333,"value":813.8216015403309},
						{"time":2,"value":744.427619956735}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-1,"value":0},
						{"time":1,"value":-718.2498822089738},
						{"time":1.6833333333333333,"value":-1442.7845711670052},
						{"time":2,"value":-1683.3982075134104}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-560},
						{"time":-2,"value":-560},
						{"time":-1.5,"value":-196.00000000000068},
						{"time":-1,"value":-86.00000000000114},
						{"time":1,"value":0},
						{"time":1.5,"value":-45.99999999999716},
						{"time":1.6833333333333333,"value":85.00000000000242}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":1100}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"7175220269991170"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Mobile","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":-2,"value":5.4},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4},
						{"time":2,"value":10.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"keyframes":[
						{"time":-2,"value":10.8},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Mobile","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":1}
					],
					"propertyPath":["timelines","Layout_Desktop","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Desktop","time"],
					"sceneObjectUid":"6403247578121807"
				}
			]
		},
		"BaseLayout_EgmSingleScreen":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-2,"value":1400},
						{"time":-1,"value":783.0000000000015},
						{"time":1,"value":837.2507196944065},
						{"time":1.6833333333333333,"value":813.8216015403309},
						{"time":2,"value":744.427619956735}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-1,"value":0},
						{"time":1,"value":-718.2498822089738},
						{"time":1.6833333333333333,"value":-1442.7845711670052},
						{"time":2,"value":-1683.3982075134104}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":0.75},
						{"time":1,"value":0.7},
						{"time":1.6833333333333333,"value":0.725},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-560},
						{"time":-2,"value":-560},
						{"time":-1.5,"value":-196.00000000000068},
						{"time":-1,"value":-86.00000000000114},
						{"time":1,"value":0},
						{"time":1.5,"value":-45.99999999999716},
						{"time":1.6833333333333333,"value":85.00000000000242}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":1100}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"7175220269991170"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.85},
						{"time":1,"value":0.85},
						{"time":1.5,"value":1},
						{"time":2,"value":1.25}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Mobile","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":-2,"value":5.4},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4},
						{"time":2,"value":10.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"keyframes":[
						{"time":-2,"value":10.8},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Mobile","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Desktop","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Desktop","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_EGM","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":1}
					],
					"propertyPath":["timelines","Layout_EGM","weight"],
					"sceneObjectUid":"6403247578121807"
				}
			]
		},
		"BaseLayout_EgmDualScreen":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":-4,
			"endValue":4,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":-4,"value":21.6},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":86.4}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-4,"value":86.4},
						{"time":-1,"value":21.6},
						{"time":1,"value":21.6},
						{"time":4,"value":21.6}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2259684172978443"
				},
				{
					"keyframes":[
						{"time":-4,"value":1115},
						{"time":-2,"value":1105.0000000000005},
						{"time":-1,"value":550.0000000000014},
						{"time":1,"value":550.0000000000014},
						{"time":1.6833333333333333,"value":550.0000000000014},
						{"time":2,"value":550.0000000000014}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-1,"value":0},
						{"time":1,"value":0},
						{"time":1.6833333333333333,"value":0},
						{"time":2,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":1},
						{"time":1,"value":1},
						{"time":1.6833333333333333,"value":1},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":-2,"value":1.5},
						{"time":-1,"value":1},
						{"time":1,"value":1},
						{"time":1.6833333333333333,"value":1},
						{"time":2,"value":1}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9279909710684411"
				},
				{
					"keyframes":[
						{"time":1,"value":0}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-1050},
						{"time":-2,"value":-1040},
						{"time":-1.5,"value":-750},
						{"time":-1,"value":-490},
						{"time":1,"value":-490},
						{"time":1.5,"value":-490},
						{"time":1.6833333333333333,"value":-490},
						{"time":2,"value":-490}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":1100}
					],
					"propertyPath":["graphicExpander","expandedWidth"],
					"sceneObjectUid":"7175220269991170"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.73},
						{"time":1,"value":0.73},
						{"time":1.5,"value":0.73},
						{"time":1.6833333333333333,"value":0.73},
						{"time":2,"value":0.73}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-2,"value":1},
						{"time":-1.5,"value":1},
						{"time":-1,"value":0.73},
						{"time":1,"value":0.73},
						{"time":1.5,"value":0.73},
						{"time":1.6833333333333333,"value":0.73},
						{"time":2,"value":0.73}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7193618239035880"
				},
				{
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Mobile","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":0.9833333333333333,"value":2}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"4773984937761232"
				},
				{
					"keyframes":[
						{"time":-2,"value":5.4},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4},
						{"time":2,"value":10.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"keyframes":[
						{"time":-2,"value":10.8},
						{"time":-1,"value":5.4},
						{"time":1,"value":5.4}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7365576968087144"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Mobile","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":0}
					],
					"propertyPath":["timelines","Layout_Desktop","weight"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_Desktop","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":-4},
						{"time":4,"value":4}
					],
					"propertyPath":["timelines","Layout_EGM","time"],
					"sceneObjectUid":"6403247578121807"
				},
				{
					"valueSnap":0.01,
					"keyframes":[
						{"time":-4,"value":1}
					],
					"propertyPath":["timelines","Layout_EGM","weight"],
					"sceneObjectUid":"6403247578121807"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"BaseLayout_Mobile"}
}

Assets/GameLayout/GameLayout.construct.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/GameTitle.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.downscalingMode is "mipmapLinear" instead of the default null.

Assets/GameLayout/InnerShadow.png.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout/ReelBackground.png.ncData
------------------------------------------------------------
default ncData file

Assets/LayersAndMasks/main.maskGroups.ncData
------------------------------------------------------------
default ncData file

Assets/LayersAndMasks/MainScene.layers
------------------------------------------------------------
{"layers":["GameBackground","Reels","WinningSymbols","GameTitle","Dashboard","GameIntro","GameMenus"]}

Assets/LayersAndMasks/MainScene.layers.ncData
------------------------------------------------------------
default ncData file

Assets/ParticleSystems/FallingStars.particleSysDef.ncData
------------------------------------------------------------
default ncData file

Assets/ParticleSystems/SampleParticle.png.ncData
------------------------------------------------------------
default ncData file

Assets/ParticleSystems/StarBurst.particleSysDef.ncData
------------------------------------------------------------
default ncData file

Assets/ParticleSystems/StarParticle.png.ncData
------------------------------------------------------------
Deviations from default ncData:

- imageConfigurations.downscalingMode is "mipmapLinear" instead of the default null.

Assets/Sounds/ReelSpinSound.wav.ncData
------------------------------------------------------------
default ncData file

Assets/Sounds/ReelStop.wav.ncData
------------------------------------------------------------
default ncData file

Assets/Sounds/SpinBegin.wav.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarGrayThick_Plate.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarGrayThick_Text.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarGrayThin_Plate.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarGrayThin_Text.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarWhite_Plate.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BarWhite_Text.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Bonus_Star.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Bonus_Text.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/BonusConstruct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Bonus_Star",
				"uid":"4323194875749118",
				"position":[0.53,-0.93,0],
				"scale":[0.4679,0.4913,1],
				"graphicAsset":"Bonus_Star",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,192.3,85.5],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Bonus_Text",
				"uid":"6252760189555979",
				"position":[-3.29,-3.22,0],
				"scale":[0.4238,0.4319,1],
				"graphicAsset":"Bonus_Text",
				"subLayer":0.01,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,212.4,94.4],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"1809679290810033",
				"position":[0,0,1000],
				"coreViewWidth":400,
				"coreViewHeight":400,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":400,
				"constructPrecompTargetHeight":400
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":0,"value":0.53,"rightHandleValue":3.8887,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-5.361,
							"leftHandleValue":0.7538,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.8864,
							"rightHandleSpan":0.4
						},
						{
							"time":0.383333,
							"value":5.537,
							"leftHandleValue":0.7581,
							"leftHandleSpan":0.4,
							"rightHandleValue":-13.2348,
							"rightHandleSpan":0.8
						},
						{"time":0.75,"value":0.517,"leftHandleValue":1.7338,"leftHandleSpan":1},
						{"time":2,"value":0.53}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0,"value":-0.93,"rightHandleValue":-1.2185,"rightHandleSpan":0.4},
						{
							"time":0.1,
							"value":-1.108,
							"leftHandleValue":-0.6302,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.9874,
							"rightHandleSpan":0.4
						},
						{
							"time":0.283333,
							"value":-10.814,
							"leftHandleValue":0.9468,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.4736,
							"rightHandleSpan":0.4
						},
						{
							"time":0.716667,
							"value":-0.959,
							"leftHandleValue":3.7002,
							"leftHandleSpan":0.9,
							"rightHandleValue":1.2911,
							"rightHandleSpan":0.7
						},
						{"time":2,"value":-0.93,"leftHandleValue":0.1337,"leftHandleSpan":0.7}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4679,"rightHandleValue":-0.023,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.40031,
							"leftHandleValue":0.0096,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0155,
							"rightHandleSpan":0.2
						},
						{
							"time":0.283333,
							"value":0.66279,
							"leftHandleValue":0.0325,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0181,
							"rightHandleSpan":0.3
						},
						{
							"time":0.666667,
							"value":0.47725,
							"leftHandleValue":0.0788,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0129,
							"rightHandleSpan":0.1
						},
						{
							"time":0.966667,
							"value":0.44483,
							"leftHandleValue":-0.0007,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0175,
							"rightHandleSpan":1
						},
						{
							"time":1.266667,
							"value":0.60377,
							"leftHandleValue":-0.1236,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0155,
							"rightHandleSpan":0.2
						},
						{
							"time":1.383333,
							"value":0.54948,
							"leftHandleValue":0.0439,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1269,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.4679,"leftHandleValue":-0.015,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4913,"rightHandleValue":-0.0241,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.42033,
							"leftHandleValue":0.0101,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0162,
							"rightHandleSpan":0.2
						},
						{
							"time":0.283333,
							"value":0.69594,
							"leftHandleValue":0.0341,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0016,
							"rightHandleSpan":0.2
						},
						{
							"time":0.666667,
							"value":0.50112,
							"leftHandleValue":0.0854,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0136,
							"rightHandleSpan":0.1
						},
						{
							"time":0.966667,
							"value":0.46707,
							"leftHandleValue":-0.0007,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0183,
							"rightHandleSpan":1
						},
						{
							"time":1.266667,
							"value":0.63397,
							"leftHandleValue":-0.1297,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0163,
							"rightHandleSpan":0.2
						},
						{
							"time":1.383333,
							"value":0.57696,
							"leftHandleValue":0.0461,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1333,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.4913,"leftHandleValue":-0.0157,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-5.2605,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":-18.454,
							"leftHandleValue":-1.7077,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1853,
							"rightHandleSpan":0.2
						},
						{
							"time":0.083333,
							"value":3.935,
							"leftHandleValue":-10.0695,
							"leftHandleSpan":0.4,
							"rightHandleValue":97.6694,
							"rightHandleSpan":0.3
						},
						{"time":0.5,"value":372,"leftHandleValue":-79.6611,"leftHandleSpan":0.3,"rightHandleValue":8.0261,"rightHandleSpan":0.4},
						{
							"time":0.533333,
							"value":380.804,
							"leftHandleValue":0.2407,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.7307,
							"rightHandleSpan":0.4
						},
						{
							"time":0.633333,
							"value":355.601,
							"leftHandleValue":-2.0591,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.0687,
							"rightHandleSpan":0.3
						},
						{
							"time":0.983333,
							"value":360.805,
							"leftHandleValue":0.4832,
							"leftHandleSpan":1,
							"rightHandleValue":0.4889,
							"rightHandleSpan":1
						},
						{"time":1.3,"value":356,"leftHandleValue":1.2912,"leftHandleSpan":0.3,"rightHandleValue":1.6065,"rightHandleSpan":0.4},
						{
							"time":1.416667,
							"value":364.095,
							"leftHandleValue":0.8197,
							"leftHandleSpan":0.4,
							"rightHandleValue":-5.843,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":360,"leftHandleValue":-0.3582,"leftHandleSpan":1}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0,"value":-3.29,"rightHandleValue":0.7934,"rightHandleSpan":0.6},
						{
							"time":0.316667,
							"value":-5.263,
							"leftHandleValue":1.5972,
							"leftHandleSpan":0.3,
							"rightHandleValue":6.8116,
							"rightHandleSpan":0.2
						},
						{
							"time":0.666667,
							"value":-2.838,
							"leftHandleValue":-4.2644,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.9057,
							"rightHandleSpan":0.4
						},
						{
							"time":1.316667,
							"value":-5.719,
							"leftHandleValue":5.3829,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.0606,
							"rightHandleSpan":0.4
						},
						{"time":1.716667,"value":-3.472,"leftHandleValue":-0.8677,"leftHandleSpan":1},
						{"time":2,"value":-3.29}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				},
				{
					"keyframes":[
						{"time":0,"value":-3.22,"rightHandleValue":-3.2696,"rightHandleSpan":0.8},
						{
							"time":0.316667,
							"value":3.843,
							"leftHandleValue":-3.5078,
							"leftHandleSpan":0.3,
							"rightHandleValue":-4.5788,
							"rightHandleSpan":0.6
						},
						{
							"time":0.583333,
							"value":-1.439,
							"leftHandleValue":-5.5209,
							"leftHandleSpan":1,
							"rightHandleValue":-3.1196,
							"rightHandleSpan":0.4
						},
						{
							"time":1.033333,
							"value":-4.003,
							"leftHandleValue":0.4816,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.0463,
							"rightHandleSpan":0.8
						},
						{
							"time":1.283333,
							"value":2.008,
							"leftHandleValue":-1.5356,
							"leftHandleSpan":0.3,
							"rightHandleValue":-10.1659,
							"rightHandleSpan":0.3
						},
						{"time":1.8,"value":-3.197,"leftHandleValue":2.4187,"leftHandleSpan":0.7},
						{"time":2,"value":-3.22}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4238,"rightHandleValue":-0.0009,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":0.4238,
							"leftHandleValue":-0.0536,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0485,
							"rightHandleSpan":0.4
						},
						{
							"time":0.316667,
							"value":0.67791,
							"leftHandleValue":-0.0251,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0101,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.3936,
							"leftHandleValue":0.015,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0003,
							"rightHandleSpan":0.4
						},
						{
							"time":0.566667,
							"value":0.49179,
							"leftHandleValue":0.0014,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0399,
							"rightHandleSpan":0.3
						},
						{"time":1,"value":0.39607,"leftHandleValue":0.0188,"leftHandleSpan":1,"rightHandleValue":0.0026,"rightHandleSpan":0.4},
						{
							"time":1.183333,
							"value":0.42546,
							"leftHandleValue":-0.024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0356,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":0.61379,
							"leftHandleValue":0.0031,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0329,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.39637,
							"leftHandleValue":0.0007,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0135,
							"rightHandleSpan":0.4
						},
						{"time":1.65,"value":0.4238,"leftHandleValue":0.0617,"leftHandleSpan":0.9},
						{"time":2,"value":0.4238}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4319,"rightHandleValue":-0.0009,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":0.4319,
							"leftHandleValue":-0.0546,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0228,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":0.69086,
							"leftHandleValue":0.0001,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0103,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.40113,
							"leftHandleValue":0.0153,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0003,
							"rightHandleSpan":0.4
						},
						{
							"time":0.566667,
							"value":0.50119,
							"leftHandleValue":0.0014,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0406,
							"rightHandleSpan":0.3
						},
						{"time":1,"value":0.40364,"leftHandleValue":0.0192,"leftHandleSpan":1,"rightHandleValue":0.0027,"rightHandleSpan":0.4},
						{
							"time":1.183333,
							"value":0.43359,
							"leftHandleValue":-0.0245,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0363,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":0.62552,
							"leftHandleValue":0.0031,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0335,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.40395,
							"leftHandleValue":0.0007,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0332,
							"rightHandleSpan":0.5
						},
						{"time":1.65,"value":0.4319,"leftHandleValue":0.057,"leftHandleSpan":0.9},
						{"time":2,"value":0.4319}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.316667,"value":0,"rightHandleValue":0.3422,"rightHandleSpan":0.1},
						{
							"time":0.383333,
							"value":-6.543,
							"leftHandleValue":-0.5987,
							"leftHandleSpan":0.5,
							"rightHandleValue":1.3667,
							"rightHandleSpan":0.4
						},
						{
							"time":0.516667,
							"value":4.314,
							"leftHandleValue":0.3607,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.901,
							"rightHandleSpan":0.4
						},
						{
							"time":0.65,
							"value":-2.844,
							"leftHandleValue":-0.2378,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.4984,
							"rightHandleSpan":0.6
						},
						{
							"time":0.916667,
							"value":-1.236,
							"leftHandleValue":5.4774,
							"leftHandleSpan":0.9,
							"rightHandleValue":4.1934,
							"rightHandleSpan":0.6
						},
						{
							"time":1.266667,
							"value":0,
							"leftHandleValue":-1.0954,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.5026,
							"rightHandleSpan":0.3
						},
						{
							"time":1.333333,
							"value":4.778,
							"leftHandleValue":0.8875,
							"leftHandleSpan":0.6,
							"rightHandleValue":-2.1333,
							"rightHandleSpan":0.4
						},
						{
							"time":1.433333,
							"value":-3.15,
							"leftHandleValue":-1.0292,
							"leftHandleSpan":0.4,
							"rightHandleValue":10.0112,
							"rightHandleSpan":0.7
						},
						{
							"time":1.633333,
							"value":-1.369,
							"leftHandleValue":1.4133,
							"leftHandleSpan":0.6,
							"rightHandleValue":5.0772,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-1.7674,"leftHandleSpan":0.9}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				},
				{
					"keyframes":[
						{"time":0.466667,"value":-704.7,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.866667,"value":705.9,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.2,"value":-704.7,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.5,"value":705.9,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"4323194875749118"
				},
				{
					"keyframes":[
						{"time":0.466667,"value":-767.8,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.866667,"value":789.5,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.2,"value":-767.8,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.5,"value":789.5,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"6252760189555979"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/BonusConstruct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major1_Fill.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major1_Outline.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major1_Shell.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major1Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Major1_Shell",
				"uid":"7114710497465075",
				"position":[0.45,0.52,0],
				"scale":[0.4934,0.4934,1],
				"graphicAsset":"Major1_Shell",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Major1_Outline",
				"uid":"8426846563212233",
				"position":[-2.16,9.37,0],
				"scale":[0.4474,0.4492,1],
				"graphicAsset":"Major1_Outline",
				"subLayer":0.02,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,156.5,55.9],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"Major1_Fill",
				"uid":"2917034236671276",
				"position":[-2.18,6.59,0],
				"scale":[0.4725,0.4781,1],
				"graphicAsset":"Major1_Fill",
				"subLayer":0.01,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,148.1,52.9],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"6581741668587752",
				"position":[0,0,1000],
				"coreViewWidth":500,
				"coreViewHeight":500,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":500,
				"constructPrecompTargetHeight":500
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.45},
						{"time":0.13333333333333333,"value":1.407,"rightHandleValue":0.9937,"rightHandleSpan":0.99},
						{
							"time":0.21666666666666667,
							"value":12.023,
							"leftHandleValue":-6.5745,
							"leftHandleSpan":0.3,
							"rightHandleValue":1.9184,
							"rightHandleSpan":0.4
						},
						{
							"time":0.25,
							"value":10.925,
							"leftHandleValue":-0.736,
							"leftHandleSpan":0.4,
							"rightHandleValue":14.4002,
							"rightHandleSpan":0.7
						},
						{
							"time":0.36666666666666664,
							"value":15.455,
							"leftHandleValue":-4.8312,
							"leftHandleSpan":0.8,
							"rightHandleValue":-14.0663,
							"rightHandleSpan":0.6
						},
						{
							"time":1.25,
							"value":-14.383,
							"leftHandleValue":9.1609,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2698,
							"rightHandleSpan":0.4
						},
						{"time":1.4,"value":2.012,"leftHandleValue":2.187,"leftHandleSpan":0.6,"rightHandleValue":19.5066,"rightHandleSpan":0.4},
						{
							"time":1.4666666666666666,
							"value":-4.238,
							"leftHandleValue":1.3204,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.6051,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-2.831,
							"leftHandleValue":16.2673,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.9377,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":1.97,
							"leftHandleValue":-0.3131,
							"leftHandleSpan":0.4,
							"rightHandleValue":-10.0545,
							"rightHandleSpan":0.8
						},
						{
							"time":1.7333333333333334,
							"value":-0.647,
							"leftHandleValue":5.5423,
							"leftHandleSpan":0.9,
							"rightHandleValue":2.2003,
							"rightHandleSpan":0.1
						},
						{"time":2,"value":0.45,"leftHandleValue":-0.0308,"leftHandleSpan":0.7}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.52,"rightHandleValue":-4.2852,"rightHandleSpan":0.3},
						{
							"time":0.2,
							"value":7.108,
							"leftHandleValue":-5.5468,
							"leftHandleSpan":0.4,
							"rightHandleValue":13.691,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":10.562,
							"leftHandleValue":-11.6416,
							"leftHandleSpan":0.6,
							"rightHandleValue":3.1658,
							"rightHandleSpan":0.1
						},
						{
							"time":0.3333333333333333,
							"value":10.241,
							"leftHandleValue":-4.6685,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.6815,
							"rightHandleSpan":0.05
						},
						{
							"time":1.25,
							"value":-2.153,
							"leftHandleValue":15.6351,
							"leftHandleSpan":0.8,
							"rightHandleValue":1.7012,
							"rightHandleSpan":0.5
						},
						{
							"time":1.4,
							"value":-0.663,
							"leftHandleValue":6.7407,
							"leftHandleSpan":0.7,
							"rightHandleValue":13.5789,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":-4.802,
							"leftHandleValue":4.914,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.076,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":4.635,
							"leftHandleValue":3.6363,
							"leftHandleSpan":0.4,
							"rightHandleValue":-16.2724,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":-0.676,
							"leftHandleValue":13.5085,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.0401,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":-0.869,
							"leftHandleValue":5.8405,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.1108,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":1.098,
							"leftHandleValue":-2.7966,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.2293,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.52,"leftHandleValue":0.4866,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":0.5395,"rightHandleSpan":0.4},
						{
							"time":0.11666666666666667,
							"value":4.32,
							"leftHandleValue":-0.2111,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.8088,
							"rightHandleSpan":0.5
						},
						{
							"time":0.26666666666666666,
							"value":-32.994,
							"leftHandleValue":13.6833,
							"leftHandleSpan":0.4,
							"rightHandleValue":-8.087,
							"rightHandleSpan":0.1
						},
						{
							"time":1.2666666666666666,
							"value":-47.581,
							"leftHandleValue":-17.567,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.5886,
							"rightHandleSpan":0.4
						},
						{"time":1.45,"value":1.282,"leftHandleValue":1.417,"leftHandleSpan":0.6,"rightHandleValue":-3.296,"rightHandleSpan":0.4},
						{"time":2,"value":0,"leftHandleValue":2.1563,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4934,"rightHandleValue":-0.0324,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41446,
							"leftHandleValue":-0.0162,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0955,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.75239,
							"leftHandleValue":0.0018,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0358,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.69074,
							"leftHandleValue":-0.0136,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0408,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.76209,
							"leftHandleValue":-0.0241,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0187,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.43011,
							"leftHandleValue":-0.0047,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0212,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.55278,
							"leftHandleValue":0.0112,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0145,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.47708,
							"leftHandleValue":-0.0066,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0379,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4934,"leftHandleValue":0.0105,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4934,"rightHandleValue":-0.0324,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41446,
							"leftHandleValue":-0.0162,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0955,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.75239,
							"leftHandleValue":0.0018,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0358,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.69074,
							"leftHandleValue":-0.0136,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0408,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.76209,
							"leftHandleValue":-0.0241,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0187,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.43011,
							"leftHandleValue":-0.0047,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0212,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.55278,
							"leftHandleValue":0.0112,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0145,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.47708,
							"leftHandleValue":-0.0066,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0379,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4934,"leftHandleValue":0.0105,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.4383,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":9.975,
							"leftHandleValue":-0.0155,
							"leftHandleSpan":0.3,
							"rightHandleValue":-6.2697,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-7.645,
							"leftHandleValue":4.0732,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.5734,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":7.651,
							"leftHandleValue":-2.2661,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2313,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.161,
							"leftHandleValue":0.0168,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.2937,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.6903,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1211,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.402,
							"leftHandleValue":-0.6816,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2624,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-19.383,
							"leftHandleValue":-0.1834,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.3058,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":16.114,
							"leftHandleValue":-14.0516,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4864,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-11.089,
							"leftHandleValue":4.7516,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.9034,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.118,
							"leftHandleValue":-0.9491,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7544,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.2574,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-3.4771,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":-8.1,
							"leftHandleValue":0.8194,
							"leftHandleSpan":0.3,
							"rightHandleValue":5.3748,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2666666666666666,
							"value":7.586,
							"leftHandleValue":-7.1253,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.3395,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-8.947,
							"leftHandleValue":2.1857,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0913,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":4.247,
							"leftHandleValue":0.5918,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7415,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.8319,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"7114710497465075"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-2.16,"rightHandleValue":-0.1308,"rightHandleSpan":0.3},
						{
							"time":0.2,
							"value":-4.125,
							"leftHandleValue":6.3892,
							"leftHandleSpan":0.2,
							"rightHandleValue":8.7811,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":-15.429,
							"leftHandleValue":-2.7316,
							"leftHandleSpan":0.5,
							"rightHandleValue":6.7738,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":-13.286,
							"leftHandleValue":-5.404,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.8269,
							"rightHandleSpan":0.2
						},
						{
							"time":1.2166666666666666,
							"value":4.732,
							"leftHandleValue":-2.875,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.3365,
							"rightHandleSpan":0.6
						},
						{
							"time":1.35,
							"value":-1.54,
							"leftHandleValue":1.3927,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.0149,
							"rightHandleSpan":0.99
						},
						{
							"time":1.4166666666666667,
							"value":7.494,
							"leftHandleValue":-9.2439,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.7406,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-5.867,
							"leftHandleValue":0.1576,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.814,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-6.231,
							"leftHandleValue":17.6014,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.2386,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":-1.623,
							"leftHandleValue":-0.4026,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.0718,
							"rightHandleSpan":0.8
						},
						{
							"time":1.7333333333333334,
							"value":-3.235,
							"leftHandleValue":5.872,
							"leftHandleSpan":0.8,
							"rightHandleValue":3.0976,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-2.16,"leftHandleValue":-0.2856,"leftHandleSpan":0.8}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":9.37,"rightHandleValue":-9.3454,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":17.778,
							"leftHandleValue":0.5959,
							"leftHandleSpan":0.4,
							"rightHandleValue":11.3647,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":13.661,
							"leftHandleValue":-8.8832,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.1714,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":12.768,
							"leftHandleValue":-4.7192,
							"leftHandleSpan":0.8,
							"rightHandleValue":-3.9398,
							"rightHandleSpan":0.05
						},
						{
							"time":1.25,
							"value":26.948,
							"leftHandleValue":-6.0041,
							"leftHandleSpan":0.2,
							"rightHandleValue":1.81,
							"rightHandleSpan":0.3
						},
						{
							"time":1.4,
							"value":6.798,
							"leftHandleValue":1.8145,
							"leftHandleSpan":0.5,
							"rightHandleValue":13.7627,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":3.722,
							"leftHandleValue":4.3766,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5197,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":14.431,
							"leftHandleValue":3.2635,
							"leftHandleSpan":0.4,
							"rightHandleValue":-16.0151,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":8.183,
							"leftHandleValue":14.4359,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.325,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":7.487,
							"leftHandleValue":5.8721,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.2231,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":10.146,
							"leftHandleValue":-3.1291,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.0196,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":9.37,"leftHandleValue":0.4711,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":0.4037,"rightHandleSpan":0.4},
						{
							"time":0.1,
							"value":-1.647,
							"leftHandleValue":-0.1489,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2338,
							"rightHandleSpan":0.6
						},
						{
							"time":0.26666666666666666,
							"value":39.096,
							"leftHandleValue":-14.3258,
							"leftHandleSpan":0.4,
							"rightHandleValue":7.9981,
							"rightHandleSpan":0.1
						},
						{
							"time":1.2666666666666666,
							"value":42.457,
							"leftHandleValue":22.7581,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.6616,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3833333333333333,
							"value":6.745,
							"leftHandleValue":4.7791,
							"leftHandleSpan":0.3,
							"rightHandleValue":-6.9925,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":1.237,
							"leftHandleValue":1.5628,
							"leftHandleSpan":0.4,
							"rightHandleValue":-7.1665,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":0,"leftHandleValue":2.2761,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4474,"rightHandleValue":-0.0294,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.37582,
							"leftHandleValue":-0.0147,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0866,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.68225,
							"leftHandleValue":0.0017,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0325,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.62634,
							"leftHandleValue":-0.0124,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.037,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.69104,
							"leftHandleValue":-0.0219,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0169,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39001,
							"leftHandleValue":-0.0043,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0192,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.50124,
							"leftHandleValue":0.0102,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0131,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.4326,
							"leftHandleValue":-0.006,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0274,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4474,"leftHandleValue":0.0135,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4492,"rightHandleValue":-0.0295,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.37733,
							"leftHandleValue":-0.0148,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.087,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.68499,
							"leftHandleValue":0.0017,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0326,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.62886,
							"leftHandleValue":-0.0124,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0372,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.69382,
							"leftHandleValue":-0.022,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.017,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39158,
							"leftHandleValue":-0.0043,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0193,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.50326,
							"leftHandleValue":0.0102,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0132,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.43434,
							"leftHandleValue":-0.006,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0276,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4492,"leftHandleValue":0.0135,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.4383,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":9.975,
							"leftHandleValue":-0.0155,
							"leftHandleSpan":0.3,
							"rightHandleValue":-6.2697,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-7.645,
							"leftHandleValue":4.0732,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.5734,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":7.651,
							"leftHandleValue":-2.2661,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2313,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.161,
							"leftHandleValue":0.0168,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.2937,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.6903,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1211,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.402,
							"leftHandleValue":-0.6816,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2624,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-19.383,
							"leftHandleValue":-0.1834,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.3058,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":16.114,
							"leftHandleValue":-14.0516,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4864,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-11.089,
							"leftHandleValue":4.7516,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.9034,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.118,
							"leftHandleValue":-0.9491,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7544,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.2574,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-3.4771,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":-8.1,
							"leftHandleValue":0.8194,
							"leftHandleSpan":0.3,
							"rightHandleValue":5.3748,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2666666666666666,
							"value":7.586,
							"leftHandleValue":-7.1253,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.3395,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-8.947,
							"leftHandleValue":2.1857,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0913,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":4.247,
							"leftHandleValue":0.5918,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7415,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.8319,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-2.18,"rightHandleValue":1.5668,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-1.277,
							"leftHandleValue":-0.0076,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.8129,
							"rightHandleSpan":0.4
						},
						{
							"time":0.25,
							"value":-3.503,
							"leftHandleValue":2.0648,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.056,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":-1.902,
							"leftHandleValue":5.7222,
							"leftHandleSpan":0.99,
							"rightHandleValue":3.1819,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":-1.088,
							"leftHandleValue":-1.6751,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.3573,
							"rightHandleSpan":0.8
						},
						{
							"time":1.2833333333333332,
							"value":-6.78,
							"leftHandleValue":-1.7971,
							"leftHandleSpan":0.05,
							"rightHandleValue":3.4261,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-0.113,
							"leftHandleValue":-0.4179,
							"leftHandleSpan":0.4,
							"rightHandleValue":20.136,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-6.179,
							"leftHandleValue":1.7058,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.9728,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-6.068,
							"leftHandleValue":17.1219,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.1156,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":-1.332,
							"leftHandleValue":-0.3973,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.2713,
							"rightHandleSpan":0.8
						},
						{
							"time":1.7333333333333334,
							"value":-3.26,
							"leftHandleValue":6.0865,
							"leftHandleSpan":0.8,
							"rightHandleValue":3.0194,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-2.18,"leftHandleValue":-0.3827,"leftHandleSpan":0.8}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":6.59,"rightHandleValue":-6.8383,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":15.116,
							"leftHandleValue":-6.2778,
							"leftHandleSpan":0.6,
							"rightHandleValue":13.0318,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":14.642,
							"leftHandleValue":-9.7025,
							"leftHandleSpan":0.6,
							"rightHandleValue":2.8404,
							"rightHandleSpan":0.1
						},
						{
							"time":0.3333333333333333,
							"value":14.005,
							"leftHandleValue":-4.6782,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.8291,
							"rightHandleSpan":0.05
						},
						{
							"time":1.25,
							"value":14.622,
							"leftHandleValue":-0.7748,
							"leftHandleSpan":0.9,
							"rightHandleValue":0.8272,
							"rightHandleSpan":0.4
						},
						{"time":1.4,"value":4.657,"leftHandleValue":2.735,"leftHandleSpan":0.4,"rightHandleValue":13.6451,"rightHandleSpan":0.4},
						{
							"time":1.45,
							"value":1.154,
							"leftHandleValue":4.5622,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7103,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":11.404,
							"leftHandleValue":3.4203,
							"leftHandleSpan":0.4,
							"rightHandleValue":-16.1971,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":5.354,
							"leftHandleValue":14.152,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.2279,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":4.838,
							"leftHandleValue":5.838,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.1972,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":7.316,
							"leftHandleValue":-3.0399,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.0766,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":6.59,"leftHandleValue":0.4854,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":5.0066,"rightHandleSpan":0.2},
						{
							"time":1.2666666666666666,
							"value":-2.33,
							"leftHandleValue":4.7257,
							"leftHandleSpan":0.7,
							"rightHandleValue":9.5014,
							"rightHandleSpan":0.4
						},
						{"time":1.8666666666666667,"value":0.303,"leftHandleValue":-4.5779,"leftHandleSpan":0.7},
						{"time":2,"value":0}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4725,"rightHandleValue":-0.031,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.3969,
							"leftHandleValue":-0.0155,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0915,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.72052,
							"leftHandleValue":0.0017,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0343,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.66148,
							"leftHandleValue":-0.0131,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0391,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.72981,
							"leftHandleValue":-0.0231,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0179,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.41189,
							"leftHandleValue":-0.0045,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0203,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.52936,
							"leftHandleValue":0.0108,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0139,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.45687,
							"leftHandleValue":-0.0063,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0363,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4725,"leftHandleValue":0.01,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4781,"rightHandleValue":-0.0314,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.4016,
							"leftHandleValue":-0.0157,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0926,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.72906,
							"leftHandleValue":0.0018,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0347,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.66932,
							"leftHandleValue":-0.0132,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0396,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.73846,
							"leftHandleValue":-0.0234,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0181,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.41677,
							"leftHandleValue":-0.0046,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0206,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.53563,
							"leftHandleValue":0.0109,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.014,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.46228,
							"leftHandleValue":-0.0064,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0367,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4781,"leftHandleValue":0.0101,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.4383,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":9.975,
							"leftHandleValue":-0.0155,
							"leftHandleSpan":0.3,
							"rightHandleValue":-6.2697,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-7.645,
							"leftHandleValue":4.0732,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.5734,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":7.651,
							"leftHandleValue":-2.2661,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2313,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.161,
							"leftHandleValue":0.0168,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.2937,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.6903,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1211,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.402,
							"leftHandleValue":-0.6816,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2624,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-19.383,
							"leftHandleValue":-0.1834,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.3058,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":16.114,
							"leftHandleValue":-14.0516,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4864,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-11.089,
							"leftHandleValue":4.7516,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.9034,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.118,
							"leftHandleValue":-0.9491,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7544,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.2574,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-3.4771,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":-8.1,
							"leftHandleValue":0.8194,
							"leftHandleSpan":0.3,
							"rightHandleValue":5.3748,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2666666666666666,
							"value":7.586,
							"leftHandleValue":-7.1253,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.3395,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-8.947,
							"leftHandleValue":2.1857,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0913,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":4.247,
							"leftHandleValue":0.5918,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7415,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.8319,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-705},
						{"time":1.2333333333333334,"value":691.8},
						{"time":1.4333333333333333,"value":-705},
						{"time":1.6166666666666667,"value":691.8}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"2917034236671276"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-749},
						{"time":1.2333333333333334,"value":726.2},
						{"time":1.4333333333333333,"value":-749},
						{"time":1.6166666666666667,"value":726.2}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"8426846563212233"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":1},
						{"time":0.11666666666666667,"value":0.8977,"rightHandleValue":-0.0576,"rightHandleSpan":0.8},
						{
							"time":0.26666666666666666,
							"value":2.0033,
							"leftHandleValue":-0.065,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0356,
							"rightHandleSpan":0.4
						},
						{"time":0.5,"value":1.25,"leftHandleValue":0.0664,"leftHandleSpan":0.4,"rightHandleValue":0.2184,"rightHandleSpan":0.5},
						{
							"time":1.0333333333333332,
							"value":1.3233,
							"leftHandleValue":1.2174,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.3153,
							"rightHandleSpan":0.6
						},
						{
							"time":1.25,
							"value":1.999,
							"leftHandleValue":-0.1669,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0145,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.9892,
							"leftHandleValue":-0.0549,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0433,
							"rightHandleSpan":0.4
						},
						{"time":1.6,"value":1.5,"leftHandleValue":-0.0349,"leftHandleSpan":0.4,"rightHandleValue":-0.134,"rightHandleSpan":0.4},
						{"time":2,"value":1,"leftHandleValue":-0.1754,"leftHandleSpan":0.8}
					],
					"propertyPath":["material","0","colorMultiply","alpha"],
					"sceneObjectUid":"8426846563212233"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Major1Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major2_Fill.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major2_Outline.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major2_Shell.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major2Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Major2_Shell",
				"uid":"0792440268599528",
				"position":[0.88,0.29,0],
				"scale":[0.4998,0.4998,1],
				"graphicAsset":"Major2_Shell",
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Major2_Outline",
				"uid":"9078666617603137",
				"position":[-0.78,3.59,0],
				"scale":[0.4252,0.4287,1],
				"graphicAsset":"Major2_Outline",
				"subLayer":0.2953394666666669,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,164.6,58.8],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"Major2_Fill",
				"uid":"2159010928159013",
				"position":[-0.75,6.76,0],
				"scale":[0.4269,0.438,1],
				"graphicAsset":"Major2_Fill",
				"subLayer":0.02,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,164,58.6],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"9075793834701746",
				"position":[0,0,1000],
				"coreViewWidth":500,
				"coreViewHeight":500,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":500,
				"constructPrecompTargetHeight":500
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.88,"rightHandleValue":-3.1591,"rightHandleSpan":0.6},
						{
							"time":0.2,
							"value":-4.887,
							"leftHandleValue":8.5331,
							"leftHandleSpan":0.2,
							"rightHandleValue":8.4173,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":-20.575,
							"leftHandleValue":-4.4108,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.8781,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":-18.018,
							"leftHandleValue":-6.3839,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.3135,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":20.935,
							"leftHandleValue":-11.4401,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2839,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3833333333333333,
							"value":-1.56,
							"leftHandleValue":-0.0919,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.7511,
							"rightHandleSpan":0.8
						},
						{
							"time":1.4166666666666667,
							"value":6.962,
							"leftHandleValue":-8.0683,
							"leftHandleSpan":0.7,
							"rightHandleValue":3.0485,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-7.037,
							"leftHandleValue":-0.5583,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.3164,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-1.627,
							"leftHandleValue":14.7375,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.2877,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":4.642,
							"leftHandleValue":-0.3741,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4578,
							"rightHandleSpan":0.3
						},
						{
							"time":1.6833333333333333,
							"value":2.917,
							"leftHandleValue":-7.2411,
							"leftHandleSpan":0.7,
							"rightHandleValue":2.0587,
							"rightHandleSpan":0.2
						},
						{
							"time":1.7833333333333332,
							"value":1.937,
							"leftHandleValue":-4.0428,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.4543,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.88,"leftHandleValue":0.7619,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.29,"rightHandleValue":-3.8882,"rightHandleSpan":0.3},
						{
							"time":0.2,
							"value":6.854,
							"leftHandleValue":-6.3262,
							"leftHandleSpan":0.4,
							"rightHandleValue":15.2202,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":10.955,
							"leftHandleValue":-13.0683,
							"leftHandleSpan":0.6,
							"rightHandleValue":3.5431,
							"rightHandleSpan":0.1
						},
						{
							"time":0.3333333333333333,
							"value":10.7,
							"leftHandleValue":-5.2994,
							"leftHandleSpan":0.7,
							"rightHandleValue":-3.8706,
							"rightHandleSpan":0.1
						},
						{
							"time":1.25,
							"value":-7.375,
							"leftHandleValue":24.7578,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.9281,
							"rightHandleSpan":0.3
						},
						{
							"time":1.4,
							"value":-0.684,
							"leftHandleValue":8.3303,
							"leftHandleSpan":0.7,
							"rightHandleValue":15.1354,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":-5.353,
							"leftHandleValue":5.551,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.4108,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":4.82,
							"leftHandleValue":4.1674,
							"leftHandleSpan":0.4,
							"rightHandleValue":-18.3294,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":-1.25,
							"leftHandleValue":14.9511,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.2122,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":-1.321,
							"leftHandleValue":6.388,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.5918,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":0.903,
							"leftHandleValue":-3.108,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.3731,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.29,"leftHandleValue":0.5472,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":1.4584,"rightHandleSpan":0.4},
						{
							"time":0.16666666666666666,
							"value":0.367,
							"leftHandleValue":10.1982,
							"leftHandleSpan":0.3,
							"rightHandleValue":-11.0241,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":-39.666,
							"leftHandleValue":9.6628,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.6219,
							"rightHandleSpan":0.1
						},
						{
							"time":1.2666666666666666,
							"value":-55.417,
							"leftHandleValue":-23.6543,
							"leftHandleSpan":0.4,
							"rightHandleValue":13.5276,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":1.206,
							"leftHandleValue":1.6228,
							"leftHandleSpan":0.6,
							"rightHandleValue":-2.2997,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.7564,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4998,"rightHandleValue":-0.0328,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41983,
							"leftHandleValue":-0.0146,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0891,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.73983,
							"leftHandleValue":0.0031,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0354,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.67971,
							"leftHandleValue":-0.0131,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0402,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.74918,
							"leftHandleValue":-0.0228,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0185,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.4368,
							"leftHandleValue":-0.0077,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0231,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.55995,
							"leftHandleValue":0.0109,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0147,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.48326,
							"leftHandleValue":-0.0067,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0384,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4998,"leftHandleValue":0.0106,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4998,"rightHandleValue":-0.0328,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41983,
							"leftHandleValue":-0.0146,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0891,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.73983,
							"leftHandleValue":0.0031,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0354,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.67971,
							"leftHandleValue":-0.0131,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0402,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.74918,
							"leftHandleValue":-0.0228,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0185,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.4368,
							"leftHandleValue":-0.0077,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0231,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.55995,
							"leftHandleValue":0.0109,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0147,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.48326,
							"leftHandleValue":-0.0067,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0384,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4998,"leftHandleValue":0.0106,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":5.0724,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.401,
							"leftHandleValue":-0.0177,
							"leftHandleSpan":0.3,
							"rightHandleValue":-7.1507,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-8.737,
							"leftHandleValue":2.6052,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.6793,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":8.761,
							"leftHandleValue":0.9597,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.0846,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.202,
							"leftHandleValue":0.1773,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.4413,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.7406,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-2.1298,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":-6.503,
							"leftHandleValue":0.5865,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5784,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":22.12,
							"leftHandleValue":-0.0005,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.848,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":-18.416,
							"leftHandleValue":16.0385,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7957,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":12.651,
							"leftHandleValue":1.0968,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.7724,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":-8.151,
							"leftHandleValue":1.1577,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5015,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":3.313,
							"leftHandleValue":1.3321,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.8679,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.34,
							"leftHandleValue":-1.1471,
							"leftHandleSpan":0.3,
							"rightHandleValue":-17.6578,
							"rightHandleSpan":0.9
						},
						{
							"time":1.2666666666666666,
							"value":-10.62,
							"leftHandleValue":0.9467,
							"leftHandleSpan":0.05,
							"rightHandleValue":3.2753,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":12.525,
							"leftHandleValue":-3.06,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0557,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-6.238,
							"leftHandleValue":-0.7038,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.7632,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.4609,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"0792440268599528"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-0.78,"rightHandleValue":0.0836,"rightHandleSpan":0.4},
						{
							"time":0.15,
							"value":-3.013,
							"leftHandleValue":1.4802,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.5253,
							"rightHandleSpan":0.9
						},
						{
							"time":0.23333333333333334,
							"value":10.372,
							"leftHandleValue":1.1609,
							"leftHandleSpan":0.5,
							"rightHandleValue":-3.9285,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":17.396,
							"leftHandleValue":3.3779,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.0596,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":15.725,
							"leftHandleValue":-0.7898,
							"leftHandleSpan":0.5,
							"rightHandleValue":-16.1647,
							"rightHandleSpan":0.6
						},
						{
							"time":1.2166666666666666,
							"value":-13.112,
							"leftHandleValue":3.0374,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.252,
							"rightHandleSpan":0.6
						},
						{
							"time":1.4,
							"value":-1.98,
							"leftHandleValue":4.5767,
							"leftHandleSpan":0.5,
							"rightHandleValue":21.2652,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-9.144,
							"leftHandleValue":1.0719,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.4127,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-3.124,
							"leftHandleValue":13.823,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.0247,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":3.506,
							"leftHandleValue":-0.4218,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4685,
							"rightHandleSpan":0.3
						},
						{
							"time":1.6833333333333333,
							"value":1.556,
							"leftHandleValue":-6.9631,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.9849,
							"rightHandleSpan":0.2
						},
						{
							"time":1.7833333333333332,
							"value":0.28,
							"leftHandleValue":-3.8974,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.5142,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-0.78,"leftHandleValue":0.7949,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":3.59,"rightHandleValue":-6.7768,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":7.578,
							"leftHandleValue":2.7469,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.1291,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":3.7,
							"leftHandleValue":-10.6278,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.5396,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":2.75,
							"leftHandleValue":-5.2118,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.2087,
							"rightHandleSpan":0.2
						},
						{
							"time":0.48333333333333334,
							"value":2.358,
							"leftHandleValue":0.4517,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3077,
							"rightHandleSpan":0.3
						},
						{
							"time":1.25,
							"value":21.805,
							"leftHandleValue":-3.8223,
							"leftHandleSpan":0.1,
							"rightHandleValue":2.1974,
							"rightHandleSpan":0.3
						},
						{
							"time":1.4,
							"value":1.216,
							"leftHandleValue":0.7434,
							"leftHandleSpan":0.6,
							"rightHandleValue":15.5041,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":-2.622,
							"leftHandleValue":5.2731,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.1342,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":8.266,
							"leftHandleValue":3.8621,
							"leftHandleSpan":0.4,
							"rightHandleValue":-17.8078,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":2.213,
							"leftHandleValue":15.2768,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.3382,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":1.907,
							"leftHandleValue":6.4396,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.6182,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":4.303,
							"leftHandleValue":-3.183,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.3234,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":3.59,"leftHandleValue":0.5357,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":1.3584,"rightHandleSpan":0.3},
						{
							"time":0.16666666666666666,
							"value":4.16,
							"leftHandleValue":-14.0119,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.5024,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":45.618,
							"leftHandleValue":-9.3491,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.2399,
							"rightHandleSpan":0.05
						},
						{"time":1.0666666666666667,"value":59.864,"leftHandleValue":14.3171,"leftHandleSpan":0.4},
						{"time":1.15,"value":56.548,"rightHandleValue":-10.7089,"rightHandleSpan":0.8},
						{
							"time":1.3666666666666667,
							"value":12.35,
							"leftHandleValue":46.4685,
							"leftHandleSpan":0.5,
							"rightHandleValue":-12.1939,
							"rightHandleSpan":0.1
						},
						{
							"time":1.6,
							"value":-1.816,
							"leftHandleValue":3.7291,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.4073,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":0.6863,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4252,"rightHandleValue":-0.0279,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.35717,
							"leftHandleValue":-0.0124,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0758,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.6294,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0301,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.57826,
							"leftHandleValue":-0.0111,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0342,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.63736,
							"leftHandleValue":-0.0194,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0158,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.3716,
							"leftHandleValue":-0.0065,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0196,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.47637,
							"leftHandleValue":0.0093,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0125,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.41113,
							"leftHandleValue":-0.0057,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0261,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4252,"leftHandleValue":0.0128,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4287,"rightHandleValue":-0.0281,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.36011,
							"leftHandleValue":-0.0125,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0764,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.63459,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0303,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.58302,
							"leftHandleValue":-0.0112,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0344,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.64261,
							"leftHandleValue":-0.0195,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0159,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.37466,
							"leftHandleValue":-0.0066,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0198,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.48029,
							"leftHandleValue":0.0094,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0126,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.41452,
							"leftHandleValue":-0.0058,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0263,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4287,"leftHandleValue":0.0129,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":5.0724,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.401,
							"leftHandleValue":-0.0177,
							"leftHandleSpan":0.3,
							"rightHandleValue":-7.1507,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-8.737,
							"leftHandleValue":2.6052,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.6793,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":8.761,
							"leftHandleValue":0.9597,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.0846,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.202,
							"leftHandleValue":0.1773,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.4413,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.7406,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-2.1298,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":-6.503,
							"leftHandleValue":0.5865,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5784,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":22.12,
							"leftHandleValue":-0.0005,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.848,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":-18.416,
							"leftHandleValue":16.0385,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7957,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":12.651,
							"leftHandleValue":1.0968,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.7724,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":-8.151,
							"leftHandleValue":1.1577,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5015,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":3.313,
							"leftHandleValue":1.3321,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.8679,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.34,
							"leftHandleValue":-1.1471,
							"leftHandleSpan":0.3,
							"rightHandleValue":-17.6578,
							"rightHandleSpan":0.9
						},
						{
							"time":1.2666666666666666,
							"value":-10.62,
							"leftHandleValue":0.9467,
							"leftHandleSpan":0.05,
							"rightHandleValue":3.2753,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":12.525,
							"leftHandleValue":-3.06,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0557,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-6.238,
							"leftHandleValue":-0.7038,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.7632,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.4609,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-0.75,"rightHandleValue":-0.3873,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-3.722,
							"leftHandleValue":0.3436,
							"leftHandleSpan":0.4,
							"rightHandleValue":10.8613,
							"rightHandleSpan":0.4
						},
						{
							"time":0.25,
							"value":-6.314,
							"leftHandleValue":2.4087,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.0487,
							"rightHandleSpan":0.6
						},
						{
							"time":0.3333333333333333,
							"value":-4.614,
							"leftHandleValue":5.4159,
							"leftHandleSpan":0.99,
							"rightHandleValue":3.0738,
							"rightHandleSpan":0.4
						},
						{
							"time":0.48333333333333334,
							"value":-3.343,
							"leftHandleValue":-1.2206,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.1286,
							"rightHandleSpan":0.3
						},
						{
							"time":1.25,
							"value":4.715,
							"leftHandleValue":-4.0019,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.0699,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-3.143,
							"leftHandleValue":-0.1001,
							"leftHandleSpan":0.5,
							"rightHandleValue":21.8491,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-9.569,
							"leftHandleValue":1.0333,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.5809,
							"rightHandleSpan":0.5
						},
						{
							"time":1.55,
							"value":-2.95,
							"leftHandleValue":13.3396,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.8963,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":3.828,
							"leftHandleValue":-0.4365,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4742,
							"rightHandleSpan":0.3
						},
						{
							"time":1.6833333333333333,
							"value":1.859,
							"leftHandleValue":-6.9288,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.968,
							"rightHandleSpan":0.2
						},
						{
							"time":1.7833333333333332,
							"value":0.416,
							"leftHandleValue":-3.7461,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.5944,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-0.75,"leftHandleValue":0.8047,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":6.76,"rightHandleValue":-6.9093,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":13.984,
							"leftHandleValue":-5.3889,
							"leftHandleSpan":0.6,
							"rightHandleValue":14.3062,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":13.587,
							"leftHandleValue":-10.9953,
							"leftHandleSpan":0.6,
							"rightHandleValue":3.1918,
							"rightHandleSpan":0.2
						},
						{
							"time":0.3333333333333333,
							"value":12.949,
							"leftHandleValue":-5.2695,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.3574,
							"rightHandleSpan":0.05
						},
						{
							"time":1.1833333333333333,
							"value":13.985,
							"leftHandleValue":-0.103,
							"leftHandleSpan":0.8,
							"rightHandleValue":2.5049,
							"rightHandleSpan":0.7
						},
						{"time":1.4,"value":4.27,"leftHandleValue":4.602,"leftHandleSpan":0.4,"rightHandleValue":15.176,"rightHandleSpan":0.4},
						{
							"time":1.45,
							"value":0.294,
							"leftHandleValue":5.1201,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.9457,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":11.715,
							"leftHandleValue":3.7122,
							"leftHandleSpan":0.4,
							"rightHandleValue":-17.6219,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":5.54,
							"leftHandleValue":15.5147,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.4444,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":4.997,
							"leftHandleValue":6.5526,
							"leftHandleSpan":0.99,
							"rightHandleValue":4.6142,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":7.511,
							"leftHandleValue":-3.2707,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.2591,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":6.76,"leftHandleValue":0.5248,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":5.8572,"rightHandleSpan":0.3},
						{
							"time":1.25,
							"value":-3.976,
							"leftHandleValue":11.7784,
							"leftHandleSpan":0.99,
							"rightHandleValue":2.7344,
							"rightHandleSpan":0.4
						},
						{"time":1.6,"value":-1.305,"leftHandleValue":8.352,"leftHandleSpan":0.8,"rightHandleValue":0.9797,"rightHandleSpan":0.4},
						{"time":2,"value":0,"leftHandleValue":1.105,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4269,"rightHandleValue":-0.028,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.3586,
							"leftHandleValue":-0.0125,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0761,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.63192,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0302,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.58057,
							"leftHandleValue":-0.0112,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0343,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.63991,
							"leftHandleValue":-0.0194,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0158,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.37309,
							"leftHandleValue":-0.0065,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0197,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.47827,
							"leftHandleValue":0.0093,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0125,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.41278,
							"leftHandleValue":-0.0057,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0262,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4269,"leftHandleValue":0.0129,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.438,"rightHandleValue":-0.0288,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.36792,
							"leftHandleValue":-0.0128,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0781,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.64835,
							"leftHandleValue":0.0027,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.031,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.59566,
							"leftHandleValue":-0.0115,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0352,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.65655,
							"leftHandleValue":-0.0199,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0162,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.38279,
							"leftHandleValue":-0.0067,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0202,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.49071,
							"leftHandleValue":0.0096,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0129,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.42351,
							"leftHandleValue":-0.0059,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0269,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.438,"leftHandleValue":0.0132,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":5.0724,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.401,
							"leftHandleValue":-0.0177,
							"leftHandleSpan":0.3,
							"rightHandleValue":-7.1507,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-8.737,
							"leftHandleValue":2.6052,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.6793,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":8.761,
							"leftHandleValue":0.9597,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.0846,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.202,
							"leftHandleValue":0.1773,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.4413,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.7406,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-2.1298,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":-6.503,
							"leftHandleValue":0.5865,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5784,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":22.12,
							"leftHandleValue":-0.0005,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.848,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":-18.416,
							"leftHandleValue":16.0385,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7957,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":12.651,
							"leftHandleValue":1.0968,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.7724,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":-8.151,
							"leftHandleValue":1.1577,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5015,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":3.313,
							"leftHandleValue":1.3321,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":4.8679,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":11.34,
							"leftHandleValue":-1.1471,
							"leftHandleSpan":0.3,
							"rightHandleValue":-17.6578,
							"rightHandleSpan":0.9
						},
						{
							"time":1.2666666666666666,
							"value":-10.62,
							"leftHandleValue":0.9467,
							"leftHandleSpan":0.05,
							"rightHandleValue":3.2753,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":12.525,
							"leftHandleValue":-3.06,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0557,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-6.238,
							"leftHandleValue":-0.7038,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.7632,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.4609,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-783},
						{"time":1.2333333333333334,"value":763.1},
						{"time":1.4333333333333333,"value":-783},
						{"time":1.6166666666666667,"value":763.1}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"2159010928159013"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-780.8},
						{"time":1.2333333333333334,"value":771.4},
						{"time":1.4333333333333333,"value":-780.8},
						{"time":1.6166666666666667,"value":771.4}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"9078666617603137"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":1},
						{"time":0.11666666666666667,"value":0.8977,"rightHandleValue":-0.0576,"rightHandleSpan":0.8},
						{
							"time":0.26666666666666666,
							"value":2.0033,
							"leftHandleValue":-0.065,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0356,
							"rightHandleSpan":0.4
						},
						{"time":0.5,"value":1.25,"leftHandleValue":0.0664,"leftHandleSpan":0.4,"rightHandleValue":0.2184,"rightHandleSpan":0.5},
						{
							"time":1.0333333333333332,
							"value":1.3233,
							"leftHandleValue":1.2174,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.3153,
							"rightHandleSpan":0.6
						},
						{
							"time":1.25,
							"value":1.999,
							"leftHandleValue":-0.1669,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0145,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.9892,
							"leftHandleValue":-0.0549,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0433,
							"rightHandleSpan":0.4
						},
						{"time":1.6,"value":1.5,"leftHandleValue":-0.0349,"leftHandleSpan":0.4,"rightHandleValue":-0.134,"rightHandleSpan":0.4},
						{"time":2,"value":1,"leftHandleValue":-0.1754,"leftHandleSpan":0.8}
					],
					"propertyPath":["material","0","colorMultiply","alpha"],
					"sceneObjectUid":"9078666617603137"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Major2Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major3_Fill.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major3_Outline.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major3_Shell.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Major3Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Major3_Shell",
				"uid":"9624595711777741",
				"position":[0.32,1.47,0],
				"scale":[0.43580000000000285,0.4728,1],
				"graphicAsset":"Major3_Shell",
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{"effectNodes":["SampleMainTexture","ColorMultiply"]}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Major3_Outline",
				"uid":"2154728038528084",
				"position":[-0.82,10.72,0],
				"scale":[0.3831,0.3861,1],
				"graphicAsset":"Major3_Outline",
				"subLayer":0.1753394666666661,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,182.7,65.3],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"Major3_Fill",
				"uid":"1485253888539336",
				"position":[-5.35,15.98,0],
				"scale":[0.38910000000000283,0.4208,1],
				"graphicAsset":"Major3_Fill",
				"subLayer":0.02,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,179.9,64.3],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"8145384019161461",
				"position":[0,0,1000],
				"coreViewWidth":500,
				"coreViewHeight":500,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":500,
				"constructPrecompTargetHeight":500
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.32,"rightHandleValue":0.0695,"rightHandleSpan":0.4},
						{
							"time":0.13333333333333333,
							"value":0.936,
							"leftHandleValue":0.9289,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.343,
							"rightHandleSpan":0.99
						},
						{
							"time":0.21666666666666667,
							"value":16.449,
							"leftHandleValue":-9.0856,
							"leftHandleSpan":0.3,
							"rightHandleValue":3.4429,
							"rightHandleSpan":0.4
						},
						{
							"time":0.25,
							"value":17.821,
							"leftHandleValue":-1.8558,
							"leftHandleSpan":0.4,
							"rightHandleValue":19.3974,
							"rightHandleSpan":0.6
						},
						{
							"time":0.36666666666666664,
							"value":24.573,
							"leftHandleValue":-5.0413,
							"leftHandleSpan":0.8,
							"rightHandleValue":-21.2807,
							"rightHandleSpan":0.6
						},
						{
							"time":1.25,
							"value":-24.761,
							"leftHandleValue":19.7301,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.5884,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":1.966,
							"leftHandleValue":4.6644,
							"leftHandleSpan":0.6,
							"rightHandleValue":23.4794,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-5.955,
							"leftHandleValue":1.4724,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.6014,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5166666666666666,
							"value":5.427,
							"leftHandleValue":3.2931,
							"leftHandleSpan":0.4,
							"rightHandleValue":-14.8512,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":2.483,
							"leftHandleValue":-6.3193,
							"leftHandleSpan":0.6,
							"rightHandleValue":-9.5607,
							"rightHandleSpan":0.9
						},
						{
							"time":1.7,
							"value":1.299,
							"leftHandleValue":-1.8338,
							"leftHandleSpan":0.8,
							"rightHandleValue":-5.5161,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8333333333333333,
							"value":-0.026,
							"leftHandleValue":3.2465,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.2091,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.32,"leftHandleValue":-0.1825,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":1.47,"rightHandleValue":-4.2681,"rightHandleSpan":0.3},
						{
							"time":0.2,
							"value":10.416,
							"leftHandleValue":-9.0253,
							"leftHandleSpan":0.4,
							"rightHandleValue":18.1853,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":17.248,
							"leftHandleValue":-15.9469,
							"leftHandleSpan":0.7,
							"rightHandleValue":4.179,
							"rightHandleSpan":0.2
						},
						{
							"time":0.3333333333333333,
							"value":16.964,
							"leftHandleValue":-5.667,
							"leftHandleSpan":0.8,
							"rightHandleValue":-4.4738,
							"rightHandleSpan":0.05
						},
						{
							"time":1.25,
							"value":-6.041,
							"leftHandleValue":30.0161,
							"leftHandleSpan":0.9,
							"rightHandleValue":-2.2807,
							"rightHandleSpan":0.3
						},
						{
							"time":1.4,
							"value":0.421,
							"leftHandleValue":10.0109,
							"leftHandleSpan":0.7,
							"rightHandleValue":16.4721,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":-4.942,
							"leftHandleValue":6.1076,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.637,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":6.369,
							"leftHandleValue":4.5209,
							"leftHandleSpan":0.4,
							"rightHandleValue":-19.9877,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":-0.042,
							"leftHandleValue":16.3803,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.2426,
							"rightHandleSpan":0.7
						},
						{
							"time":1.6833333333333333,
							"value":-0.179,
							"leftHandleValue":6.3867,
							"leftHandleSpan":0.99,
							"rightHandleValue":5.0183,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8,
							"value":2.158,
							"leftHandleValue":-3.3818,
							"leftHandleSpan":0.6,
							"rightHandleValue":-1.589,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":1.47,"leftHandleValue":0.6658,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":0.7727,"rightHandleSpan":0.4},
						{
							"time":0.11666666666666667,
							"value":6.085,
							"leftHandleValue":-0.2911,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.1366,
							"rightHandleSpan":0.5
						},
						{
							"time":0.26666666666666666,
							"value":-43.928,
							"leftHandleValue":17.6387,
							"leftHandleSpan":0.4,
							"rightHandleValue":-5.793,
							"rightHandleSpan":0.05
						},
						{"time":0.9166666666666666,"value":-75.306,"leftHandleValue":-3.8141,"leftHandleSpan":0.3},
						{"time":1.0166666666666666,"value":-74.252,"rightHandleValue":6.4392,"rightHandleSpan":0.8},
						{
							"time":1.2833333333333332,
							"value":-60.638,
							"leftHandleValue":-5.424,
							"leftHandleSpan":0.05,
							"rightHandleValue":26.7466,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":1.766,
							"leftHandleValue":0.7062,
							"leftHandleSpan":0.6,
							"rightHandleValue":-3.8152,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":2.5444,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4358,"rightHandleValue":-0.0287,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.36607,
							"leftHandleValue":-0.0163,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0927,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.68889,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0327,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.63189,
							"leftHandleValue":-0.0128,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0374,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.69797,
							"leftHandleValue":-0.0232,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0169,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.37869,
							"leftHandleValue":-0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.017,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.48824,
							"leftHandleValue":0.0105,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0128,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.42138,
							"leftHandleValue":-0.0059,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0267,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4358,"leftHandleValue":0.0131,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4728,"rightHandleValue":-0.0311,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.39715,
							"leftHandleValue":-0.0177,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1006,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.74737,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0354,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.68554,
							"leftHandleValue":-0.0139,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0406,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.75722,
							"leftHandleValue":-0.0252,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0183,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.41084,
							"leftHandleValue":-0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0184,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.5297,
							"leftHandleValue":0.0114,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0139,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.45716,
							"leftHandleValue":-0.0063,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0363,
							"rightHandleSpan":0.6
						},
						{"time":2,"value":0.4728,"leftHandleValue":0.01,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":6.045,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":12.826,
							"leftHandleValue":0.9408,
							"leftHandleSpan":0.2,
							"rightHandleValue":-8.0445,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-9.829,
							"leftHandleValue":2.9308,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.7358,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":9.883,
							"leftHandleValue":0.9469,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.1677,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.242,
							"leftHandleValue":0.2775,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3305,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.811,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1385,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.604,
							"leftHandleValue":-0.4915,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.8944,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-24.857,
							"leftHandleValue":0.1843,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.0395,
							"rightHandleSpan":0.1
						},
						{
							"time":1.25,
							"value":20.718,
							"leftHandleValue":-18.2945,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.8259,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":-14.298,
							"leftHandleValue":-0.9156,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.899,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.183,
							"leftHandleValue":-1.3882,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2485,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.4068,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-9.5824,"rightHandleSpan":0.3},
						{
							"time":1.2666666666666666,
							"value":6.068,
							"leftHandleValue":-14.56,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.8716,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-7.157,
							"leftHandleValue":1.7486,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0745,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":3.384,
							"leftHandleValue":0.5247,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5044,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.4424,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"9624595711777741"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-0.82,"rightHandleValue":-0.0314,"rightHandleSpan":0.7},
						{
							"time":0.2,
							"value":-5.93,
							"leftHandleValue":10.6721,
							"leftHandleSpan":0.2,
							"rightHandleValue":8.0441,
							"rightHandleSpan":0.4
						},
						{
							"time":0.26666666666666666,
							"value":-25.548,
							"leftHandleValue":-4.5101,
							"leftHandleSpan":0.4,
							"rightHandleValue":7.4841,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":-22.627,
							"leftHandleValue":-7.0947,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.4137,
							"rightHandleSpan":0.2
						},
						{
							"time":1.2333333333333334,
							"value":15.95,
							"leftHandleValue":-6.684,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.8825,
							"rightHandleSpan":0.5
						},
						{
							"time":1.3666666666666667,
							"value":-0.739,
							"leftHandleValue":0.4179,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2555,
							"rightHandleSpan":0.99
						},
						{
							"time":1.4166666666666667,
							"value":9.374,
							"leftHandleValue":-9.122,
							"leftHandleSpan":0.5,
							"rightHandleValue":3.4382,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-6.41,
							"leftHandleValue":-0.1526,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3734,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5166666666666666,
							"value":4.319,
							"leftHandleValue":3.6523,
							"leftHandleSpan":0.4,
							"rightHandleValue":-15.7251,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":0.443,
							"leftHandleValue":-6.2967,
							"leftHandleSpan":0.6,
							"rightHandleValue":-9.4184,
							"rightHandleSpan":0.9
						},
						{
							"time":1.7,
							"value":0.055,
							"leftHandleValue":-0.992,
							"leftHandleSpan":0.7,
							"rightHandleValue":-5.3204,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8333333333333333,
							"value":-0.981,
							"leftHandleValue":3.2721,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.1935,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-0.82,"leftHandleValue":-0.1092,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":10.72,"rightHandleValue":-10.755,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":19.231,
							"leftHandleValue":3.3326,
							"leftHandleSpan":0.4,
							"rightHandleValue":14.188,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":11.875,
							"leftHandleValue":-9.0007,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.1972,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":10.747,
							"leftHandleValue":-5.8641,
							"leftHandleSpan":0.8,
							"rightHandleValue":-3.179,
							"rightHandleSpan":0.6
						},
						{
							"time":0.4166666666666667,
							"value":10.269,
							"leftHandleValue":1.9328,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.3273,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":36.145,
							"leftHandleValue":-3.3575,
							"leftHandleSpan":0.05,
							"rightHandleValue":2.4786,
							"rightHandleSpan":0.3
						},
						{
							"time":1.4,
							"value":7.544,
							"leftHandleValue":0.2973,
							"leftHandleSpan":0.5,
							"rightHandleValue":16.9108,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":3.689,
							"leftHandleValue":5.4917,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.0069,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":16.481,
							"leftHandleValue":4.0196,
							"leftHandleSpan":0.4,
							"rightHandleValue":-19.4488,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":9.335,
							"leftHandleValue":17.3382,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.3963,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6333333333333333,
							"value":11.525,
							"leftHandleValue":-1.2234,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.181,
							"rightHandleSpan":0.4
						},
						{
							"time":1.7166666666666666,
							"value":11.206,
							"leftHandleValue":-6.5175,
							"leftHandleSpan":0.8,
							"rightHandleValue":-3.4466,
							"rightHandleSpan":0.5
						},
						{"time":1.8499999999999999,"value":11.152,"leftHandleValue":0.5529,"leftHandleSpan":0.99},
						{"time":2,"value":10.72}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":0.4406,"rightHandleSpan":0.4},
						{
							"time":0.1,
							"value":-2.465,
							"leftHandleValue":-0.3873,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.409,
							"rightHandleSpan":0.6
						},
						{
							"time":0.26666666666666666,
							"value":53.114,
							"leftHandleValue":-18.2068,
							"leftHandleSpan":0.4,
							"rightHandleValue":10.4668,
							"rightHandleSpan":0.1
						},
						{
							"time":1.2333333333333334,
							"value":58.645,
							"leftHandleValue":34.6649,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.2558,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":53.697,
							"leftHandleValue":5.1181,
							"leftHandleSpan":0.4,
							"rightHandleValue":-16.0527,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":3.334,
							"leftHandleValue":3.8055,
							"leftHandleSpan":0.6,
							"rightHandleValue":-5.1087,
							"rightHandleSpan":0.5
						},
						{"time":1.9,"value":0.103,"leftHandleValue":-4.574,"leftHandleSpan":0.99},
						{"time":2,"value":0}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3831,"rightHandleValue":-0.0252,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.3218,
							"leftHandleValue":-0.0143,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0815,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.60558,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0287,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.55548,
							"leftHandleValue":-0.0113,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0329,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.61356,
							"leftHandleValue":-0.0204,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0148,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.33289,
							"leftHandleValue":-0.0009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0149,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.4292,
							"leftHandleValue":0.0092,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0112,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.37042,
							"leftHandleValue":-0.0051,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0235,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.3831,"leftHandleValue":0.0115,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3861,"rightHandleValue":-0.0254,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.32432,
							"leftHandleValue":-0.0144,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0822,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.61032,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0289,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.55983,
							"leftHandleValue":-0.0113,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0331,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.61837,
							"leftHandleValue":-0.0205,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.015,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.3355,
							"leftHandleValue":-0.0009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.015,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.43256,
							"leftHandleValue":0.0093,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0113,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.37333,
							"leftHandleValue":-0.0052,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0237,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.3861,"leftHandleValue":0.0116,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":6.045,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":12.826,
							"leftHandleValue":0.9408,
							"leftHandleSpan":0.2,
							"rightHandleValue":-8.0445,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-9.829,
							"leftHandleValue":2.9308,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.7358,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":9.883,
							"leftHandleValue":0.9469,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.1677,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.242,
							"leftHandleValue":0.2775,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3305,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.811,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1385,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.604,
							"leftHandleValue":-0.4915,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.8944,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-24.857,
							"leftHandleValue":0.1843,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.0395,
							"rightHandleSpan":0.1
						},
						{
							"time":1.25,
							"value":20.718,
							"leftHandleValue":-18.2945,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.8259,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":-14.298,
							"leftHandleValue":-0.9156,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.899,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.183,
							"leftHandleValue":-1.3882,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2485,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.4068,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-9.5824,"rightHandleSpan":0.3},
						{
							"time":1.2666666666666666,
							"value":6.068,
							"leftHandleValue":-14.56,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.8716,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-7.157,
							"leftHandleValue":1.7486,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0745,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":3.384,
							"leftHandleValue":0.5247,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5044,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.4424,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-5.35,"rightHandleValue":3.3278,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-6.717,
							"leftHandleValue":1.6554,
							"leftHandleSpan":0.4,
							"rightHandleValue":11.6437,
							"rightHandleSpan":0.4
						},
						{
							"time":0.25,
							"value":-9.625,
							"leftHandleValue":2.4133,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.6489,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":-4.781,
							"leftHandleValue":2.563,
							"leftHandleSpan":0.4,
							"rightHandleValue":-6.4195,
							"rightHandleSpan":0.4
						},
						{"time":0.4,"value":-6.59,"leftHandleValue":3.6382,"leftHandleSpan":0.6,"rightHandleValue":1.6132,"rightHandleSpan":0.1},
						{
							"time":1.25,
							"value":-14.805,
							"leftHandleValue":6.206,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.2351,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-2.753,
							"leftHandleValue":-1.8641,
							"leftHandleSpan":0.6,
							"rightHandleValue":24.5533,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-10.458,
							"leftHandleValue":2.1855,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.0105,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5166666666666666,
							"value":-0.636,
							"leftHandleValue":3.8852,
							"leftHandleSpan":0.4,
							"rightHandleValue":-15.996,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":-4.489,
							"leftHandleValue":-6.5361,
							"leftHandleSpan":0.6,
							"rightHandleValue":-8.8889,
							"rightHandleSpan":0.9
						},
						{
							"time":1.7,
							"value":-4.49,
							"leftHandleValue":-1.1449,
							"leftHandleSpan":0.7,
							"rightHandleValue":-5.2874,
							"rightHandleSpan":0.3
						},
						{
							"time":1.8333333333333333,
							"value":-5.514,
							"leftHandleValue":3.2726,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.2025,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-5.35,"leftHandleValue":-0.0466,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":15.98,"rightHandleValue":-10.9179,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":30.73,
							"leftHandleValue":-10.6505,
							"leftHandleSpan":0.6,
							"rightHandleValue":16.2417,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":29.485,
							"leftHandleValue":-11.2056,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.816,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":28.64,
							"leftHandleValue":-5.8204,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.485,
							"rightHandleSpan":0.05
						},
						{
							"time":1.0833333333333333,
							"value":29.153,
							"leftHandleValue":-0.1896,
							"leftHandleSpan":0.9,
							"rightHandleValue":0.3287,
							"rightHandleSpan":0.99
						},
						{
							"time":1.4,
							"value":13.052,
							"leftHandleValue":17.1417,
							"leftHandleSpan":0.5,
							"rightHandleValue":17.4625,
							"rightHandleSpan":0.5
						},
						{
							"time":1.45,
							"value":8.992,
							"leftHandleValue":3.4811,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7399,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5,
							"value":22.414,
							"leftHandleValue":3.9162,
							"leftHandleSpan":0.4,
							"rightHandleValue":-19.5576,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":14.574,
							"leftHandleValue":17.8331,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.4985,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6333333333333333,
							"value":16.546,
							"leftHandleValue":-1.1564,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.0851,
							"rightHandleSpan":0.2
						},
						{
							"time":1.7166666666666666,
							"value":16.289,
							"leftHandleValue":-6.7724,
							"leftHandleSpan":0.7,
							"rightHandleValue":-3.47,
							"rightHandleSpan":0.6
						},
						{"time":1.8499999999999999,"value":16.596,"leftHandleValue":0.9212,"leftHandleSpan":0.99},
						{"time":2,"value":15.98}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":8.762,"rightHandleSpan":0.2},
						{
							"time":1.2666666666666666,
							"value":-3.631,
							"leftHandleValue":7.0952,
							"leftHandleSpan":0.7,
							"rightHandleValue":16.2266,
							"rightHandleSpan":0.5
						},
						{"time":1.8666666666666667,"value":0.453,"leftHandleValue":-6.9656,"leftHandleSpan":0.8},
						{"time":2,"value":0}
					],
					"propertyPath":["position","z"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3891,"rightHandleValue":-0.0256,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.32684,
							"leftHandleValue":-0.0145,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0828,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.61506,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0292,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.56418,
							"leftHandleValue":-0.0114,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0334,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.62317,
							"leftHandleValue":-0.0207,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0151,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.33811,
							"leftHandleValue":-0.0009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0152,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.43592,
							"leftHandleValue":0.0093,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0114,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.37623,
							"leftHandleValue":-0.0052,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0239,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.3891,"leftHandleValue":0.0117,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4208,"rightHandleValue":-0.0277,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.35347,
							"leftHandleValue":-0.0157,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0895,
							"rightHandleSpan":0.4
						},
						{
							"time":0.21666666666666667,
							"value":0.66517,
							"leftHandleValue":0.0003,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0315,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.61014,
							"leftHandleValue":-0.0124,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0361,
							"rightHandleSpan":0.99
						},
						{
							"time":1.25,
							"value":0.67394,
							"leftHandleValue":-0.0224,
							"leftHandleSpan":0.05,
							"rightHandleValue":0.0163,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.36565,
							"leftHandleValue":-0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0164,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":0.47144,
							"leftHandleValue":0.0101,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0124,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6833333333333333,
							"value":0.40688,
							"leftHandleValue":-0.0056,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0258,
							"rightHandleSpan":0.5
						},
						{"time":2,"value":0.4208,"leftHandleValue":0.0127,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":6.045,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":12.826,
							"leftHandleValue":0.9408,
							"leftHandleSpan":0.2,
							"rightHandleValue":-8.0445,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-9.829,
							"leftHandleValue":2.9308,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.7358,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":9.883,
							"leftHandleValue":0.9469,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.1677,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6166666666666667,
							"value":-4.242,
							"leftHandleValue":0.2775,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3305,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":3.811,"leftHandleSpan":0.8}
					],
					"propertyPath":["rotation","x"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":2.1385,"rightHandleSpan":0.4},
						{
							"time":0.06666666666666667,
							"value":6.604,
							"leftHandleValue":-0.4915,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.8944,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":-24.857,
							"leftHandleValue":0.1843,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.0395,
							"rightHandleSpan":0.1
						},
						{
							"time":1.25,
							"value":20.718,
							"leftHandleValue":-18.2945,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.8259,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4333333333333333,
							"value":-14.298,
							"leftHandleValue":-0.9156,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.899,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5666666666666667,
							"value":8.183,
							"leftHandleValue":-1.3882,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.2485,
							"rightHandleSpan":0.4
						},
						{
							"time":1.75,
							"value":-3.313,
							"leftHandleValue":-1.4068,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.1749,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":1.2743,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","y"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0,"rightHandleValue":-9.5824,"rightHandleSpan":0.3},
						{
							"time":1.2666666666666666,
							"value":6.068,
							"leftHandleValue":-14.56,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.8716,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":-7.157,
							"leftHandleValue":1.7486,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0745,
							"rightHandleSpan":0.4
						},
						{
							"time":1.6,
							"value":3.384,
							"leftHandleValue":0.5247,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5044,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0,"leftHandleValue":-3.4424,"leftHandleSpan":0.7}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-867.4},
						{"time":1.2333333333333334,"value":828.8},
						{"time":1.4333333333333333,"value":-867.4},
						{"time":1.6166666666666667,"value":828.8}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"1485253888539336"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.31666666666666665,"value":-879.7},
						{"time":1.2333333333333334,"value":843.1},
						{"time":1.4333333333333333,"value":-879.7},
						{"time":1.6166666666666667,"value":843.1}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"2154728038528084"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":1},
						{"time":0.11666666666666667,"value":0.8977,"rightHandleValue":-0.0576,"rightHandleSpan":0.8},
						{
							"time":0.26666666666666666,
							"value":2.0033,
							"leftHandleValue":-0.065,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0356,
							"rightHandleSpan":0.4
						},
						{"time":0.5,"value":1.25,"leftHandleValue":0.0664,"leftHandleSpan":0.4,"rightHandleValue":0.2184,"rightHandleSpan":0.5},
						{
							"time":1.0333333333333332,
							"value":1.3233,
							"leftHandleValue":1.2174,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.3153,
							"rightHandleSpan":0.6
						},
						{
							"time":1.25,
							"value":1.999,
							"leftHandleValue":-0.1669,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0145,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.9892,
							"leftHandleValue":-0.0549,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0433,
							"rightHandleSpan":0.4
						},
						{"time":1.6,"value":1.5,"leftHandleValue":-0.0349,"leftHandleSpan":0.4,"rightHandleValue":-0.134,"rightHandleSpan":0.4},
						{"time":2,"value":1,"leftHandleValue":-0.1754,"leftHandleSpan":0.8}
					],
					"propertyPath":["material","0","colorMultiply","alpha"],
					"sceneObjectUid":"2154728038528084"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Major3Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_PlateBottom.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_PlateMiddle.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_PlateTop.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_TextBottom.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_TextMiddle.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1_TextTop.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor1Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{},
			"4":{},
			"5":{},
			"6":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Minor1_PlateBottom",
				"uid":"3387500474395755",
				"position":[0.15,-86.01123723968968,0],
				"scale":[0.3886,0.3828,1],
				"graphicAsset":"Minor1_PlateBottom",
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,154.4,64.3],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Minor1_PlateMiddle",
				"uid":"1313735379907511",
				"position":[0.75,-6.62,0],
				"scale":[0.3867,0.3898,1],
				"graphicAsset":"Minor1_PlateMiddle",
				"subLayer":0.01,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,155.2,64.6],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"Minor1_PlateTop",
				"uid":"6372651676122202",
				"position":[0.37,124.73721518987342,0],
				"scale":[0.4064,0.4097,1],
				"graphicAsset":"Minor1_PlateTop",
				"subLayer":0.02,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,147.6,61.5],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"GraphicObject",
				"name":"Minor1_TextBottom",
				"uid":"9729975288200182",
				"position":[0.5,-81.47630378089146,0],
				"scale":[0.3415,0.3545,1],
				"graphicAsset":"Minor1_TextBottom",
				"subLayer":0.03,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,175.7,73.2],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":4,
				"type":"GraphicObject",
				"name":"Minor1_TextMiddle",
				"uid":"6330434839548620",
				"position":[1.02,-3.0113335125688927,0],
				"scale":[0.3846,0.4104,1],
				"graphicAsset":"Minor1_TextMiddle",
				"subLayer":0.04,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,156,65],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":5,
				"type":"GraphicObject",
				"name":"Minor1_TextTop",
				"uid":"5798682828807290",
				"position":[0.86,79.11214864867158,0],
				"scale":[0.4,0.412,1],
				"graphicAsset":"Minor1_TextTop",
				"subLayer":0.05,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,90,150,62.5],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":6,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"0033076661934514",
				"position":[0,0,1000],
				"coreViewWidth":400,
				"coreViewHeight":400,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":400,
				"constructPrecompTargetHeight":400
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.15},
						{"time":0.31666666666666665,"value":0.126,"rightHandleValue":-2.477,"rightHandleSpan":0.5},
						{
							"time":0.36666666666666664,
							"value":19.78,
							"leftHandleValue":-11.1407,
							"leftHandleSpan":0.8,
							"rightHandleValue":3.45,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4666666666666667,
							"value":-10.677,
							"leftHandleValue":7.2336,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.6919,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5666666666666667,
							"value":6.087,
							"leftHandleValue":-1.5967,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.9379,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6666666666666666,
							"value":-3.114,
							"leftHandleValue":0.8956,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2588,
							"rightHandleSpan":0.4
						},
						{"time":0.8333333333333334,"value":0.152,"leftHandleValue":5.4611,"leftHandleSpan":0.6},
						{"time":1.15,"value":0.131,"rightHandleValue":-0.5845,"rightHandleSpan":0.4},
						{
							"time":1.2,
							"value":6.134,
							"leftHandleValue":-0.6866,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.3891,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":-4.144,
							"leftHandleValue":-0.7824,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.6226,
							"rightHandleSpan":0.6
						},
						{
							"time":1.45,
							"value":-1.141,
							"leftHandleValue":3.8776,
							"leftHandleSpan":0.7,
							"rightHandleValue":4.415,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":0.15,"leftHandleValue":-1.7856,"leftHandleSpan":0.99}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-86.011,"rightHandleValue":-2.5171,"rightHandleSpan":0.9},
						{"time":0.6,"value":-87.477,"leftHandleValue":3.4362,"leftHandleSpan":0.6},
						{"time":0.8,"value":-87.424,"rightHandleValue":2.4009,"rightHandleSpan":0.99},
						{
							"time":1.15,
							"value":-75.641,
							"leftHandleValue":-15.606,
							"leftHandleSpan":0.2,
							"rightHandleValue":-1.1468,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1833333333333333,
							"value":-73.048,
							"leftHandleValue":1.6001,
							"leftHandleSpan":0.5,
							"rightHandleValue":-5.1894,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2666666666666666,
							"value":-109.85,
							"leftHandleValue":3.8946,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.9606,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-82.4,
							"leftHandleValue":2.2094,
							"leftHandleSpan":0.5,
							"rightHandleValue":-11.2839,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-86.011,"leftHandleValue":2.8586,"leftHandleSpan":0.7}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3886,"rightHandleValue":-0.0002,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":0.38908,
							"leftHandleValue":0.0222,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0186,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.32437,
							"leftHandleValue":-0.0226,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0531,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.5268,
							"leftHandleValue":-0.0115,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.01,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.375,
							"leftHandleValue":-0.0139,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0066,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6833333333333333,
							"value":0.41498,
							"leftHandleValue":-0.0028,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0199,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.38612,
							"leftHandleValue":0.0097,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0039,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.33938,
							"leftHandleValue":0.0102,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0138,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.47129,
							"leftHandleValue":-0.0002,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0097,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.3725,
							"leftHandleValue":0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0593,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3886,"leftHandleValue":-0.0186,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3828,"rightHandleValue":-0.0002,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":0.38327,
							"leftHandleValue":0.0219,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0183,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.31953,
							"leftHandleValue":-0.0222,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0524,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.51894,
							"leftHandleValue":-0.0113,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0099,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.3694,
							"leftHandleValue":-0.0137,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0065,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6833333333333333,
							"value":0.40879,
							"leftHandleValue":-0.0028,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0196,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.38035,
							"leftHandleValue":0.0095,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0038,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.33432,
							"leftHandleValue":0.01,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0136,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.46425,
							"leftHandleValue":-0.0002,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0096,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.36694,
							"leftHandleValue":0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0584,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3828,"leftHandleValue":-0.0184,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.31666666666666665,"value":0,"rightHandleValue":1.4221,"rightHandleSpan":0.4},
						{
							"time":0.36666666666666664,
							"value":-6.598,
							"leftHandleValue":2.997,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.0348,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4666666666666667,
							"value":3.621,
							"leftHandleValue":-0.9844,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.3698,
							"rightHandleSpan":0.5
						},
						{
							"time":0.6666666666666666,
							"value":1.091,
							"leftHandleValue":-7.1449,
							"leftHandleSpan":0.9,
							"rightHandleValue":-2.9789,
							"rightHandleSpan":0.3
						},
						{"time":1.15,"value":0,"leftHandleValue":0.8383,"leftHandleSpan":0.6,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.75},
						{"time":0.13333333333333333,"value":0.755,"rightHandleValue":-2.4569,"rightHandleSpan":0.99},
						{
							"time":0.21666666666666667,
							"value":-14.945,
							"leftHandleValue":23.7528,
							"leftHandleSpan":0.6,
							"rightHandleValue":-11.8898,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":10.991,
							"leftHandleValue":-3.2377,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.3328,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":-4.917,
							"leftHandleValue":-0.1221,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.7795,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5333333333333333,
							"value":3.883,
							"leftHandleValue":0.0895,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0884,
							"rightHandleSpan":0.3
						},
						{"time":0.7,"value":0.762,"leftHandleValue":-4.7831,"leftHandleSpan":0.7},
						{"time":2,"value":0.75}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-6.62,"rightHandleValue":0.3172,"rightHandleSpan":0.5},
						{
							"time":0.18333333333333332,
							"value":-4.888,
							"leftHandleValue":-3.3894,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1876,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":-9.396,
							"leftHandleValue":-0.0676,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.0552,
							"rightHandleSpan":0.2
						},
						{
							"time":1.1,
							"value":-6.555,
							"leftHandleValue":-1.3585,
							"leftHandleSpan":0.9,
							"rightHandleValue":2.0547,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1833333333333333,
							"value":1.9,
							"leftHandleValue":-11.196,
							"leftHandleSpan":0.5,
							"rightHandleValue":5.326,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":-13.683,
							"leftHandleValue":-1.8974,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.8605,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3666666666666667,
							"value":-3.227,
							"leftHandleValue":0.0672,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.327,
							"rightHandleSpan":0.5
						},
						{
							"time":1.5333333333333332,
							"value":-5.503,
							"leftHandleValue":-6.0391,
							"leftHandleSpan":0.9,
							"rightHandleValue":-3.377,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-6.62,"leftHandleValue":1.1408,"leftHandleSpan":0.6}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3867,"rightHandleValue":0.0188,"rightHandleSpan":0.99},
						{
							"time":0.18333333333333332,
							"value":0.31741,
							"leftHandleValue":0.0741,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0072,
							"rightHandleSpan":0.3
						},
						{
							"time":0.3,
							"value":0.4982,
							"leftHandleValue":0.0086,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0173,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.37254,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0089,
							"rightHandleSpan":0.4
						},
						{
							"time":0.65,
							"value":0.39354,
							"leftHandleValue":0.0453,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0163,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1333333333333333,
							"value":0.3526,
							"leftHandleValue":0.056,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.0724,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.46916,
							"leftHandleValue":-0.0029,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0096,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.3709,
							"leftHandleValue":0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0591,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3867,"leftHandleValue":-0.0183,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3898,"rightHandleValue":0.019,"rightHandleSpan":0.99},
						{
							"time":0.18333333333333332,
							"value":0.31996,
							"leftHandleValue":0.0747,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0073,
							"rightHandleSpan":0.3
						},
						{
							"time":0.3,
							"value":0.50219,
							"leftHandleValue":0.0087,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0175,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.37552,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.009,
							"rightHandleSpan":0.4
						},
						{
							"time":0.65,
							"value":0.39669,
							"leftHandleValue":0.0456,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0165,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1333333333333333,
							"value":0.35543,
							"leftHandleValue":0.0564,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.073,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.47292,
							"leftHandleValue":-0.0029,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0097,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.37388,
							"leftHandleValue":0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0595,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3898,"leftHandleValue":-0.0185,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.18333333333333332,"value":0,"rightHandleValue":-1.3191,"rightHandleSpan":0.2},
						{
							"time":0.23333333333333334,
							"value":6.788,
							"leftHandleValue":-0.3398,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.7046,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":-3.725,
							"leftHandleValue":1.0577,
							"leftHandleSpan":0.5,
							"rightHandleValue":5.2992,
							"rightHandleSpan":0.6
						},
						{
							"time":0.5333333333333333,
							"value":-1.122,
							"leftHandleValue":5.7625,
							"leftHandleSpan":0.9,
							"rightHandleValue":3.0318,
							"rightHandleSpan":0.2
						},
						{"time":1.15,"value":0,"leftHandleValue":-0.858,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.37},
						{"time":0.05,"value":0.303,"rightHandleValue":15.2456,"rightHandleSpan":0.3},
						{
							"time":0.1,
							"value":26.53,
							"leftHandleValue":1.9652,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.4567,
							"rightHandleSpan":0.3
						},
						{
							"time":0.2,
							"value":-14.393,
							"leftHandleValue":-5.7673,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.8163,
							"rightHandleSpan":0.4
						},
						{"time":0.3,"value":7.984,"leftHandleValue":0.582,"leftHandleSpan":0.5,"rightHandleValue":-3.0036,"rightHandleSpan":0.4},
						{
							"time":0.4,
							"value":-3.914,
							"leftHandleValue":-1.2548,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.9657,
							"rightHandleSpan":0.4
						},
						{"time":0.55,"value":0.375,"leftHandleValue":6.1358,"leftHandleSpan":0.6},
						{"time":1.1166666666666667,"value":0.357,"rightHandleValue":1.1503,"rightHandleSpan":0.9},
						{
							"time":1.2,
							"value":-8.279,
							"leftHandleValue":6.3346,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.6548,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":6.699,
							"leftHandleValue":1.1568,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.1377,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3666666666666667,
							"value":-2.83,
							"leftHandleValue":-0.9487,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.1965,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6166666666666667,
							"value":1.077,
							"leftHandleValue":-6.008,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.394,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.37,"leftHandleValue":0.2873,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":124.737,"rightHandleValue":-3.9463,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":115.126,
							"leftHandleValue":-1.4452,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.418,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":143.201,
							"leftHandleValue":-3.4969,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1986,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":122.773,
							"leftHandleValue":-1.0801,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.7897,
							"rightHandleSpan":0.5
						},
						{
							"time":0.7333333333333333,
							"value":126.574,
							"leftHandleValue":-2.6795,
							"leftHandleSpan":0.99,
							"rightHandleValue":-2.0083,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1166666666666667,
							"value":120.883,
							"leftHandleValue":5.7304,
							"leftHandleSpan":0.05,
							"rightHandleValue":-4.7728,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":109.363,
							"leftHandleValue":2.2249,
							"leftHandleSpan":0.4,
							"rightHandleValue":-5.5904,
							"rightHandleSpan":0.2
						},
						{
							"time":1.25,
							"value":148.632,
							"leftHandleValue":-1.0965,
							"leftHandleSpan":0.6,
							"rightHandleValue":-13.3874,
							"rightHandleSpan":0.8
						},
						{
							"time":1.4333333333333333,
							"value":118.696,
							"leftHandleValue":-0.7425,
							"leftHandleSpan":0.3,
							"rightHandleValue":1.2916,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":129.639,
							"leftHandleValue":0.8504,
							"leftHandleSpan":0.4,
							"rightHandleValue":-8.7077,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":124.737,"leftHandleValue":0.4509,"leftHandleSpan":0.8}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4064,"rightHandleValue":-0.03,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.33332,
							"leftHandleValue":-0.0109,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0455,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":0.54557,
							"leftHandleValue":-0.0229,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0004,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.38849,
							"leftHandleValue":-0.0084,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0126,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.4119,
							"leftHandleValue":0.0447,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0067,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1166666666666667,
							"value":0.39234,
							"leftHandleValue":0.0211,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0155,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.35499,
							"leftHandleValue":0.0072,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0143,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.49331,
							"leftHandleValue":-0.0003,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0101,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39002,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0621,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.4064,"leftHandleValue":-0.0191,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4097,"rightHandleValue":-0.0302,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.33603,
							"leftHandleValue":-0.011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0459,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":0.55,
							"leftHandleValue":-0.0231,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0004,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.39165,
							"leftHandleValue":-0.0084,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0127,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.41525,
							"leftHandleValue":0.0451,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0067,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1166666666666667,
							"value":0.39553,
							"leftHandleValue":0.0212,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0156,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.35787,
							"leftHandleValue":0.0073,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0144,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.49731,
							"leftHandleValue":-0.0003,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0102,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39318,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0626,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.4097,"leftHandleValue":-0.0192,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.5},
						{"time":0.31666666666666665,"value":0.42,"rightHandleValue":-2.5159,"rightHandleSpan":0.5},
						{
							"time":0.36666666666666664,
							"value":20.662,
							"leftHandleValue":-11.6155,
							"leftHandleSpan":0.8,
							"rightHandleValue":3.8482,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4666666666666667,
							"value":-10.595,
							"leftHandleValue":7.5271,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.7283,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5666666666666667,
							"value":6.578,
							"leftHandleValue":-1.5934,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.9567,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6666666666666666,
							"value":-2.834,
							"leftHandleValue":0.9187,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2772,
							"rightHandleSpan":0.4
						},
						{"time":0.8333333333333334,"value":0.507,"leftHandleValue":5.6091,"leftHandleSpan":0.6},
						{"time":1.15,"value":0.437,"rightHandleValue":-0.5527,"rightHandleSpan":0.4},
						{
							"time":1.2,
							"value":6.173,
							"leftHandleValue":-0.6949,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.3119,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":-3.497,
							"leftHandleValue":-0.7253,
							"leftHandleSpan":0.4,
							"rightHandleValue":14.648,
							"rightHandleSpan":0.6
						},
						{
							"time":1.5333333333333332,
							"value":1.292,
							"leftHandleValue":-7.02,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.1622,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.5,"leftHandleValue":0.6517,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"9729975288200182"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-81.476,"rightHandleValue":1.818,"rightHandleSpan":0.9},
						{
							"time":0.43333333333333335,
							"value":-79.575,
							"leftHandleValue":-7.7207,
							"leftHandleSpan":0.4,
							"rightHandleValue":-6.7213,
							"rightHandleSpan":0.6
						},
						{
							"time":0.8,
							"value":-82.818,
							"leftHandleValue":2.1157,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.2337,
							"rightHandleSpan":0.99
						},
						{
							"time":1.15,
							"value":-71.681,
							"leftHandleValue":-14.783,
							"leftHandleSpan":0.2,
							"rightHandleValue":-1.1753,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1833333333333333,
							"value":-68.783,
							"leftHandleValue":1.3438,
							"leftHandleSpan":0.5,
							"rightHandleValue":-4.6025,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2666666666666666,
							"value":-104.369,
							"leftHandleValue":3.9216,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.0635,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-78.024,
							"leftHandleValue":2.6,
							"leftHandleSpan":0.5,
							"rightHandleValue":-10.8935,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-81.476,"leftHandleValue":2.7859,"leftHandleSpan":0.7}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"9729975288200182"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3415,"rightHandleValue":-0.0002,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":0.34192,
							"leftHandleValue":0.0195,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0163,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.28506,
							"leftHandleValue":-0.0198,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0467,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.46295,
							"leftHandleValue":-0.0101,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0088,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.32955,
							"leftHandleValue":-0.0122,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0058,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6833333333333333,
							"value":0.36468,
							"leftHandleValue":-0.0025,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0321,
							"rightHandleSpan":0.5
						},
						{
							"time":1.1,
							"value":0.33932,
							"leftHandleValue":0.0147,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0034,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.29825,
							"leftHandleValue":0.009,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0121,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.41417,
							"leftHandleValue":-0.0002,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0086,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.32735,
							"leftHandleValue":0.0009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0521,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3415,"leftHandleValue":-0.0164,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"9729975288200182"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3545,"rightHandleValue":-0.0002,"rightHandleSpan":0.4},
						{
							"time":0.2833333333333333,
							"value":0.35494,
							"leftHandleValue":0.0203,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.017,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.29591,
							"leftHandleValue":-0.0206,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0485,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.48057,
							"leftHandleValue":-0.0105,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0091,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.34209,
							"leftHandleValue":-0.0127,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0061,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6833333333333333,
							"value":0.37857,
							"leftHandleValue":-0.0026,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0181,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.35223,
							"leftHandleValue":0.0088,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0035,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.3096,
							"leftHandleValue":0.0093,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0126,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.42993,
							"leftHandleValue":-0.0002,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0089,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.33981,
							"leftHandleValue":0.0009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0541,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3545,"leftHandleValue":-0.017,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"9729975288200182"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.31666666666666665,"value":0,"rightHandleValue":1.4221,"rightHandleSpan":0.4},
						{
							"time":0.36666666666666664,
							"value":-6.598,
							"leftHandleValue":2.997,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.0348,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4666666666666667,
							"value":3.621,
							"leftHandleValue":-0.9844,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.3698,
							"rightHandleSpan":0.5
						},
						{
							"time":0.6666666666666666,
							"value":1.091,
							"leftHandleValue":-7.1449,
							"leftHandleSpan":0.9,
							"rightHandleValue":-2.9789,
							"rightHandleSpan":0.3
						},
						{"time":1.15,"value":0,"leftHandleValue":0.8383,"leftHandleSpan":0.6,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"9729975288200182"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":1.02},
						{"time":0.13333333333333333,"value":1.027,"rightHandleValue":-2.5885,"rightHandleSpan":0.99},
						{
							"time":0.21666666666666667,
							"value":-15.028,
							"leftHandleValue":24.2393,
							"leftHandleSpan":0.6,
							"rightHandleValue":-12.2863,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":11.61,
							"leftHandleValue":-3.2946,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.0994,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":-4.781,
							"leftHandleValue":1.7021,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.7934,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5333333333333333,
							"value":4.244,
							"leftHandleValue":0.0794,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0942,
							"rightHandleSpan":0.3
						},
						{"time":0.7,"value":1.036,"leftHandleValue":-4.896,"leftHandleSpan":0.7},
						{"time":2,"value":1.02}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-3.011,"rightHandleValue":0.2543,"rightHandleSpan":0.4},
						{
							"time":0.18333333333333332,
							"value":-1.926,
							"leftHandleValue":-2.181,
							"leftHandleSpan":0.4,
							"rightHandleValue":-5.9179,
							"rightHandleSpan":0.4
						},
						{"time":0.65,"value":-3.059,"leftHandleValue":1.1859,"leftHandleSpan":0.9},
						{"time":1.1,"value":-2.97,"rightHandleValue":0.8132,"rightHandleSpan":0.8},
						{
							"time":1.1666666666666667,
							"value":0.236,
							"leftHandleValue":-4.3808,
							"leftHandleSpan":0.1,
							"rightHandleValue":18.9105,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":-9.361,
							"leftHandleValue":-1.5866,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.7123,
							"rightHandleSpan":0.4
						},
						{
							"time":1.3666666666666667,
							"value":0.448,
							"leftHandleValue":0.3372,
							"leftHandleSpan":0.4,
							"rightHandleValue":-13.386,
							"rightHandleSpan":0.7
						},
						{
							"time":1.6166666666666667,
							"value":-3.795,
							"leftHandleValue":6.3503,
							"leftHandleSpan":0.9,
							"rightHandleValue":1.5816,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-3.011,"leftHandleValue":-0.3176,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3846,"rightHandleValue":0.0187,"rightHandleSpan":0.99},
						{
							"time":0.18333333333333332,
							"value":0.31569,
							"leftHandleValue":0.0737,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0072,
							"rightHandleSpan":0.3
						},
						{
							"time":0.3,
							"value":0.49549,
							"leftHandleValue":0.0086,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0172,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.37051,
							"leftHandleValue":0.0026,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0089,
							"rightHandleSpan":0.4
						},
						{
							"time":0.65,
							"value":0.3914,
							"leftHandleValue":0.045,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0162,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1333333333333333,
							"value":0.35069,
							"leftHandleValue":0.0557,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.072,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.46661,
							"leftHandleValue":-0.0028,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0096,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.36889,
							"leftHandleValue":0.001,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0587,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3846,"leftHandleValue":-0.0182,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4104,"rightHandleValue":0.02,"rightHandleSpan":0.99},
						{
							"time":0.18333333333333332,
							"value":0.33687,
							"leftHandleValue":0.0787,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0076,
							"rightHandleSpan":0.3
						},
						{
							"time":0.3,
							"value":0.52873,
							"leftHandleValue":0.0091,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0184,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":0.39537,
							"leftHandleValue":0.0028,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0094,
							"rightHandleSpan":0.4
						},
						{
							"time":0.65,
							"value":0.41765,
							"leftHandleValue":0.048,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0173,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1333333333333333,
							"value":0.37421,
							"leftHandleValue":0.0594,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.0768,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.49792,
							"leftHandleValue":-0.003,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0102,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39363,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0627,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.4104,"leftHandleValue":-0.0195,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.18333333333333332,"value":0,"rightHandleValue":-1.3191,"rightHandleSpan":0.2},
						{
							"time":0.23333333333333334,
							"value":6.788,
							"leftHandleValue":-0.3398,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.7046,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":-3.725,
							"leftHandleValue":1.0577,
							"leftHandleSpan":0.5,
							"rightHandleValue":5.2992,
							"rightHandleSpan":0.6
						},
						{
							"time":0.5333333333333333,
							"value":-1.122,
							"leftHandleValue":5.7625,
							"leftHandleSpan":0.9,
							"rightHandleValue":3.0318,
							"rightHandleSpan":0.2
						},
						{"time":1.15,"value":0,"leftHandleValue":-0.858,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.86},
						{"time":0.05,"value":0.705,"rightHandleValue":54.409,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-10.164,
							"leftHandleValue":-5.5184,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.8796,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":6.924,
							"leftHandleValue":0.3889,
							"leftHandleSpan":0.5,
							"rightHandleValue":-15.2895,
							"rightHandleSpan":0.7
						},
						{
							"time":0.5,
							"value":2.73,
							"leftHandleValue":-5.2954,
							"leftHandleSpan":0.8,
							"rightHandleValue":-3.2574,
							"rightHandleSpan":0.05
						},
						{"time":1.1,"value":0.854,"leftHandleValue":0.5101,"leftHandleSpan":0.4,"rightHandleValue":0.727,"rightHandleSpan":0.9},
						{"time":1.2,"value":-4.632,"leftHandleValue":4.751,"leftHandleSpan":0.6,"rightHandleValue":0.5163,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":5.008,
							"leftHandleValue":0.7639,
							"leftHandleSpan":0.4,
							"rightHandleValue":-14.5764,
							"rightHandleSpan":0.6
						},
						{
							"time":1.5333333333333332,
							"value":0.128,
							"leftHandleValue":6.6614,
							"leftHandleSpan":0.8,
							"rightHandleValue":2.0475,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.86,"leftHandleValue":-0.6419,"leftHandleSpan":0.5}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":79.112,"rightHandleValue":-5.3554,"rightHandleSpan":0.5},
						{
							"time":0.3,
							"value":79.168,
							"leftHandleValue":7.1551,
							"leftHandleSpan":0.99,
							"rightHandleValue":2.1013,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7833333333333333,
							"value":80.382,
							"leftHandleValue":-0.5568,
							"leftHandleSpan":0.5,
							"rightHandleValue":-2.5561,
							"rightHandleSpan":0.99
						},
						{
							"time":1.15,
							"value":69.51,
							"leftHandleValue":14.9576,
							"leftHandleSpan":0.2,
							"rightHandleValue":-5.6526,
							"rightHandleSpan":0.2
						},
						{
							"time":1.2333333333333334,
							"value":94.731,
							"leftHandleValue":-2.7433,
							"leftHandleSpan":0.7,
							"rightHandleValue":-14.6512,
							"rightHandleSpan":0.9
						},
						{
							"time":1.4,
							"value":77.755,
							"leftHandleValue":21.5424,
							"leftHandleSpan":0.7,
							"rightHandleValue":-9.2694,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5333333333333332,
							"value":82.778,
							"leftHandleValue":0.4987,
							"leftHandleSpan":0.4,
							"rightHandleValue":-7.0234,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":79.112,"leftHandleValue":0.8005,"leftHandleSpan":0.8}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4,"rightHandleValue":-0.0295,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.32807,
							"leftHandleValue":-0.0107,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0448,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":0.53698,
							"leftHandleValue":-0.0225,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0004,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.38238,
							"leftHandleValue":-0.0082,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0124,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.40542,
							"leftHandleValue":0.044,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0065,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1166666666666667,
							"value":0.38617,
							"leftHandleValue":0.0207,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0152,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.34939,
							"leftHandleValue":0.0071,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0141,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.48554,
							"leftHandleValue":-0.0003,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0099,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.38387,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0611,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.4,"leftHandleValue":-0.0188,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.412,"rightHandleValue":-0.0304,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.33792,
							"leftHandleValue":-0.011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0462,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":0.55309,
							"leftHandleValue":-0.0232,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0004,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.39385,
							"leftHandleValue":-0.0085,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0128,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.41758,
							"leftHandleValue":0.0453,
							"leftHandleSpan":0.9,
							"rightHandleValue":-0.0067,
							"rightHandleSpan":0.99
						},
						{
							"time":1.1166666666666667,
							"value":0.39775,
							"leftHandleValue":0.0213,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0157,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.35988,
							"leftHandleValue":0.0073,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0145,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2666666666666666,
							"value":0.50011,
							"leftHandleValue":-0.0003,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0102,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.39539,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0629,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.412,"leftHandleValue":-0.0194,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.2833333333333332,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.5333333333333332,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":111.4},
						{"time":0.5,"value":-725.2},
						{"time":1.1666666666666667,"value":111.4},
						{"time":1.5666666666666667,"value":-725.2}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"6372651676122202"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":227.2},
						{"time":0.5,"value":-622.8},
						{"time":1.1666666666666667,"value":227.2},
						{"time":1.5666666666666667,"value":-622.8}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"5798682828807290"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":456.7},
						{"time":0.5,"value":-422.5},
						{"time":1.1666666666666667,"value":456.7},
						{"time":1.5666666666666667,"value":-422.5}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"1313735379907511"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":449.8},
						{"time":0.5,"value":-434.2},
						{"time":1.1666666666666667,"value":449.8},
						{"time":1.5666666666666667,"value":-434.2}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"6330434839548620"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":658.8},
						{"time":0.5,"value":-216.1},
						{"time":1.1666666666666667,"value":658.8},
						{"time":1.5666666666666667,"value":-216.1}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"3387500474395755"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.03333333333333333,"value":736.4},
						{"time":0.5,"value":-259.2},
						{"time":1.1666666666666667,"value":736.4},
						{"time":1.5666666666666667,"value":-259.2}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"9729975288200182"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Minor1Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor2Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{},
			"4":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"BarWhite_Plate_1",
				"uid":"2227918058887180",
				"position":[0.5,64.94,0],
				"scale":[0.4934,0.5096,1],
				"graphicAsset":"BarWhite_Plate",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,202.7,91.2],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"BarWhite_Plate_2",
				"uid":"3340187801759898",
				"position":[0.5,-42.06,0],
				"scale":[0.4934,0.5096,1],
				"graphicAsset":"BarWhite_Plate",
				"subLayer":0.01,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,202.7,91.2],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"BarWhite_Text_1",
				"uid":"3478878384837261",
				"position":[-1.15,106.89,0],
				"scale":[0.5007,0.5047,1],
				"graphicAsset":"BarWhite_Text",
				"subLayer":0.02,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,199.7,89.9],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"GraphicObject",
				"name":"BarWhite_Text_2",
				"uid":"6751361341252427",
				"position":[-1.15,-0.11,0],
				"scale":[0.5007,0.5047,1],
				"graphicAsset":"BarWhite_Text",
				"subLayer":0.03,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,199.7,89.9],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":4,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"5061231007728378",
				"position":[0,0,1000],
				"coreViewWidth":400,
				"coreViewHeight":400,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":400,
				"constructPrecompTargetHeight":400
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":0,"value":0.5},
						{"time":0.05,"value":0.41,"rightHandleValue":54.9965,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-10.772,
							"leftHandleValue":-5.6666,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.0129,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":6.648,
							"leftHandleValue":0.3933,
							"leftHandleSpan":0.5,
							"rightHandleValue":-2.4773,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4,
							"value":-2.887,
							"leftHandleValue":-1.0403,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.0161,
							"rightHandleSpan":0.4
						},
						{"time":0.55,"value":0.507,"leftHandleValue":4.7049,"leftHandleSpan":0.5},
						{"time":1.1,"value":0.497,"rightHandleValue":1.0837,"rightHandleSpan":0.9},
						{"time":1.2,"value":-4.043,"leftHandleValue":2.303,"leftHandleSpan":0.5,"rightHandleValue":0.3531,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":3.922,
							"leftHandleValue":0.6363,
							"leftHandleSpan":0.4,
							"rightHandleValue":-11.949,
							"rightHandleSpan":0.6
						},
						{
							"time":1.533333,
							"value":-0.107,
							"leftHandleValue":6.1124,
							"leftHandleSpan":0.7,
							"rightHandleValue":1.6633,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.5,"leftHandleValue":-0.5236,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0,"value":64.94,"rightHandleValue":-4.5094,"rightHandleSpan":0.4},
						{
							"time":0.15,
							"value":68.444,
							"leftHandleValue":-2.7951,
							"leftHandleSpan":0.5,
							"rightHandleValue":-7.0046,
							"rightHandleSpan":0.4
						},
						{
							"time":0.783333,
							"value":65.963,
							"leftHandleValue":1.9236,
							"leftHandleSpan":0.8,
							"rightHandleValue":-2.0948,
							"rightHandleSpan":1
						},
						{
							"time":1.15,
							"value":56.982,
							"leftHandleValue":12.3309,
							"leftHandleSpan":0.2,
							"rightHandleValue":-5.4414,
							"rightHandleSpan":0.2
						},
						{
							"time":1.233333,
							"value":79.354,
							"leftHandleValue":-0.0082,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.3279,
							"rightHandleSpan":0.4
						},
						{
							"time":1.316667,
							"value":73.638,
							"leftHandleValue":-1.5888,
							"leftHandleSpan":0.5,
							"rightHandleValue":1.793,
							"rightHandleSpan":0.4
						},
						{
							"time":1.433333,
							"value":60.917,
							"leftHandleValue":1.4201,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.6783,
							"rightHandleSpan":0.6
						},
						{
							"time":1.633333,
							"value":64.478,
							"leftHandleValue":6.9828,
							"leftHandleSpan":1,
							"rightHandleValue":0.6327,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":64.94,"leftHandleValue":-0.3927,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4934,"rightHandleValue":-0.0364,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.40468,
							"leftHandleValue":-0.0132,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0553,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":0.66236,
							"leftHandleValue":-0.0278,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0005,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.47166,
							"leftHandleValue":-0.0102,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0076,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.52307,
							"leftHandleValue":0.007,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0251,
							"rightHandleSpan":0.4
						},
						{
							"time":0.683333,
							"value":0.49958,
							"leftHandleValue":-0.001,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0091,
							"rightHandleSpan":1
						},
						{
							"time":1.116667,
							"value":0.47613,
							"leftHandleValue":0.0241,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.019,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.43055,
							"leftHandleValue":0.0085,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0171,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.60867,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0138,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.47304,
							"leftHandleValue":0.0023,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0526,
							"rightHandleSpan":0.6
						},
						{"time":1.716667,"value":0.49138,"leftHandleValue":0.0148,"leftHandleSpan":1},
						{"time":2,"value":0.4934}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5096,"rightHandleValue":-0.0376,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41797,
							"leftHandleValue":-0.0136,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0297,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.68411,
							"leftHandleValue":-0.0024,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0005,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.48715,
							"leftHandleValue":-0.0105,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0078,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.54025,
							"leftHandleValue":0.0073,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.023,
							"rightHandleSpan":0.4
						},
						{
							"time":0.666667,
							"value":0.51606,
							"leftHandleValue":-0.0022,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0093,
							"rightHandleSpan":1
						},
						{
							"time":1.116667,
							"value":0.49176,
							"leftHandleValue":0.0251,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0197,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.44469,
							"leftHandleValue":0.0088,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0176,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.62866,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0143,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.48857,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0019,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.52348,
							"leftHandleValue":0.0029,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0119,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.5096,"leftHandleValue":-0.0074,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5},
						{"time":0.166667,"value":0.494,"rightHandleValue":-1.2071,"rightHandleSpan":0.9},
						{
							"time":0.216667,
							"value":-5.054,
							"leftHandleValue":8.9177,
							"leftHandleSpan":0.2,
							"rightHandleValue":-41.8436,
							"rightHandleSpan":0.4
						},
						{
							"time":0.35,
							"value":12.224,
							"leftHandleValue":-2.1842,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1153,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":-5.782,
							"leftHandleValue":2.9041,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0501,
							"rightHandleSpan":0.4
						},
						{
							"time":0.55,
							"value":3.996,
							"leftHandleValue":-0.4396,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.2067,
							"rightHandleSpan":0.4
						},
						{"time":0.716667,"value":0.508,"leftHandleValue":-5.3397,"leftHandleSpan":0.6},
						{"time":1.15,"value":0.436,"rightHandleValue":5.8062,"rightHandleSpan":0.7},
						{
							"time":1.283333,
							"value":-1.54,
							"leftHandleValue":4.7777,
							"leftHandleSpan":0.8,
							"rightHandleValue":4.3636,
							"rightHandleSpan":0.5
						},
						{
							"time":1.45,
							"value":-0.143,
							"leftHandleValue":1.885,
							"leftHandleSpan":0.6,
							"rightHandleValue":1.6234,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.5,"leftHandleValue":-0.5414,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0,"value":-42.06,"rightHandleValue":-0.3783,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-43.956,
							"leftHandleValue":3.5725,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0392,
							"rightHandleSpan":0.4
						},
						{
							"time":0.316667,
							"value":-38.942,
							"leftHandleValue":0.2043,
							"leftHandleSpan":0.4,
							"rightHandleValue":-7.4735,
							"rightHandleSpan":0.4
						},
						{"time":0.85,"value":-42.755,"leftHandleValue":2.0421,"leftHandleSpan":0.8},
						{"time":1.1,"value":-42.127,"rightHandleValue":7.2505,"rightHandleSpan":1},
						{
							"time":1.166667,
							"value":-34.741,
							"leftHandleValue":-2.9915,
							"leftHandleSpan":0.1,
							"rightHandleValue":13.6405,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":-57.449,
							"leftHandleValue":-5.0693,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.2359,
							"rightHandleSpan":0.4
						},
						{
							"time":1.383333,
							"value":-39.092,
							"leftHandleValue":-0.6846,
							"leftHandleSpan":0.5,
							"rightHandleValue":-9.3242,
							"rightHandleSpan":0.6
						},
						{
							"time":1.6,
							"value":-43.277,
							"leftHandleValue":4.3566,
							"leftHandleSpan":0.6,
							"rightHandleValue":2.5178,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":-42.06,"leftHandleValue":-0.3522,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0,"value":0.4934,"rightHandleValue":0.0007,"rightHandleSpan":0.4},
						{
							"time":0.116667,
							"value":0.50372,
							"leftHandleValue":0.0012,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0014,
							"rightHandleSpan":0.8
						},
						{
							"time":0.2,
							"value":0.40724,
							"leftHandleValue":0.0607,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0292,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":0.66616,
							"leftHandleValue":-0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0183,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.47495,
							"leftHandleValue":0.0145,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0012,
							"rightHandleSpan":0.4
						},
						{
							"time":0.666667,
							"value":0.50268,
							"leftHandleValue":0.0611,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0217,
							"rightHandleSpan":1
						},
						{
							"time":1.133333,
							"value":0.44938,
							"leftHandleValue":0.0715,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.0946,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.60833,
							"leftHandleValue":-0.0036,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0138,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.47274,
							"leftHandleValue":0.0023,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0526,
							"rightHandleSpan":0.6
						},
						{"time":1.716667,"value":0.49124,"leftHandleValue":0.0146,"leftHandleSpan":1},
						{"time":2,"value":0.4934}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5096,"rightHandleValue":0.0008,"rightHandleSpan":0.4},
						{
							"time":0.116667,
							"value":0.52026,
							"leftHandleValue":0.0012,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0014,
							"rightHandleSpan":0.8
						},
						{
							"time":0.2,
							"value":0.42061,
							"leftHandleValue":0.0627,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0302,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":0.68803,
							"leftHandleValue":-0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0189,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.49055,
							"leftHandleValue":0.015,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0013,
							"rightHandleSpan":0.4
						},
						{
							"time":0.666667,
							"value":0.51918,
							"leftHandleValue":0.0631,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0224,
							"rightHandleSpan":1
						},
						{
							"time":1.133333,
							"value":0.46414,
							"leftHandleValue":0.0738,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.0977,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.6283,
							"leftHandleValue":-0.0037,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0143,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.48826,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0019,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.52319,
							"leftHandleValue":0.0029,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0119,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0.5096,"leftHandleValue":-0.0076,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.2,"value":0,"rightHandleValue":-1.4203,"rightHandleSpan":0.3},
						{
							"time":0.25,
							"value":6.733,
							"leftHandleValue":-1.1461,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0307,
							"rightHandleSpan":0.4
						},
						{
							"time":0.35,
							"value":-3.695,
							"leftHandleValue":0.4251,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.4306,
							"rightHandleSpan":0.5
						},
						{"time":0.55,"value":-1.113,"leftHandleValue":6.82,"leftHandleSpan":0.9,"rightHandleValue":2.9126,"rightHandleSpan":0.2},
						{"time":1.15,"value":0,"leftHandleValue":-0.7629,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0,"value":-1.15},
						{"time":0.05,"value":-0.943,"rightHandleValue":15.0986,"rightHandleSpan":0.3},
						{
							"time":0.1,
							"value":24.657,
							"leftHandleValue":2.1928,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.8675,
							"rightHandleSpan":0.3
						},
						{
							"time":0.2,
							"value":-16.149,
							"leftHandleValue":-5.9722,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.961,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":6.477,
							"leftHandleValue":0.5558,
							"leftHandleSpan":0.5,
							"rightHandleValue":-3.0024,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4,
							"value":-5.491,
							"leftHandleValue":-1.2255,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.9334,
							"rightHandleSpan":0.4
						},
						{"time":0.55,"value":-1.165,"leftHandleValue":6.0971,"leftHandleSpan":0.6},
						{"time":1.15,"value":-1.004,"rightHandleValue":1.5352,"rightHandleSpan":0.3},
						{
							"time":1.2,
							"value":-8.644,
							"leftHandleValue":0.2602,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.2471,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":4.037,
							"leftHandleValue":0.9485,
							"leftHandleSpan":0.4,
							"rightHandleValue":-10.7676,
							"rightHandleSpan":0.6
						},
						{
							"time":1.45,
							"value":0.475,
							"leftHandleValue":-5.9762,
							"leftHandleSpan":0.8,
							"rightHandleValue":-5.983,
							"rightHandleSpan":0.6
						},
						{"time":1.666667,"value":-1.147,"leftHandleValue":2.9772,"leftHandleSpan":0.4},
						{"time":2,"value":-1.15}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0,"value":106.89,"rightHandleValue":-3.825,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":97.572,
							"leftHandleValue":-1.3984,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.5001,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":124.76,
							"leftHandleValue":-3.1221,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.5364,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":104.95,
							"leftHandleValue":-0.9566,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.2403,
							"rightHandleSpan":0.5
						},
						{
							"time":0.733333,
							"value":108.434,
							"leftHandleValue":-3.1806,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.7581,
							"rightHandleSpan":1
						},
						{
							"time":1.116667,
							"value":103.504,
							"leftHandleValue":4.9937,
							"leftHandleSpan":0.05,
							"rightHandleValue":-8.7716,
							"rightHandleSpan":0.5
						},
						{
							"time":1.166667,
							"value":97.996,
							"leftHandleValue":-9.3522,
							"leftHandleSpan":0.2,
							"rightHandleValue":22.2766,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":129.181,
							"leftHandleValue":0.2917,
							"leftHandleSpan":0.4,
							"rightHandleValue":-15.3466,
							"rightHandleSpan":0.9
						},
						{
							"time":1.433333,
							"value":101.308,
							"leftHandleValue":3.1608,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.9068,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":111.239,
							"leftHandleValue":0.8019,
							"leftHandleSpan":0.4,
							"rightHandleValue":-7.9797,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":106.89,"leftHandleValue":0.5524,"leftHandleSpan":0.8}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5007,"rightHandleValue":-0.0369,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41067,
							"leftHandleValue":-0.0134,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0292,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.67216,
							"leftHandleValue":-0.0024,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0005,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.47864,
							"leftHandleValue":-0.0103,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0077,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.53081,
							"leftHandleValue":0.0071,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0255,
							"rightHandleSpan":0.4
						},
						{
							"time":0.683333,
							"value":0.50697,
							"leftHandleValue":-0.001,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0092,
							"rightHandleSpan":1
						},
						{
							"time":1.116667,
							"value":0.48317,
							"leftHandleValue":0.0244,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0193,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.43692,
							"leftHandleValue":0.0086,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0173,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.61768,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.014,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.48004,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0625,
							"rightHandleSpan":0.7
						},
						{"time":1.716667,"value":0.49865,"leftHandleValue":0.0091,"leftHandleSpan":1},
						{"time":2,"value":0.5007}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5047,"rightHandleValue":-0.0372,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.41395,
							"leftHandleValue":-0.0135,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0294,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.67753,
							"leftHandleValue":-0.0024,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0005,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.48246,
							"leftHandleValue":-0.0104,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0077,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.53505,
							"leftHandleValue":0.0072,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0257,
							"rightHandleSpan":0.4
						},
						{
							"time":0.683333,
							"value":0.51102,
							"leftHandleValue":-0.001,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0093,
							"rightHandleSpan":1
						},
						{
							"time":1.116667,
							"value":0.48703,
							"leftHandleValue":0.0246,
							"leftHandleSpan":0.05,
							"rightHandleValue":-0.0195,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.44041,
							"leftHandleValue":0.0087,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0175,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.62261,
							"leftHandleValue":0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0141,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.48388,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.063,
							"rightHandleSpan":0.7
						},
						{"time":1.716667,"value":0.50263,"leftHandleValue":0.0091,"leftHandleSpan":1},
						{"time":2,"value":0.5047}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0,"value":-1.15},
						{"time":0.2,"value":-0.949,"rightHandleValue":-0.6134,"rightHandleSpan":0.8},
						{
							"time":0.216667,
							"value":-7.552,
							"leftHandleValue":9.3548,
							"leftHandleSpan":0.6,
							"rightHandleValue":-53.4226,
							"rightHandleSpan":0.4
						},
						{
							"time":0.35,
							"value":13.583,
							"leftHandleValue":-4.3865,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.1526,
							"rightHandleSpan":0.3
						},
						{
							"time":0.45,
							"value":-8.798,
							"leftHandleValue":0.9084,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0704,
							"rightHandleSpan":0.4
						},
						{
							"time":0.55,
							"value":3.111,
							"leftHandleValue":-0.5761,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5627,
							"rightHandleSpan":0.4
						},
						{"time":0.716667,"value":-1.168,"leftHandleValue":-6.6211,"leftHandleSpan":0.6},
						{"time":2,"value":-1.15}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				},
				{
					"keyframes":[
						{"time":0,"value":-0.11,"rightHandleValue":0.4635,"rightHandleSpan":0.9},
						{
							"time":0.2,
							"value":-9.331,
							"leftHandleValue":14.4326,
							"leftHandleSpan":0.3,
							"rightHandleValue":-3.157,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":17.726,
							"leftHandleValue":2.6539,
							"leftHandleSpan":0.3,
							"rightHandleValue":-2.7963,
							"rightHandleSpan":0.4
						},
						{
							"time":0.466667,
							"value":-2.701,
							"leftHandleValue":-2.4123,
							"leftHandleSpan":0.4,
							"rightHandleValue":11.4037,
							"rightHandleSpan":0.4
						},
						{"time":0.883333,"value":-0.378,"leftHandleValue":-2.5779,"leftHandleSpan":0.8},
						{"time":1.116667,"value":-0.449,"rightHandleValue":0.4665,"rightHandleSpan":1},
						{
							"time":1.183333,
							"value":7.542,
							"leftHandleValue":-10.4106,
							"leftHandleSpan":0.6,
							"rightHandleValue":6.1999,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":-6.184,
							"leftHandleValue":-1.5132,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.5843,
							"rightHandleSpan":0.4
						},
						{
							"time":1.366667,
							"value":3.031,
							"leftHandleValue":0.493,
							"leftHandleSpan":0.4,
							"rightHandleValue":-13.4375,
							"rightHandleSpan":0.7
						},
						{
							"time":1.616667,
							"value":-1.021,
							"leftHandleValue":6.3494,
							"leftHandleSpan":0.9,
							"rightHandleValue":1.5543,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-0.11,"leftHandleValue":-0.3121,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5007,"rightHandleValue":0.0007,"rightHandleSpan":0.4},
						{
							"time":0.116667,
							"value":0.51117,
							"leftHandleValue":0.0012,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0014,
							"rightHandleSpan":0.8
						},
						{
							"time":0.2,
							"value":0.41326,
							"leftHandleValue":0.0616,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0297,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":0.67601,
							"leftHandleValue":-0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0186,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.48198,
							"leftHandleValue":0.0148,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0012,
							"rightHandleSpan":0.4
						},
						{
							"time":0.666667,
							"value":0.51011,
							"leftHandleValue":0.062,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.022,
							"rightHandleSpan":1
						},
						{
							"time":1.133333,
							"value":0.45603,
							"leftHandleValue":0.0725,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.096,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.61733,
							"leftHandleValue":-0.0036,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0141,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.47973,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0626,
							"rightHandleSpan":0.7
						},
						{"time":1.716667,"value":0.4985,"leftHandleValue":0.0088,"leftHandleSpan":1},
						{"time":2,"value":0.5007}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5047,"rightHandleValue":0.0008,"rightHandleSpan":0.4},
						{
							"time":0.116667,
							"value":0.51526,
							"leftHandleValue":0.0012,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0014,
							"rightHandleSpan":0.8
						},
						{
							"time":0.2,
							"value":0.41657,
							"leftHandleValue":0.0621,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0299,
							"rightHandleSpan":0.3
						},
						{
							"time":0.316667,
							"value":0.68142,
							"leftHandleValue":-0,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0188,
							"rightHandleSpan":0.4
						},
						{
							"time":0.45,
							"value":0.48583,
							"leftHandleValue":0.0149,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0013,
							"rightHandleSpan":0.4
						},
						{
							"time":0.666667,
							"value":0.51419,
							"leftHandleValue":0.0625,
							"leftHandleSpan":0.8,
							"rightHandleValue":-0.0222,
							"rightHandleSpan":1
						},
						{
							"time":1.133333,
							"value":0.45968,
							"leftHandleValue":0.0731,
							"leftHandleSpan":0.1,
							"rightHandleValue":-0.0968,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.62226,
							"leftHandleValue":-0.0036,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0142,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.48356,
							"leftHandleValue":0.0024,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0631,
							"rightHandleSpan":0.7
						},
						{"time":1.716667,"value":0.50249,"leftHandleValue":0.0089,"leftHandleSpan":1},
						{"time":2,"value":0.5047}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.2,"value":0,"rightHandleValue":-1.4203,"rightHandleSpan":0.3},
						{
							"time":0.25,
							"value":6.733,
							"leftHandleValue":-1.1461,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0307,
							"rightHandleSpan":0.4
						},
						{
							"time":0.35,
							"value":-3.695,
							"leftHandleValue":0.4251,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.4306,
							"rightHandleSpan":0.5
						},
						{"time":0.55,"value":-1.113,"leftHandleValue":6.82,"leftHandleSpan":0.9,"rightHandleValue":2.9126,"rightHandleSpan":0.2},
						{"time":1.15,"value":0,"leftHandleValue":-0.7629,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				},
				{
					"keyframes":[
						{"time":0.066667,"value":-762.6,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.466667,"value":575,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-762.6,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":575,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"2227918058887180"
				},
				{
					"keyframes":[
						{"time":0.066667,"value":-808.4,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.466667,"value":509.7,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-808.4,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":509.7,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"3478878384837261"
				},
				{
					"keyframes":[
						{"time":0.066667,"value":-609.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.466667,"value":728.4,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-609.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":728.4,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"3340187801759898"
				},
				{
					"keyframes":[
						{"time":0.066667,"value":-657.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.466667,"value":660.9,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-657.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":660.9,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"6751361341252427"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Minor2Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Minor3Construct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"BarWhite_Plate",
				"uid":"3167232686563551",
				"position":[0,12.29,0],
				"scale":[0.5949,0.6148,1],
				"graphicAsset":"BarWhite_Plate",
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,168.1,75.6],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"BarWhite_Text",
				"uid":"5058770658948113",
				"position":[-1.72,63.12,0],
				"scale":[0.5991,0.6039,1],
				"graphicAsset":"BarWhite_Text",
				"subLayer":0.01,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,166.9,75.1],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"3266166304940326",
				"position":[0,0,1000],
				"coreViewWidth":400,
				"coreViewHeight":400,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":400,
				"constructPrecompTargetHeight":400
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":55.8164,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":-11.624,
							"leftHandleValue":-5.8533,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.2271,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":6.247,
							"leftHandleValue":0.4061,
							"leftHandleSpan":0.5,
							"rightHandleValue":-2.5113,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4,
							"value":-3.465,
							"leftHandleValue":-1.0434,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.0578,
							"rightHandleSpan":0.4
						},
						{"time":0.55,"value":0,"leftHandleValue":4.7736,"leftHandleSpan":0.5,"rightHandleValue":0.7368,"rightHandleSpan":0.7},
						{
							"time":1.283333,
							"value":0.643,
							"leftHandleValue":-2.1771,
							"leftHandleSpan":0.1,
							"rightHandleValue":-1.5207,
							"rightHandleSpan":0.1
						},
						{"time":2,"value":0,"leftHandleValue":0.4389,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0,"value":12.29,"rightHandleValue":-6.4828,"rightHandleSpan":0.5},
						{
							"time":0.15,
							"value":17.484,
							"leftHandleValue":-1.1779,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.3902,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":13.028,
							"leftHandleValue":-3.9458,
							"leftHandleSpan":0.8,
							"rightHandleValue":-1.9168,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":10.703,
							"leftHandleValue":3.5131,
							"leftHandleSpan":0.1,
							"rightHandleValue":-2.5071,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2,
							"value":22.123,
							"leftHandleValue":-1.6314,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.2928,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":9.747,
							"leftHandleValue":-0.2221,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5295,
							"rightHandleSpan":0.4
						},
						{
							"time":1.35,
							"value":16.216,
							"leftHandleValue":-1.0321,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.7818,
							"rightHandleSpan":0.4
						},
						{
							"time":1.45,
							"value":9.828,
							"leftHandleValue":-0.9263,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.0926,
							"rightHandleSpan":0.6
						},
						{"time":1.666667,"value":12.256,"leftHandleValue":-4.0331,"leftHandleSpan":0.4},
						{"time":2,"value":12.29}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5949,"rightHandleValue":-0.044,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.48793,
							"leftHandleValue":-0.0213,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0436,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.8463,
							"leftHandleValue":-0.0014,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0048,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.56603,
							"leftHandleValue":-0.0094,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0065,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.63068,
							"leftHandleValue":0.0097,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0581,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.59091,
							"leftHandleValue":0.0334,
							"leftHandleSpan":1,
							"rightHandleValue":-0.0059,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.5181,
							"leftHandleValue":0.0141,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0198,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.75742,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0204,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.56923,
							"leftHandleValue":0.0053,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0006,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.6111,
							"leftHandleValue":0.0039,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0286,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.5949,"leftHandleValue":-0.0009,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0,"value":0.6148,"rightHandleValue":-0.0454,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.50425,
							"leftHandleValue":-0.022,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.045,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.87461,
							"leftHandleValue":-0.0014,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0049,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.58496,
							"leftHandleValue":-0.0097,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0067,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.65177,
							"leftHandleValue":0.01,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0601,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.61068,
							"leftHandleValue":0.0345,
							"leftHandleSpan":1,
							"rightHandleValue":-0.0061,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.53543,
							"leftHandleValue":0.0145,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0205,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.78275,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0211,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.58827,
							"leftHandleValue":0.0055,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0006,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.63155,
							"leftHandleValue":0.004,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0295,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.6148,"leftHandleValue":-0.001,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0,"value":-1.72},
						{"time":0.05,"value":-1.411,"rightHandleValue":15.6869,"rightHandleSpan":0.3},
						{
							"time":0.1,
							"value":25.732,
							"leftHandleValue":2.1152,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.6438,
							"rightHandleSpan":0.3
						},
						{
							"time":0.2,
							"value":-18.079,
							"leftHandleValue":-6.8899,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.7983,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":6.306,
							"leftHandleValue":0.6274,
							"leftHandleSpan":0.5,
							"rightHandleValue":-3.1354,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4,
							"value":-6.324,
							"leftHandleValue":-1.2645,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.0928,
							"rightHandleSpan":0.4
						},
						{"time":0.55,"value":-1.743,"leftHandleValue":6.4166,"leftHandleSpan":0.6},
						{"time":1.15,"value":-1.498,"rightHandleValue":0.7873,"rightHandleSpan":0.3},
						{
							"time":1.2,
							"value":-6.254,
							"leftHandleValue":-0.174,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1443,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":1.138,
							"leftHandleValue":0.5276,
							"leftHandleSpan":0.4,
							"rightHandleValue":-11.1724,
							"rightHandleSpan":0.6
						},
						{
							"time":1.533333,
							"value":-2.368,
							"leftHandleValue":5.67,
							"leftHandleSpan":0.8,
							"rightHandleValue":1.7034,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":-1.72,"leftHandleValue":-0.4977,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				},
				{
					"keyframes":[
						{"time":0,"value":63.12,"rightHandleValue":-4.6637,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":51.77,
							"leftHandleValue":-2.2563,
							"leftHandleSpan":0.4,
							"rightHandleValue":8.8551,
							"rightHandleSpan":0.4
						},
						{
							"time":0.15,
							"value":89.794,
							"leftHandleValue":-0.1793,
							"leftHandleSpan":0.3,
							"rightHandleValue":-1.2908,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":60.077,
							"leftHandleValue":-0.6983,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.2301,
							"rightHandleSpan":0.5
						},
						{"time":0.533333,"value":63.971,"leftHandleValue":5.9616,"leftHandleSpan":1},
						{"time":0.716667,"value":63.886,"rightHandleValue":-2.9959,"rightHandleSpan":1},
						{
							"time":1.15,
							"value":54.971,
							"leftHandleValue":13.6326,
							"leftHandleSpan":0.2,
							"rightHandleValue":-5.2525,
							"rightHandleSpan":0.2
						},
						{
							"time":1.233333,
							"value":78.929,
							"leftHandleValue":-1.5401,
							"leftHandleSpan":0.7,
							"rightHandleValue":-0.39,
							"rightHandleSpan":0.4
						},
						{
							"time":1.283333,
							"value":73.785,
							"leftHandleValue":1.3477,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.4836,
							"rightHandleSpan":0.7
						},
						{
							"time":1.433333,
							"value":58.803,
							"leftHandleValue":-0.3509,
							"leftHandleSpan":0.3,
							"rightHandleValue":5.7521,
							"rightHandleSpan":0.6
						},
						{
							"time":1.633333,
							"value":62.549,
							"leftHandleValue":6.7262,
							"leftHandleSpan":1,
							"rightHandleValue":0.6687,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":63.12,"leftHandleValue":-0.3855,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				},
				{
					"keyframes":[
						{"time":0,"value":0.5991,"rightHandleValue":-0.0443,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.49137,
							"leftHandleValue":-0.0214,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0439,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.85228,
							"leftHandleValue":-0.0014,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0048,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.57003,
							"leftHandleValue":-0.0095,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0065,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.63513,
							"leftHandleValue":0.0097,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0585,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1,
							"value":0.59508,
							"leftHandleValue":0.0336,
							"leftHandleSpan":1,
							"rightHandleValue":-0.0059,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":0.52176,
							"leftHandleValue":0.0142,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.02,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.76276,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0206,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.57325,
							"leftHandleValue":0.0054,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0006,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.61542,
							"leftHandleValue":0.0039,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0288,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.5991,"leftHandleValue":-0.001,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","x"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				},
				{
					"keyframes":[
						{"time":0,"value":0.6039,"rightHandleValue":-0.0446,"rightHandleSpan":0.4},
						{
							"time":0.05,
							"value":0.49531,
							"leftHandleValue":-0.0216,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0442,
							"rightHandleSpan":0.3
						},
						{
							"time":0.15,
							"value":0.85911,
							"leftHandleValue":-0.0014,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0048,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":0.57459,
							"leftHandleValue":-0.0095,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0066,
							"rightHandleSpan":0.4
						},
						{
							"time":0.416667,
							"value":0.64022,
							"leftHandleValue":0.0098,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.059,
							"rightHandleSpan":0.3
						},
						{"time":1.1,"value":0.59985,"leftHandleValue":0.0339,"leftHandleSpan":1,"rightHandleValue":-0.006,"rightHandleSpan":0.4},
						{
							"time":1.15,
							"value":0.52594,
							"leftHandleValue":0.0143,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0201,
							"rightHandleSpan":0.3
						},
						{
							"time":1.266667,
							"value":0.76887,
							"leftHandleValue":0.0011,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0207,
							"rightHandleSpan":0.4
						},
						{
							"time":1.416667,
							"value":0.57784,
							"leftHandleValue":0.0054,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0006,
							"rightHandleSpan":0.4
						},
						{
							"time":1.533333,
							"value":0.62035,
							"leftHandleValue":0.0039,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.029,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.6039,"leftHandleValue":-0.001,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","y"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				},
				{
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.05,"value":0,"rightHandleValue":-17.8412,"rightHandleSpan":0.4},
						{
							"time":0.2,
							"value":3.659,
							"leftHandleValue":1.9867,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.9371,
							"rightHandleSpan":0.7
						},
						{
							"time":0.4,
							"value":1.102,
							"leftHandleValue":-2.2069,
							"leftHandleSpan":0.7,
							"rightHandleValue":-2.7845,
							"rightHandleSpan":0.1
						},
						{"time":1.15,"value":0,"leftHandleValue":0.7265,"leftHandleSpan":0.7,"rightHandleValue":-0.4471,"rightHandleSpan":0.4},
						{"time":1.2,"value":3.925,"leftHandleValue":0.1665,"leftHandleSpan":0.6,"rightHandleValue":-1.078,"rightHandleSpan":0.4},
						{
							"time":1.283333,
							"value":-2.381,
							"leftHandleValue":-0.3783,
							"leftHandleSpan":0.4,
							"rightHandleValue":9.4136,
							"rightHandleSpan":0.7
						},
						{
							"time":1.533333,
							"value":0.531,
							"leftHandleValue":-4.5147,
							"leftHandleSpan":0.9,
							"rightHandleValue":-1.47,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":0.451,"leftHandleSpan":0.5}
					],
					"propertyPath":["rotation","z"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				},
				{
					"keyframes":[
						{"time":0.1,"value":-569.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.5,"value":540.1,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-569.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":540.1,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"3167232686563551"
				},
				{
					"keyframes":[
						{"time":0.1,"value":-623.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":0.5,"value":478.4,"keyframeType":"left","secondaryValue":-1500},
						{"time":1.166667,"value":-623.3,"keyframeType":"right","secondaryValue":-1500},
						{"time":1.516667,"value":478.4,"keyframeType":"left","secondaryValue":-1500}
					],
					"propertyPath":["material","0","sheen","progress"],
					"interpolation":"bezier",
					"sceneObjectUid":"5058770658948113"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/Minor3Construct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Wild_CherryLeft.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Wild_CherryRight.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Wild_Leaf.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/Wild_Text.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs/WildConstruct.construct
------------------------------------------------------------
{
	"blueprint":{
		"type":"Blueprint",
		"hierarchy":{
			"0":{},
			"1":{},
			"2":{},
			"3":{},
			"4":{}
		},
		"objects":[
			{
				"i":0,
				"type":"GraphicObject",
				"name":"Wild_CherryRight",
				"uid":"5260181590830166",
				"position":[29.62,20.11,0],
				"rotation":[0,0,13.5],
				"scale":[0.3989,0.3751,1],
				"graphicAsset":"Wild_CherryRight",
				"subLayer":0.01,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,200.6,87.7],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":1,
				"type":"GraphicObject",
				"name":"Wild_CherryLeft",
				"uid":"1318609139099603",
				"position":[-48.11,22.99,0],
				"rotation":[0,0,0.75],
				"scale":[0.3181,0.2925,1],
				"graphicAsset":"Wild_CherryLeft",
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,251.5,110],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":2,
				"type":"GraphicObject",
				"name":"Wild_Leaf",
				"uid":"0824628194821993",
				"position":[-31.38,109.96,0],
				"rotation":[0,0,2.3],
				"scale":[0.249,0.2336,1],
				"graphicAsset":"Wild_Leaf",
				"subLayer":0.02,
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,321.3,140.6],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":3,
				"type":"GraphicObject",
				"name":"Wild_Text",
				"uid":"5181909378657975",
				"position":[0.15,-74.91,0],
				"scale":[0.4063,0.4063,1],
				"graphicAsset":"Wild_Text",
				"subLayer":0.03,
				"masking":{"enabled":false,"maskGroups":["MainMaskGroup"]},
				"materials":[
					{
						"effectNodes":["SampleMainTexture","ColorMultiply","Sheen"],
						"effectControllerValues":{"sheen":[-1500,45,196.9,86.1],"sheen_color":[1,1,1,0.8]}
					}
				]
			},
			{
				"i":4,
				"type":"OrthographicCamera",
				"name":"Orthographic Precomp Camera",
				"uid":"7877893287921742",
				"position":[0,0,1000],
				"coreViewWidth":450,
				"coreViewHeight":550,
				"viewNear":0,
				"viewFar":2000,
				"constructPrecompTargetWidth":450,
				"constructPrecompTargetHeight":550
			}
		]
	},
	"timelines":{
		"SymbolAnimation":{
			"autoplayMode":"none",
			"initialTime":0,
			"playbackRate":1,
			"startValue":0,
			"endValue":2,
			"animatedProperties":[
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":29.62,"rightHandleValue":7.1342,"rightHandleSpan":0.8},
						{
							"time":0.3833333333333333,
							"value":18.183,
							"leftHandleValue":8.6471,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.4674,
							"rightHandleSpan":0.4
						},
						{
							"time":0.55,
							"value":58.033,
							"leftHandleValue":-3.4231,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.6484,
							"rightHandleSpan":0.3
						},
						{
							"time":0.7166666666666667,
							"value":14.492,
							"leftHandleValue":-0.8105,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.0352,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9,
							"value":43.934,
							"leftHandleValue":-3.4103,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.4182,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0666666666666667,
							"value":25.027,
							"leftHandleValue":2.1516,
							"leftHandleSpan":0.4,
							"rightHandleValue":16.1966,
							"rightHandleSpan":0.8
						},
						{
							"time":1.4666666666666666,
							"value":25.068,
							"leftHandleValue":5.2508,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.7609,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":29.62,"leftHandleValue":-0.7491,"leftHandleSpan":0.99}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":20.11,"rightHandleValue":-14.3071,"rightHandleSpan":0.4},
						{
							"time":0.1,
							"value":-7.594,
							"leftHandleValue":-12.6178,
							"leftHandleSpan":0.4,
							"rightHandleValue":29.9504,
							"rightHandleSpan":0.4
						},
						{
							"time":0.2833333333333333,
							"value":116.024,
							"leftHandleValue":-4.8074,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0697,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":17.193,
							"leftHandleValue":35.6725,
							"leftHandleSpan":0.5,
							"rightHandleValue":-7.101,
							"rightHandleSpan":0.3
						},
						{
							"time":0.5833333333333334,
							"value":-1.833,
							"leftHandleValue":-0.9768,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.5166,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7166666666666667,
							"value":40.464,
							"leftHandleValue":1.9218,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.026,
							"rightHandleSpan":0.3
						},
						{
							"time":0.9166666666666666,
							"value":22.642,
							"leftHandleValue":1.4232,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.3337,
							"rightHandleSpan":0.4
						},
						{
							"time":1.05,
							"value":29.354,
							"leftHandleValue":-1.6043,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.6334,
							"rightHandleSpan":0.5
						},
						{
							"time":1.1,
							"value":14.202,
							"leftHandleValue":-1.0036,
							"leftHandleSpan":0.4,
							"rightHandleValue":5.0981,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2166666666666666,
							"value":85.214,
							"leftHandleValue":-2.1811,
							"leftHandleSpan":0.3,
							"rightHandleValue":5.2533,
							"rightHandleSpan":0.3
						},
						{
							"time":1.3833333333333333,
							"value":18.926,
							"leftHandleValue":12.1432,
							"leftHandleSpan":0.3,
							"rightHandleValue":-9.1994,
							"rightHandleSpan":0.05
						},
						{"time":2,"value":20.11,"leftHandleValue":-6.9594,"leftHandleSpan":0.9}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3989,"rightHandleValue":0.008,"rightHandleSpan":0.4},
						{
							"time":0.18333333333333332,
							"value":0.42991,
							"leftHandleValue":0.0224,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0984,
							"rightHandleSpan":0.99
						},
						{
							"time":0.5833333333333334,
							"value":0.45629,
							"leftHandleValue":-0.0092,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.0253,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7666666666666666,
							"value":0.38759,
							"leftHandleValue":-0.0367,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0995,
							"rightHandleSpan":0.7
						},
						{
							"time":1.0833333333333333,
							"value":0.46352,
							"leftHandleValue":-0.0799,
							"leftHandleSpan":0.1,
							"rightHandleValue":0.0271,
							"rightHandleSpan":0.3
						},
						{
							"time":1.1333333333333333,
							"value":0.46206,
							"leftHandleValue":0.0115,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1054,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4166666666666667,
							"value":0.40866,
							"leftHandleValue":0.0035,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0265,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.3989,"leftHandleValue":-0.0014,"leftHandleSpan":0.6}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3751,"rightHandleValue":-0.0309,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":0.29778,
							"leftHandleValue":0.0052,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0088,
							"rightHandleSpan":0.4
						},
						{
							"time":0.2833333333333333,
							"value":0.48126,
							"leftHandleValue":0.0107,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0047,
							"rightHandleSpan":0.2
						},
						{
							"time":0.5166666666666666,
							"value":0.36326,
							"leftHandleValue":0.0611,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0262,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.30862,
							"leftHandleValue":-0.0048,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0249,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7333333333333333,
							"value":0.41525,
							"leftHandleValue":0.0064,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0373,
							"rightHandleSpan":0.7
						},
						{
							"time":1.05,
							"value":0.4092,
							"leftHandleValue":-0.0359,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0069,
							"rightHandleSpan":0.5
						},
						{
							"time":1.1,
							"value":0.3611,
							"leftHandleValue":0.0016,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0253,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":0.44703,
							"leftHandleValue":0.0317,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.1337,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":0.3751,"leftHandleValue":0.0058,"leftHandleSpan":0.99}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":13.5},
						{"time":0.25,"value":13.5,"rightHandleValue":2.3209,"rightHandleSpan":0.2},
						{
							"time":0.35,
							"value":-1.939,
							"leftHandleValue":1.696,
							"leftHandleSpan":0.7,
							"rightHandleValue":2.8708,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5333333333333333,
							"value":24.79,
							"leftHandleValue":0.0173,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.5134,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7166666666666667,
							"value":5.258,
							"leftHandleValue":0.4261,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.674,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9,
							"value":19.507,
							"leftHandleValue":-0.6337,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.174,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0833333333333333,
							"value":9.129,
							"leftHandleValue":0.6995,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0218,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":16.684,
							"leftHandleValue":0.618,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.4991,
							"rightHandleSpan":0.4
						},
						{"time":1.5666666666666667,"value":13.5,"leftHandleValue":-5.7201,"leftHandleSpan":0.5},
						{"time":2,"value":13.5}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-48.11,"rightHandleValue":-0.5378,"rightHandleSpan":0.4},
						{
							"time":0.13333333333333333,
							"value":-52.504,
							"leftHandleValue":0.6766,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.2068,
							"rightHandleSpan":0.8
						},
						{
							"time":0.3833333333333333,
							"value":-34.174,
							"leftHandleValue":-6.4044,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.8738,
							"rightHandleSpan":0.4
						},
						{
							"time":0.55,
							"value":-79.312,
							"leftHandleValue":7.4328,
							"leftHandleSpan":0.4,
							"rightHandleValue":-4.454,
							"rightHandleSpan":0.3
						},
						{
							"time":0.7166666666666667,
							"value":-30.259,
							"leftHandleValue":-0.1948,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.1991,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9166666666666666,
							"value":-64.502,
							"leftHandleValue":-2.2836,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.0799,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0666666666666667,
							"value":-44.565,
							"leftHandleValue":-1.7738,
							"leftHandleSpan":0.4,
							"rightHandleValue":-8.0696,
							"rightHandleSpan":0.3
						},
						{
							"time":1.3166666666666667,
							"value":-52.366,
							"leftHandleValue":3.2889,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.8785,
							"rightHandleSpan":0.4
						},
						{"time":1.5666666666666667,"value":-47.575,"leftHandleValue":10.5513,"leftHandleSpan":0.6},
						{"time":2,"value":-48.11}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":22.99,"rightHandleValue":-11.9545,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":-8.724,
							"leftHandleValue":-0.1321,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.1243,
							"rightHandleSpan":0.3
						},
						{
							"time":0.26666666666666666,
							"value":114.894,
							"leftHandleValue":11.0055,
							"leftHandleSpan":0.2,
							"rightHandleValue":-2.233,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3,
							"value":106.682,
							"leftHandleValue":4.2162,
							"leftHandleSpan":0.4,
							"rightHandleValue":-67.6873,
							"rightHandleSpan":0.8
						},
						{
							"time":0.5166666666666666,
							"value":33.768,
							"leftHandleValue":23.5397,
							"leftHandleSpan":0.5,
							"rightHandleValue":-10.9011,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6,
							"value":10.004,
							"leftHandleValue":-1.8646,
							"leftHandleSpan":0.4,
							"rightHandleValue":12.5831,
							"rightHandleSpan":0.5
						},
						{
							"time":0.7833333333333333,
							"value":31.348,
							"leftHandleValue":8.6655,
							"leftHandleSpan":0.8,
							"rightHandleValue":0.4412,
							"rightHandleSpan":0.4
						},
						{
							"time":0.8833333333333333,
							"value":33.662,
							"leftHandleValue":0.3185,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7677,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0666666666666667,
							"value":26.137,
							"leftHandleValue":3.1811,
							"leftHandleSpan":0.05,
							"rightHandleValue":-5.7454,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1,
							"value":11.378,
							"leftHandleValue":-1.4505,
							"leftHandleSpan":0.4,
							"rightHandleValue":15.751,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2333333333333334,
							"value":90.979,
							"leftHandleValue":5.7574,
							"leftHandleSpan":0.4,
							"rightHandleValue":-9.658,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":17.204,
							"leftHandleValue":13.7482,
							"leftHandleSpan":0.4,
							"rightHandleValue":-10.4722,
							"rightHandleSpan":0.4
						},
						{
							"time":1.5833333333333333,
							"value":17.477,
							"leftHandleValue":0.3735,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.6489,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":22.99,"leftHandleValue":-0.3698,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.3181,"rightHandleValue":0.0064,"rightHandleSpan":0.4},
						{
							"time":0.18333333333333332,
							"value":0.34283,
							"leftHandleValue":0.0178,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0784,
							"rightHandleSpan":0.99
						},
						{
							"time":0.5833333333333334,
							"value":0.36387,
							"leftHandleValue":-0.0074,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.0202,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7666666666666666,
							"value":0.30908,
							"leftHandleValue":-0.0293,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0793,
							"rightHandleSpan":0.7
						},
						{
							"time":1.0833333333333333,
							"value":0.36963,
							"leftHandleValue":-0.0637,
							"leftHandleSpan":0.1,
							"rightHandleValue":0.0235,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1333333333333333,
							"value":0.36847,
							"leftHandleValue":0.0071,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0908,
							"rightHandleSpan":0.3
						},
						{"time":1.6166666666666667,"value":0.31404,"leftHandleValue":0.0306,"leftHandleSpan":0.99},
						{"time":2,"value":0.3181}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.2925,"rightHandleValue":-0.0241,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":0.2322,
							"leftHandleValue":0.004,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0068,
							"rightHandleSpan":0.4
						},
						{
							"time":0.2833333333333333,
							"value":0.37528,
							"leftHandleValue":0.0084,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.012,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.28327,
							"leftHandleValue":0.0546,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.0379,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6166666666666667,
							"value":0.25883,
							"leftHandleValue":-0.0366,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1486,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0166666666666666,
							"value":0.31731,
							"leftHandleValue":-0.0607,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.0143,
							"rightHandleSpan":0.8
						},
						{
							"time":1.1,
							"value":0.28158,
							"leftHandleValue":0.0143,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0135,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2166666666666666,
							"value":0.3529,
							"leftHandleValue":-0.0101,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0017,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":0.28372,
							"leftHandleValue":0.0112,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0044,
							"rightHandleSpan":0.1
						},
						{"time":2,"value":0.2925,"leftHandleValue":0.0034,"leftHandleSpan":0.7}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.75},
						{"time":0.25,"value":0.75,"rightHandleValue":-2.5787,"rightHandleSpan":0.2},
						{
							"time":0.35,
							"value":17.904,
							"leftHandleValue":-1.8844,
							"leftHandleSpan":0.7,
							"rightHandleValue":-3.1898,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5333333333333333,
							"value":-11.794,
							"leftHandleValue":-0.0192,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.6815,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7166666666666667,
							"value":9.908,
							"leftHandleValue":-0.4735,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7489,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9,
							"value":-5.924,
							"leftHandleValue":0.7041,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1933,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0833333333333333,
							"value":5.606,
							"leftHandleValue":-0.7772,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0242,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":-2.787,
							"leftHandleValue":-0.6866,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.7768,
							"rightHandleSpan":0.4
						},
						{"time":1.5666666666666667,"value":0.75,"leftHandleValue":6.3557,"leftHandleSpan":0.5},
						{"time":2,"value":0.75}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-31.38,"rightHandleValue":-1.1334,"rightHandleSpan":0.4},
						{
							"time":0.25,
							"value":-32.443,
							"leftHandleValue":-4.0406,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.5303,
							"rightHandleSpan":0.8
						},
						{
							"time":0.26666666666666666,
							"value":-38.849,
							"leftHandleValue":9.3065,
							"leftHandleSpan":0.6,
							"rightHandleValue":-14.2888,
							"rightHandleSpan":0.3
						},
						{
							"time":0.31666666666666665,
							"value":-63.534,
							"leftHandleValue":-1.8373,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.8171,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4166666666666667,
							"value":-20.635,
							"leftHandleValue":0.5498,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.8298,
							"rightHandleSpan":0.4
						},
						{
							"time":0.48333333333333334,
							"value":-31.906,
							"leftHandleValue":1.2899,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.4508,
							"rightHandleSpan":0.5
						},
						{
							"time":0.5666666666666667,
							"value":-21.442,
							"leftHandleValue":0.9244,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.7787,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6333333333333333,
							"value":-35.376,
							"leftHandleValue":0.2493,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.1986,
							"rightHandleSpan":0.5
						},
						{
							"time":0.7666666666666666,
							"value":-30.945,
							"leftHandleValue":6.3555,
							"leftHandleSpan":0.8,
							"rightHandleValue":1.2573,
							"rightHandleSpan":0.5
						},
						{
							"time":0.9166666666666666,
							"value":-35.645,
							"leftHandleValue":1.0144,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.2966,
							"rightHandleSpan":0.9
						},
						{
							"time":1.1166666666666667,
							"value":-37.859,
							"leftHandleValue":-0.5638,
							"leftHandleSpan":0.2,
							"rightHandleValue":13.0551,
							"rightHandleSpan":0.8
						},
						{
							"time":1.2666666666666666,
							"value":-34.76,
							"leftHandleValue":5.6904,
							"leftHandleSpan":0.8,
							"rightHandleValue":2.0356,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4,
							"value":-33.495,
							"leftHandleValue":3.3763,
							"leftHandleSpan":0.6,
							"rightHandleValue":4.6579,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":-31.38,"leftHandleValue":-0.485,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":109.96,"rightHandleValue":-19.1086,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":60.318,
							"leftHandleValue":1.0688,
							"leftHandleSpan":0.4,
							"rightHandleValue":-2.5927,
							"rightHandleSpan":0.3
						},
						{
							"time":0.25,
							"value":221.977,
							"leftHandleValue":-29.5805,
							"leftHandleSpan":0.3,
							"rightHandleValue":11.9962,
							"rightHandleSpan":0.2
						},
						{
							"time":0.31666666666666665,
							"value":208.241,
							"leftHandleValue":10.7078,
							"leftHandleSpan":0.5,
							"rightHandleValue":-14.8252,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5,
							"value":109.96,
							"leftHandleValue":89.7621,
							"leftHandleSpan":0.6,
							"rightHandleValue":-19.673,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5666666666666667,
							"value":60.977,
							"leftHandleValue":7.8533,
							"leftHandleSpan":0.4,
							"rightHandleValue":-11.5671,
							"rightHandleSpan":0.3
						},
						{
							"time":0.7,
							"value":144.406,
							"leftHandleValue":-5.5309,
							"leftHandleSpan":0.4,
							"rightHandleValue":1.3555,
							"rightHandleSpan":0.3
						},
						{
							"time":0.85,
							"value":117.376,
							"leftHandleValue":-0.7757,
							"leftHandleSpan":0.5,
							"rightHandleValue":2.3731,
							"rightHandleSpan":0.4
						},
						{
							"time":1.05,
							"value":123.418,
							"leftHandleValue":-4.2564,
							"leftHandleSpan":0.4,
							"rightHandleValue":6.2523,
							"rightHandleSpan":0.5
						},
						{
							"time":1.1,
							"value":101.375,
							"leftHandleValue":-6.3895,
							"leftHandleSpan":0.3,
							"rightHandleValue":12.5895,
							"rightHandleSpan":0.3
						},
						{
							"time":1.2166666666666666,
							"value":193.651,
							"leftHandleValue":0.8445,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.9074,
							"rightHandleSpan":0.3
						},
						{
							"time":1.3833333333333333,
							"value":109.425,
							"leftHandleValue":23.3123,
							"leftHandleSpan":0.4,
							"rightHandleValue":-3.5616,
							"rightHandleSpan":0.1
						},
						{
							"time":1.4666666666666666,
							"value":100.03,
							"leftHandleValue":0.0568,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.2296,
							"rightHandleSpan":0.1
						},
						{"time":2,"value":109.96,"leftHandleValue":-7.662,"leftHandleSpan":0.99}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.249,"rightHandleValue":0.0028,"rightHandleSpan":0.4},
						{
							"time":0.13333333333333333,
							"value":0.27174,
							"leftHandleValue":-0.0035,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0618,
							"rightHandleSpan":0.99
						},
						{
							"time":0.5833333333333334,
							"value":0.28483,
							"leftHandleValue":-0.0153,
							"leftHandleSpan":0.2,
							"rightHandleValue":-0.0158,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7666666666666666,
							"value":0.24194,
							"leftHandleValue":-0.0229,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0715,
							"rightHandleSpan":0.9
						},
						{
							"time":1.1,
							"value":0.29854,
							"leftHandleValue":-0.0734,
							"leftHandleSpan":0.3,
							"rightHandleValue":-0.0831,
							"rightHandleSpan":0.4
						},
						{"time":1.6166666666666667,"value":0.24582,"leftHandleValue":0.023,"leftHandleSpan":0.99},
						{"time":2,"value":0.249}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.2336,"rightHandleValue":-0.0192,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":0.18545,
							"leftHandleValue":0.0032,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0055,
							"rightHandleSpan":0.4
						},
						{
							"time":0.2833333333333333,
							"value":0.29971,
							"leftHandleValue":0.0067,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0093,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5166666666666666,
							"value":0.22623,
							"leftHandleValue":0.0346,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0302,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6166666666666667,
							"value":0.20671,
							"leftHandleValue":-0.0292,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.1124,
							"rightHandleSpan":0.3
						},
						{
							"time":1.05,
							"value":0.25484,
							"leftHandleValue":-0.0471,
							"leftHandleSpan":0.7,
							"rightHandleValue":0.007,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1,
							"value":0.22488,
							"leftHandleValue":0.0025,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0108,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2166666666666666,
							"value":0.28184,
							"leftHandleValue":-0.008,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0164,
							"rightHandleSpan":0.4
						},
						{"time":1.5833333333333333,"value":0.23126,"leftHandleValue":-0.0258,"leftHandleSpan":0.8},
						{"time":2,"value":0.2336}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":2.3},
						{"time":0.25,"value":2.3,"rightHandleValue":0.5341,"rightHandleSpan":0.7},
						{
							"time":0.26666666666666666,
							"value":6.078,
							"leftHandleValue":-5.7319,
							"leftHandleSpan":0.6,
							"rightHandleValue":10.6045,
							"rightHandleSpan":0.4
						},
						{
							"time":0.31666666666666665,
							"value":22.241,
							"leftHandleValue":-0.9983,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.38,
							"rightHandleSpan":0.4
						},
						{
							"time":0.43333333333333335,
							"value":-13.93,
							"leftHandleValue":2.9371,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7034,
							"rightHandleSpan":0.4
						},
						{
							"time":0.55,
							"value":15.406,
							"leftHandleValue":-3.9094,
							"leftHandleSpan":0.4,
							"rightHandleValue":2.1048,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6833333333333333,
							"value":-8.523,
							"leftHandleValue":-2.1138,
							"leftHandleSpan":0.4,
							"rightHandleValue":3.1482,
							"rightHandleSpan":0.4
						},
						{
							"time":0.8,
							"value":11.245,
							"leftHandleValue":0.401,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.6104,
							"rightHandleSpan":0.4
						},
						{
							"time":0.9166666666666666,
							"value":-5.036,
							"leftHandleValue":0.493,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.5077,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0333333333333332,
							"value":8.271,
							"leftHandleValue":-1.0805,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.2588,
							"rightHandleSpan":0.4
						},
						{
							"time":1.15,
							"value":-2.521,
							"leftHandleValue":1.4382,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.7743,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2833333333333332,
							"value":6.282,
							"leftHandleValue":0.7776,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.44,
							"rightHandleSpan":0.3
						},
						{"time":1.4666666666666666,"value":2.3,"leftHandleValue":-8.5759,"leftHandleSpan":0.7},
						{"time":2,"value":2.3}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.15,"rightHandleValue":-0.5454,"rightHandleSpan":0.6},
						{
							"time":0.48333333333333334,
							"value":-1.25,
							"leftHandleValue":2.7428,
							"leftHandleSpan":0.05,
							"rightHandleValue":5.0097,
							"rightHandleSpan":0.6
						},
						{
							"time":0.8666666666666667,
							"value":0.443,
							"leftHandleValue":-2.9826,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.5909,
							"rightHandleSpan":0.3
						},
						{"time":2,"value":0.15,"leftHandleValue":0.1592,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","x"],
					"sceneObjectUid":"5181909378657975"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":-74.91,"rightHandleValue":-3.9316,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":-86.417,
							"leftHandleValue":-1.5091,
							"leftHandleSpan":0.4,
							"rightHandleValue":4.5991,
							"rightHandleSpan":0.3
						},
						{
							"time":0.31666666666666665,
							"value":-8.92,
							"leftHandleValue":8.4358,
							"leftHandleSpan":0.4,
							"rightHandleValue":-1.7702,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":-18.727,
							"leftHandleValue":4.9873,
							"leftHandleSpan":0.4,
							"rightHandleValue":-7.7061,
							"rightHandleSpan":0.6
						},
						{
							"time":0.5333333333333333,
							"value":-80.61,
							"leftHandleValue":17.9421,
							"leftHandleSpan":0.5,
							"rightHandleValue":-10.2504,
							"rightHandleSpan":0.5
						},
						{
							"time":0.7,
							"value":-61.685,
							"leftHandleValue":-6.7075,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.5969,
							"rightHandleSpan":0.2
						},
						{
							"time":1.0666666666666667,
							"value":-74.29,
							"leftHandleValue":-9.9613,
							"leftHandleSpan":0.7,
							"rightHandleValue":-1.0103,
							"rightHandleSpan":0.4
						},
						{
							"time":1.1,
							"value":-76.874,
							"leftHandleValue":-1.1861,
							"leftHandleSpan":0.4,
							"rightHandleValue":8.0947,
							"rightHandleSpan":0.5
						},
						{
							"time":1.2166666666666666,
							"value":-7.614,
							"leftHandleValue":0.0959,
							"leftHandleSpan":0.2,
							"rightHandleValue":0.5342,
							"rightHandleSpan":0.4
						},
						{
							"time":1.25,
							"value":-15.174,
							"leftHandleValue":5.6531,
							"leftHandleSpan":0.4,
							"rightHandleValue":-47.4622,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":-78.498,
							"leftHandleValue":0.3605,
							"leftHandleSpan":0.6,
							"rightHandleValue":-3.2087,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":-74.91,"leftHandleValue":-0.6575,"leftHandleSpan":0.4}
					],
					"propertyPath":["position","y"],
					"sceneObjectUid":"5181909378657975"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4063,"rightHandleValue":0.0466,"rightHandleSpan":0.7},
						{
							"time":0.2833333333333333,
							"value":0.39241,
							"leftHandleValue":0.0181,
							"leftHandleSpan":0.6,
							"rightHandleValue":0.0014,
							"rightHandleSpan":0.4
						},
						{
							"time":0.36666666666666664,
							"value":0.40941,
							"leftHandleValue":-0.0122,
							"leftHandleSpan":0.2,
							"rightHandleValue":0.0521,
							"rightHandleSpan":0.4
						},
						{
							"time":0.4666666666666667,
							"value":0.61675,
							"leftHandleValue":0.0135,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0321,
							"rightHandleSpan":0.3
						},
						{
							"time":0.6,
							"value":0.41781,
							"leftHandleValue":0.0124,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0085,
							"rightHandleSpan":0.4
						},
						{
							"time":0.8166666666666667,
							"value":0.41973,
							"leftHandleValue":0.0412,
							"leftHandleSpan":0.8,
							"rightHandleValue":0.0141,
							"rightHandleSpan":0.4
						},
						{
							"time":1.0166666666666666,
							"value":0.41444,
							"leftHandleValue":0.0187,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.014,
							"rightHandleSpan":0.7
						},
						{
							"time":1.1333333333333333,
							"value":0.46745,
							"leftHandleValue":0.0264,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.0182,
							"rightHandleSpan":0.4
						},
						{
							"time":1.2166666666666666,
							"value":0.57487,
							"leftHandleValue":-0.007,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0201,
							"rightHandleSpan":0.4
						},
						{
							"time":1.35,
							"value":0.39149,
							"leftHandleValue":0.013,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0039,
							"rightHandleSpan":0.4
						},
						{
							"time":1.4666666666666666,
							"value":0.43298,
							"leftHandleValue":0.0067,
							"leftHandleSpan":0.4,
							"rightHandleValue":-0.0538,
							"rightHandleSpan":0.4
						},
						{"time":2,"value":0.4063,"leftHandleValue":0.0008,"leftHandleSpan":0.8}
					],
					"propertyPath":["scale","x"],
					"sceneObjectUid":"5181909378657975"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0.4063,"rightHandleValue":-0.0339,"rightHandleSpan":0.4},
						{
							"time":0.08333333333333333,
							"value":0.31683,
							"leftHandleValue":0.009,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0099,
							"rightHandleSpan":0.4
						},
						{
							"time":0.3333333333333333,
							"value":0.49416,
							"leftHandleValue":0.0197,
							"leftHandleSpan":0.6,
							"rightHandleValue":-0.0212,
							"rightHandleSpan":0.6
						},
						{
							"time":0.45,
							"value":0.66589,
							"leftHandleValue":-0.047,
							"leftHandleSpan":0.5,
							"rightHandleValue":-0.0067,
							"rightHandleSpan":0.4
						},
						{
							"time":0.5833333333333334,
							"value":0.3059,
							"leftHandleValue":-0.0069,
							"leftHandleSpan":0.3,
							"rightHandleValue":0.0022,
							"rightHandleSpan":0.4
						},
						{
							"time":0.7166666666666667,
							"value":0.51123,
							"leftHandleValue":0.0125,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0064,
							"rightHandleSpan":0.2
						},
						{
							"time":1.05,
							"value":0.42,
							"leftHandleValue":-0.0582,
							"leftHandleSpan":0.8,
							"rightHandleValue":0.0097,
							"rightHandleSpan":0.5
						},
						{
							"time":1.1,
							"value":0.37819,
							"leftHandleValue":-0.0026,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0495,
							"rightHandleSpan":0.7
						},
						{
							"time":1.2166666666666666,
							"value":0.68565,
							"leftHandleValue":-0.0728,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.0168,
							"rightHandleSpan":0.3
						},
						{
							"time":1.3833333333333333,
							"value":0.38249,
							"leftHandleValue":-0.0154,
							"leftHandleSpan":0.5,
							"rightHandleValue":0.0075,
							"rightHandleSpan":0.2
						},
						{"time":1.6,"value":0.40245,"leftHandleValue":0.0359,"leftHandleSpan":0.7},
						{"time":2,"value":0.4063}
					],
					"propertyPath":["scale","y"],
					"sceneObjectUid":"5181909378657975"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0,"value":0},
						{"time":0.45,"value":0,"rightHandleValue":-1.3045,"rightHandleSpan":0.2},
						{
							"time":0.5166666666666666,
							"value":5.712,
							"leftHandleValue":0.7627,
							"leftHandleSpan":0.5,
							"rightHandleValue":-1.4428,
							"rightHandleSpan":0.4
						},
						{
							"time":0.6333333333333333,
							"value":-3.765,
							"leftHandleValue":-0.4829,
							"leftHandleSpan":0.4,
							"rightHandleValue":0.9511,
							"rightHandleSpan":0.4
						},
						{
							"time":0.75,
							"value":2.482,
							"leftHandleValue":0.3183,
							"leftHandleSpan":0.4,
							"rightHandleValue":-5.5498,
							"rightHandleSpan":0.6
						},
						{
							"time":0.9833333333333333,
							"value":1.079,
							"leftHandleValue":-3.4967,
							"leftHandleSpan":0.7,
							"rightHandleValue":-3.4963,
							"rightHandleSpan":0.2
						},
						{"time":2,"value":0,"leftHandleValue":1.1345,"leftHandleSpan":0.99}
					],
					"propertyPath":["rotation","z"],
					"sceneObjectUid":"5181909378657975"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.5,"value":-950.1},
						{"time":0.8666666666666667,"value":1061.8},
						{"time":1.2333333333333334,"value":-950.1},
						{"time":1.5,"value":1061.8}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"1318609139099603"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.5,"value":-890.4},
						{"time":0.8666666666666667,"value":714.1},
						{"time":1.2333333333333334,"value":-890.4},
						{"time":1.5,"value":714.1}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"5260181590830166"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.5,"value":-1508.3},
						{"time":0.8666666666666667,"value":1062},
						{"time":1.2333333333333334,"value":-1508.3},
						{"time":1.5,"value":1062}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"0824628194821993"
				},
				{
					"interpolation":"bezier",
					"keyframes":[
						{"time":0.5,"value":-657.5},
						{"time":0.8666666666666667,"value":917.7},
						{"time":1.2333333333333334,"value":-657.5},
						{"time":1.5,"value":917.7}
					],
					"propertyPath":["material","0","sheen","progress"],
					"sceneObjectUid":"5181909378657975"
				}
			]
		}
	},
	"layers":[],
	"constructSettings":{"targetScene":"MainScene","defaultTimeline":"NeutralState"}
}

Assets/SymbolConstructs/WildConstruct.construct.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Bonus.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Major1.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Major2.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Major3.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Minor1.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Minor2.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Minor3.png.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages/Wild.png.ncData
------------------------------------------------------------
default ncData file

Assets/CodeAssets.ncData
------------------------------------------------------------
default ncData file

Assets/Dashboard.ncData
------------------------------------------------------------
default ncData file

Assets/Fonts.ncData
------------------------------------------------------------
default ncData file

Assets/GameLayout.ncData
------------------------------------------------------------
default ncData file

Assets/LayersAndMasks.ncData
------------------------------------------------------------
default ncData file

Assets/ParticleSystems.ncData
------------------------------------------------------------
default ncData file

Assets/Sounds.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolConstructs.ncData
------------------------------------------------------------
default ncData file

Assets/SymbolImages.ncData
------------------------------------------------------------
default ncData file

TypescriptProjectCode/FlowStates/00 GameIntro.ts
------------------------------------------------------------
class GameIntro extends FlowState
{
    userTouchedScreen:boolean;
    constructor()
    {
        super()
        this.userTouchedScreen = false;
        this.addElement(0,"startGameIntro");
        this.addPause(1,"waitForUserToTouchScreen");
        this.addElement(1.05,"playIntroOutro")
        // this.addElement(3,"fadeIntroBackground")
    }


    startGameIntro()
    {
        pr.gameLayout.descendantsByName.GameIntroBackground.addReleaseCallback(this,"userTouchedScreenCallback");
        pr.gameLayout.descendantsByName.GameIntroAnimation.enable();
        pr.gameLayout.descendantsByName.GameIntroAnimation.timelines.Intro.playOnce();
    }


    userTouchedScreenCallback()
    {
        this.userTouchedScreen = true;
        pr.gameLayout.descendantsByName.GameIntroAnimation.timelines.Outro.playOnceAndTakeWeight(.15,undefined,pr.gameLayout.descendantsByName.GameIntroAnimation.timelines.Outro,pr.gameLayout.descendantsByName.GameIntroAnimation,"disable");
        pr.gameLayout.descendantsByName.GameIntroBackground.removeReleaseCallback(this,"userTouchedScreenCallback")
        pr.gameLayout.descendantsByName.GameIntroBackground.buttonActive = false;
        pr.adjustGameLayout();
    }


    waitForUserToTouchScreen()
    {
        return(this.userTouchedScreen);
    }


    playIntroOutro()
    {
        pr.gameLayout.descendantsByName.GameIntroBackground.colorMultiply.swoop.alpha(0,.75,undefined,pr.gameLayout.descendantsByName.GameIntroBackground,"disable");
        nc.flows.MainGameFlow.GameIdle.setToCurrentState();
    }
}




TypescriptProjectCode/FlowStates/01 GameIdle.ts
------------------------------------------------------------
class GameIdle extends FlowState
{
    constructor()
    {
        super()
        this.addElement(0,"startIdle");
    }


    startIdle()
    {

    }
}

TypescriptProjectCode/FlowStates/02 StartGame.ts
------------------------------------------------------------
class StartGame extends FlowState
{
    constructor()
    {
        super()
        this.addElement(0,"startGame");
    }


    async startGame()
    {
        // update the balance and clear the win meter
        pr.dashboard.descendantsByName.WinMeter.string = "";
        if(gameSystemManager.currentGameOutcome!==undefined)
        {
            let balanceString = gameSystemManager.formatCurrency(gameSystemManager.currentGameOutcome.balanceAfter);
            pr.dashboard.descendantsByName.BalanceMeter.string = balanceString;
        }

        // start a new game if the local info in the gameSystemManager indicates that's possible
        if(gameSystemManager.attemptBet(pr,"processNewGameOutcome")===true)
        {
            nc.flows.MainGameFlow.SpinReels.setToCurrentState(true); 
            gameSystemManager.gameStarted();
        }
        else
        {
            console.log("GameOutcome could not be requested.");
            nc.flows.MainGameFlow.GameIdle.setToCurrentState();
        }

        // reset items that may have been in progress when the game started
        pr.payline.colorMultiply.swoop.alpha(0,.5);
    }
}

TypescriptProjectCode/FlowStates/03 SpinReels.ts
------------------------------------------------------------
class SpinReels extends FlowState
{
    allReelsHaveStarted:boolean
    offset:number
    constructor()
    {
        super()
        this.addElement(0,"startSpin",undefined);
        this.addElement(.05,"startReelSpinSound");
        for(let i=0; i<pr.symbolReels.length; i++)
        {
            this.addElement(.01+.05*i,"spinReel",i);
        }
        this.addPause(1.5,"waitForGameOutcome")
        for(let i=0; i<pr.symbolReels.length; i++)
        {
            this.addElement(1.51+.2*i,"stopReel",i,"offset");
        }
    }


    startSpin()
    {
        nc.sounds.SpinBegin.playOnce();
        this.allReelsHaveStarted = false;
        nc.appEvents.fixedUpdate.addCallback(this,"fixedUpdate");
        pr.dashboard.descendantsByName.SpinButtonCenter.rotation.swoop.z(0,0);
        pr.dashboard.descendantsByName.SpinButtonCenter.rotation.swoop.z(-360,.75,nc.tweenTypes.ExtremeEaseIn);
    }


    startReelSpinSound()
    {
        nc.sounds.ReelSpinSound.play();
    }


    fixedUpdate()
    {
        if(this.allReelsHaveStarted===true)
        {
            // benchmark 1: all reels are done with full speed motion (each has reached at least 'bounce') - pause the spin sound
            // benchmark 2: all reels are done with all motion (each is 'stopped') - move to the next FlowState
            let allReelsDoneSpinning = true;
            let allReelsAreStopped = true;
            for(let i=0; i<pr.symbolReels.length; i++)
            {
                let reelState = pr.symbolReels[i].reelState;
                if(reelState!=="stopped")
                {
                    allReelsAreStopped=false;
                    // a reel in its 'bounce' state is done spinning, but it can't begin another spin until it is fully 'stopped'
                    if(reelState!=="bounce")
                    {
                        allReelsDoneSpinning=false;
                        break;
                    }
                }
            }
            if(allReelsDoneSpinning===true && nc.sounds.ReelSpinSound.playbackState==="playing")
            {
                nc.sounds.ReelSpinSound.pause();
            }
            if(allReelsAreStopped===true)
            {
                nc.appEvents.fixedUpdate.removeCallback(this,"fixedUpdate");
                nc.flows.MainGameFlow.WinCelebration.setToCurrentState();
            }
        }
    }


    spinReel(reelIdx)
    {
        pr.symbolReels[reelIdx].beginSpin();
        if(reelIdx===pr.symbolReels.length-1){this.allReelsHaveStarted=true;}
    }


    waitForGameOutcome()
    {
        if(gameSystemManager.currentGameOutcome!==undefined){return(true);}
    }


    stopReel(reelIdx)
    {
        // a reel that was slammed (or has otherwise already stopped) no longer needs a stop request, and 'beginStop' is only valid while it is still spinning
        let reelState = pr.symbolReels[reelIdx].reelState;
        if(reelState==="windup" || reelState==="spinFree")
        {
            pr.symbolReels[reelIdx].beginStop(true);
        }
    }
}

TypescriptProjectCode/FlowStates/05 WinCelebration.ts
------------------------------------------------------------
class WinCelebration extends FlowState
{
    winRollupAmount:number;
    centerWinMeter:TextBox;
    winHighlightIndex:number;
    // symbols currently showing a SymbolAnimation Precomp, with the image and Timeline needed to put them back
    animatedSymbols:{symbol:any,graphicAsset:GraphicAsset,timeline:Timeline}[];
    constructor()
    {
        super()
        this.centerWinMeter = pr.gameLayout.descendantsByName.CenterWinMeter;
        this.winRollupAmount = 0;
        this.animatedSymbols = [];
        this.addElement(0,"startWinCelebration");
        this.addElement(.2,"highlightWin");
        // each win is shown long enough for the 2 second SymbolAnimation to play (it starts at .2)
        this.addElement(2.3,"unhighlightWinSymbols");
        this.addElement(2.4,"goToNextWin");
    }


    updateCenterWinMeterValue()
    {
        let meterString = gameSystemManager.formatCurrency(this.winRollupAmount);
        this.centerWinMeter.string = meterString;
        pr.dashboard.descendantsByName.WinMeter.string = meterString;
    }


    winRollupComplete()
    {
        this.winRollupAmount = gameSystemManager.currentGameOutcome.totalWin;
        nc.swoopValue(this,"winRollupAmount",gameSystemManager.currentGameOutcome.totalWin,0);
        this.updateCenterWinMeterValue();
        this.centerWinMeter.colorMultiply.swoop.alpha(0,1.5,nc.tweenTypes.ExtremeEaseOut,this.centerWinMeter,"disable");
        gameSystemManager.gameEnded();
    }


    startWinCelebration()
    {
        if(gameSystemManager.currentGameOutcome.totalWin===0)
        {
            nc.flows.MainGameFlow.GameIdle.setToCurrentState(true);
            gameSystemManager.gameEnded();
            return;
        }
        this.winHighlightIndex = 0;
        this.winRollupAmount = 0;
        this.centerWinMeter.enable();
        this.centerWinMeter.colorMultiply.alpha = 1;
        this.centerWinMeter.string = "";
        this.centerWinMeter.scale.swoop.all(0,0)
        this.centerWinMeter.position.swoop.y(-100,0)
        this.centerWinMeter.position.swoop.y(200,8,nc.tweenTypes.ExtremeEaseIn);
        pr.gameLayout.descendantsByName.CenterWinMeterShadow.enabled = true;
        pr.gameLayout.descendantsByName.CenterWinMeterShadow.colorMultiply.alpha = 0;
        let shadowAlpha = 0;
        let rollupTime = 0;
        let winMultiplier = gameSystemManager.currentGameOutcome.totalWin/gameSystemManager.currentGameOutcome.bet;
        if(winMultiplier<=1)
        {
            this.centerWinMeter.scale.swoop.all(.5,.1);
            rollupTime = .25;
            shadowAlpha = .4;
        }
        else if(winMultiplier<=5)
        {
            this.centerWinMeter.scale.swoop.all(.65,.1);
            rollupTime = .5;
            shadowAlpha = .5;
        }
        else if(winMultiplier<=15)
        {
            this.centerWinMeter.scale.swoop.all(.75,.1);
            rollupTime = 1.25;
            shadowAlpha = .6;
        }
        else if(winMultiplier<=25)
        {
            this.centerWinMeter.scale.swoop.all(.85,.1);
            rollupTime = 2;
            shadowAlpha = .7;
        }
        else
        {
            this.centerWinMeter.scale.swoop.all(1,.1);
            rollupTime = 4;
            shadowAlpha = .8;
        }
        pr.gameLayout.descendantsByName.CenterWinMeterShadow.colorMultiply.swoop.alpha(shadowAlpha,3,nc.tweenTypes.ExtremeEaseIn);
        nc.swoopValue(this,"winRollupAmount",gameSystemManager.currentGameOutcome.totalWin,rollupTime,undefined,this,"winRollupComplete",undefined,undefined,undefined,this,"updateCenterWinMeterValue");
    }


    highlightWin()
    {   
        let symbol;
        if(this.winHighlightIndex<gameSystemManager.currentGameOutcome.wins.length)
        {
            pr.gameLayout.descendantsByName.ReelBackground.brightnessContrast.swoop.brightness(-.1,.5);
            pr.gameLayout.descendantsByName.GameBackgroundPattern.brightnessContrast.swoop.brightness(-.15,.55);
            let winDescription = gameSystemManager.currentGameOutcome.wins[this.winHighlightIndex];
            if(winDescription.winType==="line"){pr.payline.displayPayline(winDescription.line,.35,.1);}
            else{pr.payline.colorMultiply.alpha = 0;}
            for(let i=0; i<pr.symbolReels.length; i++)
            {
                for(let j=0; j<pr.symbolReels[i].numMainSymbols; j++)
                {
                    let isSymbolWinning = false;
                    for(let k=0; k<winDescription.winningSymbols.length; k++)
                    {
                        if(winDescription.winningSymbols[k][0]===i && winDescription.winningSymbols[k][1]===j)
                        {
                            isSymbolWinning=true;
                            break;
                        }
                    }
                    symbol = pr.symbolReels[i].getSymbol(j) as GraphicObject;
                    if(isSymbolWinning===true)
                    {
                        symbol.brightnessContrast.swoop.brightness(.1,1,nc.tweenTypes.ExtremeEaseIn);
                        symbol.layer = nc.layers.WinningSymbols;
                        // symbols with a SymbolAnimation Construct (e.g. 'Major1Construct' for 'Major1') show its Precomp while the animation plays
                        let constructDef = nc.constructDefs[symbol.graphicAsset.name+"Construct"];
                        if(constructDef!==undefined)
                        {
                            // symbols of the same type share one Precomp, so the Timeline only needs starting once (zero fades keep the keyframed motion intact)
                            let timeline:Timeline = constructDef.precomp.constructInstance.timelines.SymbolAnimation;
                            if(timeline.playbackState!==constants.playbackStates.playing){timeline.playOnceAndTakeWeight(0,0,undefined,this,"restoreWinSymbols");}
                            this.animatedSymbols.push({symbol:symbol,graphicAsset:symbol.graphicAsset,timeline:timeline});
                            // keep the symbol's EffectNodes (including its BrightnessContrast) and values, or it can no longer be dimmed
                            symbol.setGraphicAsset(constructDef.precomp.graphicAsset,true);
                            // the animation overshoots the symbol's bounds, so the ReelMask must not clip it while it plays
                            symbol.masking.enabled = false;
                        }
                    }
                    else
                    {
                        symbol.brightnessContrast.swoop.brightness(-.3,1,nc.tweenTypes.ExtremeEaseIn);
                        symbol.layer = nc.layers.Reels;
                    }
                }
            }
        }
        else
        {
            pr.payline.colorMultiply.swoop.alpha(0,.7);
            pr.gameLayout.descendantsByName.ReelBackground.brightnessContrast.swoop.brightness(0,.25);
            pr.gameLayout.descendantsByName.GameBackgroundPattern.brightnessContrast.swoop.brightness(0,.35);
        }
        this.winHighlightIndex++;
        this.winHighlightIndex=this.winHighlightIndex%(gameSystemManager.currentGameOutcome.wins.length+1);
    }


    unhighlightWinSymbols()
    {
        this.restoreWinSymbols();
        for(let i=0; i<pr.symbolReels.length; i++)
        {
            for(let j=0; j<pr.symbolReels[i].numMainSymbols; j++)
            {
                pr.symbolReels[i].getSymbol(j).brightnessContrast.swoop.brightness(0,1,nc.tweenTypes.Ease);
            }
        }
    }


    goToNextWin()
    {
        this.setTime(.1,true);
    }


    // puts every symbol that is showing a SymbolAnimation Precomp back to its image (runs when the animation completes, and as part of the cleanup)
    restoreWinSymbols()
    {
        let animatedSymbols = this.animatedSymbols;
        this.animatedSymbols = [];
        for(let i=0; i<animatedSymbols.length; i++)
        {
            animatedSymbols[i].symbol.setGraphicAsset(animatedSymbols[i].graphicAsset,true);
            animatedSymbols[i].symbol.masking.enabled = true;
            animatedSymbols[i].timeline.stop();
        }
    }


    cleanUpWinCelebration()
    {
        // (unhighlightWinSymbols restores the symbol images as well)
        this.unhighlightWinSymbols();
        // catch-all: whatever state an interrupted win cycle left the symbols in, every symbol is masked by the reel again
        for(let i=0; i<pr.symbolReels.length; i++)
        {
            for(let j=0; j<pr.symbolReels[i].numMainSymbols; j++)
            {
                (pr.symbolReels[i].getSymbol(j) as GraphicObject).masking.enabled = true;
            }
        }
        pr.gameLayout.descendantsByName.ReelBackground.brightnessContrast.swoop.brightness(0,.25);
        pr.gameLayout.descendantsByName.GameBackgroundPattern.brightnessContrast.swoop.brightness(0,.35);
    }
}

TypescriptProjectCode/PreloadConfiguration/PreloadConfiguration.ts
------------------------------------------------------------
async function preloadConfiguration(projectConfiguration)
{
    CODE.includeIf___published;
        // Preserving the drawing buffer enables several useful development features, 
        // but may cause performance issues in published software on some devices.
        projectConfiguration.preserveDrawingBuffer = false;
    CODE.includeEnd___published;
    projectConfiguration.canvasParent = document.body;
// define resource loading override function (this is optional)
    this.resourceLoadingOverride=function(filename)
    {
        if(filename.endsWith("_assetList.js")===true || filename.endsWith("_assetData.js")===true){filename = projectConfiguration.projectName+String.fromCharCode(95)+projectConfiguration.publishTimestamp+"_loadedAssets/" + filename;}
        var s=document.createElement('script'); 
        s.setAttribute('src',filename); 
        document.body.appendChild(s);
    };
// define canvas positioning function (this is optional)
    this.canvasPositionOverride=function(canvas,left,top,width,height)
    {
        canvas.style.width = width+'px';
        canvas.style.height = height+'px';
        canvas.style.left = left+'px';
        canvas.style.top = top+'px';
    };
};

TypescriptProjectCode/DashboardManager.ts
------------------------------------------------------------
class DashboardManager
{
    dashboard:Dashboard;
    spinButton:Button;
    soundButton:Button;
    autoplayButton:Button;
    autoplayRotationMotion:Motion;
    mainMenuContainer:SceneObject;
    mainMenuBackground:Button
    menuBackgroundDimmer:Button
    autoplayMenu:Button;
    menuButton:Button;
    autoplayOptionButtons:Button[];
    autoplaySpinsRemaining:number;
    autoplayStartDelay:WaitThen;

    constructor()
    {
        // initial values
        this.autoplaySpinsRemaining=0;

        // create shortcuts to key items
        this.dashboard = pr.gameLayout.descendantsByName.Dashboard;
        this.spinButton = this.dashboard.descendantsByName.SpinButton;
        this.soundButton =  this.dashboard.descendantsByName.SoundButton;
        this.autoplayButton = this.dashboard.descendantsByName["Autoplay Button"];
        this.menuButton = this.dashboard.descendantsByName.MenuButton;
        this.mainMenuContainer = this.dashboard.descendantsByName.MainMenuContainer;
        this.mainMenuBackground = this.dashboard.descendantsByName.MainMenuBackground;
        this.menuBackgroundDimmer = this.dashboard.descendantsByName.MenuBackgroundDimmer;
        this.autoplayMenu = this.dashboard.descendantsByName["Autoplay Menu"];

        // make the gamelayout view area invisible
        this.dashboard.descendantsByName.ViewArea.enabled = false;

        // add button callbacks
        this.spinButton.addReleaseCallback(this,"spinButtonReleaseCallback");
        this.soundButton.addReleaseCallback(this,"soundButtonReleaseCallback");
        this.autoplayButton.addReleaseCallback(this,"autoplayButtonReleaseCallback");
        this.menuButton.addReleaseCallback(this,"menuButtonReleaseCallback");

        // populate autoplay options
        this.populateAutoplayOptions();
        // set up autoplay rotation motion
        this.autoplayRotationMotion = this.dashboard.descendantsByName["Autoplay Button"].rotation.addMotion.z(100,-100,1,nc.motionTypes.InfiniteAdd);
        this.autoplayRotationMotion.influence = 0;
        // create the WaitThen responsible for starting autoplay
        this.autoplayStartDelay = new WaitThen("autoplayStartDelay");
    }


    populateAutoplayOptions()
    {
        if(gameSystemManager.autoplayOptions!==undefined && gameSystemManager.autoplayOptions.length>0)
        {
            this.autoplayOptionButtons = [];
            this.autoplayMenu.graphicExpander.expandedAreaTop = 175 + 175*gameSystemManager.autoplayOptions.length;
            for(let i=0; i<gameSystemManager.autoplayOptions.length; i++)
            {
                let newButton = new TextBox(this.autoplayMenu,"Autoplay Option Button");
                let numSpins = gameSystemManager.autoplayOptions[i];
                newButton.string = nc.getPhrase(nc.phraseIDs.AutoplaySelection,{nSpins:numSpins});
                newButton["numSpins"] = numSpins;
                newButton.position.y = 225+175*i
                newButton.buttonActive = true;
                newButton.horizontalJustification = constants.justifications.center;
                newButton.textFormat.lineHeightMultiplier = .8;
                newButton.colorMultiply.red = .89;
                newButton.colorMultiply.green = .89;
                newButton.colorMultiply.blue = .92;
                newButton.addReleaseCallback(this,"autoplayOptionButtonCallback",newButton);
            }
        }
        else
        {
            this.autoplayButton.disable();
        }
    }


    spinButtonReleaseCallback()
    {
        // bounce the spin button when released
        this.spinButton.position.y = -25;
        this.spinButton.position.swoop.y(0,.1);
        this.spinButton.scale.swoop.all(1.35,0);
        this.spinButton.scale.swoop.all(1.5,.15);

        // trigger the mainPlayer input function
        pr.mainPlayerInput();
    }


    menuButtonReleaseCallback()
    {
        if(this.mainMenuContainer.enabled===false)
        {
            this.showMainMenu();
        }
        else
        {
            this.hideMainMenu();
        }
    }


    showMainMenu()
    {
        let container = this.dashboard.descendantsByName.MainMenuContainer;
        container.enabled = true;
        this.dashboard.descendantsByName.MenuBackgroundDimmer.enabled = true;
        container.scale.swoop.y(0,0);
        container.scale.swoop.y(1,.07,nc.tweenTypes.ExtremeEaseIn);
        this.menuBackgroundDimmer.addReleaseCallback(this,"hideMainMenu");
    }


    hideMainMenu()
    {
        this.dashboard.descendantsByName.MainMenuContainer.enabled = false;
        this.dashboard.descendantsByName.MenuBackgroundDimmer.enabled = false;
        this.menuBackgroundDimmer.removeReleaseCallback(this,"hideMainMenu");
    }


    processGameStarted()
    {
        // dim the menu button
        this.dashboard.descendantsByName.MenuButton.buttonActive = false;
        this.dashboard.descendantsByName.MenuButton.brightnessContrast.brightness = -.5;

        // dim the autoplay button
        if(this.autoplaySpinsRemaining===0)
        {
            this.autoplayButton.buttonActive = false;
            this.autoplayButton.brightnessContrast.brightness = -.5;
        }
    }


    processGameEnded()
    {
        // undim the menu button
        this.dashboard.descendantsByName.MenuButton.buttonActive = true;
        this.dashboard.descendantsByName.MenuButton.brightnessContrast.brightness = 0;

        // undim the autoplay button
        this.autoplayButton.buttonActive = true;
        this.autoplayButton.brightnessContrast.brightness = 0;
    }


    autoplayButtonReleaseCallback()
    {
        if(this.autoplaySpinsRemaining===0)
        {
            if(!this.autoplayMenu.enabled){this.showAutoplayMenu();}
            else{this.hideAutoplayMenu();}
        }
        else
        {
            this.stopAutoplay();
        }
    }


    showAutoplayMenu()
    {
        this.menuBackgroundDimmer.enabled = true;
        this.autoplayMenu.enabled = true;
        this.autoplayButton.layer = nc.layers.GameMenus;
        this.autoplayMenu.scale.swoop.y(0,0);
        this.autoplayMenu.scale.swoop.y(1,.07,nc.tweenTypes.ExtremeEaseIn);
        this.menuBackgroundDimmer.addReleaseCallback(this,"hideAutoplayMenu");
    }


    hideAutoplayMenu()
    {
        this.menuBackgroundDimmer.enabled = false;
        this.autoplayMenu.enabled = false;
        this.autoplayButton.layer = nc.layers.Dashboard;
        this.menuBackgroundDimmer.removeReleaseCallback(this,"hideAutoplayMenu");
    }


    autoplayOptionButtonCallback(event:object,camera:Camera,button:Button)
    {
        this.startAutoplay(button["numSpins"])
        this.hideAutoplayMenu();
    }


    startAutoplay(numSpins:number)
    {
        this.autoplaySpinsRemaining = numSpins;
        this.autoplayRotationMotion.influence = 1;
        this.dashboard.descendantsByName.AutoplayCountdownBackground.enabled = true;
        this.dashboard.descendantsByName.AutoplayCountdown.string = this.autoplaySpinsRemaining.toString();
        this.autoplayIfApplicable();
    }


    stopAutoplay()
    {
        this.autoplayStartDelay.stop(false);
        this.autoplaySpinsRemaining = 0;
        this.autoplayRotationMotion.influence = 0;
        this.autoplayButton.rotation.z=0;
        this.dashboard.descendantsByName.AutoplayCountdownBackground.enabled = false;
        if(gameSystemManager.gameInProgress===true)
        {
            this.autoplayButton.buttonActive = false;
            this.autoplayButton.brightnessContrast.brightness = -.5;
        }
    }


    autoplayIfApplicable()
    {
        if(this.autoplaySpinsRemaining>0)
        {
            this.autoplayStartDelay.activate(.5,pr,"mainPlayerInput");
        }
    }


    decrementAutoplay()
    {
        this.autoplayStartDelay.stop(false);
        if(this.autoplaySpinsRemaining>0)
        {
            if(this.autoplaySpinsRemaining===1)
            {
                pr.dashboardManager.stopAutoplay();
            }
            else
            {
                // decrement the autoplay spins and update the autoplay countdown
                this.autoplaySpinsRemaining--;
                pr.dashboard.descendantsByName.AutoplayCountdown.string = this.autoplaySpinsRemaining.toString();
            }
        }
    }


    soundButtonReleaseCallback()
    {
        if(pr.dashboard.descendantsByName.SoundButton.graphicAsset === nc.graphicAssets.SoundButton)
        {
            // toggle to muted  
            pr.dashboard.descendantsByName.SoundButton.graphicAsset = nc.graphicAssets.SoundMute;
            nc.volumeControls.MainVolumeControl.volume = 0;
        }
        else
        {
            // toggle to sound on  
            pr.dashboard.descendantsByName.SoundButton.graphicAsset = nc.graphicAssets.SoundButton;
            nc.volumeControls.MainVolumeControl.volume = 1;
        }
    }
}

TypescriptProjectCode/GameSystemManager.ts
------------------------------------------------------------
class GameSystemManager
{
    unitBet:number;
    currentBet:number;
    availableBets:number[];
    currentBalance:number;   
    autoplayOptions:number[];
    initialGameLogicData:InitialGameLogicData;
    currentGameOutcome:GameOutcome;
    gameSystemReplica:GameSystemReplica;
    grpcConnection:GrpcConnection
    gameInProgress:boolean;


    async init()
    {
        // initial values
        this.gameInProgress = false;

        // if in LocalDev...
        CODE.includeIf___LocalDev;
            this.gameSystemReplica = new GameSystemReplica();
        CODE.includeEnd___LocalDev;
        
        // if in EgmPublish...
        CODE.includeIf___EgmPublish;
            this.grpcConnection = new GrpcConnection();
            await this.grpcConnection.init();
        CODE.includeEnd___EgmPublish;
    }
    

    async fetchGameSystemInfo(processPreloadGameSystemInfoCallbackOwner?:object,processPreloadGameSystemInfoCallbackName?:string)
    {
        let gameSystemInfoFromExternalSource;
        let initialGameLogicDataFromExternalSource;


        // if in LocalDev...
        CODE.includeIf___LocalDev;
            // fetch game system info from 'external' source...
            gameSystemInfoFromExternalSource = await this.gameSystemReplica.getPostloadInfo()
            // populate local properties from fetched data
            this.unitBet = gameSystemInfoFromExternalSource["unitBet"];
            this.currentBet = gameSystemInfoFromExternalSource["currentBet"];
            this.currentBalance = gameSystemInfoFromExternalSource["currentBalance"];
            this.availableBets = gameSystemInfoFromExternalSource["availableBets"];
            this.autoplayOptions = gameSystemInfoFromExternalSource["autoplayOptions"];

            // fetch inital game logic data from 'external' source...
            initialGameLogicDataFromExternalSource = await this.gameSystemReplica.getInitialLogicData()
            // populate local properties from fetched data
            this.initialGameLogicData = new InitialGameLogicData();
            this.initialGameLogicData.initialSymbolWindow = initialGameLogicDataFromExternalSource["initialSymbolWindow"];
            this.initialGameLogicData.reelData = initialGameLogicDataFromExternalSource["reelData"];
            this.initialGameLogicData.paylines = initialGameLogicDataFromExternalSource["paylines"];
        CODE.includeEnd___LocalDev;

        // if in WebPublish
        CODE.includeIf___WebPublish;

        CODE.includeEnd___WebPublish;

        // if in EgmPublish
        CODE.includeIf___EgmPublish;
            gameSystemInfoFromExternalSource = await this.grpcConnection.makeRequestToRemoteProcess({type:"getPostLoadInfo"});
            if (gameSystemInfoFromExternalSource !== undefined)
            {
                // populate local properties from fetched data
                this.unitBet = gameSystemInfoFromExternalSource["unitBet"];
                this.currentBet = gameSystemInfoFromExternalSource["currentBet"];
                this.currentBalance = gameSystemInfoFromExternalSource["currentBalance"];
                this.availableBets = gameSystemInfoFromExternalSource["availableBets"];
                this.autoplayOptions = gameSystemInfoFromExternalSource["autoplayOptions"];
            }
            // fetch inital game logic data from 'external' source...
            initialGameLogicDataFromExternalSource = await this.grpcConnection.makeRequestToRemoteProcess({type:"getInitialLogicData"});
            if (gameSystemInfoFromExternalSource !== undefined)
            {
                // populate local properties from fetched data
                this.initialGameLogicData = new InitialGameLogicData();
                this.initialGameLogicData.initialSymbolWindow = initialGameLogicDataFromExternalSource["initialSymbolWindow"];
                this.initialGameLogicData.reelData = initialGameLogicDataFromExternalSource["reelData"];
                this.initialGameLogicData.paylines = initialGameLogicDataFromExternalSource["paylines"];
            }
        CODE.includeEnd___EgmPublish;

        // perform 'processPreloadGameSystemInfo' callback
        if(processPreloadGameSystemInfoCallbackOwner!==undefined && processPreloadGameSystemInfoCallbackName!==undefined)
        {
            processPreloadGameSystemInfoCallbackOwner[processPreloadGameSystemInfoCallbackName]();
        }
    }


    attemptBet(processNewGameOutcomeCallbackOwner?:object, processNewGameOutcomeCallbackName?:string)
    {   
        if(this.currentBalance>=this.currentBet)
        {
            // clear the current game outcome
            this.currentGameOutcome = undefined;

            // first, update the balance based on what we think we know locally
            this.currentBalance-=this.currentBet;

            // informing the external system of an attempted bet - this is intentially not awaited so that this function can immediately return "true", which allows the reels to begin spinning.
            this.requestBetFromExternalSystem(processNewGameOutcomeCallbackOwner, processNewGameOutcomeCallbackName);
          
            return(true);
        }
        else
        {
            return(false);
        }
    }


    private async requestBetFromExternalSystem(processNewGameOutcomeCallbackOwner?:object, processNewGameOutcomeCallbackName?:string)
    {
        let gameOutcomeFromExternalSource;

        // assemble bet request
        let betRequest = new BetRequest();
        betRequest.betAmount = this.currentBet;

        // if in LocalDev...
        CODE.includeIf___LocalDev;
            // get game outcome from 'external' source...
            gameOutcomeFromExternalSource = await this.gameSystemReplica.getGameOutcome(betRequest);
            
            // map external gameOutcome properties to the gameOutcome object
            this.currentGameOutcome = new GameOutcome();
            this.currentGameOutcome.bet = gameOutcomeFromExternalSource.bet;
            this.currentGameOutcome.reelStops = gameOutcomeFromExternalSource.reelStops;
            this.currentGameOutcome.wins = gameOutcomeFromExternalSource.wins;
            this.currentGameOutcome.totalWin = gameOutcomeFromExternalSource.totalWin;
            this.currentGameOutcome.balanceBefore = gameOutcomeFromExternalSource.balanceBefore;
            this.currentGameOutcome.balanceAfter = gameOutcomeFromExternalSource.balanceAfter;

            // update current balance
            this.currentBalance = this.currentGameOutcome.balanceAfter;
        CODE.includeEnd___LocalDev;


        // if in WebPublish
        CODE.includeIf___WebPublish;
            // contact webAPI for gameOutcome...
        CODE.includeEnd___WebPublish;


        // if in EgmPublish
        CODE.includeIf___EgmPublish;
        // get game outcome from source...
            gameOutcomeFromExternalSource = await this.grpcConnection.makeRequestToRemoteProcess({type:"getGameOutcome",payload:betRequest});
        // map external gameOutcome properties to the gameOutcome object
            this.currentGameOutcome = new GameOutcome();
            this.currentGameOutcome.bet = gameOutcomeFromExternalSource.bet;
            this.currentGameOutcome.reelStops = gameOutcomeFromExternalSource.reelStops;
            this.currentGameOutcome.wins = gameOutcomeFromExternalSource.wins;
            this.currentGameOutcome.totalWin = gameOutcomeFromExternalSource.totalWin;
            this.currentGameOutcome.balanceBefore = gameOutcomeFromExternalSource.balanceBefore;
            this.currentGameOutcome.balanceAfter = gameOutcomeFromExternalSource.balanceAfter;
        // update current balance
            this.currentBalance = this.currentGameOutcome.balanceAfter;
        CODE.includeEnd___EgmPublish;


        // perform 'processNewGameOutcome' callback
        if(processNewGameOutcomeCallbackOwner!==undefined && processNewGameOutcomeCallbackName!==undefined)
        {
            processNewGameOutcomeCallbackOwner[processNewGameOutcomeCallbackName]();
        }
    }


    gameStarted()
    {
        this.gameInProgress = true;
        pr.dashboardManager.processGameStarted();
        pr.dashboardManager.decrementAutoplay();
    }
    

    gameEnded()
    {
        this.gameInProgress = false;
        pr.dashboardManager.processGameEnded();
        pr.dashboardManager.autoplayIfApplicable();
    }


    formatCurrency(val:number):string
    {
        const formattedValue = new Intl.NumberFormat('en-US', {style: 'currency',currency: 'USD'}).format(val);
        return(formattedValue);
    }
}


class InitialGameLogicData
{
    initialSymbolWindow:string[][];
    reelData:string[][];
    paylines:number[][];
}


class GameOutcome
{
    bet:number;
    reelStops:number[];
    wins:WinDescription[];
    totalWin:number;
    balanceBefore:number;
    balanceAfter:number;

    constructor()
    {
        this.bet=null;
        this.reelStops=null;
        this.wins=null;
        this.totalWin=null;
        this.balanceBefore=null;
        this.balanceAfter=null;
    }
}


class BetRequest
{
    betAmount:number;

    constructor()
    {
        this.betAmount=null;
    }
}
  

class WinDescription
{
    winType:string;
    line:number;
    winAmount:number;
    winningSymbols:number[][];
    featureFlags:string[];

    constructor()
    {
        this.winType=null;
        this.line=null;
        this.winAmount=null;
        this.winningSymbols=null;
        this.featureFlags=null;
    }
}



TypescriptProjectCode/GameSystemReplica.ts
------------------------------------------------------------
class GameSystemReplica
{
    unitBet:number
    currentBet:number
    availableBets:number[]
    currentBalance:number
    autoplayOptions:number[]

    initialSymbolWindow:string[][];
    reelData:string[][]
    paylines:number[][];
    outcomes:any
    

    constructor()
    {
        this.unitBet = 0.25;
        this.currentBet = 1.5;
        this.availableBets = [0.25,0.50,0.75,1.00,1.50,2.50,3.00,5.00,7.50,10.00,15.00,20.00,25.00,50.00,75.00,100.00];
        this.currentBalance = 1000.0;
        this.autoplayOptions = [25,50,100,500];
        this.populateBulkData();
    }


    async simulateServerResponseTime(base:number,variation:number)
    {
        let simulatedServerResponseTime = base+Math.floor(variation*Math.random());
        await new Promise(resolve => setTimeout(resolve,simulatedServerResponseTime));
    }


    async getPostloadInfo()
    {
        await this.simulateServerResponseTime(25,50);
        let info = {};
        info["unitBet"] = this.unitBet;
        info["currentBet"] = this.currentBet;
        info["currentBalance"] = this.currentBalance;
        info["availableBets"] = this.availableBets;
        info["autoplayOptions"] = this.autoplayOptions;
        return(info);
    }


    async getInitialLogicData()
    {
        // simulate server response time...
        await this.simulateServerResponseTime(50,150);

        //create initial gameData
        let initialGameData = {};
        initialGameData["reelData"] = this.reelData;
        initialGameData["availableBets"] = this.availableBets;
        initialGameData["initialSymbolWindow"] = this.initialSymbolWindow;
        initialGameData["currentBet"] = this.currentBet;
        initialGameData["unitBet"] = this.unitBet;
        initialGameData["currentBalance"] = this.currentBalance;
        initialGameData["paylines"] = this.paylines;
        return(initialGameData);
    }


    async getGameOutcome(betRequest)
    {
        // simulate server response time...
        await this.simulateServerResponseTime(100,300);

        // create new gameOutcome
        let gameOutcome = this.outcomes[Math.floor ((this.outcomes.length) * Math.random())];
        gameOutcome["bet"] = betRequest.betAmount;
        gameOutcome["balanceBefore"] = this.currentBalance;
        this.currentBalance-=betRequest.betAmount;        
        this.currentBalance+=gameOutcome["totalWin"];
        gameOutcome["balanceAfter"] = this.currentBalance;
        return(gameOutcome);
    }


    populateBulkData()
    {
        this.initialSymbolWindow = [
            ["Major1","Minor1","Wild","Minor2","Major2","Major2"],
            ["Major2","Minor3","Bonus","Minor1","Major3","Major3"],
            ["Minor1","Major3","Major3","Minor2","Major1","Major1"],
            ["Major2","Major2","Minor3","Bonus","Minor1","Major3"],
            ["Major1","Major1","Minor1","Wild","Minor2","Major2"]
        ];
        this.reelData = [
            ["Major1","Major1","Major1","Minor1","Minor1","Major2","Major2","Major2","Minor3","Minor3","Bonus","Minor1","Minor1","Wild","Minor3","Minor3","Major3","Major3","Major3","Minor2","Minor2","Minor1","Minor1","Major1","Major1","Major1","Minor3","Minor3","Major2","Major2","Major2","Minor1","Minor1","Major1","Major1","Major1","Minor3","Minor3","Major3","Major3","Major3","Minor1","Minor1","Wild","Minor3","Minor3","Major2","Major2","Major2","Minor2","Minor2","Minor1","Minor1","Minor3","Minor3","Wild","Minor2","Minor2","Bonus","Minor1","Minor1","Major1","Major1","Major1","Minor3","Minor3","Wild","Minor2","Minor2","Bonus","Minor1","Minor1","Major2","Major2","Major2","Minor2","Minor2","Minor3","Minor3","Wild","Minor1","Minor1","Major3","Major3","Major3","Minor3","Minor3","Wild","Minor2","Minor2","Minor1","Minor1","Major2","Major2","Major2","Minor3","Minor3","Major1","Major1","Major1","Minor1","Minor1","Major3","Major3","Major3","Minor3","Minor3","Wild","Minor2","Minor2","Minor1","Minor1","Major2","Major2","Major2","Minor3","Minor3","Wild","Minor1","Minor1","Major3","Major3","Major3","Minor2","Minor2","Major2","Major2","Major2","Minor3","Minor3"],["Minor2","Wild","Minor3","Minor3","Major2","Major2","Major2","Minor1","Minor1","Wild","Minor2","Minor2","Major2","Major2","Major2","Minor3","Minor3","Major1","Major1","Major1","Minor2","Minor2","Wild","Minor3","Minor3","Major3","Major3","Major3","Minor2","Minor2","Wild","Minor1","Minor1","Major3","Major3","Major3","Minor2","Minor2","Major1","Major1","Major1","Minor1","Minor1","Bonus","Minor2","Minor2","Major2","Major2","Major2","Minor3","Minor3","Major1","Major1","Major1","Minor2","Minor2","Wild","Minor3","Minor3","Major1","Major1","Major1","Minor2","Minor2","Bonus","Minor1","Minor1","Major2","Major2","Major2","Minor2","Minor2","Major3","Major3","Major3","Major1","Major1","Major1","Minor1","Minor1","Wild","Minor2","Minor2","Minor3","Minor3","Major3","Major3","Major3","Minor1","Minor1","Bonus","Minor2","Minor2","Wild","Minor1","Minor1","Major2","Major2","Major2","Minor2","Minor2","Major1","Major1","Major1","Minor1","Minor1","Major3","Major3","Major3","Minor2","Minor2","Wild","Minor3","Minor3","Major3","Major3","Major3","Minor2","Minor2","Major1","Major1","Major1","Minor3","Minor3","Major3","Major3","Major3"],["Wild","Minor1","Minor1","Major3","Major3","Major3","Minor3","Minor3","Major2","Major2","Major2","Minor1","Minor1","Wild","Minor2","Minor2","Minor3","Minor3","Bonus","Minor1","Minor1","Major1","Major1","Major1","Minor3","Minor3","Major2","Major2","Major2","Minor2","Minor2","Major1","Major1","Major1","Minor1","Minor1","Major2","Major2","Major2","Minor3","Minor3","Wild","Minor1","Minor1","Major1","Major1","Major1","Minor3","Minor3","Bonus","Minor1","Minor1","Minor2","Minor2","Wild","Minor3","Minor3","Major2","Major2","Major2","Minor1","Minor1","Wild","Minor3","Minor3","Major2","Major2","Major2","Minor2","Minor2","Minor1","Minor1","Major1","Major1","Major1","Minor3","Minor3","Major2","Major2","Major2","Minor2","Minor2","Minor1","Minor1","Minor3","Minor3","Wild","Minor2","Minor2","Major3","Major3","Major3","Minor1","Minor1","Major1","Major1","Major1","Minor3","Minor3","Wild","Minor2","Minor2","Minor1","Minor1","Major3","Major3","Major3","Minor3","Minor3","Major2","Major2","Major2","Minor1","Minor1","Major3","Major3","Major3","Minor2","Minor2","Bonus","Minor3","Minor3","Wild","Minor1","Minor1","Major3","Major3","Major3","Minor3","Minor3"],["Minor2","Major3","Major3","Major3","Minor3","Minor3","Major1","Major1","Major1","Minor2","Minor2","Wild","Minor3","Minor3","Major3","Major3","Major3","Minor2","Minor2","Wild","Minor3","Minor3","Major2","Major2","Major2","Minor2","Minor2","Major3","Major3","Major3","Minor1","Minor1","Wild","Minor2","Minor2","Major1","Major1","Major1","Minor3","Minor3","Major3","Major3","Major3","Minor2","Minor2","Major1","Major1","Major1","Minor1","Minor1","Major3","Major3","Major3","Minor2","Minor2","Major1","Major1","Major1","Wild","Minor1","Minor1","Major3","Major3","Major3","Minor2","Minor2","Bonus","Minor3","Minor3","Major1","Major1","Major1","Minor1","Minor1","Wild","Minor2","Minor2","Major2","Major2","Major2","Minor1","Minor1","Bonus","Minor2","Minor2","Major3","Major3","Major3","Minor3","Minor3","Major2","Major2","Major2","Minor2","Minor2","Minor1","Minor1","Wild","Minor3","Minor3","Major2","Major2","Major2","Minor2","Minor2","Bonus","Minor3","Minor3","Wild","Minor2","Minor2","Major1","Major1","Major1","Minor1","Minor1","Wild","Minor2","Minor2","Major1","Major1","Major1","Minor1","Minor1","Major2","Major2","Major2"],["Major2","Major2","Major2","Minor3","Minor3","Bonus","Minor1","Minor1","Major3","Major3","Major3","Minor2","Minor2","Wild","Minor3","Minor3","Major3","Major3","Major3","Minor1","Minor1","Minor2","Minor2","Bonus","Minor3","Minor3","Major2","Major2","Major2","Minor1","Minor1","Major1","Major1","Major1","Minor3","Minor3","Major3","Major3","Major3","Minor1","Minor1","Wild","Minor3","Minor3","Major3","Major3","Major3","Minor1","Minor1","Wild","Minor2","Minor2","Major1","Major1","Major1","Minor3","Minor3","Minor1","Minor1","Major2","Major2","Major2","Minor2","Minor2","Minor3","Minor3","Major3","Major3","Major3","Minor1","Minor1","Minor2","Minor2","Major2","Major2","Major2","Minor3","Minor3","Major1","Major1","Major1","Minor1","Minor1","Minor2","Minor2","Major2","Major2","Major2","Minor3","Minor3","Minor1","Minor1","Wild","Minor2","Minor2","Major2","Major2","Major2","Minor3","Minor3","Wild","Minor1","Minor1","Major2","Major2","Major2","Minor3","Minor3","Major1","Major1","Major1","Minor2","Minor2","Wild","Minor1","Minor1","Bonus","Minor3","Minor3","Wild","Minor1","Minor1","Major1","Major1","Major1","Minor3","Minor3","Wild","Minor1","Minor1"]
        ];
        this.paylines = [
            [0, 0, 0, 0, 0],
            [1, 1, 1, 1, 1],
            [2, 2, 2, 2, 2],
            [3, 3, 3, 3, 3],
            [0, 1, 1, 1, 0],
            [1, 2, 2, 2, 1],
            [2, 3, 3, 3, 2],
            [1, 0, 0, 0, 1],
            [2, 1, 1, 1, 2],
            [3, 2, 2, 2, 3],
            [0, 1, 0, 1, 0],
            [1, 2, 1, 2, 1],
            [2, 3, 2, 3, 2],
            [1, 0, 1, 0, 1],
            [2, 1, 2, 1, 2],
            [3, 2, 3, 2, 3],
            [0, 0, 1, 0, 0],
            [1, 1, 2, 1, 1],
            [2, 2, 3, 2, 2],
            [1, 1, 0, 1, 1],
            [2, 2, 1, 2, 2],
            [3, 3, 2, 3, 3]
        ]
        this.outcomes = [
            {"reelStops":[98,53,101,61,98],"totalWin":0.96,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[35,12,25,44,115],"totalWin":0,"wins":[]},
            {"reelStops":[23,53,103,26,18],"totalWin":0,"wins":[]},
            {"reelStops":[64,40,55,83,29],"totalWin":0,"wins":[]},
            {"reelStops":[43,22,72,65,123],"totalWin":3,"wins":[{"winningSymbols":[[0,2],[1,2],[2,3],[3,2],[4,2]],"line":18,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[55,99,95,61,115],"totalWin":0,"wins":[]},
            {"reelStops":[55,39,23,17,78],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[41,27,102,1,76],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[90,46,7,116,48],"totalWin":4.2,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[54,0,58,22,80],"totalWin":2.88,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1],[3,1]],"line":1,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[112,19,66,46,39],"totalWin":0,"wins":[]},
            {"reelStops":[52,49,113,79,92],"totalWin":0,"wins":[]},
            {"reelStops":[128,28,17,111,109],"totalWin":0,"wins":[]},
            {"reelStops":[113,109,37,61,29],"totalWin":4.44,"wins":[{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[128,66,116,21,48],"totalWin":0,"wins":[]},
            {"reelStops":[11,120,47,119,67],"totalWin":0.48,"wins":[{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[84,85,127,81,65],"totalWin":2.28,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[5,80,53,47,48],"totalWin":2.16,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[49,29,35,30,89],"totalWin":0,"wins":[]},
            {"reelStops":[72,107,69,45,67],"totalWin":0,"wins":[]},
            {"reelStops":[61,21,82,119,85],"totalWin":1.92,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[43,43,65,40,58],"totalWin":0.6,"wins":[{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[98,28,72,106,64],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[72,125,104,77,74],"totalWin":0,"wins":[]},
            {"reelStops":[25,66,75,16,51],"totalWin":3.6,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[97,66,42,4,91],"totalWin":0,"wins":[]},
            {"reelStops":[25,46,31,32,92],"totalWin":0,"wins":[]},
            {"reelStops":[107,122,19,2,49],"totalWin":0,"wins":[]},
            {"reelStops":[77,125,129,113,72],"totalWin":4.68,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[103,111,112,110,31],"totalWin":0,"wins":[]},
            {"reelStops":[74,65,6,82,108],"totalWin":0,"wins":[]},
            {"reelStops":[24,24,77,91,118],"totalWin":0,"wins":[]},
            {"reelStops":[15,81,22,100,83],"totalWin":0,"wins":[]},
            {"reelStops":[67,110,37,37,49],"totalWin":0,"wins":[]},
            {"reelStops":[34,66,114,8,19],"totalWin":0,"wins":[]},
            {"reelStops":[70,43,2,87,70],"totalWin":0,"wins":[]},
            {"reelStops":[44,90,128,7,30],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[116,24,22,3,109],"totalWin":0,"wins":[]},
            {"reelStops":[53,109,47,9,56],"totalWin":3.6,"wins":[{"winningSymbols":[[0,2],[1,2],[2,3],[3,2],[4,2]],"line":18,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[2,126,41,67,32],"totalWin":1.92,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[66,64,47,76,118],"totalWin":24,"wins":[{"winningSymbols":[[0,3],[1,0],[2,2]],"winType":"scatter","winAmount":24,"featureFlags":["bonus"]}],"bonusWin":24},
            {"reelStops":[23,38,69,74,10],"totalWin":0.6,"wins":[{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[1,53,53,97,113],"totalWin":4.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,1],[3,0],[4,0]],"line":16,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1],[3,0]],"line":13,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[122,46,35,46,41],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[53,109,30,91,62],"totalWin":1.8,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[91,74,20,95,127],"totalWin":0,"wins":[]},
            {"reelStops":[11,57,8,107,59],"totalWin":0,"wins":[]},
            {"reelStops":[44,13,121,87,115],"totalWin":1.5,"wins":[{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[62,67,82,13,90],"totalWin":0,"wins":[]},
            {"reelStops":[126,5,92,18,21],"totalWin":0,"wins":[]},
            {"reelStops":[84,70,36,42,3],"totalWin":0,"wins":[]},
            {"reelStops":[58,115,72,31,5],"totalWin":0,"wins":[]},
            {"reelStops":[128,30,76,52,103],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[29,82,65,56,80],"totalWin":0,"wins":[]},
            {"reelStops":[83,5,58,0,93],"totalWin":0,"wins":[]},
            {"reelStops":[10,3,65,103,74],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[23,71,4,13,62],"totalWin":0,"wins":[]},
            {"reelStops":[60,5,19,96,63],"totalWin":0,"wins":[]},
            {"reelStops":[31,1,110,87,106],"totalWin":0,"wins":[]},
            {"reelStops":[124,4,59,72,9],"totalWin":3.6,"wins":[{"winningSymbols":[[0,3],[1,2],[2,3],[3,2]],"line":15,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3],[3,2]],"line":18,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[128,62,72,11,62],"totalWin":0,"wins":[]},
            {"reelStops":[51,119,99,66,22],"totalWin":0,"wins":[]},
            {"reelStops":[80,61,29,118,10],"totalWin":0,"wins":[]},
            {"reelStops":[23,79,25,89,94],"totalWin":0,"wins":[]},
            {"reelStops":[113,63,101,62,60],"totalWin":0,"wins":[]},
            {"reelStops":[2,87,107,59,48],"totalWin":0,"wins":[]},
            {"reelStops":[50,46,71,81,41],"totalWin":0,"wins":[]},
            {"reelStops":[4,15,105,79,50],"totalWin":0,"wins":[]},
            {"reelStops":[19,64,30,4,12],"totalWin":0,"wins":[]},
            {"reelStops":[92,95,75,114,105],"totalWin":6,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2],[3,2]],"line":2,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3],[3,2]],"line":18,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[76,88,83,76,55],"totalWin":0.48,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[111,91,55,61,114],"totalWin":3,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[10,9,85,7,18],"totalWin":4.08,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2],[3,2],[4,3]],"line":9,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3],[3,2],[4,3]],"line":15,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[76,82,129,95,59],"totalWin":3.72,"wins":[{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[43,86,125,116,37],"totalWin":7.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0],[3,0],[4,0]],"line":0,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0],[4,0]],"line":16,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[90,3,17,90,3],"totalWin":0,"wins":[]},
            {"reelStops":[58,0,28,84,25],"totalWin":0,"wins":[]},
            {"reelStops":[80,74,15,121,30],"totalWin":0,"wins":[]},
            {"reelStops":[7,3,42,15,13],"totalWin":0,"wins":[]},
            {"reelStops":[34,122,30,107,117],"totalWin":0,"wins":[]},
            {"reelStops":[2,92,63,17,70],"totalWin":0,"wins":[]},
            {"reelStops":[97,59,68,15,113],"totalWin":0,"wins":[]},
            {"reelStops":[71,82,122,47,28],"totalWin":0,"wins":[]},
            {"reelStops":[55,7,92,111,31],"totalWin":1.92,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[33,126,61,80,88],"totalWin":3.12,"wins":[{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[50,109,105,94,37],"totalWin":2.76,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[62,70,91,1,78],"totalWin":0,"wins":[]},
            {"reelStops":[61,54,53,55,31],"totalWin":10.56,"wins":[{"winningSymbols":[[0,1],[1,2],[2,1],[3,2],[4,1]],"line":11,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2],[4,2]],"line":20,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3],[3,3],[4,3]],"line":3,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3],[4,3]],"line":21,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[93,126,2,53,22],"totalWin":0,"wins":[]},
            {"reelStops":[13,29,106,83,14],"totalWin":3,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[64,106,29,91,33],"totalWin":0,"wins":[]},
            {"reelStops":[23,94,90,110,28],"totalWin":0,"wins":[]},
            {"reelStops":[44,49,20,23,63],"totalWin":0,"wins":[]},
            {"reelStops":[40,109,13,72,82],"totalWin":2.28,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2],[3,2]],"line":9,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3],[3,2]],"line":15,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[99,102,36,28,40],"totalWin":0,"wins":[]},
            {"reelStops":[65,37,59,101,84],"totalWin":0,"wins":[]},
            {"reelStops":[108,2,54,44,41],"totalWin":0,"wins":[]},
            {"reelStops":[129,116,63,43,34],"totalWin":0,"wins":[]},
            {"reelStops":[119,81,67,97,96],"totalWin":0,"wins":[]},
            {"reelStops":[1,23,35,40,19],"totalWin":0,"wins":[]},
            {"reelStops":[57,82,94,124,34],"totalWin":0,"wins":[]},
            {"reelStops":[89,74,57,88,63],"totalWin":0,"wins":[]},
            {"reelStops":[34,29,54,118,36],"totalWin":3.36,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[92,1,22,39,60],"totalWin":0.96,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[98,91,84,59,44],"totalWin":2.52,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[120,125,75,96,43],"totalWin":0,"wins":[]},
            {"reelStops":[57,73,96,63,107],"totalWin":0,"wins":[]},
            {"reelStops":[10,105,71,4,28],"totalWin":0.48,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[91,19,39,7,95],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[45,123,72,88,28],"totalWin":0,"wins":[]},
            {"reelStops":[29,36,117,101,100],"totalWin":0,"wins":[]},
            {"reelStops":[50,27,66,16,28],"totalWin":0,"wins":[]},
            {"reelStops":[21,28,100,24,81],"totalWin":0.48,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[31,92,3,28,31],"totalWin":0,"wins":[]},
            {"reelStops":[111,99,32,68,33],"totalWin":0,"wins":[]},
            {"reelStops":[125,33,62,63,18],"totalWin":0,"wins":[]},
            {"reelStops":[58,3,129,51,23],"totalWin":0,"wins":[]},
            {"reelStops":[114,84,85,9,73],"totalWin":0.96,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[129,62,28,43,60],"totalWin":0,"wins":[]},
            {"reelStops":[57,92,77,104,26],"totalWin":0,"wins":[]},
            {"reelStops":[22,102,2,68,36],"totalWin":0,"wins":[]},
            {"reelStops":[14,25,33,54,72],"totalWin":0,"wins":[]},
            {"reelStops":[67,12,40,4,107],"totalWin":0,"wins":[]},
            {"reelStops":[47,13,4,55,19],"totalWin":0,"wins":[]},
            {"reelStops":[77,17,86,7,26],"totalWin":0.9,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[114,102,106,79,96],"totalWin":0,"wins":[]},
            {"reelStops":[83,119,116,81,75],"totalWin":0,"wins":[]},
            {"reelStops":[100,27,42,79,46],"totalWin":0,"wins":[]},
            {"reelStops":[116,65,77,92,79],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[56,26,2,118,11],"totalWin":0,"wins":[]},
            {"reelStops":[30,119,52,116,108],"totalWin":0.6,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[62,123,120,83,69],"totalWin":0,"wins":[]},
            {"reelStops":[122,121,8,7,15],"totalWin":0,"wins":[]},
            {"reelStops":[110,86,59,90,13],"totalWin":0.96,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[8,80,129,78,15],"totalWin":1.92,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[110,100,110,32,10],"totalWin":0,"wins":[]},
            {"reelStops":[31,52,29,25,75],"totalWin":0.6,"wins":[{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[44,124,71,14,23],"totalWin":0,"wins":[]},
            {"reelStops":[126,107,40,36,17],"totalWin":0,"wins":[]},
            {"reelStops":[116,42,17,44,15],"totalWin":0,"wins":[]},
            {"reelStops":[70,123,79,45,57],"totalWin":0,"wins":[]},
            {"reelStops":[69,75,63,124,64],"totalWin":0,"wins":[]},
            {"reelStops":[77,17,80,80,71],"totalWin":0,"wins":[]},
            {"reelStops":[46,114,90,1,118],"totalWin":0,"wins":[]},
            {"reelStops":[31,103,27,29,47],"totalWin":0,"wins":[]},
            {"reelStops":[2,63,97,87,48],"totalWin":1.44,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[61,51,74,79,51],"totalWin":2.4,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[4,28,82,78,30],"totalWin":0,"wins":[]},
            {"reelStops":[98,33,16,105,30],"totalWin":0,"wins":[]},
            {"reelStops":[16,90,124,60,32],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[73,6,33,103,105],"totalWin":0,"wins":[]},
            {"reelStops":[28,24,14,49,116],"totalWin":0,"wins":[]},
            {"reelStops":[129,65,121,95,73],"totalWin":0,"wins":[]},
            {"reelStops":[105,24,40,50,58],"totalWin":4.32,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[48,85,42,108,8],"totalWin":0,"wins":[]},
            {"reelStops":[122,75,90,89,71],"totalWin":0,"wins":[]},
            {"reelStops":[56,23,105,85,37],"totalWin":0,"wins":[]},
            {"reelStops":[108,108,88,73,67],"totalWin":1.8,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[108,87,40,110,124],"totalWin":3.36,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[105,125,76,76,117],"totalWin":6,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3],[3,3],[4,2]],"line":6,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2],[3,3],[4,2]],"line":12,"winType":"line","winAmount":3,"featureFlags":[]}]},
            {"reelStops":[89,4,102,99,92],"totalWin":0,"wins":[]},
            {"reelStops":[79,21,95,48,41],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[59,79,43,2,66],"totalWin":3.12,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[87,24,89,45,115],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[49,117,51,15,40],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[110,114,3,74,80],"totalWin":0,"wins":[]},
            {"reelStops":[67,8,78,7,24],"totalWin":1.38,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[107,99,103,74,9],"totalWin":0,"wins":[]},
            {"reelStops":[54,12,91,96,55],"totalWin":0,"wins":[]},
            {"reelStops":[116,31,2,115,28],"totalWin":4.8,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0],[3,0],[4,1]],"line":7,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1],[4,1]],"line":19,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[18,112,25,32,124],"totalWin":0,"wins":[]},
            {"reelStops":[51,53,61,124,85],"totalWin":1.92,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[5,45,105,31,5],"totalWin":0,"wins":[]},
            {"reelStops":[15,45,100,92,93],"totalWin":0,"wins":[]},
            {"reelStops":[15,14,97,27,89],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[54,109,44,73,110],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[49,45,45,51,3],"totalWin":0,"wins":[]},
            {"reelStops":[100,84,110,121,69],"totalWin":0,"wins":[]},
            {"reelStops":[40,21,24,48,65],"totalWin":0,"wins":[]},
            {"reelStops":[68,12,44,114,84],"totalWin":0,"wins":[]},
            {"reelStops":[108,56,18,53,103],"totalWin":0,"wins":[]},
            {"reelStops":[24,38,127,58,19],"totalWin":0,"wins":[]},
            {"reelStops":[82,66,110,10,58],"totalWin":0,"wins":[]},
            {"reelStops":[109,48,102,116,63],"totalWin":0,"wins":[]},
            {"reelStops":[118,103,79,10,48],"totalWin":0,"wins":[]},
            {"reelStops":[100,12,1,121,40],"totalWin":0,"wins":[]},
            {"reelStops":[110,61,56,124,21],"totalWin":0,"wins":[]},
            {"reelStops":[36,110,125,106,58],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[7,93,109,53,86],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[33,51,70,102,67],"totalWin":3,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[54,11,109,14,44],"totalWin":3,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[74,1,56,89,125],"totalWin":0.6,"wins":[{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[79,111,121,73,16],"totalWin":4.08,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1],[3,0]],"line":13,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0]],"line":16,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[32,126,19,121,9],"totalWin":3,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[63,92,17,35,41],"totalWin":2.4,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[56,21,69,23,92],"totalWin":1.92,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[37,21,29,89,57],"totalWin":0,"wins":[]},
            {"reelStops":[66,43,125,35,86],"totalWin":0,"wins":[]},
            {"reelStops":[31,21,119,17,71],"totalWin":0,"wins":[]},
            {"reelStops":[94,39,48,53,111],"totalWin":0,"wins":[]},
            {"reelStops":[19,109,49,32,21],"totalWin":1.44,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[107,12,49,125,103],"totalWin":0,"wins":[]},
            {"reelStops":[43,123,84,114,91],"totalWin":1.92,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[63,3,30,106,71],"totalWin":0,"wins":[]},
            {"reelStops":[95,76,7,95,42],"totalWin":0,"wins":[]},
            {"reelStops":[96,66,80,43,11],"totalWin":0,"wins":[]},
            {"reelStops":[86,64,6,71,39],"totalWin":0,"wins":[]},
            {"reelStops":[69,114,41,64,54],"totalWin":0,"wins":[]},
            {"reelStops":[120,101,63,86,48],"totalWin":0,"wins":[]},
            {"reelStops":[57,118,27,43,119],"totalWin":0,"wins":[]},
            {"reelStops":[58,93,74,91,108],"totalWin":0,"wins":[]},
            {"reelStops":[61,41,100,95,84],"totalWin":0,"wins":[]},
            {"reelStops":[129,62,2,123,6],"totalWin":0,"wins":[]},
            {"reelStops":[85,111,109,41,26],"totalWin":0,"wins":[]},
            {"reelStops":[77,73,106,52,96],"totalWin":0,"wins":[]},
            {"reelStops":[60,101,98,82,4],"totalWin":3,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[124,90,54,67,50],"totalWin":1.68,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[55,37,6,50,83],"totalWin":0,"wins":[]},
            {"reelStops":[74,70,106,90,5],"totalWin":0,"wins":[]},
            {"reelStops":[96,32,93,98,120],"totalWin":0,"wins":[]},
            {"reelStops":[43,120,53,61,126],"totalWin":4.56,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[88,95,62,1,50],"totalWin":0,"wins":[]},
            {"reelStops":[72,89,13,104,44],"totalWin":0.96,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[34,67,87,60,27],"totalWin":0,"wins":[]},
            {"reelStops":[41,61,127,78,76],"totalWin":0.48,"wins":[{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[90,16,39,106,38],"totalWin":0,"wins":[]},
            {"reelStops":[34,120,129,97,85],"totalWin":4.5,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1],[3,0]],"line":13,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0]],"line":16,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[74,41,54,104,115],"totalWin":15,"wins":[{"winningSymbols":[[1,2],[3,1],[4,1]],"winType":"scatter","winAmount":15,"featureFlags":["bonus"]}],"bonusWin":15},
            {"reelStops":[127,61,24,63,94],"totalWin":0,"wins":[]},
            {"reelStops":[67,75,88,115,66],"totalWin":0,"wins":[]},
            {"reelStops":[113,40,62,100,70],"totalWin":0,"wins":[]},
            {"reelStops":[36,8,93,36,67],"totalWin":0,"wins":[]},
            {"reelStops":[73,87,72,14,115],"totalWin":0,"wins":[]},
            {"reelStops":[28,21,62,117,59],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[17,123,93,126,13],"totalWin":0,"wins":[]},
            {"reelStops":[20,93,116,59,97],"totalWin":0.48,"wins":[{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[128,121,62,121,10],"totalWin":3.36,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[127,0,18,70,19],"totalWin":0,"wins":[]},
            {"reelStops":[65,14,78,104,127],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[121,69,99,21,66],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[116,31,65,73,124],"totalWin":0,"wins":[]},
            {"reelStops":[51,16,128,115,80],"totalWin":0,"wins":[]},
            {"reelStops":[14,90,102,76,51],"totalWin":2.4,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[29,26,3,21,89],"totalWin":0,"wins":[]},
            {"reelStops":[70,102,112,122,5],"totalWin":0.48,"wins":[{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[6,78,107,66,115],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,2],[2,1],[3,2],[4,2]],"line":20,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[32,42,82,118,52],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[96,70,55,122,104],"totalWin":0,"wins":[]},
            {"reelStops":[30,61,4,100,124],"totalWin":0,"wins":[]},
            {"reelStops":[113,78,64,56,99],"totalWin":6,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2],[3,2],[4,1]],"line":5,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1],[3,2],[4,1]],"line":11,"winType":"line","winAmount":3,"featureFlags":[]}]},
            {"reelStops":[94,14,14,39,20],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[111,95,126,65,39],"totalWin":0,"wins":[]},
            {"reelStops":[44,91,62,20,28],"totalWin":3.36,"wins":[{"winningSymbols":[[0,3],[1,2],[2,3],[3,2]],"line":15,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3],[3,2]],"line":18,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[98,14,61,3,10],"totalWin":0,"wins":[]},
            {"reelStops":[127,90,9,64,104],"totalWin":0,"wins":[]},
            {"reelStops":[61,90,24,42,128],"totalWin":0,"wins":[]},
            {"reelStops":[21,58,90,97,8],"totalWin":0,"wins":[]},
            {"reelStops":[36,116,63,100,74],"totalWin":0,"wins":[]},
            {"reelStops":[10,86,77,60,51],"totalWin":0,"wins":[]},
            {"reelStops":[113,14,59,14,61],"totalWin":2.16,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[57,18,77,43,48],"totalWin":0,"wins":[]},
            {"reelStops":[16,70,23,117,78],"totalWin":0,"wins":[]},
            {"reelStops":[4,67,54,64,113],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[62,96,30,1,117],"totalWin":0,"wins":[]},
            {"reelStops":[44,40,8,11,104],"totalWin":0,"wins":[]},
            {"reelStops":[51,16,22,102,41],"totalWin":0,"wins":[]},
            {"reelStops":[24,25,30,32,79],"totalWin":0,"wins":[]},
            {"reelStops":[12,21,4,109,54],"totalWin":6.48,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[35,73,41,104,91],"totalWin":0,"wins":[]},
            {"reelStops":[108,106,39,3,5],"totalWin":0,"wins":[]},
            {"reelStops":[70,5,33,15,103],"totalWin":0.96,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[51,19,73,119,100],"totalWin":1.92,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[129,80,57,75,20],"totalWin":0,"wins":[]},
            {"reelStops":[93,112,51,32,129],"totalWin":0,"wins":[]},
            {"reelStops":[58,108,98,116,47],"totalWin":0,"wins":[]},
            {"reelStops":[73,10,4,36,34],"totalWin":0,"wins":[]},
            {"reelStops":[75,9,33,53,69],"totalWin":0,"wins":[]},
            {"reelStops":[53,8,129,23,22],"totalWin":4.5,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[28,8,22,4,32],"totalWin":0,"wins":[]},
            {"reelStops":[8,6,26,81,68],"totalWin":0,"wins":[]},
            {"reelStops":[55,88,109,42,26],"totalWin":0,"wins":[]},
            {"reelStops":[7,80,72,59,100],"totalWin":0.48,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[36,54,23,114,31],"totalWin":1.8,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[117,104,11,92,112],"totalWin":6.48,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[113,92,9,88,65],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[7,1,68,58,60],"totalWin":0,"wins":[]},
            {"reelStops":[79,28,116,96,5],"totalWin":1.38,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[9,8,63,56,58],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[35,45,65,123,104],"totalWin":0,"wins":[]},
            {"reelStops":[31,85,124,61,63],"totalWin":0,"wins":[]},
            {"reelStops":[101,4,103,117,52],"totalWin":0,"wins":[]},
            {"reelStops":[81,118,73,18,36],"totalWin":0,"wins":[]},
            {"reelStops":[61,41,0,76,29],"totalWin":0,"wins":[]},
            {"reelStops":[114,54,36,67,68],"totalWin":2.52,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[42,6,111,11,16],"totalWin":3.6,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0],[3,0]],"line":7,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[4,125,83,77,99],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[34,31,52,53,62],"totalWin":0,"wins":[]},
            {"reelStops":[61,36,116,93,87],"totalWin":0,"wins":[]},
            {"reelStops":[42,37,84,105,77],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[21,18,17,12,4],"totalWin":0,"wins":[]},
            {"reelStops":[124,61,19,69,83],"totalWin":0,"wins":[]},
            {"reelStops":[78,51,41,5,71],"totalWin":1.8,"wins":[{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[127,76,53,88,70],"totalWin":0,"wins":[]},
            {"reelStops":[39,99,30,37,47],"totalWin":0,"wins":[]},
            {"reelStops":[107,97,58,59,7],"totalWin":2.4,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[41,59,28,52,115],"totalWin":1.08,"wins":[{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[82,88,20,20,16],"totalWin":0,"wins":[]},
            {"reelStops":[3,40,107,92,50],"totalWin":0,"wins":[]},
            {"reelStops":[19,76,89,93,103],"totalWin":3.6,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3],[3,2]],"line":15,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3],[3,2]],"line":18,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[84,100,34,106,126],"totalWin":0,"wins":[]},
            {"reelStops":[93,63,7,96,79],"totalWin":0,"wins":[]},
            {"reelStops":[113,5,2,81,27],"totalWin":0,"wins":[]},
            {"reelStops":[125,124,85,121,129],"totalWin":0,"wins":[]},
            {"reelStops":[59,23,80,28,55],"totalWin":0,"wins":[]},
            {"reelStops":[56,75,44,113,44],"totalWin":0,"wins":[]},
            {"reelStops":[0,110,106,86,2],"totalWin":0,"wins":[]},
            {"reelStops":[0,31,100,76,109],"totalWin":0,"wins":[]},
            {"reelStops":[88,47,79,61,103],"totalWin":0,"wins":[]},
            {"reelStops":[16,108,52,29,1],"totalWin":2.58,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[74,43,113,123,112],"totalWin":0,"wins":[]},
            {"reelStops":[113,79,6,35,16],"totalWin":1.08,"wins":[{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[105,73,21,51,36],"totalWin":1.8,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[58,48,29,41,12],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[39,26,125,100,55],"totalWin":5.4,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[59,1,38,83,119],"totalWin":0,"wins":[]},
            {"reelStops":[99,43,120,25,15],"totalWin":0,"wins":[]},
            {"reelStops":[118,3,18,48,2],"totalWin":0,"wins":[]},
            {"reelStops":[92,70,95,1,47],"totalWin":0,"wins":[]},
            {"reelStops":[17,32,94,88,27],"totalWin":0,"wins":[]},
            {"reelStops":[83,64,105,108,64],"totalWin":0,"wins":[]},
            {"reelStops":[67,47,100,36,106],"totalWin":0,"wins":[]},
            {"reelStops":[35,84,13,27,108],"totalWin":0.48,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[119,121,35,21,106],"totalWin":0,"wins":[]},
            {"reelStops":[99,91,38,44,52],"totalWin":1.56,"wins":[{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[104,62,27,9,53],"totalWin":0,"wins":[]},
            {"reelStops":[31,18,74,106,24],"totalWin":0,"wins":[]},
            {"reelStops":[44,55,107,0,23],"totalWin":3,"wins":[{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[121,92,91,95,29],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[112,13,63,24,37],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[63,96,30,10,37],"totalWin":0,"wins":[]},
            {"reelStops":[20,29,84,114,99],"totalWin":7.68,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2],[3,2],[4,2]],"line":2,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2],[3,2],[4,1]],"line":5,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2],[3,1],[4,2]],"line":14,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2],[3,1],[4,1]],"line":17,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[51,28,128,13,4],"totalWin":1.92,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[79,61,64,63,7],"totalWin":0,"wins":[]},
            {"reelStops":[120,98,101,71,30],"totalWin":0,"wins":[]},
            {"reelStops":[123,37,50,12,93],"totalWin":0,"wins":[]},
            {"reelStops":[79,75,41,31,69],"totalWin":2.28,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[32,54,71,77,73],"totalWin":4.2,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[110,10,16,118,56],"totalWin":0,"wins":[]},
            {"reelStops":[78,88,114,37,20],"totalWin":0,"wins":[]},
            {"reelStops":[34,27,35,121,50],"totalWin":0,"wins":[]},
            {"reelStops":[42,13,75,86,35],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[92,59,106,106,93],"totalWin":0,"wins":[]},
            {"reelStops":[124,27,103,79,89],"totalWin":0,"wins":[]},
            {"reelStops":[69,24,22,51,113],"totalWin":0,"wins":[]},
            {"reelStops":[21,94,66,34,71],"totalWin":0,"wins":[]},
            {"reelStops":[53,101,28,36,42],"totalWin":0.6,"wins":[{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[19,51,86,105,127],"totalWin":0,"wins":[]},
            {"reelStops":[129,106,58,69,55],"totalWin":0,"wins":[]},
            {"reelStops":[70,70,128,32,54],"totalWin":0,"wins":[]},
            {"reelStops":[87,34,1,3,125],"totalWin":0,"wins":[]},
            {"reelStops":[11,92,49,55,123],"totalWin":5.22,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[9,69,0,114,82],"totalWin":0,"wins":[]},
            {"reelStops":[30,10,27,110,112],"totalWin":0,"wins":[]},
            {"reelStops":[47,96,100,122,24],"totalWin":0,"wins":[]},
            {"reelStops":[85,82,91,59,129],"totalWin":0,"wins":[]},
            {"reelStops":[117,113,60,8,27],"totalWin":1.8,"wins":[{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[9,89,119,79,94],"totalWin":22,"wins":[{"winningSymbols":[[0,1],[1,1],[2,0],[3,3]],"winType":"scatter","winAmount":22,"featureFlags":["bonus"]}],"bonusWin":22},
            {"reelStops":[87,78,109,0,23],"totalWin":0.48,"wins":[{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[34,45,68,102,100],"totalWin":0,"wins":[]},
            {"reelStops":[74,15,128,110,0],"totalWin":0,"wins":[]},
            {"reelStops":[127,87,42,112,114],"totalWin":0,"wins":[]},
            {"reelStops":[10,57,53,65,42],"totalWin":0,"wins":[]},
            {"reelStops":[62,61,80,88,52],"totalWin":0,"wins":[]},
            {"reelStops":[5,122,98,74,92],"totalWin":0,"wins":[]},
            {"reelStops":[62,85,33,105,21],"totalWin":0,"wins":[]},
            {"reelStops":[118,30,115,68,40],"totalWin":0,"wins":[]},
            {"reelStops":[30,125,60,56,59],"totalWin":1.5,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[98,61,58,15,115],"totalWin":0,"wins":[]},
            {"reelStops":[60,111,70,44,40],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[33,60,69,84,42],"totalWin":0,"wins":[]},
            {"reelStops":[118,97,82,59,121],"totalWin":0,"wins":[]},
            {"reelStops":[8,32,20,48,67],"totalWin":0,"wins":[]},
            {"reelStops":[39,75,69,38,129],"totalWin":0.96,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[58,45,39,25,121],"totalWin":0,"wins":[]},
            {"reelStops":[56,117,68,75,111],"totalWin":14.4,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0],[3,0],[4,0]],"line":0,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1],[3,1],[4,1]],"line":1,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1],[3,1],[4,0]],"line":4,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0],[3,0],[4,1]],"line":7,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1],[4,0]],"line":10,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1],[3,0],[4,1]],"line":13,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0],[4,0]],"line":16,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1],[4,1]],"line":19,"winType":"line","winAmount":1.8,"featureFlags":[]}]},
            {"reelStops":[61,121,63,23,68],"totalWin":0,"wins":[]},
            {"reelStops":[67,9,110,85,121],"totalWin":0,"wins":[]},
            {"reelStops":[125,123,117,123,81],"totalWin":0,"wins":[]},
            {"reelStops":[1,77,119,75,3],"totalWin":1.92,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[50,108,39,95,63],"totalWin":1.86,"wins":[{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[84,95,76,60,126],"totalWin":2.4,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[96,115,75,91,26],"totalWin":0,"wins":[]},
            {"reelStops":[59,100,44,1,17],"totalWin":4.2,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[51,5,4,11,78],"totalWin":0,"wins":[]},
            {"reelStops":[91,7,17,114,99],"totalWin":0,"wins":[]},
            {"reelStops":[12,66,99,80,90],"totalWin":4.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0],[3,0],[4,0]],"line":0,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0],[3,0],[4,1]],"line":7,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[103,19,81,33,22],"totalWin":0.96,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[83,89,105,51,76],"totalWin":0,"wins":[]},
            {"reelStops":[120,30,40,44,42],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[91,102,32,78,13],"totalWin":0,"wins":[]},
            {"reelStops":[122,103,26,123,79],"totalWin":0,"wins":[]},
            {"reelStops":[19,18,32,48,64],"totalWin":0,"wins":[]},
            {"reelStops":[85,99,71,43,25],"totalWin":6,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2],[3,2]],"line":2,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3],[3,2]],"line":18,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[114,121,92,81,90],"totalWin":0,"wins":[]},
            {"reelStops":[113,62,115,13,106],"totalWin":0,"wins":[]},
            {"reelStops":[18,122,16,25,2],"totalWin":0,"wins":[]},
            {"reelStops":[27,108,24,20,33],"totalWin":4.8,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[41,65,108,99,4],"totalWin":6,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2],[3,2]],"line":2,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3],[3,2]],"line":18,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[47,124,24,30,61],"totalWin":0,"wins":[]},
            {"reelStops":[74,51,90,19,45],"totalWin":0,"wins":[]},
            {"reelStops":[81,111,74,59,59],"totalWin":0,"wins":[]},
            {"reelStops":[109,99,61,33,109],"totalWin":1.8,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0]],"line":16,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[67,79,0,89,85],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[35,49,59,65,25],"totalWin":0,"wins":[]},
            {"reelStops":[7,57,72,99,114],"totalWin":0,"wins":[]},
            {"reelStops":[19,72,23,99,65],"totalWin":0,"wins":[]},
            {"reelStops":[108,77,85,74,114],"totalWin":0.96,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[68,107,88,13,113],"totalWin":0,"wins":[]},
            {"reelStops":[41,72,29,72,118],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[49,48,42,14,46],"totalWin":0,"wins":[]},
            {"reelStops":[52,8,108,103,90],"totalWin":0.48,"wins":[{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[22,16,73,65,34],"totalWin":3,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[125,30,10,27,57],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[23,19,50,78,129],"totalWin":0,"wins":[]},
            {"reelStops":[123,87,27,38,98],"totalWin":0,"wins":[]},
            {"reelStops":[61,48,7,30,37],"totalWin":0,"wins":[]},
            {"reelStops":[9,64,40,1,97],"totalWin":3.36,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[122,123,18,99,37],"totalWin":0,"wins":[]},
            {"reelStops":[122,33,15,112,101],"totalWin":0,"wins":[]},
            {"reelStops":[24,77,112,36,103],"totalWin":0,"wins":[]},
            {"reelStops":[106,14,103,123,48],"totalWin":0,"wins":[]},
            {"reelStops":[24,85,97,19,55],"totalWin":0,"wins":[]},
            {"reelStops":[92,38,26,49,128],"totalWin":0,"wins":[]},
            {"reelStops":[19,41,3,5,125],"totalWin":0,"wins":[]},
            {"reelStops":[44,52,129,71,50],"totalWin":0,"wins":[]},
            {"reelStops":[37,110,44,29,65],"totalWin":0,"wins":[]},
            {"reelStops":[51,47,106,23,2],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[16,32,25,46,57],"totalWin":0,"wins":[]},
            {"reelStops":[75,50,3,39,119],"totalWin":0,"wins":[]},
            {"reelStops":[48,55,38,43,122],"totalWin":0.6,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[54,60,21,87,24],"totalWin":3,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[40,32,75,13,124],"totalWin":0,"wins":[]},
            {"reelStops":[33,24,108,84,97],"totalWin":0,"wins":[]},
            {"reelStops":[6,99,52,98,70],"totalWin":0,"wins":[]},
            {"reelStops":[86,4,106,101,22],"totalWin":0,"wins":[]},
            {"reelStops":[104,22,128,68,53],"totalWin":7.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0],[3,0]],"line":7,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1],[3,0]],"line":13,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[119,54,35,91,85],"totalWin":0,"wins":[]},
            {"reelStops":[101,101,123,96,30],"totalWin":0,"wins":[]},
            {"reelStops":[10,96,84,73,34],"totalWin":2.4,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[32,30,12,77,3],"totalWin":2.52,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[55,32,127,55,23],"totalWin":0.6,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[15,50,78,22,44],"totalWin":0,"wins":[]},
            {"reelStops":[50,85,101,93,37],"totalWin":1.8,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2],[3,3],[4,2]],"line":12,"winType":"line","winAmount":1.8,"featureFlags":[]}]},
            {"reelStops":[6,47,5,118,120],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[49,49,48,30,107],"totalWin":0,"wins":[]},
            {"reelStops":[53,18,110,20,61],"totalWin":0,"wins":[]},
            {"reelStops":[121,65,109,10,76],"totalWin":0,"wins":[]},
            {"reelStops":[80,0,65,83,63],"totalWin":0,"wins":[]},
            {"reelStops":[54,99,113,7,34],"totalWin":0,"wins":[]},
            {"reelStops":[104,12,115,74,114],"totalWin":0,"wins":[]},
            {"reelStops":[34,126,115,104,129],"totalWin":0,"wins":[]},
            {"reelStops":[28,69,126,35,114],"totalWin":0,"wins":[]},
            {"reelStops":[35,10,62,48,11],"totalWin":0,"wins":[]},
            {"reelStops":[117,33,99,25,85],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[79,10,103,60,109],"totalWin":0,"wins":[]},
            {"reelStops":[101,96,63,96,115],"totalWin":0,"wins":[]},
            {"reelStops":[33,87,5,2,74],"totalWin":0,"wins":[]},
            {"reelStops":[34,19,5,126,97],"totalWin":0.96,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[71,52,74,97,24],"totalWin":0,"wins":[]},
            {"reelStops":[29,68,114,11,95],"totalWin":0,"wins":[]},
            {"reelStops":[64,28,112,21,102],"totalWin":1.68,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[56,96,101,122,47],"totalWin":0,"wins":[]},
            {"reelStops":[3,17,16,76,129],"totalWin":0,"wins":[]},
            {"reelStops":[106,79,79,124,73],"totalWin":9.12,"wins":[{"winningSymbols":[[0,1],[1,1],[2,0],[3,1],[4,1]],"line":19,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[46,11,66,65,83],"totalWin":4.2,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[101,72,15,79,49],"totalWin":0,"wins":[]},
            {"reelStops":[42,45,123,122,123],"totalWin":0,"wins":[]},
            {"reelStops":[105,2,15,2,62],"totalWin":3.36,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[66,4,87,112,42],"totalWin":0,"wins":[]},
            {"reelStops":[92,123,11,42,107],"totalWin":0,"wins":[]},
            {"reelStops":[66,4,78,100,106],"totalWin":4.8,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0],[3,0]],"line":0,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0]],"line":16,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[27,26,125,104,45],"totalWin":0,"wins":[]},
            {"reelStops":[69,47,116,30,111],"totalWin":0,"wins":[]},
            {"reelStops":[125,82,52,5,115],"totalWin":0.96,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[47,68,111,88,3],"totalWin":2.4,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[58,86,15,3,11],"totalWin":0,"wins":[]},
            {"reelStops":[6,108,31,33,89],"totalWin":0,"wins":[]},
            {"reelStops":[86,41,75,77,54],"totalWin":0,"wins":[]},
            {"reelStops":[13,126,65,67,123],"totalWin":0,"wins":[]},
            {"reelStops":[23,7,122,111,35],"totalWin":0,"wins":[]},
            {"reelStops":[44,76,125,3,58],"totalWin":0,"wins":[]},
            {"reelStops":[64,40,112,65,84],"totalWin":0.96,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[17,6,129,12,43],"totalWin":0,"wins":[]},
            {"reelStops":[113,42,118,6,23],"totalWin":23,"wins":[{"winningSymbols":[[1,1],[2,1],[4,0]],"winType":"scatter","winAmount":23,"featureFlags":["bonus"]}],"bonusWin":23},
            {"reelStops":[43,39,78,81,92],"totalWin":0,"wins":[]},
            {"reelStops":[57,112,14,10,41],"totalWin":0,"wins":[]},
            {"reelStops":[11,34,109,120,106],"totalWin":0,"wins":[]},
            {"reelStops":[66,70,53,53,25],"totalWin":8.1,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0],[3,0]],"line":0,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1],[3,1]],"line":1,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0],[3,0]],"line":7,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1],[3,0]],"line":13,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0]],"line":16,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[67,55,84,69,81],"totalWin":0.48,"wins":[{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[60,123,3,64,36],"totalWin":0,"wins":[]},
            {"reelStops":[73,114,42,84,71],"totalWin":0,"wins":[]},
            {"reelStops":[100,25,126,89,88],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[103,7,56,18,125],"totalWin":0,"wins":[]},
            {"reelStops":[116,41,54,122,56],"totalWin":3.6,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0],[3,0],[4,1]],"line":7,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1],[4,1]],"line":19,"winType":"line","winAmount":1.8,"featureFlags":[]}]},
            {"reelStops":[19,97,63,117,112],"totalWin":0,"wins":[]},
            {"reelStops":[83,41,64,11,5],"totalWin":0,"wins":[]},
            {"reelStops":[77,46,117,32,63],"totalWin":0.48,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[37,15,77,12,57],"totalWin":0,"wins":[]},
            {"reelStops":[115,5,86,45,105],"totalWin":0,"wins":[]},
            {"reelStops":[70,57,58,114,122],"totalWin":0,"wins":[]},
            {"reelStops":[118,81,98,30,104],"totalWin":0,"wins":[]},
            {"reelStops":[10,70,27,53,87],"totalWin":0,"wins":[]},
            {"reelStops":[5,57,11,9,19],"totalWin":0,"wins":[]},
            {"reelStops":[66,70,109,35,106],"totalWin":0,"wins":[]},
            {"reelStops":[71,48,63,57,112],"totalWin":0,"wins":[]},
            {"reelStops":[52,109,86,54,122],"totalWin":1.08,"wins":[{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[69,30,0,98,92],"totalWin":5.28,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[101,93,18,70,4],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[90,41,45,83,33],"totalWin":0,"wins":[]},
            {"reelStops":[113,25,45,99,67],"totalWin":0,"wins":[]},
            {"reelStops":[36,81,82,43,84],"totalWin":0.48,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[47,42,52,116,75],"totalWin":3.66,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2],[3,2]],"line":2,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2],[3,2]],"line":9,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[66,51,69,65,83],"totalWin":0,"wins":[]},
            {"reelStops":[56,125,39,46,68],"totalWin":2.28,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[124,35,94,58,103],"totalWin":0,"wins":[]},
            {"reelStops":[78,35,51,72,84],"totalWin":2.76,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[10,97,82,97,60],"totalWin":0,"wins":[]},
            {"reelStops":[37,49,0,33,105],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[54,100,57,106,57],"totalWin":0,"wins":[]},
            {"reelStops":[49,97,48,107,66],"totalWin":0,"wins":[]},
            {"reelStops":[1,82,19,105,26],"totalWin":0,"wins":[]},
            {"reelStops":[86,49,45,85,108],"totalWin":1.08,"wins":[{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[61,63,39,91,19],"totalWin":0,"wins":[]},
            {"reelStops":[66,113,123,43,64],"totalWin":0,"wins":[]},
            {"reelStops":[122,33,105,84,122],"totalWin":3.6,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[83,23,66,77,78],"totalWin":0,"wins":[]},
            {"reelStops":[20,13,106,42,17],"totalWin":0,"wins":[]},
            {"reelStops":[110,35,27,37,33],"totalWin":0,"wins":[]},
            {"reelStops":[94,124,61,43,32],"totalWin":0,"wins":[]},
            {"reelStops":[119,15,2,108,128],"totalWin":0,"wins":[]},
            {"reelStops":[68,3,60,119,11],"totalWin":0,"wins":[]},
            {"reelStops":[31,78,7,90,92],"totalWin":0,"wins":[]},
            {"reelStops":[101,102,95,63,74],"totalWin":0,"wins":[]},
            {"reelStops":[92,74,8,30,75],"totalWin":0,"wins":[]},
            {"reelStops":[51,58,54,116,96],"totalWin":0,"wins":[]},
            {"reelStops":[76,124,103,18,89],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[81,74,83,112,27],"totalWin":0,"wins":[]},
            {"reelStops":[44,117,51,17,30],"totalWin":0,"wins":[]},
            {"reelStops":[82,28,64,16,49],"totalWin":0,"wins":[]},
            {"reelStops":[128,112,35,102,39],"totalWin":0,"wins":[]},
            {"reelStops":[100,121,62,9,22],"totalWin":0,"wins":[]},
            {"reelStops":[62,44,14,72,7],"totalWin":0,"wins":[]},
            {"reelStops":[59,13,80,37,1],"totalWin":0,"wins":[]},
            {"reelStops":[2,93,129,53,92],"totalWin":5.4,"wins":[{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[55,100,96,93,26],"totalWin":0.6,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[104,5,9,54,42],"totalWin":1.92,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[94,85,30,123,122],"totalWin":0,"wins":[]},
            {"reelStops":[73,1,7,56,19],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[59,121,82,67,79],"totalWin":0,"wins":[]},
            {"reelStops":[75,15,56,47,113],"totalWin":0,"wins":[]},
            {"reelStops":[39,6,63,60,82],"totalWin":0,"wins":[]},
            {"reelStops":[103,17,10,31,116],"totalWin":0,"wins":[]},
            {"reelStops":[23,6,57,124,74],"totalWin":0,"wins":[]},
            {"reelStops":[102,35,101,22,122],"totalWin":0,"wins":[]},
            {"reelStops":[100,89,35,50,90],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[74,24,112,83,81],"totalWin":0,"wins":[]},
            {"reelStops":[72,114,80,15,12],"totalWin":0,"wins":[]},
            {"reelStops":[117,29,14,82,22],"totalWin":4.56,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1],[3,1],[4,0]],"line":4,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1],[4,0]],"line":10,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[60,54,5,79,51],"totalWin":0,"wins":[]},
            {"reelStops":[93,80,4,96,104],"totalWin":7.2,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3],[4,3]],"line":3,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3],[3,3],[4,2]],"line":6,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2],[3,3],[4,2]],"line":12,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3],[4,3]],"line":21,"winType":"line","winAmount":1.8,"featureFlags":[]}]},
            {"reelStops":[49,70,123,25,37],"totalWin":0,"wins":[]},
            {"reelStops":[16,71,72,32,114],"totalWin":0,"wins":[]},
            {"reelStops":[49,97,77,102,125],"totalWin":0,"wins":[]},
            {"reelStops":[13,5,86,62,29],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[70,122,21,90,21],"totalWin":0,"wins":[]},
            {"reelStops":[3,82,85,116,79],"totalWin":0,"wins":[]},
            {"reelStops":[98,94,112,13,92],"totalWin":0.48,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[59,24,0,13,87],"totalWin":0,"wins":[]},
            {"reelStops":[52,111,101,88,39],"totalWin":1.08,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[121,124,70,113,81],"totalWin":0,"wins":[]},
            {"reelStops":[64,49,119,121,27],"totalWin":4.56,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[23,41,50,7,2],"totalWin":0,"wins":[]},
            {"reelStops":[61,39,77,82,16],"totalWin":0,"wins":[]},
            {"reelStops":[127,119,49,3,25],"totalWin":0,"wins":[]},
            {"reelStops":[23,44,29,85,64],"totalWin":0,"wins":[]},
            {"reelStops":[92,117,9,30,128],"totalWin":0,"wins":[]},
            {"reelStops":[55,77,117,27,115],"totalWin":6,"wins":[{"winningSymbols":[[0,3],[2,2],[4,1]],"winType":"scatter","winAmount":6,"featureFlags":["bonus"]}],"bonusWin":6},
            {"reelStops":[14,0,75,51,44],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[7,29,16,76,22],"totalWin":20.44,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[2,2],[4,1]],"winType":"scatter","winAmount":19,"featureFlags":["bonus"]}],"bonusWin":19},
            {"reelStops":[77,93,77,11,10],"totalWin":0.6,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[32,106,25,117,126],"totalWin":0,"wins":[]},
            {"reelStops":[93,60,15,0,66],"totalWin":0,"wins":[]},
            {"reelStops":[66,47,37,23,50],"totalWin":4.8,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0],[3,0]],"line":0,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0]],"line":16,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[39,45,18,80,42],"totalWin":0,"wins":[]},
            {"reelStops":[45,88,110,111,25],"totalWin":0,"wins":[]},
            {"reelStops":[9,40,36,69,64],"totalWin":0,"wins":[]},
            {"reelStops":[111,106,76,72,45],"totalWin":0,"wins":[]},
            {"reelStops":[87,110,24,26,64],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[2,93,76,17,81],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[106,40,84,111,89],"totalWin":0.96,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[62,55,105,14,66],"totalWin":4.32,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[91,56,16,28,39],"totalWin":0,"wins":[]},
            {"reelStops":[53,125,76,66,35],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[94,73,34,40,112],"totalWin":0,"wins":[]},
            {"reelStops":[76,76,47,47,105],"totalWin":1.38,"wins":[{"winningSymbols":[[0,3],[1,2],[2,3],[3,2]],"line":15,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[92,107,99,97,10],"totalWin":0,"wins":[]},
            {"reelStops":[111,17,14,100,77],"totalWin":0,"wins":[]},
            {"reelStops":[31,7,11,90,114],"totalWin":6.48,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[105,86,2,27,112],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2],[3,1]],"line":14,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[56,85,14,110,67],"totalWin":0,"wins":[]},
            {"reelStops":[43,65,116,17,129],"totalWin":0,"wins":[]},
            {"reelStops":[21,89,68,118,90],"totalWin":0,"wins":[]},
            {"reelStops":[101,93,57,21,56],"totalWin":0,"wins":[]},
            {"reelStops":[33,123,91,16,42],"totalWin":0,"wins":[]},
            {"reelStops":[5,75,23,74,52],"totalWin":0,"wins":[]},
            {"reelStops":[82,65,30,60,21],"totalWin":0,"wins":[]},
            {"reelStops":[0,108,19,115,48],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[91,76,81,112,93],"totalWin":0,"wins":[]},
            {"reelStops":[32,124,10,21,71],"totalWin":0,"wins":[]},
            {"reelStops":[121,41,102,10,7],"totalWin":0,"wins":[]},
            {"reelStops":[0,98,116,59,72],"totalWin":0,"wins":[]},
            {"reelStops":[90,17,77,78,106],"totalWin":0,"wins":[]},
            {"reelStops":[38,94,18,10,92],"totalWin":0,"wins":[]},
            {"reelStops":[101,55,39,87,32],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[126,28,55,94,125],"totalWin":1.08,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[55,22,109,85,77],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[69,81,112,33,72],"totalWin":0,"wins":[]},
            {"reelStops":[87,85,17,75,8],"totalWin":0.96,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[70,86,125,75,26],"totalWin":0,"wins":[]},
            {"reelStops":[36,89,31,21,112],"totalWin":0,"wins":[]},
            {"reelStops":[46,40,35,0,88],"totalWin":0,"wins":[]},
            {"reelStops":[43,8,68,100,109],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[93,96,84,16,97],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[56,63,79,16,122],"totalWin":2.34,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[9,26,73,75,37],"totalWin":0,"wins":[]},
            {"reelStops":[89,15,129,24,11],"totalWin":0,"wins":[]},
            {"reelStops":[67,81,101,77,128],"totalWin":1.92,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[3,69,38,108,54],"totalWin":0,"wins":[]},
            {"reelStops":[34,120,87,40,44],"totalWin":0,"wins":[]},
            {"reelStops":[76,43,91,74,84],"totalWin":0,"wins":[]},
            {"reelStops":[117,48,90,100,35],"totalWin":0,"wins":[]},
            {"reelStops":[77,55,27,122,17],"totalWin":1.08,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[59,63,62,61,110],"totalWin":0,"wins":[]},
            {"reelStops":[29,39,74,74,60],"totalWin":0,"wins":[]},
            {"reelStops":[129,106,18,43,116],"totalWin":0,"wins":[]},
            {"reelStops":[60,39,7,24,44],"totalWin":0,"wins":[]},
            {"reelStops":[119,60,79,25,3],"totalWin":0,"wins":[]},
            {"reelStops":[35,60,38,85,74],"totalWin":0,"wins":[]},
            {"reelStops":[75,116,19,41,79],"totalWin":0,"wins":[]},
            {"reelStops":[76,73,20,93,110],"totalWin":2.4,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[72,76,54,95,128],"totalWin":0,"wins":[]},
            {"reelStops":[21,72,62,68,19],"totalWin":0,"wins":[]},
            {"reelStops":[49,71,91,41,95],"totalWin":0,"wins":[]},
            {"reelStops":[17,30,28,88,89],"totalWin":0,"wins":[]},
            {"reelStops":[123,34,19,62,50],"totalWin":0,"wins":[]},
            {"reelStops":[81,57,103,42,25],"totalWin":0,"wins":[]},
            {"reelStops":[13,65,26,46,75],"totalWin":0,"wins":[]},
            {"reelStops":[54,7,71,58,129],"totalWin":3,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0],[3,0]],"line":7,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[103,28,125,83,123],"totalWin":3.36,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[128,97,28,21,69],"totalWin":0,"wins":[]},
            {"reelStops":[74,102,63,108,122],"totalWin":0,"wins":[]},
            {"reelStops":[100,117,98,92,113],"totalWin":0,"wins":[]},
            {"reelStops":[87,120,106,90,101],"totalWin":0,"wins":[]},
            {"reelStops":[39,56,0,17,115],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[77,112,122,13,24],"totalWin":6.96,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0],[3,0],[4,0]],"line":0,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0],[3,0],[4,1]],"line":7,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3],[3,2]],"line":18,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[25,2,116,107,107],"totalWin":0,"wins":[]},
            {"reelStops":[3,14,73,120,122],"totalWin":0,"wins":[]},
            {"reelStops":[56,87,34,45,13],"totalWin":0,"wins":[]},
            {"reelStops":[35,79,48,3,69],"totalWin":0.9,"wins":[{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[100,69,92,54,59],"totalWin":0,"wins":[]},
            {"reelStops":[9,67,26,20,93],"totalWin":0,"wins":[]},
            {"reelStops":[35,90,80,77,102],"totalWin":0,"wins":[]},
            {"reelStops":[11,121,86,95,45],"totalWin":0.6,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[19,58,111,3,25],"totalWin":0,"wins":[]},
            {"reelStops":[79,107,70,105,88],"totalWin":0,"wins":[]},
            {"reelStops":[70,107,3,26,82],"totalWin":0,"wins":[]},
            {"reelStops":[40,38,77,92,33],"totalWin":0,"wins":[]},
            {"reelStops":[92,117,114,99,107],"totalWin":0,"wins":[]},
            {"reelStops":[5,104,78,121,67],"totalWin":0,"wins":[]},
            {"reelStops":[41,26,91,45,123],"totalWin":0,"wins":[]},
            {"reelStops":[63,110,111,69,31],"totalWin":0,"wins":[]},
            {"reelStops":[34,95,89,83,70],"totalWin":0,"wins":[]},
            {"reelStops":[90,15,129,55,89],"totalWin":0,"wins":[]},
            {"reelStops":[39,122,72,107,115],"totalWin":0,"wins":[]},
            {"reelStops":[40,74,59,96,48],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[50,95,70,83,27],"totalWin":0.96,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[3,92,111,55,0],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[92,109,86,107,13],"totalWin":0,"wins":[]},
            {"reelStops":[105,99,76,31,37],"totalWin":0,"wins":[]},
            {"reelStops":[85,76,48,53,52],"totalWin":1.92,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[13,33,108,8,126],"totalWin":0,"wins":[]},
            {"reelStops":[23,125,88,22,34],"totalWin":0,"wins":[]},
            {"reelStops":[111,108,63,38,93],"totalWin":2.4,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[67,50,19,126,83],"totalWin":0,"wins":[]},
            {"reelStops":[115,100,17,77,75],"totalWin":0,"wins":[]},
            {"reelStops":[121,22,23,24,86],"totalWin":0,"wins":[]},
            {"reelStops":[44,13,8,22,105],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2],[3,1]],"line":14,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[41,79,43,10,38],"totalWin":6.06,"wins":[{"winningSymbols":[[0,1],[1,1],[2,0],[3,1],[4,1]],"line":19,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2],[3,1]],"line":14,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[120,81,26,12,89],"totalWin":0,"wins":[]},
            {"reelStops":[126,108,47,88,40],"totalWin":0,"wins":[]},
            {"reelStops":[58,57,31,105,42],"totalWin":1.8,"wins":[{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[12,15,21,55,93],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[54,6,20,90,102],"totalWin":0.48,"wins":[{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[127,91,17,0,114],"totalWin":0,"wins":[]},
            {"reelStops":[35,71,53,107,100],"totalWin":0,"wins":[]},
            {"reelStops":[45,75,21,47,30],"totalWin":0,"wins":[]},
            {"reelStops":[51,1,101,68,110],"totalWin":0.96,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[55,101,28,111,107],"totalWin":0,"wins":[]},
            {"reelStops":[57,103,14,98,121],"totalWin":0,"wins":[]},
            {"reelStops":[12,56,52,47,16],"totalWin":4.32,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[76,53,93,124,15],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[50,51,36,113,43],"totalWin":0,"wins":[]},
            {"reelStops":[74,73,63,35,51],"totalWin":0,"wins":[]},
            {"reelStops":[76,86,125,89,127],"totalWin":0,"wins":[]},
            {"reelStops":[9,57,101,14,92],"totalWin":0,"wins":[]},
            {"reelStops":[93,91,16,36,80],"totalWin":0.9,"wins":[{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[80,44,58,61,116],"totalWin":0,"wins":[]},
            {"reelStops":[63,61,29,35,38],"totalWin":0,"wins":[]},
            {"reelStops":[61,100,117,75,20],"totalWin":0,"wins":[]},
            {"reelStops":[42,114,62,88,115],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[72,39,93,68,86],"totalWin":0,"wins":[]},
            {"reelStops":[121,119,19,19,94],"totalWin":0,"wins":[]},
            {"reelStops":[85,14,40,104,43],"totalWin":4.2,"wins":[{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[81,33,78,83,117],"totalWin":0,"wins":[]},
            {"reelStops":[126,60,63,93,5],"totalWin":0,"wins":[]},
            {"reelStops":[43,55,27,116,116],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[29,87,124,54,53],"totalWin":0,"wins":[]},
            {"reelStops":[91,83,73,107,71],"totalWin":0,"wins":[]},
            {"reelStops":[99,12,117,12,108],"totalWin":0,"wins":[]},
            {"reelStops":[31,70,110,92,115],"totalWin":0,"wins":[]},
            {"reelStops":[129,107,117,111,47],"totalWin":0,"wins":[]},
            {"reelStops":[45,77,82,96,0],"totalWin":0,"wins":[]},
            {"reelStops":[110,98,22,1,80],"totalWin":0,"wins":[]},
            {"reelStops":[54,122,110,27,25],"totalWin":0,"wins":[]},
            {"reelStops":[72,87,21,31,81],"totalWin":0,"wins":[]},
            {"reelStops":[78,83,58,29,4],"totalWin":0,"wins":[]},
            {"reelStops":[6,6,61,93,19],"totalWin":3.12,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[12,74,101,0,103],"totalWin":0,"wins":[]},
            {"reelStops":[5,45,88,5,100],"totalWin":0,"wins":[]},
            {"reelStops":[21,59,26,14,28],"totalWin":0,"wins":[]},
            {"reelStops":[81,103,22,71,117],"totalWin":0,"wins":[]},
            {"reelStops":[61,101,110,76,0],"totalWin":0,"wins":[]},
            {"reelStops":[3,55,26,6,125],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[19,0,83,9,80],"totalWin":0,"wins":[]},
            {"reelStops":[47,43,82,76,105],"totalWin":0,"wins":[]},
            {"reelStops":[42,109,77,124,66],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[42,11,25,34,7],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[71,49,109,29,0],"totalWin":0,"wins":[]},
            {"reelStops":[40,74,102,14,50],"totalWin":0,"wins":[]},
            {"reelStops":[29,16,119,13,48],"totalWin":0,"wins":[]},
            {"reelStops":[94,82,102,57,14],"totalWin":0,"wins":[]},
            {"reelStops":[18,113,57,52,125],"totalWin":0,"wins":[]},
            {"reelStops":[48,79,93,118,28],"totalWin":0,"wins":[]},
            {"reelStops":[92,41,18,23,29],"totalWin":0,"wins":[]},
            {"reelStops":[104,45,72,99,95],"totalWin":0,"wins":[]},
            {"reelStops":[88,38,93,100,27],"totalWin":0,"wins":[]},
            {"reelStops":[34,106,94,100,14],"totalWin":0,"wins":[]},
            {"reelStops":[29,12,19,96,6],"totalWin":0,"wins":[]},
            {"reelStops":[24,42,105,111,90],"totalWin":0,"wins":[]},
            {"reelStops":[23,51,64,21,119],"totalWin":0,"wins":[]},
            {"reelStops":[58,111,82,16,57],"totalWin":0.96,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[36,13,25,78,116],"totalWin":0,"wins":[]},
            {"reelStops":[99,2,59,3,13],"totalWin":0,"wins":[]},
            {"reelStops":[113,21,16,85,122],"totalWin":0.96,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[105,93,119,117,7],"totalWin":2.04,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[27,90,101,6,38],"totalWin":0,"wins":[]},
            {"reelStops":[15,31,0,84,45],"totalWin":4.8,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3],[3,2]],"line":15,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3],[3,2]],"line":18,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[5,56,16,32,129],"totalWin":0,"wins":[]},
            {"reelStops":[112,112,41,49,46],"totalWin":0,"wins":[]},
            {"reelStops":[28,75,44,116,45],"totalWin":0,"wins":[]},
            {"reelStops":[4,115,67,7,107],"totalWin":0,"wins":[]},
            {"reelStops":[80,91,119,11,9],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[83,63,106,122,71],"totalWin":0,"wins":[]},
            {"reelStops":[71,64,24,68,13],"totalWin":2.4,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[7,18,10,91,95],"totalWin":0,"wins":[]},
            {"reelStops":[18,10,124,59,126],"totalWin":0,"wins":[]},
            {"reelStops":[7,114,119,40,83],"totalWin":0,"wins":[]},
            {"reelStops":[89,111,119,0,118],"totalWin":0,"wins":[]},
            {"reelStops":[86,18,43,6,79],"totalWin":9,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1],[3,1],[4,1]],"line":1,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1],[3,0],[4,1]],"line":13,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2],[3,1],[4,1]],"line":17,"winType":"line","winAmount":3,"featureFlags":[]}]},
            {"reelStops":[70,72,114,25,22],"totalWin":0,"wins":[]},
            {"reelStops":[124,90,113,65,38],"totalWin":0,"wins":[]},
            {"reelStops":[40,42,64,115,29],"totalWin":0,"wins":[]},
            {"reelStops":[65,81,123,8,67],"totalWin":0,"wins":[]},
            {"reelStops":[86,123,13,57,39],"totalWin":2.16,"wins":[{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[67,54,92,69,83],"totalWin":0,"wins":[]},
            {"reelStops":[59,23,57,79,6],"totalWin":0,"wins":[]},
            {"reelStops":[57,86,11,98,62],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[46,97,98,116,107],"totalWin":6.96,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1],[3,0]],"line":13,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0]],"line":16,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2],[3,2]],"line":9,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3],[3,2]],"line":15,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[28,79,108,117,56],"totalWin":3,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[24,82,107,58,71],"totalWin":0.96,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[36,40,101,78,45],"totalWin":0,"wins":[]},
            {"reelStops":[56,76,75,6,62],"totalWin":0,"wins":[]},
            {"reelStops":[97,112,96,18,33],"totalWin":0,"wins":[]},
            {"reelStops":[31,59,104,59,50],"totalWin":0,"wins":[]},
            {"reelStops":[21,75,74,86,105],"totalWin":0,"wins":[]},
            {"reelStops":[94,0,10,121,121],"totalWin":1.56,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[129,57,124,52,66],"totalWin":0,"wins":[]},
            {"reelStops":[53,8,122,53,107],"totalWin":1.92,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[123,58,127,88,99],"totalWin":0,"wins":[]},
            {"reelStops":[82,75,87,37,57],"totalWin":0,"wins":[]},
            {"reelStops":[125,45,80,28,104],"totalWin":0,"wins":[]},
            {"reelStops":[21,111,87,92,60],"totalWin":0,"wins":[]},
            {"reelStops":[85,73,74,106,56],"totalWin":0,"wins":[]},
            {"reelStops":[38,54,59,4,128],"totalWin":1.56,"wins":[{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[14,113,74,120,104],"totalWin":0.96,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[37,71,57,62,98],"totalWin":0,"wins":[]},
            {"reelStops":[92,81,95,100,108],"totalWin":1.92,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[10,78,113,54,92],"totalWin":2.16,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[53,72,109,108,63],"totalWin":0,"wins":[]},
            {"reelStops":[117,33,53,121,37],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[75,112,109,119,57],"totalWin":0,"wins":[]},
            {"reelStops":[75,22,58,30,78],"totalWin":0,"wins":[]},
            {"reelStops":[22,108,1,78,90],"totalWin":0,"wins":[]},
            {"reelStops":[107,50,0,1,77],"totalWin":1.08,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[104,124,95,108,126],"totalWin":0,"wins":[]},
            {"reelStops":[29,82,65,109,36],"totalWin":0,"wins":[]},
            {"reelStops":[61,48,62,106,99],"totalWin":0.9,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2],[3,2]],"line":9,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[7,122,18,109,119],"totalWin":0,"wins":[]},
            {"reelStops":[84,80,70,108,111],"totalWin":0,"wins":[]},
            {"reelStops":[35,59,2,96,105],"totalWin":0,"wins":[]},
            {"reelStops":[65,102,74,47,111],"totalWin":1.8,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0],[3,0]],"line":7,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[113,24,57,0,22],"totalWin":0,"wins":[]},
            {"reelStops":[62,20,25,20,1],"totalWin":0,"wins":[]},
            {"reelStops":[65,40,88,118,38],"totalWin":0,"wins":[]},
            {"reelStops":[60,10,43,22,30],"totalWin":0,"wins":[]},
            {"reelStops":[78,81,29,1,113],"totalWin":1.92,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[11,72,17,93,91],"totalWin":0,"wins":[]},
            {"reelStops":[5,9,61,44,121],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[60,30,43,59,104],"totalWin":2.4,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0],[3,0]],"line":0,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[27,121,79,56,41],"totalWin":0,"wins":[]},
            {"reelStops":[58,96,32,12,52],"totalWin":0,"wins":[]},
            {"reelStops":[42,69,38,124,126],"totalWin":3,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0],[3,0],[4,1]],"line":7,"winType":"line","winAmount":3,"featureFlags":[]}]},
            {"reelStops":[82,48,50,84,72],"totalWin":0,"wins":[]},
            {"reelStops":[77,50,112,101,116],"totalWin":0,"wins":[]},
            {"reelStops":[129,58,35,28,72],"totalWin":0,"wins":[]},
            {"reelStops":[105,75,94,52,22],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[104,10,57,6,22],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[104,88,60,114,51],"totalWin":0.9,"wins":[{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[52,85,85,2,44],"totalWin":0,"wins":[]},
            {"reelStops":[77,13,111,40,36],"totalWin":0,"wins":[]},
            {"reelStops":[27,85,83,59,15],"totalWin":0,"wins":[]},
            {"reelStops":[49,23,0,11,85],"totalWin":0,"wins":[]},
            {"reelStops":[76,99,123,58,12],"totalWin":0,"wins":[]},
            {"reelStops":[53,28,37,111,0],"totalWin":2.04,"wins":[{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[19,39,122,76,108],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[69,78,103,80,107],"totalWin":1.8,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0],[3,0]],"line":7,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[6,19,107,54,95],"totalWin":0,"wins":[]},
            {"reelStops":[24,8,89,110,74],"totalWin":0,"wins":[]},
            {"reelStops":[16,84,128,37,2],"totalWin":3.6,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[45,2,70,68,16],"totalWin":0,"wins":[]},
            {"reelStops":[47,105,86,4,74],"totalWin":0,"wins":[]},
            {"reelStops":[89,126,32,114,49],"totalWin":2.7,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2],[3,2]],"line":2,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3],[3,2]],"line":18,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[89,58,87,33,24],"totalWin":0,"wins":[]},
            {"reelStops":[74,50,28,67,77],"totalWin":0,"wins":[]},
            {"reelStops":[103,54,60,59,91],"totalWin":6.84,"wins":[{"winningSymbols":[[0,1],[1,2],[2,2],[3,2],[4,1]],"line":5,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[126,85,2,23,63],"totalWin":0,"wins":[]},
            {"reelStops":[113,68,34,65,25],"totalWin":0.6,"wins":[{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[71,0,23,99,36],"totalWin":0,"wins":[]},
            {"reelStops":[120,106,27,30,69],"totalWin":3.6,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3],[4,3]],"line":3,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3],[4,3]],"line":21,"winType":"line","winAmount":1.8,"featureFlags":[]}]},
            {"reelStops":[7,117,46,120,76],"totalWin":0,"wins":[]},
            {"reelStops":[23,1,128,51,37],"totalWin":0.48,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[100,126,8,80,77],"totalWin":0,"wins":[]},
            {"reelStops":[69,80,110,73,8],"totalWin":0,"wins":[]},
            {"reelStops":[55,44,80,75,45],"totalWin":8.1,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0],[3,0]],"line":0,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1],[3,1]],"line":1,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0],[3,0]],"line":7,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1],[3,0]],"line":13,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0]],"line":16,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[95,85,46,12,57],"totalWin":0,"wins":[]},
            {"reelStops":[115,35,96,55,96],"totalWin":1.68,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[75,99,87,13,125],"totalWin":3.84,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[71,92,92,71,72],"totalWin":1.8,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[7,92,127,97,44],"totalWin":3.6,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1],[3,1]],"line":1,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2],[3,1]],"line":14,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2],[3,1]],"line":17,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[42,35,4,95,91],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[37,110,38,56,50],"totalWin":0.48,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[114,3,63,56,114],"totalWin":4.56,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2],[3,2]],"line":9,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3],[3,2]],"line":15,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[95,4,125,36,53],"totalWin":0,"wins":[]},
            {"reelStops":[43,83,5,17,99],"totalWin":3.36,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[13,46,30,98,90],"totalWin":0,"wins":[]},
            {"reelStops":[14,122,9,58,120],"totalWin":0,"wins":[]},
            {"reelStops":[34,26,7,1,36],"totalWin":0,"wins":[]},
            {"reelStops":[110,84,106,4,91],"totalWin":0,"wins":[]},
            {"reelStops":[70,27,87,122,77],"totalWin":0,"wins":[]},
            {"reelStops":[110,4,94,98,42],"totalWin":0,"wins":[]},
            {"reelStops":[46,95,73,4,70],"totalWin":0,"wins":[]},
            {"reelStops":[7,99,4,16,30],"totalWin":0,"wins":[]},
            {"reelStops":[63,83,20,111,96],"totalWin":0,"wins":[]},
            {"reelStops":[117,24,34,54,77],"totalWin":0,"wins":[]},
            {"reelStops":[6,30,23,104,76],"totalWin":0,"wins":[]},
            {"reelStops":[21,37,27,87,89],"totalWin":0,"wins":[]},
            {"reelStops":[6,14,7,76,65],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[87,111,77,30,24],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[1,87,38,126,104],"totalWin":0.96,"wins":[{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[0,113,100,82,29],"totalWin":0,"wins":[]},
            {"reelStops":[79,92,35,54,102],"totalWin":1.56,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[62,74,78,28,63],"totalWin":0,"wins":[]},
            {"reelStops":[65,123,48,79,90],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[67,92,101,38,45],"totalWin":2.88,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[21,115,94,103,16],"totalWin":0,"wins":[]},
            {"reelStops":[66,14,72,13,49],"totalWin":0,"wins":[]},
            {"reelStops":[121,121,104,33,25],"totalWin":0,"wins":[]},
            {"reelStops":[4,113,76,11,83],"totalWin":0,"wins":[]},
            {"reelStops":[24,51,21,54,65],"totalWin":10.8,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1],[3,1]],"line":1,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2],[3,1]],"line":17,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[91,74,61,106,118],"totalWin":0,"wins":[]},
            {"reelStops":[96,33,45,113,25],"totalWin":0,"wins":[]},
            {"reelStops":[50,122,65,92,47],"totalWin":0,"wins":[]},
            {"reelStops":[17,56,77,108,84],"totalWin":0,"wins":[]},
            {"reelStops":[120,83,117,42,30],"totalWin":0,"wins":[]},
            {"reelStops":[70,101,65,101,83],"totalWin":0,"wins":[]},
            {"reelStops":[81,39,32,76,84],"totalWin":0,"wins":[]},
            {"reelStops":[38,26,48,47,113],"totalWin":0,"wins":[]},
            {"reelStops":[51,73,40,66,64],"totalWin":0,"wins":[]},
            {"reelStops":[67,83,126,3,15],"totalWin":0,"wins":[]},
            {"reelStops":[46,96,124,45,47],"totalWin":0,"wins":[]},
            {"reelStops":[48,105,76,18,84],"totalWin":0,"wins":[]},
            {"reelStops":[36,114,85,71,58],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[86,56,8,98,84],"totalWin":1.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[9,48,52,109,39],"totalWin":0,"wins":[]},
            {"reelStops":[121,33,45,33,56],"totalWin":0,"wins":[]},
            {"reelStops":[59,72,91,105,70],"totalWin":2.4,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[63,81,6,4,9],"totalWin":0.96,"wins":[{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[110,118,50,0,85],"totalWin":0,"wins":[]},
            {"reelStops":[63,80,71,116,25],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,1],[3,0]],"line":16,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[5,48,67,18,106],"totalWin":1.2,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0]],"line":0,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0]],"line":7,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[11,17,36,4,99],"totalWin":0,"wins":[]},
            {"reelStops":[0,48,66,3,6],"totalWin":0,"wins":[]},
            {"reelStops":[26,18,21,102,87],"totalWin":0,"wins":[]},
            {"reelStops":[33,83,119,118,117],"totalWin":0,"wins":[]},
            {"reelStops":[118,23,1,79,37],"totalWin":4.8,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[22,57,15,3,31],"totalWin":0,"wins":[]},
            {"reelStops":[90,33,15,3,128],"totalWin":0,"wins":[]},
            {"reelStops":[15,3,101,57,91],"totalWin":0,"wins":[]},
            {"reelStops":[126,121,10,33,26],"totalWin":0.96,"wins":[{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[124,123,43,116,108],"totalWin":0,"wins":[]},
            {"reelStops":[42,17,27,55,79],"totalWin":0,"wins":[]},
            {"reelStops":[25,36,14,17,68],"totalWin":0,"wins":[]},
            {"reelStops":[119,4,82,27,40],"totalWin":0,"wins":[]},
            {"reelStops":[2,44,23,31,114],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[129,13,14,11,70],"totalWin":0,"wins":[]},
            {"reelStops":[85,87,32,84,12],"totalWin":1.44,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[109,69,68,106,11],"totalWin":0.96,"wins":[{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[62,24,8,71,88],"totalWin":0,"wins":[]},
            {"reelStops":[17,22,41,3,7],"totalWin":4.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,0],[3,0],[4,1]],"line":7,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,0],[3,0]],"line":0,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[75,29,123,37,114],"totalWin":0,"wins":[]},
            {"reelStops":[125,121,4,85,17],"totalWin":0.96,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[86,82,108,3,37],"totalWin":1.8,"wins":[{"winningSymbols":[[0,0],[1,1],[2,0],[3,1]],"line":10,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0],[3,1]],"line":19,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[125,119,120,120,0],"totalWin":0.48,"wins":[{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[123,15,48,43,4],"totalWin":0,"wins":[]},
            {"reelStops":[81,100,55,97,129],"totalWin":0,"wins":[]},
            {"reelStops":[112,67,30,79,91],"totalWin":0,"wins":[]},
            {"reelStops":[95,96,66,114,79],"totalWin":0,"wins":[]},
            {"reelStops":[121,40,30,30,92],"totalWin":0,"wins":[]},
            {"reelStops":[13,108,93,111,28],"totalWin":0,"wins":[]},
            {"reelStops":[22,83,86,10,105],"totalWin":0,"wins":[]},
            {"reelStops":[111,58,118,37,104],"totalWin":0,"wins":[]},
            {"reelStops":[55,64,23,68,103],"totalWin":0,"wins":[]},
            {"reelStops":[98,48,23,124,125],"totalWin":0,"wins":[]},
            {"reelStops":[78,96,108,92,45],"totalWin":3.6,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1],[3,0]],"line":13,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1]],"line":11,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[92,30,104,105,128],"totalWin":0,"wins":[]},
            {"reelStops":[23,49,25,67,33],"totalWin":0,"wins":[]},
            {"reelStops":[45,91,24,58,5],"totalWin":3,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[91,82,51,68,22],"totalWin":0,"wins":[]},
            {"reelStops":[61,46,109,29,38],"totalWin":0,"wins":[]},
            {"reelStops":[77,104,42,77,22],"totalWin":0.48,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[36,97,11,76,96],"totalWin":0,"wins":[]},
            {"reelStops":[24,82,54,125,109],"totalWin":2.4,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1]],"line":20,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[79,4,49,37,3],"totalWin":0.48,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[105,19,2,63,118],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[49,88,104,112,98],"totalWin":0,"wins":[]},
            {"reelStops":[12,107,119,35,28],"totalWin":0,"wins":[]},
            {"reelStops":[80,22,111,106,109],"totalWin":2.16,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[84,36,52,21,67],"totalWin":1.2,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[93,33,118,94,36],"totalWin":0,"wins":[]},
            {"reelStops":[86,125,113,58,43],"totalWin":4.2,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1],[3,0],[4,1]],"line":13,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[53,68,65,10,84],"totalWin":7.92,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1],[3,1],[4,2]],"line":8,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2],[3,1],[4,2]],"line":14,"winType":"line","winAmount":3,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[79,120,117,102,50],"totalWin":0,"wins":[]},
            {"reelStops":[106,76,55,70,59],"totalWin":0,"wins":[]},
            {"reelStops":[18,113,10,43,126],"totalWin":0,"wins":[]},
            {"reelStops":[36,55,53,10,5],"totalWin":5.7,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,1],[3,1]],"line":1,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1],[3,1]],"line":4,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2],[3,2]],"line":5,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,1],[3,2]],"line":11,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2],[3,1]],"line":17,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[84,18,1,91,9],"totalWin":0,"wins":[]},
            {"reelStops":[74,13,48,7,0],"totalWin":0,"wins":[]},
            {"reelStops":[15,20,22,123,66],"totalWin":0,"wins":[]},
            {"reelStops":[3,118,38,20,26],"totalWin":0,"wins":[]},
            {"reelStops":[62,1,46,37,18],"totalWin":6.9,"wins":[{"winningSymbols":[[0,0],[1,0],[2,0],[3,0]],"line":0,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,0],[3,0]],"line":7,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2],[3,2]],"line":2,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2],[3,2]],"line":9,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2],[3,1]],"line":14,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,1],[3,2]],"line":20,"winType":"line","winAmount":0.9,"featureFlags":[]}]},
            {"reelStops":[61,47,37,94,68],"totalWin":2.76,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[55,37,115,33,76],"totalWin":0,"wins":[]},
            {"reelStops":[8,83,74,34,91],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,0],[2,1]],"line":13,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1]],"line":16,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,2]],"line":17,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[110,54,128,52,25],"totalWin":1.68,"wins":[{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,2],[2,2]],"line":5,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[123,95,55,19,113],"totalWin":7.8,"wins":[{"winningSymbols":[[0,3],[1,3],[2,3],[3,3]],"line":3,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3],[3,3]],"line":6,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2],[3,3]],"line":12,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2],[3,3]],"line":21,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,2]],"line":14,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[37,47,6,92,54],"totalWin":0,"wins":[]},
            {"reelStops":[124,90,120,114,100],"totalWin":1.2,"wins":[{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[52,22,67,78,70],"totalWin":0,"wins":[]},
            {"reelStops":[76,20,58,92,20],"totalWin":0.96,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[96,36,7,20,18],"totalWin":0,"wins":[]},
            {"reelStops":[10,55,113,100,73],"totalWin":0.48,"wins":[{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[122,117,109,108,77],"totalWin":0,"wins":[]},
            {"reelStops":[47,111,25,19,69],"totalWin":2.4,"wins":[{"winningSymbols":[[0,1],[1,0],[2,1],[3,0]],"line":13,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,0],[1,0],[2,1],[3,0]],"line":16,"winType":"line","winAmount":1.2,"featureFlags":[]}]},
            {"reelStops":[115,102,32,118,57],"totalWin":5.04,"wins":[{"winningSymbols":[[0,2],[1,1],[2,1],[3,1]],"line":8,"winType":"line","winAmount":1.2,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,2]],"line":2,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,3]],"line":3,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,3]],"line":6,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,2]],"line":9,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,3],[2,2]],"line":12,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]},{"winningSymbols":[[0,3],[1,3],[2,2]],"line":21,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[23,21,32,105,61],"totalWin":3,"wins":[{"winningSymbols":[[0,1],[1,1],[2,1]],"line":1,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,1]],"line":4,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,2],[1,1],[2,1]],"line":8,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,0],[1,1],[2,0]],"line":10,"winType":"line","winAmount":0.6,"featureFlags":[]},{"winningSymbols":[[0,1],[1,1],[2,0]],"line":19,"winType":"line","winAmount":0.6,"featureFlags":[]}]},
            {"reelStops":[124,109,93,58,6],"totalWin":0,"wins":[]},
            {"reelStops":[68,23,119,68,15],"totalWin":0,"wins":[]},
            {"reelStops":[63,113,82,97,55],"totalWin":0,"wins":[]},
            {"reelStops":[76,109,49,113,86],"totalWin":1.38,"wins":[{"winningSymbols":[[0,3],[1,2],[2,2],[3,2]],"line":9,"winType":"line","winAmount":0.9,"featureFlags":[]},{"winningSymbols":[[0,3],[1,2],[2,3]],"line":15,"winType":"line","winAmount":0.48,"featureFlags":[]}]},
            {"reelStops":[53,102,8,77,111],"totalWin":2.28,"wins":[{"winningSymbols":[[0,2],[1,3],[2,3],[3,3],[4,2]],"line":6,"winType":"line","winAmount":1.8,"featureFlags":[]},{"winningSymbols":[[0,2],[1,2],[2,3]],"line":18,"winType":"line","winAmount":0.48,"featureFlags":[]}]}
        ];
    }

}

TypescriptProjectCode/GrpcConnection.ts
------------------------------------------------------------
CODE.includeIf___EgmPublish;

class GrpcConnection
{
    constructor(){}


    async init()
    {
        await this.beginHandlingRequestsFromRemoteProcess();
    }


    // call this with 'await' to make a request of the associated remote process and wait for the response
    async makeRequestToRemoteProcess(request)
    {
        let response = await window["GrpcService"].requestAndResponse(JSON.stringify(request));
        if (response.type === "error")
        {
            console.log("Error performing GRPC requestAndResponse: " + JSON.stringify(response.value));
        }
        else if (response.type === "data")
        {
            return JSON.parse(response.value.message);
        }
    }   


    // this method (which is automatically invoked upon 'init'), opens the connection with the associated remote process, enabling it to trigger the 'handleRequestFromRemoteProcess' method below.
    async beginHandlingRequestsFromRemoteProcess()
    {
        let resultStringified = await window["GrpcService"].createTwoWayStream();
        let result = JSON.parse(resultStringified);
        window["GrpcService"].setResponseCallback((event) => this.handleRequestFromRemoteProcess(event));
        return (result);
    }


    // populate this method with the functionality to react to any requests that could come from the associated remote process
    handleRequestFromRemoteProcess(event)
    {
        if (event === undefined)
        {
            console.log("undefined response event");
        }
        else
        {
            if (event.type === "data")
            {
                if (event.value.message === "spin")
                {
                    pr.mainPlayerInput();
                }
            }
            else if (event.type === "error")
            {
                console.log("Unknown error occured: " + event.value.code);
            }
            else if (event.type === "status")
            {
                if (event.value.code === 14)
                {
                    console.log("Input server unavailable: " + event.value.details);
                }
                else
                {
                    console.log("Unknown status change occured");
                }
            }
            else if (event.type === "end")
            {
                console.log("End occured");
            }
            else
            {
                console.log("Unknown event type:" + event.type);
            }
        }
    }
}

CODE.includeEnd___EgmPublish;

TypescriptProjectCode/Payline.ts
------------------------------------------------------------
/** Dynamic payline object that generates a series of line segments (GraphicObjects with the 'StretchBetween' CustomAddOns),
 * that are dynamically stretched to span between symbol positions to form the given payline.
 */
class Payline extends SceneObject
{
    paylineSegments:GraphicObject[];
    stretchBetweenAddOns:StretchBetween2D[];
    paylineData:number[][]
    constructor(parent,name)
    {
        super(parent,name);
        this.paylineSegments = [];
        this.stretchBetweenAddOns = [];
        this.paylineData = gameSystemManager.initialGameLogicData.paylines;
    
        // create the payline segments
        for(let i=0; i<=pr.symbolReels.length; i++)
        {
            let newPaylineSegment = new GraphicObject(nc.graphicAssets.SampleParticle,this,"PaylineSegment"+i);

            // set the layer and sub-layer of the payline
            newPaylineSegment.layer = nc.layers.Reels;
            newPaylineSegment.subLayer =.5;

            // change the blending mode to 'add'
            newPaylineSegment.materialMaster.blending = constants.blendingModes.add;

            // add the 'StretchBetween' CustomAddOn
            let newStretchBetweenAddOn = new StretchBetween2D(newPaylineSegment);
            newStretchBetweenAddOn.firstPointBuffer = 5;
            newStretchBetweenAddOn.secondPointBuffer = 5;
            this.stretchBetweenAddOns.push(newStretchBetweenAddOn);
        }
        this.displayPayline(0,0,0);
        this.enabled = false;
    }


    displayPayline(paylineNumber:number,motionDuration:number,fadeDuration:number)
    {
        if(motionDuration===undefined){motionDuration=0;}
        this.enabled = true;
        this.colorMultiply.swoop.alpha(0,0);
        this.colorMultiply.swoop.alpha(1,fadeDuration);
        let globalSymbolPositions = [];
        
        // first get global position
        for(let i=0; i<pr.symbolReels.length; i++)
        {
            let symbol = pr.symbolReels[i].getSymbol(this.paylineData[paylineNumber][i]);
            globalSymbolPositions.push(symbol.getGlobalPosition());
        }

        // left line tab
        let posx = globalSymbolPositions[0].x;
        let posy = globalSymbolPositions[0].y;
        let tweenType = nc.tweenTypes.ExtremeEaseIn;
        let addOn = this.stretchBetweenAddOns[0];
        nc.swoopValue(addOn,"firstPointX",posx-250,motionDuration,tweenType);
        nc.swoopValue(addOn,"firstPointY",posy,motionDuration,tweenType);
        nc.swoopValue(addOn,"secondPointX",posx,motionDuration,tweenType);
        nc.swoopValue(addOn,"secondPointY",posy,motionDuration,tweenType);

        // right line tab
        let idx = pr.symbolReels.length-1;
        posx = globalSymbolPositions[idx].x;
        posy = globalSymbolPositions[idx].y;
        addOn = this.stretchBetweenAddOns[idx+1];
        nc.swoopValue(addOn,"firstPointX",posx+250,motionDuration,tweenType);
        nc.swoopValue(addOn,"firstPointY",posy,motionDuration,tweenType);
        nc.swoopValue(addOn,"secondPointX",posx,motionDuration,tweenType);
        nc.swoopValue(addOn,"secondPointY",posy,motionDuration,tweenType);

        // position all of the segments between the symbols
        for(let i=0; i<pr.symbolReels.length-1; i++)
        {
            addOn = this.stretchBetweenAddOns[i+1];
            nc.swoopValue(addOn,"firstPointX",globalSymbolPositions[i].x,motionDuration,tweenType);
            nc.swoopValue(addOn,"firstPointY",globalSymbolPositions[i].y,motionDuration,tweenType);
            nc.swoopValue(addOn,"secondPointX",globalSymbolPositions[i+1].x,motionDuration,tweenType);
            nc.swoopValue(addOn,"secondPointY",globalSymbolPositions[i+1].y,motionDuration,tweenType);
        }
    }
}

TypescriptProjectCode/ProjectMain.ts
------------------------------------------------------------
// This is the main entry point for this Incisor® project. 
// Throughout the project, this object can be referenced as 'pr'.
var gameSystemManager:GameSystemManager;


class ProjectMain
{
    gameLayout:GameLayout;
    dashboard:Dashboard;
    symbolReels:SymbolReel[];
    payline:Payline;
    dashboardManager:DashboardManager;
    

    async init()
    {
        // create a shortcut to the gameSystemManager
        gameSystemManager = new GameSystemManager();
        await gameSystemManager.init();
        await gameSystemManager.fetchGameSystemInfo();

        // put the main camera into 'maximizeSafeZone' mode
        nc.mainCamera.adaptiveCameraMode = constants.adaptiveCameraModes.maximizeSafeZone;

        // setup main GameLayout Construct
        this.gameLayout = nc.constructDefs.GameLayout.add(nc.mainScene,"GameLayout");
        // create shortcut to Dashboard
        this.dashboard = this.gameLayout.descendantsByName.Dashboard;

        // make the gamelayout view area invisible
        this.gameLayout.descendantsByName.ViewArea.enabled = false;
        // enable game intro brackground immediately, and add press callback
        this.gameLayout.descendantsByName.GameIntroBackground.enable();

        // add callback for keyDown 
        nc.appEvents.keyDown.addCallback(this,"keyDownCallback")

        // create canvas resize callback to adjust the aspect ratio of the GameLayout Construct
        nc.appEvents.canvasResize.addCallback(this,"adjustGameLayout");
        this.adjustGameLayout();

        // create instance of DashboardManager
        this.dashboardManager = new DashboardManager();

        // set bet and balance
        this.dashboard.descendantsByName.BetMeter.string = gameSystemManager.formatCurrency(gameSystemManager.currentBet);
        this.dashboard.descendantsByName.BalanceMeter.string = gameSystemManager.formatCurrency(gameSystemManager.currentBalance);
        
        // the SymbolReels are laid out within the GameLayout Construct, so they are collected rather than created here
        this.symbolReels = [];
        for(let i=0; i<gameSystemManager.initialGameLogicData.reelData.length; i++)
        {
            let symbolReel:SymbolReel = this.gameLayout.descendantsByName["SymbolReel"+i];
            // supply the symbol class, which replaces the stand-in symbols the reel was laid out with
            symbolReel.symbolClassDefinition = ReelSymbol;
            // the game system supplies a full reel strip, so the reel does not assemble its data as it spins
            symbolReel.assembleReelDataOnTheFly = false;
            symbolReel.setReelData(gameSystemManager.initialGameLogicData.reelData[i]);
            symbolReel.addReelStateChangeCallback(this,"reelStateChangeCallback",i);
            this.symbolReels.push(symbolReel);
        }

        // create Payline
        this.payline = new Payline(nc.mainScene,"Payline");

        // create main game FlowController
        nc.defineFlowController("MainGameFlow");
        nc.flows.MainGameFlow.addFlowState(GameIntro);
        nc.flows.MainGameFlow.addFlowState(GameIdle);
        nc.flows.MainGameFlow.addFlowState(StartGame);
        nc.flows.MainGameFlow.addFlowState(SpinReels);
        nc.flows.MainGameFlow.addFlowState(WinCelebration);
        nc.flows.MainGameFlow.GameIntro.setToCurrentState(true);
    }


    adjustGameLayout()
    {
        // acquire aspect ratio
        let canvasResolution = nc.getCanvasPixelResolution();
        let aspectRatio = canvasResolution.x/canvasResolution.y;

        // set GameLayout construct's time based on aspect ratio
        let timeValue=aspectRatio;
        if(aspectRatio<=1)
        {
            timeValue = -1/aspectRatio; 
        }
        this.gameLayout.timelines.BaseLayout_Desktop.time=timeValue;
        this.gameLayout.timelines.BaseLayout_EgmDualScreen.time=timeValue;
        this.gameLayout.timelines.BaseLayout_EgmSingleScreen.time=timeValue;
        this.gameLayout.timelines.BaseLayout_Mobile.time=timeValue;

        // determine which layout to use
        let isEGM = false;
        CODE.includeIf___EgmPublish;
            isEGM = true;
        CODE.includeEnd___EgmPublish;
        let isDualScreen = false;
        CODE.includeIf___isDualScreen;
            isDualScreen = true;
        CODE.includeEnd___isDualScreen;
        if(!isEGM)
        {
            if(nc.cursorMode==="touch")
            {
                this.gameLayout.timelines.BaseLayout_Mobile.takeWeight(0);
            }
            else
            {
                this.gameLayout.timelines.BaseLayout_Desktop.takeWeight(0);
            }
        }
        else
        {
            if(isDualScreen)
            {
                this.gameLayout.timelines.BaseLayout_EgmDualScreen.takeWeight(0);
            }
            else
            {
                this.gameLayout.timelines.BaseLayout_EgmSingleScreen.takeWeight(0);
            }
        }
    }


    keyDownCallback(event)
    {
        if(event.key===" ")
        {
            this.mainPlayerInput();
        }
    }


    mainPlayerInput()
    {
        // if in GameIdle, move to StartGame FlowState
        if(nc.flows.MainGameFlow.currentFlowState.name==="GameIdle")
        {
            nc.flows.MainGameFlow.StartGame.setToCurrentState(true);
        }
        // if in SpinReels, and if the conditions are met, slam the reels
        if(nc.flows.MainGameFlow.currentFlowState.name==="SpinReels")
        {
            // slam the reels if the game outcome has been populated 
            if(gameSystemManager.currentGameOutcome!==undefined && nc.flows.MainGameFlow.SpinReels.allReelsHaveStarted===true)
            {
                for(let i=0; i<pr.symbolReels.length; i++)
                {
                    pr.symbolReels[i].slam();
                }
            }
        }
        // if in WinCelebration, slam the win meter if it's rolling, otherwise move to StartGame FlowState
        if(nc.flows.MainGameFlow.currentFlowState.name==="WinCelebration")
        {
            // slam the win meters if needed
            if(nc.flows.MainGameFlow.WinCelebration.winRollupAmount!==gameSystemManager.currentGameOutcome.totalWin)
            {
                nc.flows.MainGameFlow.WinCelebration.winRollupComplete();
            }
            // move to StartGame FlowState
            else
            {
                nc.flows.MainGameFlow.WinCelebration.cleanUpWinCelebration();
                nc.flows.MainGameFlow.StartGame.setToCurrentState(true);
            }
        }
    }


    processNewGameOutcome()
    {
        // inform the symbol reels of their target stops
        for(let i=0; i<pr.symbolReels.length; i++)
        {
            pr.symbolReels[i].setTarget(gameSystemManager.currentGameOutcome.reelStops[i]);
        }

        // sync the balance meter 
        let newBalanceString = gameSystemManager.formatCurrency(gameSystemManager.currentBalance);
        pr.gameLayout.descendantsByName.Dashboard.descendantsByName.BalanceMeter.string = newBalanceString;
    }

    
    reelStateChangeCallback(newState,oldState,reelIndex)
    {
        if(newState==="bounce")
        {
            nc.sounds.ReelStop.playOnce();
        }
    }
}

TypescriptProjectCode/ReelSymbol.ts
------------------------------------------------------------
/** The symbol class for the SymbolReels laid out in the GameLayout Construct. A SymbolReel constructs one of these
 * for every position on its reel path, and calls 'setSymbol' whenever the symbol a given object represents changes.
 * The class is handed to each reel in code, through 'SymbolReel.symbolClassDefinition'.
 */
class ReelSymbol extends GraphicObject
{
    /** Written by the owning SymbolReel every time the reel lays out - where this symbol sits along the reel path. */
    pathPosition:number;


    constructor(parent:SceneObject,name:string)
    {
        // a SymbolReel constructs its symbols with a parent and a name only, so the graphic arrives through 'setSymbol'
        super(undefined,parent,name);

        // make the symbol 'masked' by the ReelMask masking group
        this.masking.makeMasked(nc.maskGroups.ReelMask,false);
        this.layer = nc.layers.Reels;

        // give the symbol a BrightnessContrast EffectNode for easy 'dimming'
        this.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.ColorMultiply,nc.effectNodes.BrightnessContrast]);
    }


    // called by the owning SymbolReel whenever the symbol this object represents changes
    setSymbol(symbol:string)
    {
        // a reel position with no data, or a symbol naming no GraphicAsset, falls back to the WhiteBox so the reel stays visible
        let graphicAsset:GraphicAsset;
        if(symbol!==undefined){graphicAsset = nc.graphicAssets[symbol];}
        if(graphicAsset===undefined){graphicAsset = nc.graphicAssets.WhiteBox;}
        this.setGraphicAsset(graphicAsset,true,false);
    }
}

Utilities/AuxiliaryPublishingSupport/ElectronEgmPublish/ElectronMain/ElectronMain.js
------------------------------------------------------------
// a new set of parameters is populated based on the given 'auxiliaryPublishingPackage' as defined in the Incisor ProjectSettings
var incisorBrowserWindowParameters = IncisorBrowserParameters; // these are populated by Incisor from the associated auxiliaryPublishingPackages

const { app, BrowserWindow} = require('electron');
const path = require('path');
const url = require('url');
var win;

function createWindow() 
{
    incisorBrowserWindowParameters.webPreferences.preload = path.join(__dirname, 'preload.js');
    incisorBrowserWindowParameters.show = false;

    // the window is created
    win = new BrowserWindow(incisorBrowserWindowParameters);
    win.setAlwaysOnTop(incisorBrowserWindowParameters.alwaysOnTop, incisorBrowserWindowParameters.level);
    win.setVisibleOnAllWorkspaces(incisorBrowserWindowParameters.visibleOnAllWorkspaces); 
    

    // load the page created
    win.loadURL
    (
        url.format
        (
            {
                pathname: path.join(__dirname, 'index.html'),
                protocol: 'file',
                slashes: true
            }
        )
    );

    // window positioning
    var windowPositioning = function () 
    {
        const bp = incisorBrowserWindowParameters;

        win.show();
        // win.setMenuBarVisibility(false); - this may be needed by some implementation of linux

        // set capabilities first
        win.setResizable(true);
        win.setMovable(true);
        win.setFullScreenable(true);

        // bounds only if not entering any fullscreen-like mode
        const wantsFullscreen = !!bp.postDelayFullscreen;
        const wantsKiosk = !!bp.postDelayKiosk;
        const wantsSimple = !!bp.postDelaySimpleFullscreen && process.platform === "darwin";

        if (!wantsFullscreen && !wantsKiosk && !wantsSimple) 
        {
            win.setBounds({ x: bp.postDelayX, y: bp.postDelayY, width: bp.postDelayWidth, height: bp.postDelayHeight });
        }

        // only call the mode we want
        if (wantsKiosk) {win.setKiosk(true);} 
        else if (wantsSimple) {win.setSimpleFullScreen(true);} 
        else if (wantsFullscreen) 
        {
            win.setFullScreen(true);
            // setImmediate(() => win.setFullScreen(true));
        } 
        else 
        {
            // optionally ensure we aren't in any mode
            win.setFullScreen(false);
            if (process.platform === "darwin") win.setSimpleFullScreen(false);
            win.setKiosk(false);
        }

        // now apply final locks
        win.setFullScreenable(bp.postDelayFullscreenable);
        win.setResizable(bp.postDelayResizable);
        win.setMovable(bp.postDelayMovable);
        win.setMenuBarVisibility(bp.postDelayMenuBarVisible);
        win.setAutoHideMenuBar(bp.postDelayAutoHideMenuBar);
    };

    // function called when window is ready to show
    var readyToShowFunction = function()
    {
        setTimeout(windowPositioning, incisorBrowserWindowParameters.windowPositionDelay, [win,incisorBrowserWindowParameters] );
    };
    win.once('ready-to-show',readyToShowFunction);

    // set win to null on close
    win.on('closed', ()=>{win = null;});
}

app.on('ready', createWindow);

app.on('window-all-closed', () => {app.quit();});

app.on('activate', () => { if (win === null) {createWindow();}});


// a simple example of a context (right click) menu.
if(incisorBrowserWindowParameters.enableContextMenu===true)
{
    const {Menu} = require('electron');
    const contextMenu = Menu.buildFromTemplate([
            { label: 'Inspect Element', click() { win.webContents.openDevTools(); } },
            { label: 'Reload', click() { win.reload(); } },
            { type: 'separator' },
            { label: 'Close', click() { win.close(); } }
        ]);

    function registerContextMenu()
    {
        if (win) { win.webContents.on('context-menu', (e, params) => { contextMenu.popup({ window: win }); }); }
    }

    app.on('ready', registerContextMenu);
}





Utilities/AuxiliaryPublishingSupport/ElectronEgmPublish/ElectronMain/GRPC.js
------------------------------------------------------------
const { ipcMain } = require('electron');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
let service;
let twoWayStream;


ipcMain.handle('GrpcService.requestAndResponse', async (event, args) => {
    let promise = new Promise((resolve, reject) => {
        service.requestAndResponse(args,
            (err, response) => {
                if (err)
                {
                    return reject({value: err, type: "error"});
                }
                resolve({value: response, type: "data"});
            }
        );
    });
    try
    {
        let response = await promise;
        return response;
    }
    catch (error)
    {
        return error;
    }
});


ipcMain.handle('GrpcService.createTwoWayStream', async (event, args) => {
    twoWayStream = service.createTwoWayStream(args,
        (err, response) => {}
    );
    try
    {
        twoWayStream.on('data', async value => {
            win.webContents.send("GrpcService.message", {value:value, type:'data'});
        });
        twoWayStream.on('error', async value => {
            win.webContents.send("GrpcService.message", {value:value, type:'error'});
        });
        twoWayStream.on('status', async value => {
            win.webContents.send("GrpcService.message", {value:value, type:'status'});
        });
        twoWayStream.on('end', async value => {
            win.webContents.send("GrpcService.message", {value:value, type:'end'});
        });
        return true;
    }
    catch (error)
    {
        return error;
    }
});


function createGrpcClient()
{
    let loadParams = {
        keepCase: true,
        longs: String,
        enums: String,
        defaults: true,
        oneofs: true,
    };
    const grpcConnectionPackageDefinitionString = protoLoader.loadSync(path.join(__dirname,'ConnectionDefinition.proto'), loadParams);
    const grpcConnectionPackageDefinition = grpc.loadPackageDefinition(grpcConnectionPackageDefinitionString);
    service = new grpcConnectionPackageDefinition.grpcConnection.GrpcService(
        'localhost:50051',
        grpc.credentials.createInsecure()
    );
}
app.on('ready', createGrpcClient);



Utilities/AuxiliaryPublishingSupport/ElectronEgmPublish/ElectronPackage/package.json
------------------------------------------------------------
{
    "name": "IncisorSlotTemplateTS",
    "productName": "Incisor Slot Template TS",
    "version": "1.0.0",
    "description": "Incisor Slot Template TS",
    "author": 
    {
        "name": "Incisor Slot Template TS",
        "email": "dev@example.com"
    },
    "main": "main.js",
    "devDependencies": 
    {
        "electron": "33.0.2",
        "electron-builder": "25.1.8"
    },
    "dependencies": 
    {
        "@grpc/grpc-js": "^1.14.3",
        "@grpc/proto-loader": "^0.8.0"
    },
    "build": 
    {
        "appId": "com.example.IncisorSlotTemplateTS",
        "productName": "IncisorSlotTemplateTS",
        "files": 
        [
            "./**/*",
            "main.js",
            "!publish/"
        ],
        "linux": 
        {
            "target": 
            [
                "AppImage",
                "deb"
            ],
            "category": "Game",
            "maintainer": "IncisorSlotTemplateTS <dev@example.com>"
        },
        "mac":
        {
            "target": ["dmg"]
        },
        "win": 
        {
            "target": ["nsis"]
        }
    }
}

Utilities/AuxiliaryPublishingSupport/ElectronEgmPublish/ElectronPreload/ElectronPreload.js
------------------------------------------------------------
// This preload.js file runs in Electron's renderer process before the web page loads and is 
// used as a secure bridge between the UI and Electron/Node functionality. It is the 
// recommended place to expose a small, controlled API to the renderer (for example via 
// contextBridge) and to set up safe IPC communication with the main process while keeping 
// nodeIntegration disabled and contextIsolation enabled for better security. Only 
// functionality that the renderer truly needs should be exposed here, and it should be done 
// in a way that avoids giving the page direct access to full Node or Electron internals.


const { contextBridge, ipcRenderer, ipcMain } = require('electron');
contextBridge.exposeInMainWorld('GrpcService', {
    createTwoWayStream: async () => { return ipcRenderer.invoke('GrpcService.createTwoWayStream', {}); },
    requestAndResponse: async (message) => { return ipcRenderer.invoke('GrpcService.requestAndResponse', { message }); },
    setResponseCallback: (callback) => ipcRenderer.on('GrpcService.message', (event, ...args) => callback(...args))
});


Utilities/AuxiliaryPublishingSupport/ElectronLocalDev/ElectronMain/ElectronMain.js
------------------------------------------------------------
// a new set of parameters is populated based on the given 'auxiliaryPublishingPackage' as defined in the Incisor ProjectSettings
var incisorBrowserWindowParameters = IncisorBrowserParameters; // these are populated by Incisor from the associated auxiliaryPublishingPackages

const { app, BrowserWindow} = require('electron');
const path = require('path');
const url = require('url');
var win;

function createWindow() 
{
    incisorBrowserWindowParameters.webPreferences.preload = path.join(__dirname, 'preload.js');
    incisorBrowserWindowParameters.show = false;

    // the window is created
    win = new BrowserWindow(incisorBrowserWindowParameters);
    win.setAlwaysOnTop(incisorBrowserWindowParameters.alwaysOnTop, incisorBrowserWindowParameters.level);
    win.setVisibleOnAllWorkspaces(incisorBrowserWindowParameters.visibleOnAllWorkspaces); 
    

    // load the page created
    win.loadURL
    (
        url.format
        (
            {
                pathname: path.join(__dirname, 'index.html'),
                protocol: 'file',
                slashes: true
            }
        )
    );

    // window positioning
    var windowPositioning = function () 
    {
        const bp = incisorBrowserWindowParameters;

        win.show();
        // win.setMenuBarVisibility(false); - this may be needed by some implementation of linux

        // set capabilities first
        win.setResizable(true);
        win.setMovable(true);
        win.setFullScreenable(true);

        // bounds only if not entering any fullscreen-like mode
        const wantsFullscreen = !!bp.postDelayFullscreen;
        const wantsKiosk = !!bp.postDelayKiosk;
        const wantsSimple = !!bp.postDelaySimpleFullscreen && process.platform === "darwin";

        if (!wantsFullscreen && !wantsKiosk && !wantsSimple) 
        {
            win.setBounds({ x: bp.postDelayX, y: bp.postDelayY, width: bp.postDelayWidth, height: bp.postDelayHeight });
        }

        // only call the mode we want
        if (wantsKiosk) {win.setKiosk(true);} 
        else if (wantsSimple) {win.setSimpleFullScreen(true);} 
        else if (wantsFullscreen) 
        {
            win.setFullScreen(true);
            // setImmediate(() => win.setFullScreen(true));
        } 
        else 
        {
            // optionally ensure we aren't in any mode
            win.setFullScreen(false);
            if (process.platform === "darwin") win.setSimpleFullScreen(false);
            win.setKiosk(false);
        }

        // now apply final locks
        win.setFullScreenable(bp.postDelayFullscreenable);
        win.setResizable(bp.postDelayResizable);
        win.setMovable(bp.postDelayMovable);
        win.setMenuBarVisibility(bp.postDelayMenuBarVisible);
        win.setAutoHideMenuBar(bp.postDelayAutoHideMenuBar);
    };

    // function called when window is ready to show
    var readyToShowFunction = function()
    {
        setTimeout(windowPositioning, incisorBrowserWindowParameters.windowPositionDelay, [win,incisorBrowserWindowParameters] );
    };
    win.once('ready-to-show',readyToShowFunction);

    // set win to null on close
    win.on('closed', ()=>{win = null;});
}

app.on('ready', createWindow);

app.on('window-all-closed', () => {app.quit();});

app.on('activate', () => { if (win === null) {createWindow();}});


// a simple example of a context (right click) menu.
if(incisorBrowserWindowParameters.enableContextMenu===true)
{
    const {Menu} = require('electron');
    const contextMenu = Menu.buildFromTemplate([
            { label: 'Inspect Element', click() { win.webContents.openDevTools(); } },
            { label: 'Reload', click() { win.reload(); } },
            { type: 'separator' },
            { label: 'Close', click() { win.close(); } }
        ]);

    function registerContextMenu()
    {
        if (win) { win.webContents.on('context-menu', (e, params) => { contextMenu.popup({ window: win }); }); }
    }

    app.on('ready', registerContextMenu);
}





Utilities/AuxiliaryPublishingSupport/ElectronLocalDev/ElectronPackage/package.json
------------------------------------------------------------
{
    "name": "__PROJECT_CODE_NAME__",
    "productName": "__PROJECT_NAME__",
    "version": "1.0.0",
    "description": "Description for __PROJECT_NAME__",
    "author": 
    {
        "name": "__PROJECT_NAME__",
        "email": "dev@example.com"
    },
    "main": "main.js",
    "devDependencies": 
    {
        "electron": "33.0.2",
        "electron-builder": "^25.1.8"
    },
    "build": 
    {
        "appId": "com.example.__PROJECT_CODE_NAME__",
        "productName": "__PROJECT_CODE_NAME__",
        "files": 
        [
            "./**/*",
            "main.js",
            "!publish/"
        ],
        "linux": 
        {
            "target": 
            [
                "AppImage",
                "deb"
            ],
            "category": "Game",
            "maintainer": "__PROJECT_CODE_NAME__ <dev@example.com>"
        },
        "mac":
        {
            "target": ["dmg"]
        },
        "win": 
        {
            "target": ["nsis"]
        }
    }
}

Utilities/AuxiliaryPublishingSupport/ElectronLocalDev/ElectronPreload/ElectronPreload.js
------------------------------------------------------------
// This preload.js file runs in Electron's renderer process before the web page loads and is 
// used as a secure bridge between the UI and Electron/Node functionality. It is the 
// recommended place to expose a small, controlled API to the renderer (for example via 
// contextBridge) and to set up safe IPC communication with the main process while keeping 
// nodeIntegration disabled and contextIsolation enabled for better security. Only 
// functionality that the renderer truly needs should be exposed here, and it should be done 
// in a way that avoids giving the page direct access to full Node or Electron internals.

// Example uses of context bridge:
// const { contextBridge } = require('electron');
// contextBridge.exposeInMainWorld('preloadObjectExposedOnMainWindow', {"note":"This object has been added to the main window from within the Electron 'preload' context."});
// contextBridge.exposeInMainWorld('preloadFunctionExposedOnMainWindow',  async () => { console.log("This is a preload function made accessable within the main window runtime.");});

Utilities/MinificationLists/DoNotMinifyLists/DoNotMinifyList.json
------------------------------------------------------------
{
	"minificationList":
    [
        "thisSymbolWillNotBeMinified",
        "thisSymbolWillAlsoNotBeMinified"
    ]
}

Utilities/MinificationLists/MinifyLists/MinifyList.json
------------------------------------------------------------
{
	"minificationList":
    [
        "thisSymbolWillBeMinified",
        "thisSymbolWillAlsoBeMinified"
    ]
}

Utilities/ProjectData.json
------------------------------------------------------------
{
	"docFormatVersion":1,
	"dataObjects":[
		{
			"type":"rowData",
			"name":"SymbolHierarchy",
			"id":"7XazMZnZuBaMDdubaieR",
			"tags":[],
			"tables":[
				{
					"name":"mainData",
					"isRowData":true,
					"data":[
						["AMajor1","Major1","Wild",""],
						["AMajor2","Major2","Wild",""],
						["AMajor3","Major3","Wild",""],
						["AMinor1","Minor1","Wild",""],
						["AMinor2","Minor2","Wild",""],
						["AMinor3","Minor3","Wild",""],
						["","","",""]
					]
				}
			]
		},
		{
			"type":"slotReels",
			"name":"Reels",
			"id":"OTGh4TvQi2TyxVcxytI5",
			"tags":[],
			"tables":[
				{
					"name":"distribution",
					"isRowData":false,
					"data":[
						["Symbols","Major1","Major2","Major3","Minor1","Minor2","Minor3","Wild","Bonus","","","","","","",""],
						["Reel0","3","9","3","9","3","9","2","3","","","","","","",""],
						["Reel1","9","3","9","3","9","3","2","0","","","","","","",""],
						["Reel2","3","9","3","9","3","9","2","2","","","","","","",""],
						["Reel3","9","3","9","3","9","3","2","0","","","","","","",""],
						["Reel4","3","9","3","9","3","9","2","1","","","","","","",""]
					]
				},
				{
					"name":"reels",
					"data":[
						[
							"Reel0",
							"Minor1",
							"Major1",
							"Major1",
							"Major1",
							"Minor1",
							"Bonus",
							"Minor3",
							"Bonus",
							"Minor1",
							"Major3",
							"Major3",
							"Major3",
							"Minor3",
							"Minor1",
							"Minor2",
							"Bonus",
							"Minor3",
							"Minor1",
							"Minor3",
							"Minor1",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor3",
							"Minor1",
							"Minor2",
							"Minor1",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor3",
							"Minor1",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor2",
							"Wild",
							"Wild"
						],
						[
							"Reel1",
							"Minor2",
							"Major3",
							"Major3",
							"Major3",
							"Minor3",
							"Major3",
							"Major3",
							"Major3",
							"Minor1",
							"Minor2",
							"Major1",
							"Major1",
							"Major1",
							"Minor2",
							"Minor1",
							"Minor2",
							"Wild",
							"Wild",
							"Minor1",
							"Minor2",
							"Major3",
							"Major3",
							"Major3",
							"Minor2",
							"Major2",
							"Major2",
							"Major2",
							"Minor2",
							"Major1",
							"Major1",
							"Major1",
							"Minor2",
							"Minor3",
							"Major1",
							"Major1",
							"Major1",
							"Minor2",
							"Minor3",
							"",
							"",
							""
						],
						[
							"Reel2",
							"Bonus",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor1",
							"Major1",
							"Major1",
							"Major1",
							"Minor1",
							"Major2",
							"Major2",
							"Major2",
							"Minor3",
							"Minor1",
							"Major2",
							"Major2",
							"Major2",
							"Minor1",
							"Minor3",
							"Wild",
							"Wild",
							"Minor2",
							"Minor1",
							"Major3",
							"Major3",
							"Major3",
							"Minor1",
							"Minor3",
							"Minor1",
							"Bonus",
							"Minor3",
							"Minor1",
							"Minor3",
							"Minor2",
							"Minor3",
							"Minor2",
							"Minor3",
							"Minor1",
							"Minor3",
							""
						],
						[
							"Reel3",
							"Minor2",
							"Minor1",
							"Minor2",
							"Minor1",
							"Wild",
							"Wild",
							"Minor1",
							"Minor3",
							"Minor2",
							"Major3",
							"Major3",
							"Major3",
							"Minor2",
							"Major3",
							"Major3",
							"Major3",
							"Minor2",
							"Minor3",
							"Major1",
							"Major1",
							"Major1",
							"Minor2",
							"Major3",
							"Major3",
							"Major3",
							"Minor2",
							"Major1",
							"Major1",
							"Major1",
							"Minor2",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor2",
							"Major1",
							"Major1",
							"Major1",
							"",
							"",
							""
						],
						[
							"Reel4",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor1",
							"Minor2",
							"Major1",
							"Major1",
							"Major1",
							"Minor3",
							"Minor1",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor3",
							"Minor1",
							"Minor2",
							"Minor1",
							"Minor3",
							"Minor1",
							"Minor2",
							"Wild",
							"Wild",
							"Minor1",
							"Minor3",
							"Major3",
							"Major3",
							"Major3",
							"Minor1",
							"Minor3",
							"Major2",
							"Major2",
							"Major2",
							"Minor3",
							"Minor1",
							"Minor3",
							"Bonus",
							"Minor1",
							"",
							""
						]
					]
				}
			],
			"numReels":5,
			"selfRepelBuffer":1,
			"selfRepelWeight":1,
			"symbolColors":{
				"Major1":{"x":1,"y":0,"z":0},
				"Major2":{"x":1,"y":0,"z":0},
				"Major3":{"x":1,"y":0,"z":0},
				"Wild":{"x":1,"y":0.8532000000000016,"z":0},
				"Bonus":{"x":0.6066666666666667,"y":0.6066666666666667,"z":1}
			},
			"symbolSeparationRules":[
				{
					"symbols":["Major1","Major2","Major3","Wild","Bonus"],
					"reels":["Reel0","Reel1","Reel2","Reel3","Reel4"],
					"bufferSize":1,
					"weight":1
				}
			],
			"symbolStacking":[
				{"symbols":["Major1","Major2","Major3"],"reels":["Reel0","Reel1","Reel2","Reel3","Reel4"],"stackHeight":3},
				{"symbols":["Wild"],"reels":["Reel0","Reel1","Reel2","Reel3","Reel4"],"stackHeight":2}
			],
			"reelsToGenerate":["Reel0","Reel1","Reel2","Reel3","Reel4"]
		},
		{
			"type":"rowData",
			"name":"Pays",
			"id":"Yzzh4Ji4shHwV678tWKN",
			"tags":[],
			"tables":[
				{
					"name":"mainData",
					"isRowData":true,
					"data":[
						["","3 oak","4 oak","5 oak",""],
						["AMajor1","10","25","100",""],
						["AMajor2","10","25","100",""],
						["AMajor3","10","25","100",""],
						["AMinor1","5","15","50",""],
						["AMinor2","5","15","50",""],
						["AMinor3","5","15","50",""],
						["","","","",""]
					]
				}
			]
		},
		{
			"type":"slotPaylines",
			"name":"Paylines",
			"id":"9bNSJwWxdVHc8HdHCzas",
			"tags":[],
			"tables":[
				{
					"name":"paylines",
					"isRowData":true,
					"data":[
						["Payline","Col0","Col1","Col2","Col3","Col4"],
						["payline 0","0","0","0","0","0"],
						["payline 1","0","0","1","0","0"],
						["payline 2","0","0","1","2","2"],
						["payline 3","0","1","0","1","0"],
						["payline 4","0","1","1","1","0"],
						["payline 5","0","1","1","1","2"],
						["payline 6","0","1","2","1","0"],
						["payline 7","1","0","0","0","1"],
						["payline 8","1","0","1","0","1"],
						["payline 9","1","0","1","2","1"],
						["payline 10","1","1","0","1","1"],
						["payline 11","1","1","1","1","1"],
						["payline 12","1","1","2","1","1"],
						["payline 13","1","1","2","3","3"],
						["payline 14","1","2","1","0","1"],
						["payline 15","1","2","1","2","1"],
						["payline 16","1","2","2","2","1"],
						["payline 17","1","2","2","2","3"],
						["payline 18","1","2","3","2","1"],
						["payline 19","2","1","0","1","2"],
						["payline 20","2","1","1","1","0"],
						["payline 21","2","1","1","1","2"],
						["payline 22","2","1","2","1","2"],
						["payline 23","2","1","2","3","2"],
						["payline 24","2","2","1","0","0"],
						["payline 25","2","2","1","2","2"],
						["payline 26","2","2","2","2","2"],
						["payline 27","2","2","3","2","2"],
						["payline 28","2","3","2","1","2"],
						["payline 29","2","3","2","3","2"],
						["payline 30","2","3","3","3","2"],
						["payline 31","3","2","1","2","3"],
						["payline 32","3","2","2","2","1"],
						["payline 33","3","2","2","2","3"],
						["payline 34","3","2","3","2","3"],
						["payline 35","3","3","2","1","1"],
						["payline 36","3","3","2","3","3"],
						["payline 37","3","3","3","3","3"],
						["payline 38","1","1","2","2","2"],
						["payline 39","2","2","1","1","1"]
					]
				},
				{"name":"columnHeights","data":[["Col0","4"],["Col1","4"],["Col2","4"],["Col3","4"],["Col4","4"]]},
				{"name":"columnTopOffsets","data":[["Col0","0"],["Col1","0"],["Col2","0"],["Col3","0"],["Col4","0"]]},
				{"name":"maxLineJump","data":[["Col 0-1","1"],["Col 1-2","1"],["Col 2-3","1"],["Col 3-4","1"]]}
			],
			"numColumns":5,
			"includedSymmetries":["symmetricFlipped","symmetric"]
		}
	],
	"exportSettings":[]
}

Utilities/ProjectState.json
------------------------------------------------------------
{
	"docFormatVersion":0,
	"panelLayout":{
		"subPanels":[
			{
				"subPanels":[
					{
						"subPanels":[
							{"subPanels":[],"panelType":"Object","isColumns":true,"divisionLocation":0.5,"stateInfo":""},
							{"subPanels":[],"panelType":"Hierarchy","isColumns":true,"divisionLocation":0.5,"stateInfo":""}
						],
						"isColumns":false,
						"divisionLocation":0.47747821956596986,
						"stateInfo":""
					},
					{"subPanels":[],"panelType":"Flows","isColumns":true,"divisionLocation":0.5,"stateInfo":""}
				],
				"isColumns":true,
				"divisionLocation":0.47510167727385966,
				"stateInfo":""
			},
			{
				"subPanels":[
					{
						"subPanels":[
							{"subPanels":[],"panelType":"Live View","isColumns":true,"divisionLocation":0.5,"stateInfo":"{}"},
							{
								"subPanels":[],
								"panelType":"Construct",
								"isColumns":true,
								"divisionLocation":0.5,
								"stateInfo":"{\"targetConstructName\":\"Major1Construct\",\"targetViewMode\":\"Editor Mode\",\"targetConstructState\":\"SymbolAnimation\"}"
							}
						],
						"isColumns":true,
						"divisionLocation":0.6774325620451619,
						"stateInfo":""
					},
					{
						"subPanels":[],
						"panelType":"Timeline",
						"isColumns":true,
						"divisionLocation":0.5,
						"stateInfo":"{\"graphModeRows\":{\"Minor1Construct\":{\"SymbolAnimation\":{\"3387500474395755|position.x\":true}}},\"currentTime\":{\"Minor1Construct\":{\"SymbolAnimation\":1.4666666666666444},\"Major1Construct\":{\"SymbolAnimation\":0},\"Major2Construct\":{\"SymbolAnimation\":0.04999999999999179},\"WildConstruct\":{\"SymbolAnimation\":0.5666666666666326},\"Major3Construct\":{\"SymbolAnimation\":0.13974387467482913},\"GameLayout\":{\"BaseLayout_Desktop\":1.4833333333333334,\"BaseLayout_Mobile\":0.6333333333333333,\"BaseLayout_EgmSingleScreen\":0.26666666666666666,\"BaseLayout_EgmDualScreen\":-0.16666666666666666},\"Dashboard\":{\"Layout_Desktop\":-1.5,\"Layout_EGM\":-0.95}},\"scroll\":{\"Dashboard\":{\"Layout_Desktop\":0.09329517767952111,\"Layout_EGM\":0.9497036102650089},\"GameLayout\":{\"BaseLayout_Mobile\":1,\"BaseLayout_Desktop\":1,\"BaseLayout_EgmSingleScreen\":1}},\"constructName\":\"Major1Construct\",\"timelineName\":\"SymbolAnimation\",\"timeView\":{\"Major1Construct\":{\"SymbolAnimation\":{\"left\":-0.1,\"right\":2.1}}}}"
					}
				],
				"isColumns":false,
				"divisionLocation":0.6558493049272016,
				"stateInfo":""
			}
		],
		"isColumns":true,
		"divisionLocation":0.31882927090997254,
		"stateInfo":""
	},
	"selectionState":{"sceneObject":["[[-1,\"Timeline Editor Scene: Major1Construct→SymbolAnimation\"],[0,\"Major1Construct\"]]"]},
	"hierarchyExpansionInfo":{
		"Construct Editor Scene: GameLayout":[
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[1,\"Construct Editor Camera\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[0,\"ViewArea\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[6,\"BackgroundShadow\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[7,\"GameBackgroundPattern\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[0,\"ReelBackground\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[2,\"ReelContainer1\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[5,\"ReelContainer4\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[1,\"BottomBarBackground\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[3,\"SpinButtonContainer\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[1,\"ReelContainer0\"],[0,\"ReelMask\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[2,\"ReelContainer1\"],[0,\"ReelMask\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[3,\"ReelContainer2\"],[0,\"ReelMask\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[4,\"ReelContainer3\"],[0,\"ReelMask\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[5,\"ReelContainer4\"],[0,\"ReelMask\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[0,\"BalanceLabel\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[1,\"BalanceMeter\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[2,\"BetLabel\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[3,\"BetMeter\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[4,\"WinMeter\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[5,\"WinLabel\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[6,\"BottomBarTitle\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[7,\"MenuButton\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[2,\"BottomBarContainer\"],[8,\"SoundButton\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"],[0,\"GameLayout\"],[3,\"Dashboard\"],[3,\"SpinButtonContainer\"],[0,\"SpinButton\"]]",
			"[[-1,\"Construct Editor Scene: GameLayout\"]]"
		],
		"Timeline Editor Scene: Dashboard→Layout_Mobile":[
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[10,\"AutplayContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"]]"
		],
		"Construct Editor Scene: Dashboard":[
			"[[-1,\"Construct Editor Scene: Dashboard\"],[1,\"Construct Editor Camera\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[0,\"ViewArea\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[2,\"BottomBarBackground\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[1,\"BalanceLabel\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[2,\"BalanceMeter\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[3,\"BetLabel\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[4,\"BetMeter\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[5,\"WinMeter\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[6,\"WinLabel\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[7,\"BottomBarTitle\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[8,\"MenuButton\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[9,\"SoundButton\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[4,\"SpinButtonContainer\"],[0,\"SpinButton\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"],[0,\"Dashboard\"],[4,\"SpinButtonContainer\"],[0,\"SpinButton\"],[0,\"SpinButtonCenter\"]]",
			"[[-1,\"Construct Editor Scene: Dashboard\"]]"
		],
		"Construct Editor Scene: GameIntroAnimation":[
			"[[-1,\"Construct Editor Scene: GameIntroAnimation\"],[0,\"GameIntroAnimation\"]]",
			"[[-1,\"Construct Editor Scene: GameIntroAnimation\"],[0,\"GameIntroAnimation\"],[0,\"GameIntroTitle\"]]",
			"[[-1,\"Construct Editor Scene: GameIntroAnimation\"]]"
		],
		"Timeline Editor Scene: GameLayout→BaseLayout_Mobile":[
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"]]"
		],
		"MainScene":[
			"[[-1,\"MainScene\"],[1,\"GameLayout\"]]",
			"[[-1,\"MainScene\"],[1,\"GameLayout\"],[1,\"GameTitleContainer\"]]",
			"[[-1,\"MainScene\"],[1,\"GameLayout\"],[2,\"ReelsContainer\"]]",
			"[[-1,\"MainScene\"]]"
		],
		"Construct Editor Scene: PaylineConstruct":[
			"[[-1,\"Construct Editor Scene: PaylineConstruct\"],[0,\"PaylineConstruct\"]]",
			"[[-1,\"Construct Editor Scene: PaylineConstruct\"]]"
		],
		"Construct Editor Scene: Major1Construct":[
			"[[-1,\"Construct Editor Scene: Major1Construct\"],[0,\"Major1Construct\"]]",
			"[[-1,\"Construct Editor Scene: Major1Construct\"]]"
		],
		"Construct Editor Scene: Major2Construct":[
			"[[-1,\"Construct Editor Scene: Major2Construct\"],[0,\"Major2Construct\"]]",
			"[[-1,\"Construct Editor Scene: Major2Construct\"]]"
		],
		"Construct Editor Scene: Minor3Construct":[
			"[[-1,\"Construct Editor Scene: Minor3Construct\"],[0,\"Minor3Construct\"]]",
			"[[-1,\"Construct Editor Scene: Minor3Construct\"]]"
		],
		"Construct Editor Scene: Major3Construct":[
			"[[-1,\"Construct Editor Scene: Major3Construct\"],[0,\"Major3Construct\"]]",
			"[[-1,\"Construct Editor Scene: Major3Construct\"]]"
		]
	},
	"timelineSceneRepExpansionInfo":{
		"Timeline Editor Scene: GameLayout→BaseLayout":[
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout\"],[1,\"GameLayout\"],[0,\"ViewArea\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout\"],[1,\"GameLayout\"],[1,\"GameTitleContainer\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout\"],[1,\"GameLayout\"],[2,\"ReelsContainer\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout\"],[1,\"GameLayout\"],[2,\"ReelsContainer\"],[1,\"ReelBackground\"]]"
		],
		"Timeline Editor Scene: GameLayout→BaseLayout_Mobile":[
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[0,\"ViewArea\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[1,\"GameTitleContainer\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[2,\"ReelsContainer\"],[0,\"ReelBackground\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[3,\"Dashboard\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[6,\"BackgroundShadow\"]]",
			"[[-1,\"Timeline Editor Scene: GameLayout→BaseLayout_Mobile\"],[0,\"GameLayout\"],[7,\"GameBackgroundPattern\"]]"
		],
		"Timeline Editor Scene: Dashboard→Layout_Mobile":[
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[0,\"ViewArea\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[1,\"MenuBackgroundDimmer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[2,\"BottomBarBackground\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[0,\"BottomBarBorder\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[1,\"BalanceLabel\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[2,\"BalanceMeter\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[3,\"BetLabel\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[4,\"BetMeter\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[5,\"WinMeter\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[6,\"WinLabel\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[7,\"BottomBarTitle\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[8,\"MenuButton\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[9,\"SoundButton\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[10,\"AutplayContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[10,\"AutplayContainer\"],[0,\"Autoplay Button\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[3,\"BottomBarContainer\"],[10,\"AutplayContainer\"],[1,\"Autoplay Menu\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[4,\"SpinButtonContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[4,\"SpinButtonContainer\"],[0,\"SpinButton\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[4,\"SpinButtonContainer\"],[0,\"SpinButton\"],[0,\"SpinButtonCenter\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[5,\"MainMenuContainer\"]]",
			"[[-1,\"Timeline Editor Scene: Dashboard→Layout_Mobile\"],[0,\"Dashboard\"],[5,\"MainMenuContainer\"],[0,\"MainMenuBackground\"]]"
		],
		"Timeline Editor Scene: GameIntroAnimation→Intro":[
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Intro\"],[0,\"GameIntroAnimation\"],[0,\"GameIntroTitle\"]]",
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Intro\"],[0,\"GameIntroAnimation\"],[0,\"GameIntroTitle\"],[0,\"PressToContinueText\"]]",
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Intro\"],[0,\"GameIntroAnimation\"],[1,\"GameIntroParticles\"]]"
		],
		"Timeline Editor Scene: GameIntroAnimation→Outro":[
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Outro\"],[0,\"GameIntroAnimation\"],[0,\"GameIntroTitle\"]]",
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Outro\"],[0,\"GameIntroAnimation\"],[0,\"GameIntroTitle\"],[0,\"PressToContinueText\"]]",
			"[[-1,\"Timeline Editor Scene: GameIntroAnimation→Outro\"],[0,\"GameIntroAnimation\"],[1,\"GameIntroParticles\"]]"
		]
	},
	"animatedPropertyGraphEditorStateInfo":{
		"Timeline Editor Scene: GameLayout→BaseLayout":[],
		"Timeline Editor Scene: GameLayout→BaseLayout_Mobile":[],
		"Timeline Editor Scene: Dashboard→Layout_Mobile":[],
		"Timeline Editor Scene: GameIntroAnimation→Intro":[
			["[[-1,\"Timeline Editor Scene: GameIntroAnimation→Intro\"],[0,\"GameIntroAnimation\"]]","Intro",0],
			["[[-1,\"Timeline Editor Scene: GameIntroAnimation→Intro\"],[0,\"GameIntroAnimation\"]]","Intro",1]
		],
		"Timeline Editor Scene: GameIntroAnimation→Outro":[]
	},
	"assetSelections":[],
	"helloThere":false,
	"spineImportHistory":[],
	"recentPermissions":"v1,pro",
	"publishingPopupStateInfo":{"currentConfiguration":"EgmDualScreenPublish","hostPublishedProject":true}
}

Utilities/ProjectTranscript.json
------------------------------------------------------------
{
	"docFormatVersion":0,
	"transcriptPhrases":{
		"CreditMeterLabel":{"en":"BALANCE","es":"CRÉDITO"},
		"WinMeterLabel":{"en":"WIN","es":"GANANCIA"},
		"BetMeterLabel":{"en":"BET","es":"APUESTA"},
		"BottomBarGameTitle":{"en":"INCISOR 7s™","es":"INCISOR 7s™"},
		"IntroPromptButton":{"en":"PRESS TO CONTINUE","es":"PRESIONE PARA CONTINUAR"},
		"AutoplaySelection":{"en":"{value:nSpins}\nSPINS","es":"{value:nSpins}\nTIRADAS"},
		"AutoplayLabel":{"en":"AUTOPLAY","es":"AUTOJUGAR"}
	}
}

Assets.ncData
------------------------------------------------------------
Deviations from default ncData:

- allowDuplicateRemoval is true instead of the default null.
- assetConfigurationFilters is {} instead of the default null.
- fontFamily is "" instead of the default null.
- imageConfigurations.allowAdditiveTrimBuffer is false instead of the default null.
- imageConfigurations.alphaThreshold is 0.015 instead of the default null.
- imageConfigurations.applyAssetPackageScaling is true instead of the default null.
- imageConfigurations.compression is "paletted" instead of the default null.
- imageConfigurations.downscalingMode is "linear" instead of the default null.
- imageConfigurations.imageScalingAffectsHugging is false instead of the default null.
- imageConfigurations.mirroring is "none" instead of the default null.
- imageConfigurations.pivotPointOffsetX is 0 instead of the default null.
- imageConfigurations.pivotPointOffsetY is 0 instead of the default null.
- imageConfigurations.pivotPointOffsetZ is 0 instead of the default null.
- imageConfigurations.premultiplyAlpha is true instead of the default null.
- imageConfigurations.resolutionScaleX is 1 instead of the default null.
- imageConfigurations.resolutionScaleY is 1 instead of the default null.
- imageConfigurations.shapify is false instead of the default null.
- imageConfigurations.shapifyEdgeRange is 10 instead of the default null.
- imageConfigurations.shapifyOptimizationLevel is 0.85 instead of the default null.
- imageConfigurations.spriteSheet is "" instead of the default null.
- imageConfigurations.spriteSheetDimensionLimit is 2048 instead of the default null.
- imageConfigurations.spriteSheetPlacementBuffer is 2 instead of the default null.
- imageConfigurations.trimBuffer is 2 instead of the default null.
- imageConfigurations.trimMode is "hugged" instead of the default null.
- imageConfigurations.unitsPerPixelX is 1 instead of the default null.
- imageConfigurations.unitsPerPixelY is 1 instead of the default null.
- imageConfigurations.unitsPerPixelZ is 1 instead of the default null.
- imageConfigurations.upscalingMode is "linear" instead of the default null.
- imageConfigurations.wrapModeH is "clamp" instead of the default null.
- imageConfigurations.wrapModeV is "clamp" instead of the default null.
- includeWhenBuilt is true instead of the default null.
- loadingTier is 100 instead of the default null.
- typeFontScale is 5 instead of the default null.

ProjectSettings.json
------------------------------------------------------------
{"docFormatVersion":0,"publicProjectName":"Incisor Slot Template TS","projectCodeName":"IncisorSlotTemplateTS","latestIncisorVersionSetUsed":"Crimson","latestIncisorVersionUsed":"2026.10.15.09.15.36","requiredPermissions":"proGaming","usingTypescript":true,"assetConfigurationDefinitions":{"assetPackageScale":["100","50"],"soundQuality":["stereo_115","mono_55"],"language":["en","es"]},"assetConfigurationDataOrder":["assetPackageScale","soundQuality","language"],"conditionalCodeTagDefinitions":["LocalDev","WebPublish","EgmPublish","isDualScreen"],"coreCanvasResolutionX":2160,"coreCanvasResolutionY":2160,"canvasTransparency":false,"mainCameraType":"orthographic","maskingMode":"overlapping","defaultTimelineTimeSnap":0.02,"preserveDrawingBuffer":true,"defaultGraphicAssetEffectNodes":["ColorMultiply"],"devModeConfiguration":"LocalDev","configurations":{"LocalDev":{"publishIndexFile":true,"supportedAssetConfigurations":[{"assetPackageScale":"100","soundQuality":"stereo_115","language":"en"}],"conditionalCodeTagsIncluded":["LocalDev"],"optionalCodeModulesExcluded":[],"minification":{"enableMinification":false,"automaticallyMinifyAllKeywords":false,"minifyPrefix":"minify_","minifySuffix":"_minify","doNotMinifyPrefix":"doNotMinify_","doNotMinifySuffix":"_doNotMinify","minifyIncisorApiKeywords":false,"minifyAssetNames":false,"substitutionAssignment":"deterministicRandom","keywordAndStringPairTreatment":"minifyBoth"},"removeComments":false,"removeWhiteSpace":false,"spriteSheetDimensionLimit":4096,"auxiliaryPublishingPackages":[]},"EgmSingleScreenPublish":{"publishIndexFile":true,"supportedAssetConfigurations":[{"assetPackageScale":"100","soundQuality":"stereo_115","language":"en"}],"conditionalCodeTagsIncluded":["EgmPublish"],"optionalCodeModulesExcluded":[],"minification":{"enableMinification":false,"automaticallyMinifyAllKeywords":true,"minifyPrefix":"minify_","minifySuffix":"_minify","doNotMinifyPrefix":"doNotMinify_","doNotMinifySuffix":"_doNotMinify","minifyIncisorApiKeywords":false,"minifyAssetNames":false,"substitutionAssignment":"deterministicRandom","keywordAndStringPairTreatment":"minifyBoth"},"removeComments":false,"removeWhiteSpace":false,"spriteSheetDimensionLimit":4096,"auxiliaryPublishingPackages":["ElectronEgmPublish"]},"EgmDualScreenPublish":{"publishIndexFile":true,"supportedAssetConfigurations":[{"assetPackageScale":"100","soundQuality":"stereo_115","language":"en"}],"conditionalCodeTagsIncluded":["EgmPublish","isDualScreen"],"optionalCodeModulesExcluded":[],"minification":{"enableMinification":false,"automaticallyMinifyAllKeywords":true,"minifyPrefix":"minify_","minifySuffix":"_minify","doNotMinifyPrefix":"doNotMinify_","doNotMinifySuffix":"_doNotMinify","minifyIncisorApiKeywords":false,"minifyAssetNames":false,"substitutionAssignment":"deterministicRandom","keywordAndStringPairTreatment":"minifyBoth"},"removeComments":false,"removeWhiteSpace":false,"spriteSheetDimensionLimit":4096,"auxiliaryPublishingPackages":["ElectronEgmPublish"]}},"auxiliaryPublishingPackageDefinitions":{"electron":{"ElectronLocalDev":{"os":"--win --x64","width":800,"height":800,"x":0,"y":0,"windowPositionDelay":0,"center":false,"minWidth":0,"minHeight":0,"maxWidth":0,"maxHeight":0,"resizable":true,"movable":true,"minimizable":true,"maximizable":true,"closable":true,"focusable":true,"level":"normal","fullscreen":false,"fullscreenable":true,"simpleFullscreen":false,"skipTaskbar":false,"kiosk":false,"icon":"","frame":true,"menuBarVisible":false,"autoHideMenuBar":true,"transparent":false,"type":"normal","backgroundColor":"#FFF","hasShadow":true,"opacity":1,"visualEffectState":"followWindow","darkTheme":false,"vibrancy":"default","zoomToPageWidth":false,"enableContextMenu":false,"incisorFileIoLayer":true,"allowUniversalFileIO":false,"webPreferences":{"nodeIntegration":false,"contextIsolation":true,"enableRemoteModule":false,"preload":"","sandbox":false,"devTools":true,"zoomFactor":1,"javascript":true,"webSecurity":true,"allowRunningInsecureContent":false,"experimentalFeatures":false,"backgroundThrottling":true,"webviewTag":false,"nativeWindowOpen":false,"scrollBounce":false,"offscreen":false,"plugins":false,"webaudio":false,"disableDialogs":false}},"ElectronEgmPublish":{"os":"--win --x64","width":800,"height":800,"x":0,"y":0,"windowPositionDelay":0,"center":false,"minWidth":0,"minHeight":0,"maxWidth":0,"maxHeight":0,"resizable":true,"movable":true,"minimizable":true,"maximizable":true,"closable":true,"focusable":true,"level":"normal","fullscreen":false,"fullscreenable":true,"simpleFullscreen":false,"skipTaskbar":false,"kiosk":false,"icon":"","frame":true,"menuBarVisible":true,"autoHideMenuBar":false,"transparent":false,"type":"normal","backgroundColor":"#FFF","hasShadow":true,"opacity":1,"visualEffectState":"followWindow","darkTheme":false,"vibrancy":"default","zoomToPageWidth":false,"enableContextMenu":true,"incisorFileIoLayer":true,"allowUniversalFileIO":false,"webPreferences":{"nodeIntegration":false,"contextIsolation":true,"enableRemoteModule":false,"preload":"","sandbox":false,"devTools":true,"zoomFactor":1,"javascript":true,"webSecurity":true,"allowRunningInsecureContent":false,"experimentalFeatures":false,"backgroundThrottling":true,"webviewTag":false,"nativeWindowOpen":false,"scrollBounce":false,"offscreen":false,"plugins":false,"webaudio":false,"disableDialogs":false}}}},"autoClearMetaFiles":true,"limitPublishedBuildsKept":0,"enableDynamicDocumentation":true,"screenShotDestination":"ScreenShots","additionalLiveViewModes":["16x9_maximize","9x16_maximize","1920x1080","1080x1920"],"fontDefinitions":[{"fontName":"ThemedFont","kerningAdjustment":0,"lineHeight":600,"characterWidth":90,"alwaysIncludeTheseCharacters":[],"phrasesUsingThisFont":["IntroPromptButton"]},{"fontName":"SampleFont","kerningAdjustment":0,"lineHeight":72,"characterWidth":12,"alwaysIncludeTheseCharacters":[],"phrasesUsingThisFont":["CreditMeterLabel","WinMeterLabel","New Phrase 1","AutoplaySelection","AutoplayLabel"]}],"loadingTierDefinitions":[{"loadingTier":100,"isAutoLoaded":true,"incrementalContentProcessing":false,"assetDataFileSizeLimitKB":800,"performDuplicateRemoval":true}],"fontReduction":{"includeStandardCharactersWhenUnPublished":true,"includeStandardCharactersWhenPublished":true,"includeTranscriptCharacters":true,"limitTranscriptCharactersByLanguage":true,"limitTranscriptCharactersByPhrase":true,"standardFontCharacters":[33,34,35,36,37,38,39,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,8482]}}

ReleaseNotes.json
------------------------------------------------------------
{
    "2026.10.14.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Symbol Constructs added for animation",
                "description":"Each symbol now has a Construct in 'Assets/SymbolConstructs' that recreates its image from separate parts, with a Precomp Camera so it generates a Precomp. The reels still display the symbol images."
            },
            {
                "name":"SymbolAnimation Timelines",
                "description":"Each symbol Construct has a two second 'SymbolAnimation' Timeline, authored with 'bezier' interpolation and Keyframe handles so each property needs only a few Keyframes."
            },
            {
                "name":"Winning symbols play their SymbolAnimation",
                "description":"During a win, WinCelebration swaps each winning symbol to its Construct's Precomp GraphicAsset while the animation plays, then restores the image when it completes and during cleanup. The old win scaling was removed."
            },
            {
                "name":"Symbol masking is turned off while animating",
                "description":"Animating symbols are no longer clipped by the ReelMask. Masking is restored with the symbol image, and the win cleanup re-enables it on every symbol."
            },
            {
                "name":"Fixed some reels not spinning when spins were requested in rapid succession",
                "description":"SpinReels now waits for every reel to be 'stopped' rather than 'bounce', so a new spin can't begin while a reel is still bouncing and ignoring 'beginSpin'."
            }
        ]
    },
    "2026.08.12.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Reels upgraded from SlotReel to SymbolReel",
                "description":"The five reels are now SymbolReels rather than SlotReels. A SymbolReel drives any property of its symbols from a KeyframedValue sampled along the reel path, so the symbol spacing and the reverse shingled sub-layering are authored as curves rather than written in code, and the windup and bounce motion are curves owned by the reel rather than tween functions."
            },
            {
                "name":"The reels are laid out in the GameLayout Construct",
                "description":"Each ReelContainer now holds its own SymbolReel, with its symbol counts, spin speed, windup duration, symbol path and starting symbols all authored in the Construct and editable in the Incisor inspector. ProjectMain collects the reels from the Construct and hands each one its symbol class and its reel strip, rather than building them from scratch."
            },
            {
                "name":"SlotReelSymbol codeAsset replaced by the ReelSymbol class",
                "description":"The symbol class is now an ordinary project class in 'TypescriptProjectCode/ReelSymbol.ts', supplied to each reel through 'SymbolReel.symbolClassDefinition'. It is no longer a CustomObject registered with the Incisor inspector, since a SymbolReel owns and builds its own symbols."
            },
            {
                "name":"The reels are fed a full reel strip",
                "description":"The reels now take their reel strips from the game system through 'setReelData' with 'assembleReelDataOnTheFly' turned off, which is the arrangement that matches a game system supplying stop indices."
            }
        ]
    },
    "2026.03.03.00.00.00":
    {
        "changeList":
        [
            {
                "name":"GRPC Refactored to be Agnostic",
                "description":"For simpler integrations with external systems, now the GRPC just sends any messages between the project and outside GRPC processes generically, with the details of the messaging stored inside of the messages themselves. This way, the GRPC protocol does not need to be edited each time a new type of message is needed, instead the message handling can just be extended directly in each context."
            }
        ]
    },
    "2026.02.07.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Added support auxiliary publishing packages",
                "description":"Added two electron publishing packages to the ProjectSettings.json"
            },
            {
                "name":"Added conditional code to support GRPC server interactions within the EgmPublish configuraiton",
                "description":"Now, initial game info and game outcomes are pulled from a GRPC server when the game is published in the 'EgmPublish' configuration."
            },
            {
                "name":"Added Sample GRPC servers to the auxiliary publishing support directories",
                "description":"These servers, when runnning, will supply the published game (using the 'EgmPublish' config), with it's initial game info and game outcomes."
            }
        ]
    },
    "2026.01.27.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Updates Slot Template Publisher",
                "description":"Certain ts files were being left in the js build - this has been updated."
            },
            {
                "name":"Stray Project Extension Removed",
                "description":"Extra menu that was accidently added has been removed."
            },
            {
                "name":"Minification Settings Restored",
                "description":"Minification settings for the template have been reduced for better 'getting started' setup."
            }
        ]
    },
    "2025.10.23.00.00.00":
    {
        "changeList":
        [
            {
                "name":"The GameLogicManager has become the GameSystemManager",
                "description":"It is now the manager for not just game logic, but also game configurations etc..."
            },
            {
                "name":"Autoplay Functionality Added",
                "description":"Button, menu, options driven by the GameSystemManager, and the actual functionality for autoplay have all been added."
            },
            {
                "name":"Main Menu Stub Added",
                "description":"Now you can press the button to see a main menu stub."
            }
        ]
    },
    "2025.10.19.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Translated 'PRESS TO CONTINUE'",
                "description":"Now using the transcript..."
            }
        ]
    },
    "2025.10.15.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Updated GameLogicManager/LocalGameServiceStub Interface",
                "description":"In order to provide a better example of how the GameLogicManager communicates with externally fetched items."
            },
            {
                "name":"Changed the SlotReels to use CustomObjects instead of CustomAddons",
                "description":"By request to make a cleaner and less verbose implementation."
            }
        ]
    },
    "2025.09.30.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Added Initial Translations.",
                "description":"For basic dashboard items."
            }
        ]
    },
    "2025.09.29.00.00.00":
    {
        "changeList":
        [
            {
                "name":"Added the Payline class and implementation.",
                "description":"Using the 'StretchBetween2d' CustomAddOn..."
            }
        ]
    }
}


tsconfig.json
------------------------------------------------------------
{
    "compilerOptions": {
        "outDir": "./ProjectCode/TypescriptGeneratedJS",
        "rootDir": "./",
        "target" : "ES2017",
        "module" : "ES6",
        "sourceMap": false,
        "types": [],
        "noImplicitAny": false,
        "strict": false
    },
    "include": ["**/*.ts","Utilities/IncisorAPI.d.ts"],
    "exclude": ["Publishing","AutoSave"]
}

Incisor® Template Library

IncisorTemplateLibrary.txt

Incisor® Template Library
This document is part of the compiled knowledge base for the Incisor® Software Development Platform.
Any use of this content is subject to the INCISOR® end user license and terms of use agreement.
https://www.incisordev.com/eultua
2026.11.05.12.18.12






----------------------------------------------------------
TABLE OF CONTENTS:
----------------------------------------------------------
Section 1: Template Library Overview
Section 2: Custom AddOns/Button/ButtonTreatmentExample
Section 3: Custom AddOns/GraphicObject/BlinnPhongLighting
Section 4: Custom AddOns/GraphicObject/Shadow
Section 5: Custom AddOns/GraphicObject/StretchBetween2D
Section 6: Custom AddOns/SceneObject/ChaseCursorExample
Section 7: Custom AddOns/TextAssembly/TextAssemblyWaveExample
Section 8: Custom AddOns/TextBox/TextBoxClockExample
Section 9: Custom AddOns/blank template
Section 10: Custom AddOns/comprehensive template
Section 11: Custom Objects/Button/ButtonTreatmentExample
Section 12: Custom Objects/TextAssembly/TextAssemblyWaveExample
Section 13: Custom Objects/TextBox/FrameRateCounter
Section 14: Custom Objects/TextBox/TextBoxClockExample
Section 15: Custom Objects/blank template
Section 16: Custom Objects/comprehensive template
Section 17: Effect Nodes/Arch
Section 18: Effect Nodes/BrightnessContrast
Section 19: Effect Nodes/Bulge
Section 20: Effect Nodes/ColorBlend
Section 21: Effect Nodes/Colorize
Section 22: Effect Nodes/ContourShading
Section 23: Effect Nodes/GradientFourColors
Section 24: Effect Nodes/GradientThreeColors
Section 25: Effect Nodes/GradientTwoColors
Section 26: Effect Nodes/HueSaturationValue
Section 27: Effect Nodes/MatCap
Section 28: Effect Nodes/NormalMap
Section 29: Effect Nodes/ShapifyStroke
Section 30: Effect Nodes/Shear
Section 31: Effect Nodes/Sheen
Section 32: Effect Nodes/blank template
Section 33: Global Extensions/CustomMenu
Section 34: Global Extensions/CustomPanel
Section 35: Global Extensions/FileIoExample
Section 36: Global Extensions/PopupExample
Section 37: Global Extensions/ProjectConnectionActions
Section 38: Global Extensions/PublishActions
Section 39: Global Extensions/UiComponentsExample
Section 40: Global Extensions/blank template
Section 41: Motion Types/Bounce
Section 42: Motion Types/InfiniteAdd
Section 43: Motion Types/Modulo
Section 44: Motion Types/MoveInCircle
Section 45: Motion Types/PingPong
Section 46: Motion Types/Sway
Section 47: Motion Types/SwayUniform
Section 48: Motion Types/blank template
Section 49: Project Extensions/CustomMenu
Section 50: Project Extensions/CustomPanel
Section 51: Project Extensions/FileIoExample
Section 52: Project Extensions/PopupExample
Section 53: Project Extensions/ProjectConnectionActions
Section 54: Project Extensions/PublishActions
Section 55: Project Extensions/Specialized Tools/ExtensionsBundleManager
Section 56: Project Extensions/UiComponentsExample
Section 57: Project Extensions/blank template
Section 58: Tween Types/AccelerateAndBounce
Section 59: Tween Types/Arc
Section 60: Tween Types/BulletTimeDoubleArc
Section 61: Tween Types/EaseIn
Section 62: Tween Types/EaseOut
Section 63: Tween Types/ExtremeEaseIn
Section 64: Tween Types/ExtremeEaseOut
Section 65: Tween Types/Oscillate
Section 66: Tween Types/Overshoot
Section 67: Tween Types/Windup
Section 68: Tween Types/WindupOvershoot
Section 69: Tween Types/blank template










----------------------------------------------------------
Section 1: Template Library Overview
----------------------------------------------------------


The Template Library is the collection of ready-made items in the Template Library tab of the Incisor® Inspector. Each section after this one describes one Template Library item: its title, its path in the Template Library, what it does, examples of using it, and its source code.

An item's path is its category, then any sub-category, then its title, for example 'Motion Types/Sway'. The 'blank template' items in each category are empty starting points.

When an item is added to a project, the user chooses its name. In the content, 'incr_replaceText_NameSubstitution' marks where that name goes, and other names that begin with 'incr_replaceText_' are likewise replaced when the item is added.

Categories and the number of items in each:
  Custom AddOns: 9
  Custom Objects: 6
  Effect Nodes: 16
  Global Extensions: 8
  Motion Types: 8
  Project Extensions: 9
  Tween Types: 12










----------------------------------------------------------
Section 2: Custom AddOns/Button/ButtonTreatmentExample
----------------------------------------------------------


Title: ButtonTreatmentExample
Template Library Path: Custom AddOns/Button/ButtonTreatmentExample
Type: CustomAddOn
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom AddOns/Button/ButtonTreatmentExample:
Adds a full set of interactive behaviors to any existing Button.

Cursor rollover fade, press and release scaling, drag-to-move, and scroll-to-rotate, with every tuning value exposed as a registered property. Sets buttonActive on its owner, so the Button does not need to be activated separately.

'rolloverAlpha' (default .6) is the alpha the Button fades to while the cursor is over it. 'pressScale' (.9) and 'releaseScale' (1.1) are the scales it takes going down and springing back, and 'returnDuration' (.25) is how long in seconds it takes to settle to its normal size afterward - it is held at or above 0. 'scrollRotateSpeed' (1) multiplies how far a scroll over the Button turns it.

A CustomAddOn attaches behavior to an object that already exists, rather than being an object in its own right. Add one to a selected object under CustomAddOn Info in the Object Panel, or build it against its owner in code - new ButtonTreatmentExample(object) - and reach it afterward as object.customAddOns.ButtonTreatmentExample. It extends CustomAddOn_Button, so only a Button will accept it, and an object carries at most one of each. Registered properties are the ones the GUI can see: adjustable in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom AddOns/Button/ButtonTreatmentExample:
// Incisor Template Library - ButtonTreatmentExample: giving a Button its rollover, press, drag and scroll behavior.
// Requires Template Library items: ButtonTreatmentExample

let button = new Button(nc.graphicAssets.icon_checkmark,nc.mainScene,"Button");
button.scale.scaleByFactor(4);

// Normally this is added to a Button under CustomAddOn Info in the Object Panel. Doing it in code is the same step. It
// extends CustomAddOn_Button, so only a Button will take it, and it sets buttonActive on its owner as it attaches -
// the Button does not have to be activated separately.
let treatment = new ButtonTreatmentExample(button);

// rolloverAlpha is what the Button fades to under the cursor. pressScale and releaseScale are the squash going down and
// the spring coming back, and returnDuration is how long in seconds it takes to settle afterward.
treatment.rolloverAlpha = .7;
treatment.pressScale = .85;
treatment.releaseScale = 1.15;
treatment.returnDuration = .3;

// Drag the Button to move it, and scroll over it to turn it - this is how fast the scroll turns it.
treatment.scrollRotateSpeed = 2;

Content of Custom AddOns/Button/ButtonTreatmentExample, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// Adds a range of interactive functionality to any Button, including cursorIn/Out, press/release, drag, and scroll.
class incr_replaceText_NameSubstitution extends CustomAddOn_Button
{
    

    constructor(owner)
    {
        // Call the super constructor
        super(owner);

        // Add properties that affect the Button's behavior
        this.rolloverAlpha = .6;
        this.pressScale = .9;
        this.releaseScale = 1.1;
        this.returnDuration = .25;
        this.scrollRotateSpeed = 1;

        // Helper Vars
        this.currentCursorPosition = new Vector3();
        this.previousCursorPosition = new Vector3();
        this.governingCamera = null;

        // Activate Button
        this.owner.buttonActive=true;

        // Adding Button Callbacks
        this.owner.addCursorInCallback(this,"cursorInCallback");
        this.owner.addCursorOutCallback(this,"cursorOutCallback");
        this.owner.addPressCallback(this,"pressCallback");
        this.owner.addReleaseCallback(this,"releaseCallback");
        this.owner.addDragCallback(this,"dragCallback");
        this.owner.addDropCallback(this,"releaseCallback"); 
        this.owner.addScrollCallback(this,"scrollCallback"); 
    }

    cursorInCallback()
    {
        this.owner.colorMultiply.alpha = this.rolloverAlpha;
    }

    cursorOutCallback()
    {
        this.owner.colorMultiply.alpha = 1;
        this.owner.scale.swoop.all(1,0);
    }

    pressCallback()
    {
        this.owner.scale.swoop.all(this.pressScale);
        if(this.governingCamera===null)
        {
            let descendants = this.owner.containingScene.getDescendants();
            for(let i=0; i<descendants.length; i++)
            {
                if(descendants[i].inheritedTypes.Camera!==undefined)
                {
                    this.governingCamera=descendants[i]  ;
                }
            }
        }
        this.governingCamera.getCursorPosition(this.currentCursorPosition);
        this.previousCursorPosition.copy(this.currentCursorPosition);
    }

    releaseCallback()
    {
        this.owner.scale.swoop.all(this.releaseScale);
        this.owner.scale.swoop.all(1,this.returnDuration);
    }

    dragCallback()
    {
        this.governingCamera.getCursorPosition(this.currentCursorPosition);
        let globalPosition = this.owner.getGlobalPosition();
        globalPosition.x+=this.currentCursorPosition.x-this.previousCursorPosition.x; 
        globalPosition.y+=this.currentCursorPosition.y-this.previousCursorPosition.y; 
        this.owner.swoopGlobalPosition([globalPosition.x,globalPosition.y,globalPosition.z]);
        this.previousCursorPosition.copy(this.currentCursorPosition);
    }

    scrollCallback(event)
    {
        this.owner.rotation.z+=event.deltaY*.1*this.scrollRotateSpeed;
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks
CODE.runBeforeInit___begin;
    // Register the CustomAddOn with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomAddOn(incr_replaceText_NameSubstitution,"Adds interactive behaviors to a Button: cursor rollover fade, press/release scaling, drag movement, and scroll rotation.");

    // Create validation function for 'returnDuration' - this will be used in the property registration to have the GUI input validated
    this.incr_replaceText_nameSubstitution_returnDurationValidation=function(val)
    {
        if(val<0){return(0);}
        return(val);
    };

    // Register properties with the Incisor inspector so that they can be supervised from within the GUI, and also animated within Construct Timelines
    var incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"rolloverAlpha","The alpha multiplier applied to the Button when the cursor is over it.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"pressScale","The scale multiplier applied to the Button when pressed.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"releaseScale","The scale multiplier applied to the Button on release before returning to normal.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"returnDuration","The duration in seconds for the Button to return to its default scale after release. Must be non-negative.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty.validationCallbackOwner = this;
    incr_replaceText_nameSubstitution_registeredProperty.validationCallbackName = "incr_replaceText_nameSubstitution_returnDurationValidation";
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"scrollRotateSpeed","The multiplier for how quickly the Button rotates in response to scroll events.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 3: Custom AddOns/GraphicObject/BlinnPhongLighting
----------------------------------------------------------


Title: BlinnPhongLighting
Template Library Path: Custom AddOns/GraphicObject/BlinnPhongLighting
Type: CustomAddOn
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom AddOns/GraphicObject/BlinnPhongLighting:
Adds Blinn-Phong lighting to a GraphicObject, generating shader code for exactly the lighting setup it is asked for.

There are no light objects in a scene - a light here is a set of EffectControllers on the material, and the counts below are what decide how many of them the generated shader carries. Attaching the AddOn reads the owner's material presets for ambient, specular, specular exponent, and normal textures, then leaves a working setup behind it: one directional light and ambient, with a starting direction and colors. The most involved of the stock AddOns, and the one worth reading before modifying.

'ambientLight' and the counts 'numDirectionalLights', 'numPointLights' and 'numSpotLights' (0 to 8 each) say how many lights of each kind the generated shader accounts for. The response flags - 'ambientResponseColor', 'ambientResponseTexture', 'specularResponseColor', 'specularResponseTexture', 'specularResponseExponent', 'specularResponseExponentTexture' and 'normalTexture' - say which of the optional material values it reads.

The response flags are read off the material presets as the AddOn attaches, and the counts are left at one directional light, so they are there to build on rather than to fill in from nothing. Every one of them regenerates the shader on the way through, so they belong in setup rather than in an animation.

The lights themselves are not registered properties and cost nothing to change - they are EffectControllers on the material, reached as 'ambientLightColor', 'directionalLightColor0' and 'directionalLightDirection0', 'pointLightColor0' and 'pointLightPosition0', and the matching spot light set. Those are what to animate.

A CustomAddOn attaches behavior to an object that already exists, rather than being an object in its own right. Add one to a selected object under CustomAddOn Info in the Object Panel, or build it against its owner in code - new BlinnPhongLighting(object) - and reach it afterward as object.customAddOns.BlinnPhongLighting. It extends CustomAddOn_GraphicObject, so only a GraphicObject will accept it, and an object carries at most one of each. Registered properties are the ones the GUI can see: adjustable in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom AddOns/GraphicObject/BlinnPhongLighting:
// Incisor Template Library - BlinnPhongLighting: lighting an object with a generated Blinn-Phong shader.
// Requires Template Library items: BlinnPhongLighting

// Coin has real surface direction to light, where a flat quad would come out evenly lit. Its .mtl also fills in the
// normal map and specular values that this AddOn reads off the material presets as it attaches.
let coin = new GraphicObject(nc.graphicAssets.Coin,nc.mainScene,"Coin");

// In the GUI this is added under CustomAddOn Info in the Object Panel, where each property below is a field. Attaching
// it already leaves a working setup behind - one directional light and ambient, with a starting direction and colors.
let lighting = new BlinnPhongLighting(coin);

// The counts say how many lights of each kind the generated shader carries. Changing one regenerates that shader, so
// these belong in setup rather than in an animation.
lighting.numDirectionalLights = 1;
lighting.numPointLights = 1;

// There are no light objects in a scene - a light is a set of EffectControllers on the material, reached the way any
// other controller is. These are cheap to change and are the ones to animate.
coin.materialMaster.directionalLightColor0.red = 1;
coin.materialMaster.directionalLightColor0.green = .95;
coin.materialMaster.directionalLightColor0.blue = .8;
coin.materialMaster.pointLightPosition0.x = 150;
coin.materialMaster.pointLightPosition0.y = 150;
coin.materialMaster.pointLightPosition0.z = 200;
coin.materialMaster.pointLightColor0.red = .2;
coin.materialMaster.pointLightColor0.green = .4;
coin.materialMaster.pointLightColor0.blue = 1;
coin.materialMaster.pointLightColor0.alpha = 1;

// Turn the coin so the highlights travel across a surface that is actually facing different ways. Rotation is in degrees.
coin.rotation.swoop.y(360,9,nc.tweenTypes.Linear);

Content of Custom AddOns/GraphicObject/BlinnPhongLighting, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
class incr_replaceText_NameSubstitution extends CustomAddOn_GraphicObject
{
    

    constructor(owner)
    {
        super(owner);
        this._ambientLight = false;
        this._numDirectionalLights = 0;
        this._numPointLights = 0;
        this._numSpotLights = 0;
        this._ambientResponseTexture = false;
        this._specularResponseTexture = false;
        this._specularResponseExponentTexture = false;
        this._normalTexture = false;
        this._ambientResponseColor = false;
        this._specularResponseColor = false;
        this._specularResponseExponent = false;
        let materialPresets = this.owner.graphicAsset.materialPresets;
        for (let m = 0; m < materialPresets.length; ++m)
        {
            let optionalValues = materialPresets[m]["optionalMaterialValues"];
            if (optionalValues !== undefined)
            {
                this._ambientResponseTexture = this._ambientResponseTexture || optionalValues.ambientTexture !== undefined;
                this._specularResponseTexture = this._specularResponseTexture || optionalValues.specularTexture !== undefined;
                this._specularResponseExponentTexture = this._specularResponseExponentTexture || optionalValues.specularExponentTexture !== undefined;
                this._normalTexture = this._normalTexture || optionalValues.normalTexture !== undefined;
                this._ambientResponseColor = this._ambientResponseColor || optionalValues.ambientColor !== undefined;
                this._specularResponseColor =  this._specularResponseColor || optionalValues.specularColor !== undefined;
                this._specularResponseExponent = this._specularResponseExponent || optionalValues.specularExponent !== undefined;
            }
        }
        this.refresh();
        this.copyPresets();
    }

    onRegisteredPropertiesRestored()
    {
        this.refresh();        
    }

    set ambientLight(val)
    {
        let _previousValue = this._ambientLight;
        this._ambientLight = val;
        this.refresh();
        if (_previousValue === false && val === true)
        {
            let materials = this.owner.getMaterials();
            for (let m = 0; m < materials.length; ++m)
            {
                let material = materials[m];
                material["ambientLightColor"].swoop.each([1, 1, 1, .3]);
            }
        }
    }

    get ambientLight()
    {
        return this._ambientLight;
    }

    set numDirectionalLights(val)
    {
        let _previousValue = this._numDirectionalLights;
        this._numDirectionalLights = val;
        this.refresh();
        for (let i = _previousValue; i < val; ++i)
        {
            let materials = this.owner.getMaterials();
            for (let m = 0; m < materials.length; ++m)
            {
                let material = materials[m];
                material["directionalLightColor" + i].swoop.each([1, 1, 1, 1]);
            }
        }
    }

    get numDirectionalLights()
    {
        return this._numDirectionalLights;
    }

    set numPointLights(val)
    {
        let _previousValue = this._numPointLights;
        this._numPointLights = val;
        this.refresh();
        for (let i = _previousValue; i < val; ++i)
        {
            let materials = this.owner.getMaterials();
            for (let m = 0; m < materials.length; ++m)
            {
                let material = materials[m];
                material["pointLightColor" + i].swoop.each([1, 1, 1, 1]);
            }
        }
    }

    get numPointLights()
    {
        return this._numPointLights;
    }

    set numSpotLights(val)
    {
        let _previousValue = this._numSpotLights;
        this._numSpotLights = val;
        this.refresh();
        for (let i = _previousValue; i < val; ++i)
        {
            let materials = this.owner.getMaterials();
            for (let m = 0; m < materials.length; ++m)
            {
                let material = materials[m];
                material["spotLightColor" + i].swoop.each([1, 1, 1, 1]);
            }
        }
    }

    get numSpotLights()
    {
        return this._numSpotLights;
    }

    set ambientResponseTexture(val)
    {
        this._ambientResponseTexture = val;
        this.refresh();
    }

    get ambientResponseTexture()
    {
        return this._ambientResponseTexture;
    }

    set ambientResponseColor(val)
    {
        this._ambientResponseColor = val;
        this.refresh();
    }

    get ambientResponseColor()
    {
        return this._ambientResponseColor;
    }
    
    set specularResponseTexture(val)
    {
        this._specularResponseTexture = val;
        this.refresh();
    }

    get specularResponseTexture()
    {
        return this._specularResponseTexture;
    }

    set specularResponseColor(val)
    {
        this._specularResponseColor = val;
        this.refresh();
    }

    get specularResponseColor()
    {
        return this._specularResponseColor;
    }

    set specularResponseExponentTexture(val)
    {
        this._specularResponseExponentTexture = val;
        this.refresh();
    }

    get specularResponseExponentTexture()
    {
        return this._specularResponseExponentTexture;
    }

    set specularResponseExponent(val)
    {
        this._specularResponseExponent = val;
        this.refresh();
    }

    get specularResponseExponent()
    {
        return this._specularResponseExponent;
    }

    set normalTexture(val)
    {
        this._normalTexture = val;
        this.refresh();
    }

    get normalTexture()
    {
        return this._normalTexture;
    }

    refresh()
    {
        let code = "incr_replaceText_NameSubstitution_";
        if (this._ambientLight)
        {
            code += "al_";
        }
        code += this._numPointLights + "pl_" + this._numDirectionalLights + "dl_" + this._numSpotLights + "sl_";
        if (this._ambientResponseTexture)
        {
            code += "at_";
        }
        if (this._specularResponseTexture)
        {
            code += "st_";
        }
         if (this._specularResponseExponentTexture)
        {
            code += "et_";
        }
        if (this._ambientResponseColor)
        {
            code += "ac_";
        }
        if (this._specularResponseColor)
        {
            code += "sc_";
        }
        if (this._specularResponseExponent)
        {
            code += "se_";
        }

        if (this._normalTexture)
        {
            //check if they have the normal map effect node defined.  if so, use it.  if not, define it and then use it.
            if (nc.effectNodes["NormalMap"] === undefined)
            {
                if (nc.effectControllers["normalMap_texture"] === undefined) nc.defineEffectController("normalMap_texture", nc.constants.effectControllerBaseTypes.Texture, ["normalMap_texture"], nc.textures.WhiteBox, "addition");
                if (nc.effectControllers["normalMap_strength"] === undefined) nc.defineEffectController("normalMap_strength", "number", ["normalMap_strength"], [1], "addition", [[0, 1]], "The strength of the per-fragment normal perturbation caused by the normal map.");
                if (nc.effectControllers["normalMap_isLeftHanded"] === undefined) nc.defineEffectController("normalMap_isLeftHanded", "number", ["normalMap_isLeftHanded"], [0], "addition", [[0, 1]], "Normal maps created using the DirectX left handed convention will have inverted Y values. Set this value to 1 to corrent this.");

                nc.defineEffectNode("NormalMap", ["varying vec3 vertPos;"], "vertPos = (modelMatrix * vec4(vertex, 1.0)).xyz;",
                    [
                        "uniform float normalMap_strength;",
                        "uniform float normalMap_isLeftHanded;",
                        "uniform sampler2D normalMap_texture;",
                        "varying vec3 vertPos;"
                    ],
                    "vec4 normalSample = texture2D(normalMap_texture, UV);\n\
                    vec3 Q1 = dFdx(vertPos);\n\
                    vec3 Q2 = dFdy(vertPos);\n\
                    vec2 st1 = dFdx(UV);\n\
                    vec2 st2 = dFdy(UV);\n\
                    vec3 N = normalize(NORMAL);\n\
                    vec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n\
                    vec3 B = -normalize(cross(N, T));\n\
                    mat3 TBN = mat3(T, B, N);\n\
                    vec3 n = normalSample.xyz;\n\
                    n.xy = (n.xy * 2.0 - vec2(1.0)) * normalMap_strength;\n\
                    n.y = normalMap_isLeftHanded > 0.5 ? -n.y : n.y;\n\
                    n = gl_FrontFacing ? n : -n;\n\
                    n = normalize(n);\n\
                    NORMAL = normalize(TBN * n);",
                    [nc.effectControllers["normalMap_texture"], nc.effectControllers["normalMap_strength"], nc.effectControllers["normalMap_isLeftHanded"]], true
                );
            }
        }

        if (nc.effectNodes[code] === undefined) this.createEffectNode(code);
        let materials = this.owner.getMaterials();
        for (let m = 0; m < materials.length; ++m)
        {
            let material = materials[m];
            let nodes = material.getEffectNodes();
            let existingIndex = nodes.findIndex((node) => node.name.startsWith("incr_replaceText_NameSubstitution_"));
            let nodeIndex = 0;
            if (existingIndex !== -1)
            {
                nodeIndex = existingIndex;
                nodes[existingIndex] = nc.effectNodes[code];
            }
            else
            {
                nodeIndex = nodes.length;
                nodes.push(nc.effectNodes[code]);
            }
            let normalMapNodeIndex = nodes.findIndex((node) => node.name === "NormalMap");
            if (this._normalTexture)
            {
                //if the effect node list already has normal map, nothing to do.
                //if it doesn't, insert it before this node
                if (normalMapNodeIndex === -1)
                {
                    nodes.splice(nodeIndex, 0, nc.effectNodes["NormalMap"]);
                }
            }
            else
            {
                //they're not using a normal map.  if you find one in the list, remove it
                if (normalMapNodeIndex !== -1)
                {
                    nodes.splice(normalMapNodeIndex, 1);
                }
            }
            material.setEffectNodes(nodes);
        }
    }

    copyPresets()
    {
        let materials = this.owner.getMaterials();
        let materialPresets = this.owner.graphicAsset.materialPresets;
        for (let m = 0; m < materials.length; ++m)
        {
            let material = materials[m];
            let optionalValues = materialPresets[m]["optionalMaterialValues"];
            if (optionalValues == undefined) continue;
            if (optionalValues.ambientTexture !== undefined && material["ambientResponseTexture"] !== undefined)
            {
                let texture = nc.textures[optionalValues.ambientTexture];
                if (texture !== undefined)
                {
                    material["ambientResponseTexture"] = texture;
                }
            }
            if (optionalValues.specularTexture !== undefined && material["specularResponseTexture"] !== undefined)
            {
                let texture = nc.textures[optionalValues.specularTexture];
                if (texture !== undefined)
                {
                    material["specularResponseTexture"] = texture;
                }
            }
            if (optionalValues.specularExponentTexture !== undefined && material["specularResponseExponentTexture"] !== undefined)
            {
                let texture = nc.textures[optionalValues.specularExponentTexture];
                if (texture !== undefined)
                {
                    material["specularResponseExponentTexture"] = texture;
                }
            }
            if (optionalValues.normalTexture !== undefined && material["normalMap_texture"] !== undefined)
            {
                let texture = nc.textures[optionalValues.normalTexture];
                if (texture !== undefined)
                {
                    material["normalMap_texture"] = texture;
                }
            }
            if (optionalValues.ambientColor !== undefined && material["ambientResponseColor"] !== undefined)
            {
                material["ambientResponseColor"].x = optionalValues.ambientColor[0]; 
                material["ambientResponseColor"].y = optionalValues.ambientColor[1];
                material["ambientResponseColor"].z = optionalValues.ambientColor[2];
            }
            if (optionalValues.specularColor !== undefined && material["specularResponseColor"] !== undefined)
            {
                material["specularResponseColor"].x = optionalValues.specularColor[0]; 
                material["specularResponseColor"].y = optionalValues.specularColor[1];
                material["specularResponseColor"].z = optionalValues.specularColor[2];
            }
            if (optionalValues.specularExponent !== undefined && material["specularResponseExponent"] !== undefined)
            {
                material["specularResponseExponent"] = optionalValues.specularExponent;
            }
            if (optionalValues.normalStrength !== undefined && material["normalStrength"] !== undefined)
            {
                material["normalStrength"] = optionalValues.normalStrength;
            }
        }
    // apply the default contour shading style setup
        this.numDirectionalLights = 1;
        this.ambientLight = true;
        for (let m = 0; m < materials.length; ++m)
        {
            let material = materials[m];
            material["directionalLightDirection0"].swoop.each([-1, -1, -1]);
            material["directionalLightColor0"].swoop.each([1, 1, .5, 1]);
            material["ambientLightColor"].swoop.each([.4, .4, 1, .75]);
        }
    }

    createEffectNode(_encodedName)
    {
        let _vertSupport = [];
        let _vertNode = "";
        let _fragSupport = [];
        let _fragNode = "";
        let _newEffectControllers = [];
        _vertSupport.push("varying vec3 vertPos;");
        _vertNode += "NORMAL = dot(NORMAL, NORMAL) > .0001 ? NORMAL : vec3(0.0, 0.0, 1.0);\n";
        _vertNode += "vertPos = (modelMatrix * vec4(vertex, 1.0)).xyz;\n";
        _fragSupport.push("varying vec3 vertPos;");
        _fragSupport.push("uniform vec3 ambientResponseColor;");
        _fragSupport.push("uniform vec3 specularResponseColor;");
        _fragSupport.push("uniform float specularResponseExponent;");
        _fragNode += "vec4 diffuseC = fragment;\n";
        if (this._ambientResponseColor)
        {
            if (nc.effectControllers["ambientResponseColor"] === undefined) nc.defineEffectController("ambientResponseColor", "Vector3", ["red", "green", "blue"], [0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1]], "The ambient light response color. Ambient light will be multiplied by this value before contributing to the lighting.",["The red component of the ambient response.", "The green component of the ambient response.", "The blue component of the ambient response."]);
            _newEffectControllers.push(nc.effectControllers["ambientResponseColor"]);
            _fragNode += "vec3 ambientC = ambientResponseColor;\n";
        }
        else
        {
            _fragNode += "vec3 ambientC = vec3(1.0);\n";
        }
        if (this._specularResponseColor)
        {
            if (nc.effectControllers["specularResponseColor"] === undefined) nc.defineEffectController("specularResponseColor", "Vector3", ["red", "green", "blue"], [0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1]], "The specular response color. Specular highlight colors will be multiplied by this value.", ["The red component of the specular response.", "The green component of the specular response.", "The blue component of the specular response."]);
            _newEffectControllers.push(nc.effectControllers["specularResponseColor"]);
            _fragNode += "vec3 specularC = specularResponseColor;\n";
        }
        else
        {
            _fragNode += "vec3 specularC = vec3(0.0);\n";
        }
        if (this._specularResponseExponent)
        {
            if (nc.effectControllers["specularResponseExponent"] === undefined) nc.defineEffectController("specularResponseExponent", "number", ["specularResponseExponent"], [0], "addition", [[0, 1000]], "The specular exponent. With higher exponent values, specular reflections will become sharper.");
            _newEffectControllers.push(nc.effectControllers["specularResponseExponent"]);
            _fragNode += "float specularE = specularResponseExponent;\n";
        }
        else
        {
            _fragNode += "float specularE = 500.0;\n";
        }
        let _defaultTexture = nc.textures.WhiteBox;
        _fragNode += "vec3 normal = normalize(NORMAL);";
        if (this._ambientResponseTexture)
        {
            if (nc.effectControllers["ambientResponseTexture"] === undefined) nc.defineEffectController("ambientResponseTexture", "Texture", [], _defaultTexture, "materialOnly");
            _newEffectControllers.push(nc.effectControllers["ambientResponseTexture"]);
            _fragSupport.push("uniform sampler2D ambientResponseTexture;");
            _fragNode += "ambientC *= texture2D(ambientResponseTexture, UV).rgb;\n";
        }
        if (this._specularResponseTexture)
        {
            if (nc.effectControllers["specularResponseTexture"] === undefined) nc.defineEffectController("specularResponseTexture", "Texture", [], _defaultTexture, "materialOnly");
            _newEffectControllers.push(nc.effectControllers["specularResponseTexture"]);
            _fragSupport.push("uniform sampler2D specularResponseTexture;");
            _fragNode += "specularC *= texture2D(specularResponseTexture, UV).rgb;\n";
        }
        if (this._specularResponseExponentTexture)
        {
            if (nc.effectControllers["specularResponseExponentTexture"] === undefined) nc.defineEffectController("specularResponseExponentTexture", "Texture", [], _defaultTexture, "materialOnly");
            _newEffectControllers.push(nc.effectControllers["specularResponseExponentTexture"]);
            _fragSupport.push("uniform sampler2D specularResponseExponentTexture;");
            _fragNode += "specularE *= dot(texture2D(specularResponseExponentTexture, UV).rgb, vec3(0.2126, 0.7152, 0.0722));\n";
        }
    // ambient light
        if (this._ambientLight)
        {
            let _name = "ambientLightColor";
            if (nc.effectControllers[_name] === undefined) nc.defineEffectController(_name, "Vector4", ["red", "green", "blue", "alpha"], [0,0,0,0], "addition", [[0, 1], [0, 1], [0, 1], [0, 1]], "The color of the ambient light ", ["The light color's red value", "The light color's green value", "The light color's blue value", "The light color's alpha value, which can be used to control the brightness of the light."]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
        }
    // directional lights
        for (let i = 0; i < this._numDirectionalLights; ++i)
        {
        // color
            let _name = "directionalLightColor" + i;
            if (nc.effectControllers[_name] === undefined) nc.defineEffectController(_name, "Vector4", ["red", "green", "blue", "alpha"], [0, 0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1], [0, 1]], "The color of directional light " + i, ["The light color's red value", "The light color's green value", "The light color's blue value", "The light color's alpha value, which can be used to control the brightness of the light."]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
        // direction
            _name = "directionalLightDirection" + i;
            if (nc.effectControllers[_name] === undefined) nc.defineEffectController(_name, "Vector3", ["x", "y", "z"], [0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1]], "The direction of directional light " + i, ["The X component of the light's direction", "The Y component of the light's direction", "The z component of the light's direction"]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec3 " + _name + ";");
        }
    // point lights
        for (let i = 0; i < this._numPointLights; ++i)
        {
        // color
            let _name = "pointLightColor" + i;
            if (nc.effectControllers[_name] === undefined) nc.defineEffectController(_name, "Vector4", ["red", "green", "blue", "alpha"], [0, 0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1], [0, 1]], "The color of directional light " + i, ["The light color's red value", "The light color's green value", "The light color's blue value", "The light color's alpha value, which can be used to control the brightness of the light."]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
        // position
            _name = "pointLightPosition" + i;
            if (nc.effectControllers[_name] === undefined) nc.defineEffectController(_name, "Vector3", ["x", "y", "z"], [0, 0, 0], "addition", [[0, 300], [0, 300], [0, 300]], "The position of point light " + i, ["The X component of the light's position", "The Y component of the light's position", "The z component of the light's position"]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec3 " + _name + ";");
        }
    // spot lights
        for (let i = 0; i < this._numSpotLights; ++i)
        {
        // color
            let _name = "spotLightColor" + i;
            if (nc.effectControllers[_name] === undefined) nc.defineEffectController(_name, "Vector4", ["red", "green", "blue", "alpha"], [0, 0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1], [0, 1]], "The color of spot light " + i, ["The light color's red value", "The light color's green value", "The light color's blue value", "The light color's alpha value, which can be used to control the brightness of the light."]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
        // position
            _name = "spotLightPosition" + i;
            if (nc.effectControllers[_name] === undefined) nc.defineEffectController(_name, "Vector4", ["X", "Y", "Z", "feather"], [0, 0, 0, 0], "addition", [[0, 300], [0, 300], [0, 300], [0, 1]], "The position of spot light " + i + " and the edge blurriness", ["The X component of the light's position", "The Y component of the light's position", "The z component of the light's position", "The amount to feather the edge of the light cone"]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
        // direction
            _name = "spotLightDirection" + i;
            if (nc.effectControllers[_name] === undefined) nc.defineEffectController(_name, "Vector4", ["X", "Y", "Z", "coneAngle"], [0, 0, 0, 0], "addition", [[0, 1], [0, 1], [0, 1], [0, 180]], "The direction of spotlight light " + i, ["The X component of the light's direction", "The Y component of the light's direction", "The z component of the light's direction", "The angle of the spot light cone"]);
            _newEffectControllers.push(nc.effectControllers[_name]);
            _fragSupport.push("uniform vec4 " + _name + ";");
        }
        //we need to know the ray from the camera to the fragment to work out the reflective portions (specular).
        // for a ortho camera, we use the optical axis of the camera instead, so the rays to all fragments are parallel.
        _fragNode += "vec3 toCam = isOrthographic ? cameraModelMatrix[2].xyz : cameraModelMatrix[3].xyz - vertPos;\n";
        _fragNode += "toCam = normalize(toCam);\n";
        _fragNode += "vec3 ambientContribution = vec3(0.0);\n";
        _fragNode += "vec3 diffuseContribution = vec3(0.0);\n";
        _fragNode += "vec3 specularContribution = vec3(0.0);\n";
        _fragNode += "vec3 toLight;\n";
        _fragNode += "float lightDistance2;\n";
        _fragNode += "vec3 fixedLightDirection;\n";
        _fragNode += "float lightDotNormal;\n";
        _fragNode += "vec3 halfDir;\n";
        _fragNode += "float specAngle;\n";
        _fragNode += "float specular;\n";
        _fragNode += "vec3 lightC;\n";
        _fragNode += "float halfFeather;\n";
        _fragNode += "float coneAngle;\n";
        _fragNode += "float coneStrength;\n";
        if (this._ambientLight)
        {
            _fragNode += "ambientContribution = ambientC * ambientLightColor.rgb * ambientLightColor.a;\n";
        }
        for (let i = 0; i < this._numDirectionalLights; ++i)
        {
            _fragNode += "fixedLightDirection = dot(directionalLightDirection" + i + ", directionalLightDirection" + i + ") > .0001 ? directionalLightDirection" + i + " : vec3(0.0, 0.0, 1.0);\n";
            _fragNode += "toLight = -normalize(fixedLightDirection);\n";
            _fragNode += "lightDotNormal = dot(toLight, normal);\n";
            _fragNode += "halfDir = normalize(toLight + toCam);\n";
            _fragNode += "specAngle = max(dot(halfDir, normal), 0.0);\n";
            _fragNode += "specular = pow(specAngle, specularE) * step(0.0, lightDotNormal);\n";
            _fragNode += "lightC = directionalLightColor" + i + ".rgb * directionalLightColor" + i + ".a;\n";
            _fragNode += "diffuseContribution += lightC * max(lightDotNormal, 0.0);\n";
            _fragNode += "specularContribution += specularC * specular * lightC;\n";
        }
        for (let i = 0; i < this._numPointLights; ++i)
        {
            _fragNode += "toLight = pointLightPosition" + i + " - vertPos;\n";
            _fragNode += "lightDistance2 = dot(toLight, toLight)*0.0001;\n";
            _fragNode += "toLight = normalize(toLight);";
            _fragNode += "lightDotNormal = dot(toLight, normal);\n";               
            _fragNode += "halfDir = normalize(toLight + toCam);\n";
            _fragNode += "specAngle = max(dot(halfDir, normal), 0.0);\n";
            _fragNode += "specular = pow(specAngle, specularE) * step(0.0, lightDotNormal);\n";
            _fragNode += "lightC = pointLightColor" + i + ".rgb * pointLightColor" + i + ".a / lightDistance2;\n";
            _fragNode += "diffuseContribution += lightC * max(lightDotNormal, 0.0);\n";
            _fragNode += "specularContribution += specularC * specular * lightC;\n";
        }
        for (let i = 0; i < this._numSpotLights; ++i)
        {
            _fragNode += "toLight = spotLightPosition" + i + ".xyz - vertPos;\n";
            _fragNode += "lightDistance2 = dot(toLight, toLight)*0.0001;\n";
            _fragNode += "toLight = normalize(toLight);";
            _fragNode += "lightDotNormal = dot(toLight, normal);\n";               
            _fragNode += "halfDir = normalize(toLight + toCam);\n";
            _fragNode += "specAngle = max(dot(halfDir, normal), 0.0);\n";
            _fragNode += "specular = pow(specAngle, specularE) * step(0.0, lightDotNormal);\n";
            _fragNode += "lightC = spotLightColor" + i + ".rgb * spotLightColor" + i + ".a / lightDistance2;\n";
            _fragNode += "fixedLightDirection = dot(spotLightDirection" + i + ".xyz, spotLightDirection" + i + ".xyz) > .0001 ? normalize(spotLightDirection" + i + ".xyz) : vec3(0.0, 0.0, 1.0);\n";
            _fragNode += "halfFeather = max(spotLightPosition" + i + ".w, .0001) * .5 * 3.14159 / 180.0;";
            _fragNode += "coneAngle = spotLightDirection" + i + ".w * 3.14159 / 180.0;";
            _fragNode += "coneStrength = smoothstep(coneAngle + halfFeather, coneAngle - halfFeather, acos(dot(toLight, -fixedLightDirection)));\n";
            _fragNode += "diffuseContribution += lightC * max(lightDotNormal, 0.0) * coneStrength;\n";
            _fragNode += "specularContribution += specularC * specular * lightC * coneStrength;\n";
        }
        _fragNode += "fragment.rgb = diffuseC.rgb;\n";
        _fragNode += "fragment.rgb *= ambientContribution + diffuseContribution;\n";
        _fragNode += "fragment.rgb += specularContribution;\n";
        _fragNode += "fragment.rgb = min(fragment.rgb, vec3(1.0)) * diffuseC.a;\n";
        nc.defineEffectNode(_encodedName, _vertSupport, _vertNode, _fragSupport, _fragNode, _newEffectControllers, true);
    }
}

CODE.runBeforeInit___begin;
    CODE.includeIf___unpublished;
        this.filterEffectNodeWarning=function(warning)
        {
            if (warning.indexOf('Construct requires') !== -1)
            {
                if (warning.indexOf("EffectNode") !== -1)
                {
                    if (warning.indexOf("BlinnPhongLighting_") !== -1 || warning.indexOf("NormalMap") !== -1)
                    {
                        return false;
                    }
                }
                if (warning.indexOf("EffectController") !== -1)
                {
                    if (warning.indexOf("normalMap_texture") !== -1 || 
                        warning.indexOf("normalMap_strength") !== -1 ||
                        warning.indexOf("normalMap_isLeftHanded") !== -1 ||
                        warning.indexOf("ambientResponseColor") !== -1 ||
                        warning.indexOf("specularResponseColor") !== -1 ||
                        warning.indexOf("specularResponseExponent") !== -1 ||
                        warning.indexOf("ambientResponseTexture") !== -1 ||
                        warning.indexOf("specularResponseTexture") !== -1 ||
                        warning.indexOf("specularResponseExponentTexture") !== -1 ||
                        warning.indexOf("ambientLightColor") !== -1 ||
                        warning.indexOf("directionalLightColor") !== -1 ||
                        warning.indexOf("directionalLightDirection") !== -1 ||
                        warning.indexOf("pointLightColor") !== -1 ||
                        warning.indexOf("pointLightPosition") !== -1 ||
                        warning.indexOf("spotLightColor") !== -1 ||
                        warning.indexOf("spotLightPosition") !== -1 ||
                        warning.indexOf("spotLightDirection") !== -1)
                    {
                        return false;
                    }
                }
            }
            return true;
        };
        nc.addWarningFilter(this, "filterEffectNodeWarning");
    CODE.includeEnd___unpublished;
    nc.registerCustomAddOn(incr_replaceText_NameSubstitution,"Applies Blinn-Phong lighting to a GraphicObject, with configurable ambient, directional, point, and spot lights.");
    var registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"ambientLight","Enables or disables ambient lighting contribution.");
    registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"numDirectionalLights","The number of directional lights (0–8) contributing to the lighting calculation.");
    registeredProperty.validationList = [0,1,2,3,4,5,6,7,8];
    registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"numPointLights","The number of point lights (0–8) contributing to the lighting calculation.");
    registeredProperty.validationList = [0,1,2,3,4,5,6,7,8];
    registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"numSpotLights","The number of spot lights (0–8) contributing to the lighting calculation.");
    registeredProperty.validationList = [0,1,2,3,4,5,6,7,8];
    registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"ambientResponseColor","Enables an ambient response color that tints the ambient light contribution.");
    registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"ambientResponseTexture","Enables an ambient response texture that multiplies the ambient light contribution.");
    registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"specularResponseColor","Enables a specular response color that tints the specular highlight contribution.");
    registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"specularResponseTexture","Enables a specular response texture that multiplies the specular highlight contribution.");
    registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"specularResponseExponent","Enables a specular exponent value that controls the sharpness of specular highlights.");
    registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"specularResponseExponentTexture","Enables a specular exponent texture that varies highlight sharpness across the surface.");
    registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"normalTexture","Enables a normal map texture that perturbs per-fragment normals for surface detail.");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 4: Custom AddOns/GraphicObject/Shadow
----------------------------------------------------------


Title: Shadow
Template Library Path: Custom AddOns/GraphicObject/Shadow
Type: CustomAddOn
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom AddOns/GraphicObject/Shadow:
Adds a basic shadow to a GraphicObject by creating a duplicate positioned behind the original.

Offset angle, distance, color, and alpha are registered properties. A drawn shadow rather than a cast one, so it costs one extra draw call and nothing else.

'angle' (default -60) is the direction the shadow is offset in, in degrees, and 'distance' (10) is how far along it. 'depth' (25) is how far behind the owner it sits in Z. The color is registered as four paths into the shadow object the AddOn built - 'shadow.colorMultiply.red', 'green' and 'blue' start at 0 for black, and 'shadow.colorMultiply.alpha' is what fades it.

A CustomAddOn attaches behavior to an object that already exists, rather than being an object in its own right. Add one to a selected object under CustomAddOn Info in the Object Panel, or build it against its owner in code - new Shadow(object) - and reach it afterward as object.customAddOns.Shadow. It extends CustomAddOn_GraphicObject, so only a GraphicObject will accept it, and an object carries at most one of each. Registered properties are the ones the GUI can see: adjustable in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom AddOns/GraphicObject/Shadow:
// Incisor Template Library - Shadow: dropping a drawn shadow behind an object.
// Requires Template Library items: Shadow

let logo = new GraphicObject(nc.graphicAssets.Incisor,nc.mainScene,"Logo");

// This would usually be added in the Object Panel under CustomAddOn Info, where every value below is a field. Attaching
// it in code is one call, and it builds its shadow GraphicObject as it goes.
let shadow = new Shadow(logo);

// angle is the direction the shadow is thrown, in degrees, and distance is how far along it. depth is how far behind
// the owner it sits in Z, which is what keeps it from fighting the artwork it belongs to.
shadow.angle = -45;
shadow.distance = 20;

// The color is registered as four paths reaching into the shadow object the AddOn made, so it is set on that object.
shadow.shadow.colorMultiply.alpha = .5;

Content of Custom AddOns/GraphicObject/Shadow, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// Adds a basic shadow to any graphic object
class incr_replaceText_NameSubstitution extends CustomAddOn_GraphicObject
{
    

    constructor(owner)
    {
        // Call the super constructor
        super(owner);
    
        // Create a new shadow GraphicObject
        this.shadow = new GraphicObject(this.owner.graphicAsset, this.owner, this.owner.name + " added shadow");

        // Since this shadow is made on the fly, this flag will prevent the shadow from being recorded in any Construct Blueprints that it might be included in.
        this.owner.excludeChildrenFromBlueprint = true;

        // Set up the shadow GraphicObject layer, subLayer, geometry, texture, and effectNodes.
        this.shadow.layer = this.owner.layer;
        this.shadow.subLayer = this.owner.subLayer-.05;
        this.shadow.geometry = this.owner.geometry;
        this.shadow.getMaterials()[0].mainTexture = this.owner.getMaterials()[0].mainTexture;
        this.shadow.setEffectNodes(this.owner.getMaterials()[0].getEffectNodes());

        // Set the initial shadow color
        this.shadow.colorMultiply.red = 0;
        this.shadow.colorMultiply.green = 0;
        this.shadow.colorMultiply.blue = 0;

        // Create a getter/setter for angle - this calls 'refreshShadowPostion' whenever angle is changed.
        var internalAngle = -60;
        Object.defineProperty(this,"angle",{
            set:function(val)
            {
                internalAngle = val;
                this.refreshShadowPosition();
            },
            get:function()
            {
                return(internalAngle);
            }
        });

        // Create a getter/setter for distance - this calls 'refreshShadowPostion' whenever distance is changed.
        var internalDistance = 10;
        Object.defineProperty(this,"distance",{
            set:function(val)
            {
                internalDistance = val;
                this.refreshShadowPosition();
            },
            get:function()
            {
                return(internalDistance);
            }
        });

        // Create a getter/setter for depth - this calls 'refreshShadowPostion' whenever depth is changed.
        var internalDepth = 25;
        Object.defineProperty(this,"depth",{
            set:function(val)
            {
                internalDepth = val;
                this.refreshShadowPosition();
            },
            get:function()
            {
                return(internalDepth);
            }
        });

        // Add disposal callback
        this.addDisposalCallback(this,"disposalCallback");

        // Call 'refreshShadowPosition' to update the shadow's position
        this.refreshShadowPosition();
    }


    // Removes the shadow GraphicObject when this CustomAddOn is disposed
    disposalCallback()
    {
        this.shadow.dispose();
    }


    // This is called any time angle, distance, or depth are changed - it positions the shadow based on those factors
    refreshShadowPosition()
    {
        let radians = this.angle*Math.PI/180;
        this.shadow.position.x = this.distance*Math.cos(radians);
        this.shadow.position.y = this.distance*Math.sin(radians);
        this.shadow.position.z = -this.depth;
    }
}

// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks
CODE.runBeforeInit___begin;
    // Register the CustomAddOn with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomAddOn(incr_replaceText_NameSubstitution,"Adds a basic shadow to any GraphicObject by creating a duplicate positioned behind the original.");
    var incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"angle","The angle in degrees of the shadow's offset direction relative to the owner.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"distance","The distance from the owner at which the shadow is placed.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .5;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"depth","The Z-depth offset placing the shadow behind the owner.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"shadow.colorMultiply.red","The red component of the shadow color.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"shadow.colorMultiply.green","The green component of the shadow color.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"shadow.colorMultiply.blue","The blue component of the shadow color.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"shadow.colorMultiply.alpha","The opacity of the shadow.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 5: Custom AddOns/GraphicObject/StretchBetween2D
----------------------------------------------------------


Title: StretchBetween2D
Template Library Path: Custom AddOns/GraphicObject/StretchBetween2D
Type: CustomAddOn
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom AddOns/GraphicObject/StretchBetween2D:
Stretches a GraphicObject between two 2D points, handling the positioning and rotation automatically.

Drives the owner's GraphicExpander, so the artwork stretches rather than scales. Points can be given in global scene space or in the owner's local parent space. The usual choice for connectors, beams, and rubber-band lines.

'firstPointX', 'firstPointY', 'secondPointX' and 'secondPointY' (all 0) are the two ends, and 'useGlobalCoordinates' (false) chooses whether they are read in global scene space or in the owner's local parent space. 'firstPointBuffer' and 'secondPointBuffer' (both 0) trim the stretch inward from each end, which is how artwork is kept clear of whatever it is connecting. 'stretchDirection' ('horizontal') is the axis of the artwork that gets stretched, and takes 'horizontal' or 'vertical'.

A CustomAddOn attaches behavior to an object that already exists, rather than being an object in its own right. Add one to a selected object under CustomAddOn Info in the Object Panel, or build it against its owner in code - new StretchBetween2D(object) - and reach it afterward as object.customAddOns.StretchBetween2D. It extends CustomAddOn_GraphicObject, so only a GraphicObject will accept it, and an object carries at most one of each. Registered properties are the ones the GUI can see: adjustable in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom AddOns/GraphicObject/StretchBetween2D:
// Incisor Template Library - StretchBetween2D: running artwork between two points and moving one of them.
// Requires Template Library items: StretchBetween2D

let beam = new GraphicObject(nc.graphicAssets.Incisor,nc.mainScene,"Beam");

// In the GUI this is added under CustomAddOn Info in the Object Panel and its endpoints typed into the fields. The
// constructor does the same, and configures the owner's GraphicExpander itself so the artwork stretches rather than
// scaling - the ends keep their proportions and only the middle grows.
let stretch = new StretchBetween2D(beam);
stretch.stretchDirection = "horizontal";
stretch.firstPointX = -400;
stretch.firstPointY = -150;
stretch.secondPointX = 400;
stretch.secondPointY = 150;

// The buffers trim the stretch inward from each end, which is how a connector is kept clear of what it connects.
stretch.firstPointBuffer = 20;
stretch.secondPointBuffer = 20;

// Every one of these is registered, so this move is equally a pair of keyframes on a Construct Timeline.
nc.swoopValue(stretch,"secondPointY",-150,2,nc.tweenTypes.Ease);

Content of Custom AddOns/GraphicObject/StretchBetween2D, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/** A CustomAddOn that will take any GraphicObject and stretch it from the middle between any two points using a GraphicExpander.
 */
class incr_replaceText_NameSubstitution extends CustomAddOn_GraphicObject
{
    


    constructor(owner)
    {
        // call the super constructor
        super(owner);

        // configure the GraphicExpander if it's not already configured
        if(this.owner.graphicExpander===undefined)
        {
            this.owner.configureGraphicExpander();
            this.owner.graphicExpander.expandedHeight = 0;
            this.owner.graphicExpander.expandedWidth = 0;
        }

        // initial var values
        this.internalUseGlobalCoordinates = false;
        this.internalStretchDirection = "horizontal";
        this.internalFirstPointX = 0;
        this.internalFirstPointY = 0;
        this.internalFirstPointBuffer = 0;
        this.internalSecondPointX = 0;
        this.internalSecondPointY = 0;
        this.internalSecondPointBuffer = 0;
        this.internalOneOverPi = 1/Math.PI;
    }


    // refreshes the owner's position and rotation based on the values for the points
    refreshLayout()
    {
        let distanceX = (this.internalSecondPointX-this.internalFirstPointX);
        let distanceY = (this.internalSecondPointY-this.internalFirstPointY);
        let length = Math.pow( distanceX*distanceX + distanceY*distanceY ,.5);
        let ratio = (1+(-this.internalFirstPointBuffer+this.internalSecondPointBuffer)/length)*.5;
        let oneMinusRatio = (1-ratio);
        let destX = (this.internalFirstPointX*ratio+this.internalSecondPointX*oneMinusRatio);
        let destY = (this.internalFirstPointY*ratio+this.internalSecondPointY*oneMinusRatio);
        let rotationZ = Math.atan2(distanceY,distanceX)*180*this.internalOneOverPi;
        if(this.internalStretchDirection==="horizontal")
        {
            this.owner.graphicExpander.expandedWidth = length-this.internalFirstPointBuffer-this.internalSecondPointBuffer;
            this.owner.graphicExpander.expandedHeight = 0;
        }
        else
        {
            this.owner.graphicExpander.expandedWidth = 0;
            this.owner.graphicExpander.expandedHeight = length-this.internalFirstPointBuffer-this.internalSecondPointBuffer;
            rotationZ+=90;
        }
        if(this.internalUseGlobalCoordinates===true)
        {
            this.owner.swoopGlobalPosition([destX,destY,0],0);
            this.owner.swoopGlobalRotation([0,0,rotationZ],0);
            this.owner.swoopGlobalScale([1,1,1],0);
        }
        else
        {
            this.owner.position.x = destX;
            this.owner.position.y = destY;
            this.owner.rotation.z = rotationZ;
        }
    }
}


CODE.runBeforeInit___begin;
// Add getters/setters onto the CustomAddOn prototype, so that setting these values also triggers a refresh.
    Object.defineProperty(incr_replaceText_NameSubstitution.prototype,"useGlobalCoordinates",{
        set:function(_val)
        {
            this.internalUseGlobalCoordinates = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalUseGlobalCoordinates);}
    });
    Object.defineProperty(incr_replaceText_NameSubstitution.prototype,"stretchDirection",{
        set:function(_val)
        {
            this.internalStretchDirection = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalStretchDirection);}
    });
    Object.defineProperty(incr_replaceText_NameSubstitution.prototype,"firstPointX",{
        set:function(_val)
        {
            this.internalFirstPointX = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalFirstPointX);}
    });
    Object.defineProperty(incr_replaceText_NameSubstitution.prototype,"firstPointY",{
        set:function(_val)
        {
            this.internalFirstPointY = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalFirstPointY);}
    });
    Object.defineProperty(incr_replaceText_NameSubstitution.prototype,"firstPointBuffer",{
        set:function(_val)
        {
            this.internalFirstPointBuffer = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalFirstPointBuffer);}
    });
    Object.defineProperty(incr_replaceText_NameSubstitution.prototype,"secondPointX",{
        set:function(_val)
        {
            this.internalSecondPointX = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalSecondPointX);}
    });
    Object.defineProperty(incr_replaceText_NameSubstitution.prototype,"secondPointY",{
        set:function(_val)
        {
            this.internalSecondPointY = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalSecondPointY);}
    });
    Object.defineProperty(incr_replaceText_NameSubstitution.prototype,"secondPointBuffer",{
        set:function(_val)
        {
            this.internalSecondPointBuffer = _val;
            this.refreshLayout();
        },
        get:function(){return(this.internalSecondPointBuffer);}
    });

    // register the CustomAddOn and its properties with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomAddOn(incr_replaceText_NameSubstitution,"Stretches a GraphicObject between two 2D points using its GraphicExpander, positioning and rotating it automatically.");
    let incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,"boolean","useGlobalCoordinates","When true, point coordinates are in global scene space. When false, they are in the owner's local parent space.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,"string","stretchDirection","The axis along which the GraphicObject is stretched: 'horizontal' or 'vertical'.");
    incr_replaceText_nameSubstitution_registeredProperty.validationList = ["horizontal","vertical"];
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,"number","firstPointX","The X coordinate of the first stretch point.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,"number","firstPointY","The Y coordinate of the first stretch point.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,"number","firstPointBuffer","An inward buffer trimming the stretch length from the first point end.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,"number","secondPointX","The X coordinate of the second stretch point.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,"number","secondPointY","The Y coordinate of the second stretch point.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,"number","secondPointBuffer","An inward buffer trimming the stretch length from the second point end.");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 6: Custom AddOns/SceneObject/ChaseCursorExample
----------------------------------------------------------


Title: ChaseCursorExample
Template Library Path: Custom AddOns/SceneObject/ChaseCursorExample
Type: CustomAddOn
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom AddOns/SceneObject/ChaseCursorExample:
Makes any SceneObject follow the cursor.

Chase speed is an interpolation factor from 0 for stationary to 1 for instant, and a rotation offset tunes which way the object faces relative to its direction of travel. A short, readable example of a fixedUpdate-driven AddOn that correctly adds and removes its callback with the owner's enabled state.

'chaseSpeed' (default .05) is how much of the remaining distance to the cursor is closed each fixed update, from 0 for stationary to 1 for instant, and it is held at or above 0. 'rotationOffset' (90) is added to the angle the object is turned to, in degrees, which is what lines artwork up with its direction of travel.

A CustomAddOn attaches behavior to an object that already exists, rather than being an object in its own right. Add one to a selected object under CustomAddOn Info in the Object Panel, or build it against its owner in code - new ChaseCursorExample(object) - and reach it afterward as object.customAddOns.ChaseCursorExample. It extends CustomAddOn_SceneObject, so only a SceneObject will accept it, and an object carries at most one of each. Registered properties are the ones the GUI can see: adjustable in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom AddOns/SceneObject/ChaseCursorExample:
// Incisor Template Library - ChaseCursorExample: pointing an object at the cursor and letting it trail after it.
// Requires Template Library items: ChaseCursorExample

// A CustomAddOn is normally added to an object in the Object Panel, under CustomAddOn Info, and tuned in the fields
// there. This is that same work done by hand, for the case where the object itself is being built at runtime.
let pointer = new GraphicObject(nc.graphicAssets.icon_play,nc.mainScene,"Pointer");
pointer.scale.scaleByFactor(4);

// The constructor takes the object to attach to, and there is no separate add step - the AddOn files itself onto its
// owner on the way up, so the reference below and pointer.customAddOns.ChaseCursorExample are the same object.
let chase = new ChaseCursorExample(pointer);

// chaseSpeed is how much of the remaining distance to the cursor is closed each fixed update, so a small number trails
// and a large one snaps. rotationOffset lines the artwork up with the direction of travel - icon_play already points
// along its own x, which is the direction the angle is measured in, so it needs no offset.
chase.chaseSpeed = .04;
chase.rotationOffset = 0;

Content of Custom AddOns/SceneObject/ChaseCursorExample, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// Adds functionality to make any SceneObject it is added to chase the cursor.
class incr_replaceText_NameSubstitution extends CustomAddOn_SceneObject
{
    

    constructor(owner)
    {
        // Call the super constructor
        super(owner);

        // The SceneObject as expressed from 0 to 1, where 0 is not moving, and 1 is instantly catching the cursor
        this.chaseSpeed = .05;

        // The rotational offset to be able to tune which direction the SceneObject faces relative to the direction of the cursor
        this.rotationOffset = 90;
       
        // Helper Vars
        this.governingCamera = null;

        // Add a callback for when the enabled state of the owner changes - you'll probably want to make this a getter/setter for best use
        this.owner.addEnabledStateChangeCallback(this,"enabledStateChangeCallback");
        nc.appEvents.fixedUpdate.addCallback(this,"fixedUpdateCallback");
    }

    // This function is called whenever the 'enabled' state of the owner or any of its ancestors changes
    enabledStateChangeCallback(state)
    {
        if(state===true)
        {
            nc.appEvents.fixedUpdate.addCallback(this,"fixedUpdateCallback");
        }
        else
        {
            nc.appEvents.fixedUpdate.removeCallback(this,"fixedUpdateCallback");
        }
    }

    // This function is called every fixed update, but the enabledStateChangeCallback function above can disable it
    fixedUpdateCallback()
    {
        if(this.governingCamera===null)
        {
            let descendants = this.owner.containingScene.getDescendants();
            for(let i=0; i<descendants.length; i++)
            {
                if(descendants[i].inheritedTypes.Camera!==undefined)
                {
                    this.governingCamera=descendants[i]  ;
                }
            }
        }
        if(this.governingCamera!==null && this.governingCamera.cursorInteractive===true)
        {
            let cursorPosition = this.governingCamera.getCursorPosition();
            let globalPosition = this.owner.getGlobalPosition();
            globalPosition.x = globalPosition.x*(1-this.chaseSpeed)+cursorPosition.x*this.chaseSpeed;
            globalPosition.y = globalPosition.y*(1-this.chaseSpeed)+cursorPosition.y*this.chaseSpeed;
            this.owner.swoopGlobalPosition([globalPosition.x,globalPosition.y,globalPosition.z]);
            this.owner.rotation.z = 180*Math.atan2(cursorPosition.y-this.owner.position.y,cursorPosition.x-this.owner.position.x)/Math.PI+this.rotationOffset;
        }
    }
}

// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks
CODE.runBeforeInit___begin;
    // Register the CustomAddOn with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomAddOn(incr_replaceText_NameSubstitution,"Makes a SceneObject follow the cursor position with a configurable chase speed and directional offset.");

    // Register 'chaseSpeed' with the Incisor inspector, so it can be supervised and animated in the GUI.
    this.incr_replaceText_nameSubstitution_chaseSpeedValidation=function(val)
    {
        if(val<0){return(0);}
        return(val);
    };
    var incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"chaseSpeed","The chase interpolation factor from 0 to 1, where 0 is stationary and 1 is instant.");
    incr_replaceText_nameSubstitution_registeredProperty.validationCallbackOwner = this;
    incr_replaceText_nameSubstitution_registeredProperty.validationCallbackName = "incr_replaceText_nameSubstitution_chaseSpeedValidation";
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    // Register 'rotationOffset' with the Incisor inspector, so it can be supervised and animated in the GUI.
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"rotationOffset","The rotational offset in degrees adjusting which direction the owner faces relative to the cursor.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = 1;
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 7: Custom AddOns/TextAssembly/TextAssemblyWaveExample
----------------------------------------------------------


Title: TextAssemblyWaveExample
Template Library Path: Custom AddOns/TextAssembly/TextAssemblyWaveExample
Type: CustomAddOn
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom AddOns/TextAssembly/TextAssemblyWaveExample:
Adds a staggered character wave to any TextAssembly, triggered by invoking doTheWave.

The trigger is registered as a function property, so it can be fired from a button in the GUI or keyframed on a Construct Timeline.

'doTheWave' is registered as a function rather than a value, so it appears as a button in the Object Panel and can be fired from a Construct Timeline - it is what starts the wave.

The rest shape it. 'underscaleMultiplier' (default .7) is how far each character dips before it rises and 'overscaleMultiplier' (2) is how far it rises. 'totalStaggerTime' (.4) is the time in seconds between the first character starting and the last, and the four phase times - 'characterUnderscaleTime' (.1), 'characterScaleUpTime' (.15), 'characterScaleDownTime' (.15) and 'characterRecoveryTime' (.1) - are how long one character spends dipping, rising, falling and settling.

A CustomAddOn attaches behavior to an object that already exists, rather than being an object in its own right. Add one to a selected object under CustomAddOn Info in the Object Panel, or build it against its owner in code - new TextAssemblyWaveExample(object) - and reach it afterward as object.customAddOns.TextAssemblyWaveExample. It extends CustomAddOn_TextAssembly, so only a TextAssembly will accept it, and an object carries at most one of each. Registered properties are the ones the GUI can see: adjustable in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom AddOns/TextAssembly/TextAssemblyWaveExample:
// Incisor Template Library - TextAssemblyWaveExample: running a wave along a line of characters.
// Requires Template Library items: TextAssemblyWaveExample

let title = new TextAssembly(nc.mainScene,"Title");
title.string = "INCISOR";

// Normally this is added to the TextAssembly under CustomAddOn Info in the Object Panel, where the timings below are
// laid out as fields. The constructor is the same attachment done in code.
let wave = new TextAssemblyWaveExample(title);

// Each character dips to underscaleMultiplier, rises to overscaleMultiplier and settles back. totalStaggerTime is how
// long the whole line takes to hand the wave from its first character to its last.
wave.underscaleMultiplier = .8;
wave.overscaleMultiplier = 1.8;
wave.totalStaggerTime = .5;

// doTheWave is registered as a function rather than a value, so in the GUI it is a button and can be fired from a
// Construct Timeline. Here it is called outright, after a beat that lets the assembly lay its characters out.
nc.waitThen(1,wave,"doTheWave");

Content of Custom AddOns/TextAssembly/TextAssemblyWaveExample, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// CustomAddOn that performs a sequence on the characters of any TextAssembly, scaling them up and down in a staggered 'wave' motion.
class incr_replaceText_NameSubstitution extends CustomAddOn_TextAssembly
{
    
    
    constructor(owner)
    {
        // Call the super constructor
        super(owner);

        // Add properties affecting 'wave' functionality
        this.underscaleMultiplier = .7;
        this.overscaleMultiplier = 2;
        this.totalStaggerTime = .4;
        this.characterUnderscaleTime = .1;
        this.characterScaleUpTime = .15;
        this.characterScaleDownTime = .15;
        this.characterRecoveryTime = .1;
    }

    doTheWave()
    {
        // Acquire the characters within the TextAssembly
        let characters = this.owner.getCharacters();

        // Loop through the characters, starting a scale-up-scale-down sequence witha staggered offset.
        let waitTime = 0;
        for(let i=0; i<characters.length; i++)
        {
            nc.waitThen(waitTime,this,"characterScaleSequence",[characters[i],this.owner.textFormat.characterScaleX*this.owner.scaleToFitFactor]);
            waitTime+=this.totalStaggerTime/characters.length;
        }
    }


    characterScaleSequence(character,baseScale)
    {
        // Var to track the running total of the sequence time
        let runningTotalSeconds=0;

        // Scale the character down during the 'wind-up'
        character.scale.swoop.all(this.underscaleMultiplier*baseScale,this.characterUnderscaleTime,nc.tweenTypes.Ease);
        runningTotalSeconds+=this.characterUnderscaleTime;

        // Scale the character up for its part of the 'wave'
        nc.waitThen(runningTotalSeconds,character.scale.swoop,"all",[this.overscaleMultiplier*baseScale,this.characterScaleUpTime,nc.tweenTypes.Ease]);
        runningTotalSeconds+=this.characterScaleUpTime;

        // Scale the character back down 
        nc.waitThen(runningTotalSeconds,character.scale.swoop,"all",[this.underscaleMultiplier*baseScale,this.characterScaleDownTime,nc.tweenTypes.Ease]);
        runningTotalSeconds+=this.characterScaleDownTime;
    
        // Scale the character back to its base scale
        nc.waitThen(runningTotalSeconds,character.scale.swoop,"all",[baseScale,this.characterRecoveryTime,nc.tweenTypes.Ease]);
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks
CODE.runBeforeInit___begin;
    // Register the CustomAddOn with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomAddOn(incr_replaceText_NameSubstitution,"Adds a wave animation to a TextAssembly, scaling characters up and down in sequence when doTheWave is invoked.");

    // Register the 'doTheWave' function so that it can be invoked from the GUI, or from within a Construct Timeline via invocation keyframe.
    nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,"function","doTheWave","Triggers the wave animation, scaling each character up and down in a staggered sequence.");

    // Register the other numeric properties for GUI/Timeline manipulation
    var incr_replaceText_nameSubstitution_registeredProperty =  nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"overscaleMultiplier","The scale multiplier applied to each character at the peak of its wave.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"underscaleMultiplier","The scale multiplier applied to each character during the wind-up before its wave peak.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"totalStaggerTime","The total time in seconds over which the wave animation is staggered across all characters.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"characterUnderscaleTime","The duration in seconds for each character's wind-up phase.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"characterScaleUpTime","The duration in seconds for each character's scale-up phase.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"characterScaleDownTime","The duration in seconds for each character's scale-down phase.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"characterRecoveryTime","The duration in seconds for each character to return to its base scale.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 8: Custom AddOns/TextBox/TextBoxClockExample
----------------------------------------------------------


Title: TextBoxClockExample
Template Library Path: Custom AddOns/TextBox/TextBoxClockExample
Type: CustomAddOn
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom AddOns/TextBox/TextBoxClockExample:
Turns any TextBox into a clock showing the current time, updating every frame.

Seconds can be shown or hidden through a registered boolean property. Note that this overwrites the TextBox's string every frame, so it takes over the object's text entirely.

'showSeconds' (default true) is the only one - false leaves hours and minutes.

A CustomAddOn attaches behavior to an object that already exists, rather than being an object in its own right. Add one to a selected object under CustomAddOn Info in the Object Panel, or build it against its owner in code - new TextBoxClockExample(object) - and reach it afterward as object.customAddOns.TextBoxClockExample. It extends CustomAddOn_TextBox, so only a TextBox will accept it, and an object carries at most one of each. Registered properties are the ones the GUI can see: adjustable in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom AddOns/TextBox/TextBoxClockExample:
// Incisor Template Library - TextBoxClockExample: turning a TextBox into a running clock.
// Requires Template Library items: TextBoxClockExample

let clock = new TextBox(nc.mainScene,"Clock");

// In the GUI this AddOn would be dropped onto the TextBox under CustomAddOn Info in the Object Panel. Building it here
// is the same step, and is what you would reach for when the TextBox is made in code rather than placed in a Construct.
let clockAddOn = new TextBoxClockExample(clock);

// showSeconds is registered, so it is a checkbox in the Object Panel and can be keyframed on a Construct Timeline.
// This AddOn writes the TextBox's string every frame, so nothing else should be setting it.
clockAddOn.showSeconds = true;

Content of Custom AddOns/TextBox/TextBoxClockExample, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// CustomAddOn that turns any TextBox unto a clock
class incr_replaceText_NameSubstitution extends CustomAddOn_TextBox
{
    
    
    constructor(owner)
    {
        // Call the super constructor
        super(owner);

        // Boolean determining if the clock will show seconds
        this.showSeconds = true;

        // Add fixedUpdate callback
        nc.appEvents.fixedUpdate.addCallback(this,"fixedUpdateCallback");
    }

    // This function is triggered every fixed update
    fixedUpdateCallback()
    {
        // Assembly the time string in the desired format
        let date = new Date();
        let hour = date.getHours();
        let ampm = "am";
        // Convert the reading onto a twelve hour clock. Noon and midnight are the two that have to be said out loud:
        // the twelve o'clock hour belongs to pm, and hour zero is written as twelve rather than as nothing.
        if(hour>=12){ampm = "pm";}
        if(hour>12){hour -= 12;}
        if(hour===0){hour = 12;}
        let minute = this.addLeadingZeros(date.getMinutes(),2);
        let second = this.addLeadingZeros(date.getSeconds(),2);
        // Set the TextBox's string to the time string
        if(this.showSeconds===true)
        {
            this.owner.string = hour + ":" + minute + ":" + second + " " + ampm;
        }
        else
        {
            this.owner.string = hour + ":" + minute + " " + ampm;
        }
    }

    // Function to pad the minutes and seconds with zeros when they would otherwise be single digits
    addLeadingZeros(number,digitsRequired)
    {
        if(digitsRequired===undefined){digitsRequired=2;}
        let stringVersion = number.toString();
        while(stringVersion.length<digitsRequired)
        {
            stringVersion = "0" + stringVersion;
        }
        return(stringVersion);
    }
}

// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks
CODE.runBeforeInit___begin;
    // Register the CustomAddOn with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomAddOn(incr_replaceText_NameSubstitution,"Turns any TextBox into a clock that displays the current time, updating every frame.");

    // Register the 'showSeconds' var so this can be manipulated in the GUI
    nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"showSeconds","When true, the clock display includes seconds. When false, only hours and minutes are shown.");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 9: Custom AddOns/blank template
----------------------------------------------------------


Title: blank template
Template Library Path: Custom AddOns/blank template
Type: CustomAddOn
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom AddOns/blank template:
A minimal CustomAddOn: a class extending CustomAddOn_SceneObject, plus the nc.registerCustomAddOn call that makes it addable from the GUI.

Change the base class to the CustomAddOn_XXXXXXX matching the object type you intend to extend. An AddOn attaches behavior to an existing object, where a CustomObject is a new object type in its own right.

It registers no properties. To add one, give the class a member and call nc.registerCustomAddOnProperty with the class, a type from constants.registeredPropertyTypes, the member's name and a description that becomes its tooltip. The call hands back a RegisteredProperty, which is where a validation callback, a validation list or a drag multiplier goes.

A CustomAddOn attaches behavior to an object that already exists, rather than being an object in its own right - where a CustomObject is a new type of object in itself. Add one to a selected object under CustomAddOn Info in the Object Panel, or build it against its owner in code, and reach it afterward as object.customAddOns.<name>. The CustomAddOn_ class it extends is what decides which objects will accept it, and an object carries at most one of each. Registered properties are the ones the GUI can see: adjustable in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Content of Custom AddOns/blank template, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// Declare CustomAddOn class, which extends one of the CustomAddOn_XXXXXXX classes.
class incr_replaceText_NameSubstitution extends CustomAddOn_SceneObject
{
    constructor(owner)
    {
        // Call the super constructor
        super(owner);
    }
}


CODE.runBeforeInit___begin;
    // Register the CustomAddOn with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomAddOn(incr_replaceText_NameSubstitution,"A project-defined CustomAddOn that extends a SceneObject with custom behaviors and registered properties.");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 10: Custom AddOns/comprehensive template
----------------------------------------------------------


Title: comprehensive template
Template Library Path: Custom AddOns/comprehensive template
Type: CustomAddOn
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom AddOns/comprehensive template:
A CustomAddOn demonstrating every registered property type and the full callback set.

Covers number, listed number, boolean, string, listed string, and function properties, along with the start, fixedUpdate, enabled-state-change, disposal, and onRegisteredPropertiesRestored callbacks. Note that the enabled-state callback tracks the owner, not the AddOn. Intended as a reference to cut down rather than a starting skeleton.

One property of every type is registered. 'numberProperty' and 'booleanProperty' and 'stringProperty' are the plain three. 'listedNumberProperty' and 'listedStringProperty' show the same types narrowed to a set of choices by giving the returned RegisteredProperty a validationList, which the GUI reads as a menu rather than a field. 'exampleMethod' is registered as a function, so it shows up as a button and can be fired from a Construct Timeline.

The callbacks are the other half of the reference. 'startCallback' runs once the whole project is built, which is where to look up other objects. 'fixedUpdateCallback' runs every fixed update, and 'enabledStateChangeCallback' adds and removes it - note that it tracks the owner's enabled state, not the AddOn's. 'disposalCallback' runs when the AddOn or its owner is disposed, and 'onRegisteredPropertiesRestored' runs after a Construct has put saved property values back.

A CustomAddOn attaches behavior to an object that already exists, rather than being an object in its own right. Add one to a selected object under CustomAddOn Info in the Object Panel, or build it against its owner in code, and reach it afterward as object.customAddOns.<name>. The CustomAddOn_ class it extends is what decides which objects will accept it, and an object carries at most one of each. Registered properties are the ones the GUI can see: adjustable in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Content of Custom AddOns/comprehensive template, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// Declare CustomAddOn class, which extends one of the CustomAddOn_XXXXXXX classes.
class incr_replaceText_NameSubstitution extends CustomAddOn_SceneObject
{
    

    constructor(owner)
    {
        // Call the super constructor
        super(owner);

        // Add some properties to the CustomAddOn... they are registered with the Incisor inspector below
        this.numberProperty = 10;
        this.listedNumberProperty = 100;
        this.booleanProperty = true;
        this.stringProperty = "A String Value!";
        this.listedStringProperty = "Listed String Value!";

        // Add a callback that happens once the project is entirely setup (SceneObjects, Constructs, CustomAddOns, etc...) and ready to 'start'
        nc.appEvents.start.addCallback(this,"startCallback");
        // Add a fixedUpdate callback
        nc.appEvents.fixedUpdate.addCallback(this,"fixedUpdateCallback");
        // Add a callback for when the enabled state of the owner changes 
        this.owner.addEnabledStateChangeCallback(this,"enabledStateChangeCallback");
        // Add a callback for when this CustomAddOn is disposed - this automatically happens if the owning object is disposed
        this.addDisposalCallback(this,"disposalCallback");
    }

    // If a function by this name is implemented in a CustomAddOn which is used within a Construct, it will be invoked directly after 
    // the registered property values are deserialized and restored for each instance of that CustomAddOn.
    onRegisteredPropertiesRestored()
    {
        console.log("The registered properties for the 'incr_replaceText_NameSubstitution' CustomAddOn have been restored.")
    }

    // This function is called with the project is ready to 'start'
    // Use this if you are going to be referencing other SceneObjects, CustomAddOns, etc., to be sure they'll be populated in time
    startCallback()
    {
        console.log("The incr_replaceText_NameSubstitution startCallback function has been invoked.");
    }

    // This function is called every fixedUpdate as long as the owning object is enabled
    fixedUpdateCallback()
    {
        console.log("The incr_replaceText_NameSubstitution fixedUpdateCallback function has been invoked.");
    }

    // This function adds or removes a fixedUpdate callback whenever the owning object's enabled state changes
    enabledStateChangeCallback(state)
    {
        if(state===true)
        {
            nc.appEvents.fixedUpdate.addCallback(this,"fixedUpdateCallback");
        }
        else
        {
            nc.appEvents.fixedUpdate.removeCallback(this,"fixedUpdateCallback");
        }
    }

    // This example function jiggles the rotation of the item, and since the function is registered below, it can be invoked from a button in the GUI and also from within a Construct Timeline animation
    exampleMethod()
    {
        this.owner.rotation.z = 15;
        this.owner.rotation.swoop.z(0,.25);
        console.log("The incr_replaceText_NameSubstitution 'exampleMethod' registered function has been invoked.");
    }

    // This function ia called when this CustomAddOn or its owner have been disposed
    disposalCallback()
    {
        console.log("The incr_replaceText_NameSubstitution disposalCallback function has been invoked.");
    }   
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks
CODE.runBeforeInit___begin;
    // Register the CustomAddOn with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomAddOn(incr_replaceText_NameSubstitution,"A project-defined CustomAddOn demonstrating all registered property types: number, listed number, boolean, string, listed string, and function.");

    // Register properties with the Incisor inspector, so that they can be supervised from within the GUI, and also animated within Construct Timelines
    var incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"numberProperty","A numeric property that can be adjusted in the GUI and animated in Construct Timelines.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"listedNumberProperty","A numeric property restricted to a predefined list of values.");
    incr_replaceText_nameSubstitution_registeredProperty.validationList = [100,200,300,400,500];
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"booleanProperty","A boolean property that can be toggled in the GUI.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.string,"stringProperty","A string property that can be edited in the GUI.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.string,"listedStringProperty","A string property restricted to a predefined list of values.");
    incr_replaceText_nameSubstitution_registeredProperty.validationList = ["Listed String Value!","Other","String","Values"];
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomAddOnProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.function,"exampleMethod","An example registered function that jiggles the owner's rotation. Can be invoked from the GUI or from a Construct Timeline.");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 11: Custom Objects/Button/ButtonTreatmentExample
----------------------------------------------------------


Title: ButtonTreatmentExample
Template Library Path: Custom Objects/Button/ButtonTreatmentExample
Type: CustomObject
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom Objects/Button/ButtonTreatmentExample:
A Button with a full set of interactive behaviors already wired up.

Cursor rollover fade, press and release scaling, drag-to-move, and scroll-to-rotate. Every tuning value is a registered property, so the feel can be adjusted in the GUI and animated on a Timeline. Compare with the CustomAddOn version, which adds the same behaviors to a Button you already have.

'rolloverAlpha' (default .6) is the alpha it fades to while the cursor is over it. 'pressScale' (.9) and 'releaseScale' (1.1) are the scales it takes going down and springing back, and 'returnDuration' (.25) is how long in seconds it takes to settle afterward - it is held at or above 0. 'scrollRotateSpeed' (1) multiplies how far a scroll over it turns it. It takes a graphic asset first, the way any Button does.

A CustomObject is a new type of SceneObject in its own right, rather than behavior fastened onto one that already exists - that is what a CustomAddOn is for. Add one from the Construct Editor's Add menu under CustomObject, or build it in code the way its base type is built - new ButtonTreatmentExample(nc.graphicAssets.icon_checkmark,nc.mainScene,"Button"). It extends Button, so it is a Button everywhere one is expected and everything that type can do it can do too. Registered properties are the ones the GUI can see: adjustable under CustomObject Info in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom Objects/Button/ButtonTreatmentExample:
// Incisor Template Library - ButtonTreatmentExample: a Button that already knows how to behave under the cursor.
// Requires Template Library items: ButtonTreatmentExample

// A CustomObject is added from the Construct Editor's Add menu, under CustomObject, and sits in the hierarchy like any
// other object. Built in code it takes what its base type takes - for a Button, the graphic asset comes first.
let button = new ButtonTreatmentExample(nc.graphicAssets.icon_checkmark,nc.mainScene,"Button");
button.scale.scaleByFactor(4);
button.position.y = 100;

// Everything a Button does it still does, since it is one - the properties below are only what it adds on top.
// rolloverAlpha is what it fades to under the cursor, pressScale and releaseScale are the squash going down and the
// spring coming back, and returnDuration is how long in seconds it takes to settle afterward.
button.rolloverAlpha = .7;
button.pressScale = .85;
button.releaseScale = 1.15;
button.returnDuration = .3;

// Drag it to move it, and scroll over it to turn it - this is how fast a scroll turns it.
button.scrollRotateSpeed = 2;

Content of Custom Objects/Button/ButtonTreatmentExample, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// Adds a Button with a range of interactive functionality, including cursorIn/Out, press/release, drag, and scroll.
class incr_replaceText_NameSubstitution extends Button
{
    

    constructor(graphicAsset,parent,name)
    {
        // Call the super constructor
        super(graphicAsset,parent,name);

        // Add properties that affect the Button's behavior
        this.rolloverAlpha = .6;
        this.pressScale = .9;
        this.releaseScale = 1.1;
        this.returnDuration = .25;
        this.scrollRotateSpeed = 1;

        // Helper Vars
        this.currentCursorPosition = new Vector3();
        this.previousCursorPosition = new Vector3();
        this.governingCamera = null;

        // Adding Button Callbacks
        this.addCursorInCallback(this,"cursorInCallback");
        this.addCursorOutCallback(this,"cursorOutCallback");
        this.addPressCallback(this,"pressCallback");
        this.addReleaseCallback(this,"releaseCallback");
        this.addDragCallback(this,"dragCallback");
        this.addDropCallback(this,"releaseCallback"); 
        this.addScrollCallback(this,"scrollCallback"); 
    }

    cursorInCallback()
    {
        this.colorMultiply.alpha = this.rolloverAlpha;
    }

    cursorOutCallback()
    {
        this.colorMultiply.alpha = 1;
        this.scale.swoop.all(1,0);
    }

    pressCallback()
    {
        this.scale.swoop.all(this.pressScale);
        if(this.governingCamera===null)
        {
            let descendants = this.containingScene.getDescendants();
            for(let i=0; i<descendants.length; i++)
            {
                if(descendants[i].inheritedTypes.Camera!==undefined)
                {
                    this.governingCamera=descendants[i]  ;
                }
            }
        }
        this.governingCamera.getCursorPosition(this.currentCursorPosition);
        this.previousCursorPosition.copy(this.currentCursorPosition);
    }

    releaseCallback()
    {
        this.scale.swoop.all(this.releaseScale);
        this.scale.swoop.all(1,this.returnDuration);
    }

    dragCallback()
    {
        this.governingCamera.getCursorPosition(this.currentCursorPosition);
        let globalPosition = this.getGlobalPosition();
        globalPosition.x+=this.currentCursorPosition.x-this.previousCursorPosition.x; 
        globalPosition.y+=this.currentCursorPosition.y-this.previousCursorPosition.y; 
        this.swoopGlobalPosition([globalPosition.x,globalPosition.y,globalPosition.z]);
        this.previousCursorPosition.copy(this.currentCursorPosition);
    }

    scrollCallback(event)
    {
        this.rotation.z+=event.deltaY*.1*this.scrollRotateSpeed;
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks
CODE.runBeforeInit___begin;
    // Register the CustomObject with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomObject(incr_replaceText_NameSubstitution,"A Button with built-in interactive behaviors: cursor rollover, press/release scaling, drag movement, and scroll rotation.");

    // Create validation function for 'returnDuration' - this will be used in the property registration to have the GUI input validated
    this.incr_replaceText_nameSubstitution_returnDurationValidation=function(val)
    {
        if(val<0){return(0);}
        return(val);
    };

    // Register properties with the Incisor inspector so that they can be supervised from within the GUI, and also animated within Construct Timelines
    var incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"rolloverAlpha","The alpha multiplier applied to the Button when the cursor is over it.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"pressScale","The scale multiplier applied to the Button when pressed.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"releaseScale","The scale multiplier applied to the Button on release before returning to normal.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"returnDuration","The duration in seconds for the Button to return to its default scale after release. Must be non-negative.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty.validationCallbackOwner = this;
    incr_replaceText_nameSubstitution_registeredProperty.validationCallbackName = "incr_replaceText_nameSubstitution_returnDurationValidation";
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"scrollRotateSpeed","The multiplier for how quickly the Button rotates in response to scroll events.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 12: Custom Objects/TextAssembly/TextAssemblyWaveExample
----------------------------------------------------------


Title: TextAssemblyWaveExample
Template Library Path: Custom Objects/TextAssembly/TextAssemblyWaveExample
Type: CustomObject
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom Objects/TextAssembly/TextAssemblyWaveExample:
A TextAssembly that scales its characters up and down in a staggered wave when doTheWave is invoked.

The trigger is registered as a function property, so it can be fired from a button in the GUI or keyframed on a Construct Timeline. A compact demonstration of per-character sequencing.

'doTheWave' is registered as a function rather than a value, so it appears as a button in the Object Panel and can be fired from a Construct Timeline - it is what starts the wave.

The rest shape it. 'underscaleMultiplier' (default .7) is how far each character dips before it rises and 'overscaleMultiplier' (2) is how far it rises. 'totalStaggerTime' (.4) is the time in seconds between the first character starting and the last, and the four phase times - 'characterUnderscaleTime' (.1), 'characterScaleUpTime' (.15), 'characterScaleDownTime' (.15) and 'characterRecoveryTime' (.1) - are how long one character spends dipping, rising, falling and settling. It arrives carrying placeholder text, so set its string to whatever it is meant to say.

A CustomObject is a new type of SceneObject in its own right, rather than behavior fastened onto one that already exists - that is what a CustomAddOn is for. Add one from the Construct Editor's Add menu under CustomObject, or build it in code the way its base type is built - new TextAssemblyWaveExample(nc.mainScene,"Title"). It extends TextAssembly, so it is a TextAssembly everywhere one is expected and everything that type can do it can do too. Registered properties are the ones the GUI can see: adjustable under CustomObject Info in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom Objects/TextAssembly/TextAssemblyWaveExample:
// Incisor Template Library - TextAssemblyWaveExample: a TextAssembly that waves its own characters.
// Requires Template Library items: TextAssemblyWaveExample

// A CustomObject is added from the Construct Editor's Add menu, under CustomObject. Built in code it takes what its
// base type takes, which for a TextAssembly is a parent and a name.
let title = new TextAssemblyWaveExample(nc.mainScene,"Title");

// It arrives carrying placeholder text. 'string' is an ordinary TextAssembly property - it is a TextAssembly, so
// everything that type can do it can do too.
title.string = "INCISOR";

// Each character dips to underscaleMultiplier, rises to overscaleMultiplier and settles back. totalStaggerTime is how
// long the whole line takes to hand the wave from its first character to its last.
title.underscaleMultiplier = .8;
title.overscaleMultiplier = 1.8;
title.totalStaggerTime = .5;

// doTheWave is registered as a function, so in the GUI it is a button and can be fired from a Construct Timeline.
// Called outright here, after a beat that lets the assembly lay its characters out.
nc.waitThen(1,title,"doTheWave");

Content of Custom Objects/TextAssembly/TextAssemblyWaveExample, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// Custom TextAssembly that performs a sequence on its characters, scaling them up and down in a staggered 'wave' motion.
class incr_replaceText_NameSubstitution extends TextAssembly
{
    
    
    constructor(parent,name)
    {
        // Call the super constructor
        super(parent,name);

        // Default the String Value
        this.string = "CUSTOM TEXT ASSEMBLY!";

        // Add properties affecting 'wave' functionality
        this.underscaleMultiplier = .7;
        this.overscaleMultiplier = 2;
        this.totalStaggerTime = .4;
        this.characterUnderscaleTime = .1;
        this.characterScaleUpTime = .15;
        this.characterScaleDownTime = .15;
        this.characterRecoveryTime = .1;
    }

    doTheWave()
    {
        // Acquire the characters within the TextAssembly
        let characters = this.getCharacters();

        // Loop through the characters, starting a scale-up-scale-down sequence witha staggered offset.
        let waitTime = 0;
        for(let i=0; i<characters.length; i++)
        {
            nc.waitThen(waitTime,this,"characterScaleSequence",[characters[i],this.textFormat.characterScaleX*this.scaleToFitFactor]);
            waitTime+=this.totalStaggerTime/characters.length;
        }
    }


    characterScaleSequence(character,baseScale)
    {
        // Var to track the running total of the sequence time
        let runningTotalSeconds=0;

        // Scale the character down during the 'wind-up'
        character.scale.swoop.all(this.underscaleMultiplier*baseScale,this.characterUnderscaleTime,nc.tweenTypes.Ease);
        runningTotalSeconds+=this.characterUnderscaleTime;

        // Scale the character up for its part of the 'wave'
        nc.waitThen(runningTotalSeconds,character.scale.swoop,"all",[this.overscaleMultiplier*baseScale,this.characterScaleUpTime,nc.tweenTypes.Ease]);
        runningTotalSeconds+=this.characterScaleUpTime;

        // Scale the character back down 
        nc.waitThen(runningTotalSeconds,character.scale.swoop,"all",[this.underscaleMultiplier*baseScale,this.characterScaleDownTime,nc.tweenTypes.Ease]);
        runningTotalSeconds+=this.characterScaleDownTime;
    
        // Scale the character back to its base scale
        nc.waitThen(runningTotalSeconds,character.scale.swoop,"all",[baseScale,this.characterRecoveryTime,nc.tweenTypes.Ease]);
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks
CODE.runBeforeInit___begin;
    // Register the CustomAddOn with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomObject(incr_replaceText_NameSubstitution,"A TextAssembly that animates its characters in a staggered wave motion when doTheWave is invoked.");

    // Register the 'doTheWave' function so that it can be invoked from the GUI, or from within a Construct Timeline via invocation keyframe.
    nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,"function","doTheWave","Triggers the wave animation, scaling each character up and down in a staggered sequence.");

    // Register the other numeric properties for GUI/Timeline manipulation
    var incr_replaceText_nameSubstitution_registeredProperty =  nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"overscaleMultiplier","The scale multiplier applied to each character at the peak of its wave.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"underscaleMultiplier","The scale multiplier applied to each character during the wind-up before its wave peak.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"totalStaggerTime","The total time in seconds over which the wave animation is staggered across all characters.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"characterUnderscaleTime","The duration in seconds for each character's wind-up phase.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"characterScaleUpTime","The duration in seconds for each character's scale-up phase.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"characterScaleDownTime","The duration in seconds for each character's scale-down phase.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"characterRecoveryTime","The duration in seconds for each character to return to its base scale.");
    incr_replaceText_nameSubstitution_registeredProperty.dragMultiplier = .002;
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 13: Custom Objects/TextBox/FrameRateCounter
----------------------------------------------------------


Title: FrameRateCounter
Template Library Path: Custom Objects/TextBox/FrameRateCounter
Type: CustomObject
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom Objects/TextBox/FrameRateCounter:
A TextBox that displays the current frame rate, pinning itself to the upper-left of the screen.

In the main scene it reparents itself to the main camera on start and re-pins on every canvas resize, so it stays in the corner whatever the window does. Anywhere else - inside a Precomp, say - it does neither and simply stays where it is put. Useful to drop into a project during optimization work and delete afterward.

'updateInterval' (default 1) is the gap in seconds between readings. Longer is steadier and easier to read, shorter catches brief stalls that a long average smooths away.

A CustomObject is a new type of SceneObject in its own right, rather than behavior fastened onto one that already exists - that is what a CustomAddOn is for. Add one from the Construct Editor's Add menu under CustomObject, or build it in code the way its base type is built - new FrameRateCounter(nc.mainScene,"FrameRate"). It extends TextBox, so it is a TextBox everywhere one is expected and everything that type can do it can do too. Registered properties are the ones the GUI can see: adjustable under CustomObject Info in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom Objects/TextBox/FrameRateCounter:
// Incisor Template Library - FrameRateCounter: reading the frame rate while a project is being tuned.
// Requires Template Library items: FrameRateCounter

// A CustomObject is added from the Construct Editor's Add menu, under CustomObject. Built in code it takes what its
// base type takes, which for a TextBox is a parent and a name.
// Placed in the main scene it reparents itself to the main camera and pins to the upper-left corner, re-pinning on
// every canvas resize. Anywhere else - inside a Precomp, say - it does neither and stays where it is put.
let counter = new FrameRateCounter(nc.mainScene,"FrameRate");

// updateInterval is the gap in seconds between readings. Longer is steadier to read, shorter catches brief stalls that
// a long average would smooth away.
counter.updateInterval = .5;

Content of Custom Objects/TextBox/FrameRateCounter, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// CustomObject that displays the current frame rate of the project, updating the value periodically.
class incr_replaceText_NameSubstitution extends TextBox
{
    constructor(parent,name)
    {
        super(parent,name);
        this.horizontalJustification = "left";
        this.verticalJustification = "top";
        this.boxWidth = 150;
        this.boxHeight = 30;
        this.updateInterval = 1;
        nc.appEvents.start.addCallback(this,"startCallback");
        this.addEnabledStateChangeCallback(this,"enabledStateChangeCallback");
        if(this.containingScene === nc.mainScene){nc.appEvents.canvasResize.addCallback(this, "canvasResize");}
        nc.appEvents.screenUpdate.addCallback(this,"screenUpdateCallback");
    }


    canvasResize()
    {
        // pin to upper left corner of screen
        let dim = nc.mainCamera.getCurrentViewDimensions();
        if(this.containingScene === nc.mainScene && this.parent !== nc.mainCamera){this.parent = nc.mainCamera;}
        this.position.swoop.each([-dim.x * .5 + this.boxWidth * .5, dim.y * .5 - this.boxHeight * .5]);
    }


    startCallback()
    {
        // reparent to mainCamera if required
        if(this.containingScene === nc.mainScene && this.parent !== nc.mainCamera){this.parent = nc.mainCamera;}
        this.screenUpdateCounter = 0;
        this.previousTime = Date.now();
        this.canvasResize();
    }


    screenUpdateCallback()
    {
        ++this.screenUpdateCounter;
        let currentTime = Date.now();
        let deltaTime = (currentTime - this.previousTime) / 1000;
        if (deltaTime > this.updateInterval)
        {
            this.string = " FPS: " + (this.screenUpdateCounter / deltaTime).toFixed(2);
            this.previousTime = currentTime + deltaTime - this.updateInterval;
            this.screenUpdateCounter = 0;
        }        
    }


    enabledStateChangeCallback(state)
    {
        if(state===true)
        {
            nc.appEvents.screenUpdate.addCallback(this,"screenUpdateCallback");
        }
        else
        {
            nc.appEvents.screenUpdate.removeCallback(this,"screenUpdateCallback");
        }
    }
}


CODE.runBeforeInit___begin;
    nc.registerCustomObject(incr_replaceText_NameSubstitution,"A TextBox that displays the current frame rate, pinned to the upper-left corner of the screen and updating at a configurable interval.");
    nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"updateInterval","The interval in seconds between frame rate display updates.");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 14: Custom Objects/TextBox/TextBoxClockExample
----------------------------------------------------------


Title: TextBoxClockExample
Template Library Path: Custom Objects/TextBox/TextBoxClockExample
Type: CustomObject
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom Objects/TextBox/TextBoxClockExample:
A TextBox that displays the current time, updating every frame.

Seconds can be shown or hidden through a registered boolean property. A small, readable example of driving text content from a per-frame callback.

'showSeconds' (default true) is the only one - false leaves hours and minutes.

A CustomObject is a new type of SceneObject in its own right, rather than behavior fastened onto one that already exists - that is what a CustomAddOn is for. Add one from the Construct Editor's Add menu under CustomObject, or build it in code the way its base type is built - new TextBoxClockExample(nc.mainScene,"Clock"). It extends TextBox, so it is a TextBox everywhere one is expected and everything that type can do it can do too. Registered properties are the ones the GUI can see: adjustable under CustomObject Info in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Examples of Custom Objects/TextBox/TextBoxClockExample:
// Incisor Template Library - TextBoxClockExample: a TextBox that keeps the time.
// Requires Template Library items: TextBoxClockExample

// A CustomObject is added from the Construct Editor's Add menu, under CustomObject. Built in code it takes what its
// base type takes, which for a TextBox is a parent and a name.
let clock = new TextBoxClockExample(nc.mainScene,"Clock");

// showSeconds is registered, so it is a checkbox in the Object Panel and can be keyframed on a Construct Timeline.
clock.showSeconds = true;

// It writes its own string every frame, so nothing else should be setting that - but it is a TextBox in every other
// way, and the rest of the type is there to use.
clock.horizontalJustification = "center";

Content of Custom Objects/TextBox/TextBoxClockExample, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// A TextBox with built-in clock functionality
class incr_replaceText_NameSubstitution extends TextBox
{
    
    
    constructor(parent,name)
    {
        // Call the super constructor
        super(parent,name);

        // Boolean determining if the clock will show seconds
        this.showSeconds = true;

        // Add fixedUpdate callback
        nc.appEvents.fixedUpdate.addCallback(this,"fixedUpdateCallback");
    }

    // This function is triggered every fixed update
    fixedUpdateCallback()
    {
        // Assemble the time string in the desired format
        let date = new Date();
        let hour = date.getHours();
        let ampm = "am";
        // Convert the reading onto a twelve hour clock. Noon and midnight are the two that have to be said out loud:
        // the twelve o'clock hour belongs to pm, and hour zero is written as twelve rather than as nothing.
        if(hour>=12){ampm = "pm";}
        if(hour>12){hour -= 12;}
        if(hour===0){hour = 12;}
        let minute = this.addLeadingZeros(date.getMinutes(),2);
        let second = this.addLeadingZeros(date.getSeconds(),2);
        // Set the TextBox's string to the time string
        if(this.showSeconds===true)
        {
            this.string = hour + ":" + minute + ":" + second + " " + ampm;
        }
        else
        {
            this.string = hour + ":" + minute + " " + ampm;
        }
    }

    // Function to pad the minutes and seconds with zeros when they would otherwise be single digits
    addLeadingZeros(number,digitsRequired)
    {
        if(digitsRequired===undefined){digitsRequired=2;}
        let stringVersion = number.toString();
        while(stringVersion.length<digitsRequired)
        {
            stringVersion = "0" + stringVersion;
        }
        return(stringVersion);
    }
}

// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks
CODE.runBeforeInit___begin;
    // Register the CustomObject with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomObject(incr_replaceText_NameSubstitution,"A TextBox that displays the current time, updating every frame.");

    // Register the 'showSeconds' var so this can be manipulated in the GUI
    nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"showSeconds","When true, the clock display includes seconds. When false, only hours and minutes are shown.");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 15: Custom Objects/blank template
----------------------------------------------------------


Title: blank template
Template Library Path: Custom Objects/blank template
Type: CustomObject
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom Objects/blank template:
A minimal CustomObject: a class extending SceneObject, plus the nc.registerCustomObject call that makes it addable from the GUI.

Change the base class to GraphicObject, Button, TextBox, TextAssembly, or ParticleSystem to suit. Start here when you know what you are building; start from the comprehensive template when you want the callback and property patterns spelled out.

It registers no properties. To add one, give the class a member and call nc.registerCustomObjectProperty with the class, a type from constants.registeredPropertyTypes, the member's name and a description that becomes its tooltip. The call hands back a RegisteredProperty, which is where a validation callback, a validation list or a drag multiplier goes.

A CustomObject is a new type of SceneObject in its own right, rather than behavior fastened onto one that already exists - that is what a CustomAddOn is for. Add one from the Construct Editor's Add menu under CustomObject, or build it in code the way its base type is built. Whichever of SceneObject, GraphicObject, Button, TextBox, TextAssembly or ParticleSystem it extends, it is one of those everywhere one is expected, and everything that type can do it can do too. Registered properties are the ones the GUI can see: adjustable under CustomObject Info in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Content of Custom Objects/blank template, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// Declare CustomObject class, which extends SceneObject, GraphicObject, Button, TextBox, TextAssembly, or ParticleSystem.
class incr_replaceText_NameSubstitution extends SceneObject
{
    constructor(parent,name)
    {
        // Call the super constructor
        super(parent,name);
    }
}


CODE.runBeforeInit___begin;
    // Register the CustomObject with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomObject(incr_replaceText_NameSubstitution,"A project-defined SceneObject type with custom behaviors and registered properties.");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 16: Custom Objects/comprehensive template
----------------------------------------------------------


Title: comprehensive template
Template Library Path: Custom Objects/comprehensive template
Type: CustomObject
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Custom Objects/comprehensive template:
A CustomObject demonstrating every registered property type and the full callback set.

Covers number, listed number, boolean, string, listed string, and function properties, along with the start, fixedUpdate, enabled-state-change, disposal, and onRegisteredPropertiesRestored callbacks. Intended as a reference to cut down rather than a starting skeleton.

One property of every type is registered. 'numberProperty', 'booleanProperty' and 'stringProperty' are the plain three. 'listedNumberProperty' and 'listedStringProperty' show the same types narrowed to a set of choices by giving the returned RegisteredProperty a validationList, which the GUI reads as a menu rather than a field. 'exampleMethod' is registered as a function, so it shows up as a button and can be fired from a Construct Timeline.

The callbacks are the other half of the reference. 'startCallback' runs once the whole project is built, which is where to look up other objects. 'fixedUpdateCallback' runs every fixed update, and 'enabledStateChangeCallback' adds and removes it. 'disposalCallback' runs when the object is disposed, and 'onRegisteredPropertiesRestored' runs after a Construct has put saved property values back.

A CustomObject is a new type of SceneObject in its own right, rather than behavior fastened onto one that already exists - that is what a CustomAddOn is for. Add one from the Construct Editor's Add menu under CustomObject, or build it in code the way its base type is built. Whichever of SceneObject, GraphicObject, Button, TextBox, TextAssembly or ParticleSystem it extends, it is one of those everywhere one is expected, and everything that type can do it can do too. Registered properties are the ones the GUI can see: adjustable under CustomObject Info in the Object Panel, saved with a Construct, and animatable on a Construct Timeline.

Content of Custom Objects/comprehensive template, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
// Declare CustomObject class, which extends SceneObject, GraphicObject, Button, TextBox, TextAssembly, or ParticleSystem.
class incr_replaceText_NameSubstitution extends SceneObject
{
    

    constructor(parent,name)
    {
        // Call the super constructor
        super(parent,name);

        // Add some properties to the CustomObject... they are registered with the Incisor inspector below
        this.numberProperty = 10;
        this.listedNumberProperty = 100;
        this.booleanProperty = true;
        this.stringProperty = "A String Value!";
        this.listedStringProperty = "Listed String Value!";

        // Add a callback that happens once the project is entirely setup (SceneObjects, Constructs, CustomAddOns, etc...) and ready to 'start'
        nc.appEvents.start.addCallback(this,"startCallback");
        // Add a fixedUpdate callback
        nc.appEvents.fixedUpdate.addCallback(this,"fixedUpdateCallback");
        // Add a callback for when the enabled state changes 
        this.addEnabledStateChangeCallback(this,"enabledStateChangeCallback");
        // Add a callback for when this CustomObject is disposed
        this.addDisposalCallback(this,"disposalCallback");
    }

    // If a function by this name is implemented in a CustomAddOn which is used within a Construct, it will be invoked directly after 
    // the registered property values are deserialized and restored for each instance of that CustomAddOn.
    onRegisteredPropertiesRestored()
    {
        console.log("The registered properties for the 'incr_replaceText_NameSubstitution' CustomAddOn have been restored.")
    }

    // This function is called with the project is ready to 'start'
    // Use this if you are going to be referencing other SceneObjects, CustomAddOns, etc., to be sure they'll be populated in time
    startCallback()
    {
        console.log("The incr_replaceText_NameSubstitution startCallback function has been invoked.");
    }

    // This function is setup up to be called every fixedUpdate as long as object is enabled
    fixedUpdateCallback()
    {
        console.log("The incr_replaceText_NameSubstitution fixedUpdateCallback function has been invoked.");
    }

    // This function adds or removes a fixedUpdate callback whenever the object's enabled state changes
    enabledStateChangeCallback(state)
    {
        if(state===true)
        {
            nc.appEvents.fixedUpdate.addCallback(this,"fixedUpdateCallback");
        }
        else
        {
            nc.appEvents.fixedUpdate.removeCallback(this,"fixedUpdateCallback");
        }
    }

    // This example function jiggles the rotation of the item, and since the function is registered below, it can be invoked from a button in the GUI and also from within a Construct Timeline animation
    exampleMethod()
    {
        this.rotation.z = 15;
        this.rotation.swoop.z(0,.25);
        console.log("The incr_replaceText_NameSubstitution 'exampleMethod' registered function has been invoked.");
    }

    // This function is called when this CustomObject is disposed.
    disposalCallback()
    {
        console.log("The incr_replaceText_NameSubstitution disposalCallback function has been invoked.");
    }   
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks
CODE.runBeforeInit___begin;
    // Register the CustomObject with the Incisor inspector, so that it can be added within the GUI.
    nc.registerCustomObject(incr_replaceText_NameSubstitution,"A project-defined SceneObject type demonstrating all registered property types: number, listed number, boolean, string, listed string, and function.");

    // Register properties with the Incisor inspector so that they can be supervised from within the GUI, and also animated within Construct Timelines
    var incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"numberProperty","A numeric property that can be adjusted in the GUI and animated in Construct Timelines.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.number,"listedNumberProperty","A numeric property restricted to a predefined list of values.");
    incr_replaceText_nameSubstitution_registeredProperty.validationList = [100,200,300,400,500];
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.boolean,"booleanProperty","A boolean property that can be toggled in the GUI.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.string,"stringProperty","A string property that can be edited in the GUI.");
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.string,"listedStringProperty","A string property restricted to a predefined list of values.");
    incr_replaceText_nameSubstitution_registeredProperty.validationList = ["Listed String Value!","Other","String","Values"];
    incr_replaceText_nameSubstitution_registeredProperty = nc.registerCustomObjectProperty(incr_replaceText_NameSubstitution,constants.registeredPropertyTypes.function,"exampleMethod","An example registered function that jiggles the object's rotation. Can be invoked from the GUI or from a Construct Timeline.");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 17: Effect Nodes/Arch
----------------------------------------------------------


Title: Arch
Template Library Path: Effect Nodes/Arch
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/Arch:
Deforms geometry by bending vertices into an arch.

Strength, horizontal stretch, and tilt are exposed as EffectControllers.

Arching text is the usual reason to reach for this, and it holds up on live text - the arch is applied in the vertex stage rather than baked into the artwork, so a TextBox that rebuilds itself around a new string comes back arched with nothing reapplied.

Because the bend is a curve, it can only shape geometry that has vertices to shape - a plain quad will tilt rather than arch. On a TextBox, raise numHorizontalGridSegments. For anything else, build the Geometry with nc.defineGeometry and newGrid.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/Arch:
// Incisor Template Library - Arch: bending an image up into an arch.
// Requires Template Library items: Arch

// Arch can only move vertices that are already there, so the image needs a subdivided Geometry rather than a plain quad.
// The bend runs horizontally, so the horizontal segments are the ones that count.
let geometryEditor = nc.defineGeometry("ArchSurface",false);
geometryEditor.newGrid(400,400,40,4);
geometryEditor.commitChanges();

let surface = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Surface");
surface.geometry = nc.geometries.ArchSurface;
surface.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.Arch,nc.effectNodes.ColorMultiply]);

// Stretch widens the arch and tilt leans it over - both are left still here so the bend is the only thing moving.
surface.materialMaster.arch.strength = 0;
surface.materialMaster.arch.stretch = 0;
surface.materialMaster.arch.tilt = 1;

// Bend it.
nc.swoopValue(surface.materialMaster.arch,"strength",-.4,2.4,nc.tweenTypes.Ease);

Content of Effect Nodes/Arch, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode bends geometry into an arch, curving it up or down around a center.

It is particularly useful on text - a TextBox or TextAssembly run through this will follow the curve, and because the
arch is driven by EffectControllers it can be animated while the text is on screen.

This is a vertex-stage node, so it moves the vertices an object already has and never touches color. A plain quad has
only its four corners and will fold rather than curve - give the object a subdivided Geometry built with
nc.defineGeometry and newGrid, or on a TextBox raise numHorizontalGridSegments and numVerticalGridSegments.

Once the node is on an object, its controller is reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution'.
*/


CODE.runBeforeInit___begin;
    // 'strength' is which way and how hard the arch bends, and its sign is what flips the curve between arching up and
    // sagging down. 'tilt' decides whether the object leans into the curve or stays upright as it travels around it.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution", "Vector3", ["strength", "stretch", "tilt"], [-.2, 0, 1], nc.constants.effectControllerMixModes.addition, [[0, 1], [0, 1], [0, 1]], "EffectController for the incr_replaceText_NameSubstitution EffectNode, which deforms geometry by pushing the vertices into an arch.", ["arch amount", "horizontal stretch", "tilt amount"]);

    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        // A plain 2D rotation, kept as a helper because the arch rotates each vertex twice by different amounts.
        ["uniform vec3 incr_replaceText_nameSubstitution;",
        "vec2 arcRotate2D(vec2 v, float a)\n\
        {\n\
            float s = sin(a);\n\
            float c = cos(a);\n\
            return mat2(c, -s, s, c) * v;\n\
        }"
        ],
        // The curve comes from rotating each vertex by an amount proportional to how far out it sits horizontally, so
        // the further from the center a column of the object is, the more it swings around. The vertex's horizontal and
        // vertical parts are rotated separately, and 'tilt' scales the second rotation - at 0 the object stays upright
        // as it follows the arch, at 1 it leans with it.
        "float incr_replaceText_nameSubstitution_stretch = incr_replaceText_nameSubstitution.y;\n\
        float incr_replaceText_nameSubstitution_tilt = incr_replaceText_nameSubstitution.z;\n\
        float incr_replaceText_nameSubstitution_strength = incr_replaceText_nameSubstitution.x * -3.14159265359 / 1000.0;\n\
        vec2 incr_replaceText_nameSubstitution_originalVertex = vertex.xy;\n\
        float incr_replaceText_nameSubstitution_r = incr_replaceText_nameSubstitution_originalVertex.x * (1.0 + incr_replaceText_nameSubstitution_stretch) * incr_replaceText_nameSubstitution_strength;\n\
        vertex.xy = arcRotate2D(vec2(incr_replaceText_nameSubstitution_originalVertex.x * (1.0 + incr_replaceText_nameSubstitution_stretch), 0.0), incr_replaceText_nameSubstitution_r) + arcRotate2D(vec2(0.0, incr_replaceText_nameSubstitution_originalVertex.y), incr_replaceText_nameSubstitution_r * 2.0 * incr_replaceText_nameSubstitution_tilt);",
        [],
        "",
        [incr_replaceText_nameSubstitution_def],
        undefined, undefined, undefined, undefined,
        "Deforms geometry by bending vertices into an arch shape. Supports strength, horizontal stretch, and tilt controls."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 18: Effect Nodes/BrightnessContrast
----------------------------------------------------------


Title: BrightnessContrast
Template Library Path: Effect Nodes/BrightnessContrast
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/BrightnessContrast:
Adjusts the brightness and contrast of the fragments on the Material it is applied to.

A fragment-stage effect that composes cleanly with the color EffectNodes. Apply it after Colorize or HueSaturationValue to grade the final result.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/BrightnessContrast:
// Incisor Template Library - BrightnessContrast: pushing the contrast of an image up.
// Requires Template Library items: BrightnessContrast

let picture = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Picture");
picture.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.BrightnessContrast,nc.effectNodes.ColorMultiply]);

// Both components are added to what the image already has, so zero leaves it alone.
picture.materialMaster.brightnessContrast.brightness = 0;
picture.materialMaster.brightnessContrast.contrast = 0;

// Push the contrast, then lift the brightness back up to pay for what the contrast took out of the midtones.
nc.swoopValue(picture.materialMaster.brightnessContrast,"contrast",.6,2,nc.tweenTypes.Ease);
nc.swoopValue(picture.materialMaster.brightnessContrast,"brightness",.3,2,nc.tweenTypes.Ease);

Content of Effect Nodes/BrightnessContrast, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode adjusts the brightness and contrast of an object's pixels.

This is a fragment-stage node, so it recolors what has already been drawn and never moves geometry. It needs no
subdivision and works on any object.

Once the node is on an object, its controller is reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution'.
*/


CODE.runBeforeInit___begin;
    // Both components are offsets rather than multipliers, so 0 is the neutral value that leaves the image alone.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution", "Vector2", ["brightness", "contrast"], [0, 0], nc.constants.effectControllerMixModes.addition, [[0, 1], [0, 1]], "EffectController for the incr_replaceText_NameSubstitution EffectNode, which adjusts the brightness and contrast of the fragments (pixels) on the Material it is applied to.", ["Brightness Adjustment", "Contrast Adjustment"]);

    // The empty vertex arguments below are what makes this a fragment-only node.
    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        [],
        "",
        ["uniform vec2 incr_replaceText_nameSubstitution;"],
        // The color is un-premultiplied first and premultiplied again at the end, so the adjustment works on the true
        // color rather than one already faded by its own alpha. The max() guards against dividing by zero on a fully
        // transparent pixel. Contrast then scales the color away from mid-gray, and brightness is added flat on top.
        "fragment.rgb /= max(fragment.a, .001);\n\
        fragment.rgb = (fragment.rgb - vec3(.5)) * (incr_replaceText_nameSubstitution.y + 1.0) + vec3(.5);\n\
        fragment.rgb += vec3(incr_replaceText_nameSubstitution.x);\n\
        fragment.rgb *= fragment.a;",
        [incr_replaceText_nameSubstitution_def],
        undefined, undefined, undefined, undefined,
        "Adjusts the brightness and contrast of the fragments on the Material it is applied to."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 19: Effect Nodes/Bulge
----------------------------------------------------------


Title: Bulge
Template Library Path: Effect Nodes/Bulge
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/Bulge:
Pushes vertices away from a center point, creating a bulge within a defined radius.

The horizontal and vertical falloff distances and the bulge strength are separately controllable.

Because the falloff is a curve, it can only bend geometry that has vertices to bend - a plain quad will fold rather than curve. On a TextBox, raise numHorizontalGridSegments and numVerticalGridSegments. For anything else, build the Geometry with nc.defineGeometry and newGrid.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/Bulge:
// Incisor Template Library - Bulge: swelling an image out from its center.
// Requires Template Library items: Bulge

// Bulge moves the vertices that are already there, so the image needs a subdivided Geometry rather than a plain quad.
let geometryEditor = nc.defineGeometry("BulgeSurface",false);
geometryEditor.newGrid(400,400,40,40);
geometryEditor.commitChanges();

let surface = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Surface");
surface.geometry = nc.geometries.BulgeSurface;
surface.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.Bulge,nc.effectNodes.ColorMultiply]);

// The radii set how far the bulge reaches before it falls off to nothing.
surface.materialMaster.bulge.radiusX = 150;
surface.materialMaster.bulge.radiusY = 150;
surface.materialMaster.bulge.strength = 0;

// The center is in the object's own space, so 0,0 is the middle of the surface.
surface.materialMaster.bulge_center.x = 0;
surface.materialMaster.bulge_center.y = 0;

// Swell it up.
nc.swoopValue(surface.materialMaster.bulge,"strength",1,1.2,nc.tweenTypes.Ease);

Content of Effect Nodes/Bulge, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode swells geometry outward from a center point, easing off to nothing at
a falloff radius.

This is a vertex-stage node, so it moves the vertices an object already has and never touches color. A plain quad has
only its four corners and will fold rather than curve - give the object a subdivided Geometry built with
nc.defineGeometry and newGrid, or on a TextBox raise numHorizontalGridSegments and numVerticalGridSegments.

Once the node is on an object, its controllers are reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution' and 'materialMaster.incr_replaceText_nameSubstitution_center'.
*/


CODE.runBeforeInit___begin;
    // The shape of the bulge. 'strength' is a proportion of each vertex's own distance from the center rather than a
    // distance in units, so a vertex sitting 80 units out is pushed at most another 80 * strength.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution", "Vector3", ["radiusX", "radiusY", "strength"], [100, 100, .5], nc.constants.effectControllerMixModes.addition, [[0, 200], [0, 200], [0, 1]], "EffectController for the incr_replaceText_NameSubstitution EffectNode, which deforms geometry by pushing the vertices away from the incr_replaceText_nameSubstitution_center.", ["The horizontal distance at which the vertex displacement drops to zero", "The vertical distance at which the vertex displacement drops to zero", "The strength of the bulge effect"]);

    // Where the bulge is centered, in the object's own space rather than screen or world space, so 0,0 sits at the
    // middle of the geometry.
    let incr_replaceText_nameSubstitution_center_def = nc.defineEffectController("incr_replaceText_nameSubstitution_center", "Vector2", ["x", "y"], [0, 0], nc.constants.effectControllerMixModes.addition, [[0, 3000], [0, 3000]], "EffectController for the incr_replaceText_NameSubstitution EffectNode, which deforms geometry by pushing the vertices away from the incr_replaceText_nameSubstitution_center.",["The x position of the center of the bulge effect","The y position of the center of the bulge effect"]);

    // The empty fragment arguments below are what makes this a vertex-only node.
    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        ["uniform vec3 incr_replaceText_nameSubstitution;", "uniform vec2 incr_replaceText_nameSubstitution_center;"],
        // Each vertex is pushed straight out along its own vector from the center. Both smoothstep calls read their
        // edges high-to-low, which inverts them - full displacement at the center, easing to none at the radius and
        // nothing past it. The two axes fall off independently and multiply, so the region is a rounded rectangle.
        "vec2 incr_replaceText_nameSubstitution_dir = vertex.xy - incr_replaceText_nameSubstitution_center;\n\
        vertex.xy += incr_replaceText_nameSubstitution_dir * smoothstep(incr_replaceText_nameSubstitution.x, 0.0, abs(incr_replaceText_nameSubstitution_dir.x)) * smoothstep(incr_replaceText_nameSubstitution.y, 0.0, abs(incr_replaceText_nameSubstitution_dir.y)) * (incr_replaceText_nameSubstitution.z);",
        [],
        "",
        [incr_replaceText_nameSubstitution_def, incr_replaceText_nameSubstitution_center_def],
        undefined, undefined, undefined, undefined,
        "Deforms geometry by pushing vertices away from a center point, creating a bulge effect within a defined radius."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 20: Effect Nodes/ColorBlend
----------------------------------------------------------


Title: ColorBlend
Template Library Path: Effect Nodes/ColorBlend
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/ColorBlend:
Blends the fragment color toward a target color by a given strength.

A straight mix between the original color and the target, so at full strength the Material becomes a flat color. Use Colorize instead to recolor while keeping the original luminosity.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/ColorBlend:
// Incisor Template Library - ColorBlend: fading an image out to a flat color.
// Requires Template Library items: ColorBlend

let picture = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Picture");
picture.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.ColorBlend,nc.effectNodes.ColorMultiply]);

// This is a straight mix toward the target color, so at full strength nothing of the original is left.
// Use Colorize instead where the image's own light and dark areas should survive the recoloring.
picture.materialMaster.colorBlend.red = 1;
picture.materialMaster.colorBlend.green = .25;
picture.materialMaster.colorBlend.blue = 0;
picture.materialMaster.colorBlend.strength = 0;

// Take it all the way over to the flat color.
nc.swoopValue(picture.materialMaster.colorBlend,"strength",1,4.5,nc.tweenTypes.Ease);

Content of Effect Nodes/ColorBlend, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode blends an object's pixels toward a single flat color.

This is a fragment-stage node, so it recolors what has already been drawn and never moves geometry. It needs no
subdivision and works on any object.

Once the node is on an object, its controller is reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution'. Swooping 'strength' is the usual way to fade the color in and out.
*/


CODE.runBeforeInit___begin;
    // The first three components are the target color and 'strength' is how far toward it to travel, so 0 leaves the
    // image alone and 1 replaces it with a flat block of that color.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution", "Vector4", ["red", "green", "blue", "strength"], [1, 0, 0, 1], nc.constants.effectControllerMixModes.addition, [[0, 1], [0, 1], [0, 1], [0, 1]], "EffectController for the incr_replaceText_NameSubstitution EffectNode, which adjusts the color blend of the fragments (pixels) on the Material it is applied to.", ["The red component of the desired hue", "The green component of the desired hue", "The blue component of the desired hue", "Mixing factor between the original color and the new color"]);

    // The empty vertex arguments below are what makes this a fragment-only node.
    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        [],
        "",
        ["uniform vec4 incr_replaceText_nameSubstitution;"],
        // The color is un-premultiplied first and premultiplied again at the end, so the blend works on the true color
        // rather than one already faded by its own alpha. The max() guards against dividing by zero on a fully
        // transparent pixel. Every channel is mixed, so this flattens detail as strength approaches 1.
        "fragment.rgb /= max(fragment.a, .001);\n\
        fragment.rgb = mix(fragment.rgb, incr_replaceText_nameSubstitution.rgb, incr_replaceText_nameSubstitution.w);\n\
        fragment.rgb *= fragment.a;",
        [incr_replaceText_nameSubstitution_def],
        undefined, undefined, undefined, undefined,
        "Blends the fragment color toward a target color by a given strength, mixing between the original color and the new color."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 21: Effect Nodes/Colorize
----------------------------------------------------------


Title: Colorize
Template Library Path: Effect Nodes/Colorize
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/Colorize:
Shifts the hue of the fragment color toward a target hue while preserving the original luminosity structure.

Unlike ColorBlend, shading and detail survive the recolor, which makes this the right choice for tinting artwork rather than flooding it.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/Colorize:
// Incisor Template Library - Colorize: tinting an image while its shading survives.
// Requires Template Library items: Colorize

let picture = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Picture");
picture.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.Colorize,nc.effectNodes.ColorMultiply]);

// Colorize keeps the luminosity it finds and recolors it, so the image's light and dark areas stay where they were.
// Use ColorBlend instead where the color should replace the image rather than tint it.
picture.materialMaster.colorize.red = .2;
picture.materialMaster.colorize.green = .6;
picture.materialMaster.colorize.blue = 1;
picture.materialMaster.colorize.alpha = 1;

// Slide the tint from blue around to orange.
nc.swoopValue(picture.materialMaster.colorize,"red",1,6,nc.tweenTypes.Ease);
nc.swoopValue(picture.materialMaster.colorize,"blue",.2,6,nc.tweenTypes.Ease);

Content of Effect Nodes/Colorize, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode recolors an object to a single hue while leaving its shading intact.

Unlike a flat color blend, this keeps each pixel's original saturation and brightness and swaps only the hue, so
highlights, shadows and texture detail all survive the recolor.

This is a fragment-stage node, so it recolors what has already been drawn and never moves geometry. It needs no
subdivision and works on any object.

Once the node is on an object, its controller is reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution'.
*/


CODE.runBeforeInit___begin;
    // Only the hue of the color set here is used - its saturation and brightness are ignored, since those come from
    // the pixel being recolored. The fourth component is how far to carry the recolor, not an opacity.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution", "Vector4", ["red", "green", "blue", "alpha"], [1, 0, 0, 1], nc.constants.effectControllerMixModes.addition, [[0, 1], [0, 1], [0, 1], [0, 1]], "EffectController for the incr_replaceText_NameSubstitution EffectNode, which adjusts the color of the fragments (pixels) on the Material it is applied to.", ["The red component of the desired hue", "The green component of the desired hue", "The blue component of the desired hue", "Mixing factor between the original color and the new color"]);

    // The empty vertex arguments below are what makes this a fragment-only node.
    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        [],
        "",
        // Hue is not something RGB can be adjusted in directly, so these two convert a color into hue, saturation and
        // value and back again. They deliberately carry no node name - support code is shared across every node on a
        // material and matched exactly, so any node declaring these identically ends up sharing one copy of them.
        ["vec3 incr_rgbToHsv(vec3 c)\
        {\
            vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\
            vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\
            vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\
            float d = q.x - min(q.w, q.y);\
            float e = 1.0e-10;\
            return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\
        }",
        "vec3 incr_hsvToRgb(vec3 c)\
        {\
            vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\
            vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\
            return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\
        }",
        "uniform vec4 incr_replaceText_nameSubstitution;"],
        // The pixel is taken apart into hue, saturation and value, its hue alone is overwritten with the target's, and
        // it is put back together. Because saturation and value are untouched, a black or gray pixel has nothing to
        // color and stays as it is.
        "fragment.rgb /= max(fragment.a, .001);\n\
        vec3 incr_replaceText_nameSubstitution_hsvColorize = incr_rgbToHsv(fragment.rgb);\n\
        incr_replaceText_nameSubstitution_hsvColorize.x = incr_rgbToHsv(incr_replaceText_nameSubstitution.rgb).x;\n\
        fragment.rgb = mix(fragment.rgb, incr_hsvToRgb(incr_replaceText_nameSubstitution_hsvColorize), incr_replaceText_nameSubstitution.w);\n\
        fragment.rgb *= fragment.a;",
        [incr_replaceText_nameSubstitution_def],
        undefined, undefined, undefined, undefined,
        "Shifts the hue of the fragment color toward a target hue while preserving the original luminosity structure."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 22: Effect Nodes/ContourShading
----------------------------------------------------------


Title: ContourShading
Template Library Path: Effect Nodes/ContourShading
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/ContourShading:
Applies simple directional shading using vertex normals.

Blends a base color and a light color according to the angle between the surface and a configurable world-space light direction. Much cheaper than BlinnPhongLighting and often enough for stylized work.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/ContourShading:
// Incisor Template Library - ContourShading: lighting a three dimensional object from a direction you can move.
// Requires Template Library items: ContourShading

// The shading comes from the angle between the light and the direction each part of the surface faces, so it needs
// geometry with real shape to it. The coin in the sample assets arrives with its own texture already applied.
let coin = new GraphicObject(nc.graphicAssets.Coin,nc.mainScene,"Coin");
coin.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.ContourShading,nc.effectNodes.ColorMultiply]);

// The light is a direction rather than a position, so it arrives from infinitely far away and strikes every part of
// the coin at the same angle.
coin.materialMaster.contourShading_direction.x = -1;
coin.materialMaster.contourShading_direction.y = -1;
coin.materialMaster.contourShading_direction.z = -1;

// The two colors are the ends of the range - baseColor where the surface faces away, lightColor where it faces the light.
coin.materialMaster.contourShading_lightColor.red = 1;
coin.materialMaster.contourShading_lightColor.green = .95;
coin.materialMaster.contourShading_lightColor.blue = .7;
coin.materialMaster.contourShading_baseColor.red = .15;
coin.materialMaster.contourShading_baseColor.green = .2;
coin.materialMaster.contourShading_baseColor.blue = .45;

// Turning the coin and swinging the light across it at once, so the highlight travels over the milled edge and the
// raised face rather than sitting still. Rotation is in degrees.
coin.rotation.swoop.y(360,9,nc.tweenTypes.Linear);
nc.swoopValue(coin.materialMaster.contourShading_direction,"x",1,6,nc.tweenTypes.Ease);

Content of Effect Nodes/ContourShading, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode lights an object with a single directional light, shading it from a
dark base color toward a light color depending on which way each part of it faces.

It is the cheapest way to give geometry a sense of form. There is no falloff, no specular highlight and no shadow - just
one direction and two colors - which is what makes it suit stylized and graphic looks rather than realistic ones.

The shading is driven entirely by which way each pixel faces, which means a flat object gets a flat result. Use it on
geometry that has real shape, or put a NormalMap node ahead of it to give a flat surface something to catch the light
with.

Once the node is on an object, its controllers are reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution_direction', '..._lightColor' and '..._baseColor'.
*/


CODE.runBeforeInit___begin;
    // Which way the light travels, as a direction rather than a position, so the light is infinitely far away and hits
    // every part of the object at the same angle.
    let incr_replaceText_nameSubstitution_direction_def = nc.defineEffectController("incr_replaceText_nameSubstitution_direction", "Vector3", ["x", "y", "z"], [-1, -1, -1], "addition", [[0,1], [0,1], [0,1]], "EffectController for world space light direction of the incr_replaceText_NameSubstitution EffectNode.", ["The x component of the world space light direction.", "The y component of the world space light direction.", "The z component of the world space light direction."]);

    // The two ends of the shading - 'baseColor' is what the object is where the light misses it and 'lightColor' is what
    // gets added where the light lands square on. Alpha works as a brightness dial on each rather than as transparency.
    let incr_replaceText_nameSubstitution_lightColor_def = nc.defineEffectController("incr_replaceText_nameSubstitution_lightColor", "Vector4", ["red", "green", "blue", "alpha"], [1, 1, .5, 1], "multiplication", [[0,1], [0,1], [0,1], [0,1]], "EffectController for the light color of the incr_replaceText_NameSubstitution EffectNode.", ["The red component of the light color.", "The green component of the light color.", "The blue component of the light color.", "The alpha component of the light color."]);
    let incr_replaceText_nameSubstitution_baseColor_def = nc.defineEffectController("incr_replaceText_nameSubstitution_baseColor", "Vector4", ["red", "green", "blue", "alpha"], [.2, .2, .5, 1], "multiplication", [[0,1], [0,1], [0,1], [0,1]], "EffectController for the base color of the incr_replaceText_NameSubstitution EffectNode.", ["The red component of the base color.", "The green component of the base color.", "The blue component of the base color.", "The alpha component of the base color."]);

    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        [],
        // Geometry built flat can arrive with no normal at all, which would leave nothing to light. Anything that short
        // is replaced with one facing the camera so the surface shades evenly instead of going black.
        "NORMAL = dot(NORMAL, NORMAL) > .0001 ? NORMAL : vec3(0.0, 0.0, 1.0);",
        ["uniform vec4 incr_replaceText_nameSubstitution_lightColor;", "uniform vec4 incr_replaceText_nameSubstitution_baseColor;", "uniform vec3 incr_replaceText_nameSubstitution_direction;"],
        // How much light a surface catches comes from the angle between it and the light, which is what the dot product
        // measures - full where the two face each other, tapering to nothing as the surface turns away. The max() is
        // what stops surfaces facing away from being lit from behind.
        "fragment *= incr_replaceText_nameSubstitution_baseColor * vec4(incr_replaceText_nameSubstitution_baseColor.aaa, 1.0) + incr_replaceText_nameSubstitution_lightColor * vec4(incr_replaceText_nameSubstitution_lightColor.aaa, 1.0) * max(0.0, dot(normalize(incr_replaceText_nameSubstitution_direction), -normalize(NORMAL)));",
        [incr_replaceText_nameSubstitution_direction_def, incr_replaceText_nameSubstitution_lightColor_def, incr_replaceText_nameSubstitution_baseColor_def],
        undefined, undefined, undefined, undefined,
        "Applies simple directional light shading using vertex normals, blending a base color and a light color based on the angle to a configurable light direction."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 23: Effect Nodes/GradientFourColors
----------------------------------------------------------


Title: GradientFourColors
Template Library Path: Effect Nodes/GradientFourColors
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/GradientFourColors:
Applies a four-color bilinear gradient across the Material using UV coordinates, with one color at each corner.

Supports standard, additive, multiply, and screen blending against the underlying color.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/GradientFourColors:
// Incisor Template Library - GradientFourColors: putting a different color in each corner of an image.
// Requires Template Library items: GradientFourColors

let picture = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Picture");
picture.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.GradientFourColors,nc.effectNodes.ColorMultiply]);

// This one is placed by the Material's UVs rather than by a center and an angle, so there is nothing to aim - each
// color takes a corner and the whole surface is interpolated between them.
picture.materialMaster.gradientFourColors_color0.red = 1;
picture.materialMaster.gradientFourColors_color0.green = .3;
picture.materialMaster.gradientFourColors_color0.blue = .3;
picture.materialMaster.gradientFourColors_color1.red = 1;
picture.materialMaster.gradientFourColors_color1.green = .9;
picture.materialMaster.gradientFourColors_color1.blue = .4;
picture.materialMaster.gradientFourColors_color2.red = .3;
picture.materialMaster.gradientFourColors_color2.green = .8;
picture.materialMaster.gradientFourColors_color2.blue = 1;
picture.materialMaster.gradientFourColors_color3.red = .6;
picture.materialMaster.gradientFourColors_color3.green = .4;
picture.materialMaster.gradientFourColors_color3.blue = 1;

// The mode components work as a set of switches - exactly one of them should be 1 at a time.
picture.materialMaster.gradientFourColors_mode.standard = 0;
picture.materialMaster.gradientFourColors_mode.multiplication = 1;

// Move one corner's color and the whole surface follows it.
nc.swoopValue(picture.materialMaster.gradientFourColors_color0,"green",1,6,nc.tweenTypes.Ease);

Content of Effect Nodes/GradientFourColors, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode puts a different color at each of an object's four corners and
blends between them.

Unlike the two and three color gradients, this one works from the object's UVs rather than from a placed and angled
axis, so it has no center, angle or scale - the gradient always fills the object and follows its shape.

This is a fragment-stage node, so it recolors what has already been drawn and never moves geometry. It needs no
subdivision and works on any object.

Once the node is on an object, its controllers are reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution_color0' through '..._color3' and '..._mode'.
*/


CODE.runBeforeInit___begin;
    // The four colors run around the object rather than row by row - color0 and color1 share one edge, color3 and
    // color2 the opposite one, so color0 and color3 sit on the same side. Their alpha is how strongly the gradient
    // takes over at that corner rather than the opacity of the object.
    let incr_replaceText_nameSubstitution_color0_def = nc.defineEffectController("incr_replaceText_nameSubstitution_color0","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 4 color gradient to the fragments (pixels) on the Material it is applied to.",["The red value of this gradient color.","The green value of this gradient color.","The blue value of this gradient color.","The alpha value of this gradient color."]);
    let incr_replaceText_nameSubstitution_color1_def = nc.defineEffectController("incr_replaceText_nameSubstitution_color1","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 4 color gradient to the fragments (pixels) on the Material it is applied to.",["The red value of this gradient color.","The green value of this gradient color.","The blue value of this gradient color.","The alpha value of this gradient color."]);
    let incr_replaceText_nameSubstitution_color2_def = nc.defineEffectController("incr_replaceText_nameSubstitution_color2","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 4 color gradient to the fragments (pixels) on the Material it is applied to.",["The red value of this gradient color.","The green value of this gradient color.","The blue value of this gradient color.","The alpha value of this gradient color."]);
    let incr_replaceText_nameSubstitution_color3_def = nc.defineEffectController("incr_replaceText_nameSubstitution_color3","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 4 color gradient to the fragments (pixels) on the Material it is applied to.",["The red value of this gradient color.","The green value of this gradient color.","The blue value of this gradient color.","The alpha value of this gradient color."]);

    // These four are weights rather than a choice of one mode - every mode is calculated and then summed in these
    // proportions, so a mode can be swooped into another one. They are not normalized, so weights totaling more than 1
    // will blow the color out.
    let incr_replaceText_nameSubstitution_mode_def = nc.defineEffectController("incr_replaceText_nameSubstitution_mode","Vector4",["standard", "add", "multiplication", "screen"],[1, 0, 0, 0],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 4 color gradient to the fragments (pixels) on the Material it is applied to.",["The contribution to the resulting color as calculated by standard blending.","The contribution to the resulting color as calculated by additive blending.","The contribution to the resulting color as calculated by multiply blending.","The contribution to the resulting color as calculated by screen blending."]);

    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        // This node takes no part in the vertex stage - it reads UVs, which arrive on their own.
        [],
        "",
        ["uniform vec4 incr_replaceText_nameSubstitution_color0;", "uniform vec4 incr_replaceText_nameSubstitution_color1;", "uniform vec4 incr_replaceText_nameSubstitution_color2;", "uniform vec4 incr_replaceText_nameSubstitution_color3;", "uniform vec4 incr_replaceText_nameSubstitution_mode;"],
        // Blending in two passes is what spreads four colors over a surface - each edge is blended along the UV's x
        // axis first, then those two results are blended into each other along y. The smoothstep on x eases the
        // horizontal blend while y is left linear.
        "vec4 incr_replaceText_nameSubstitution_col= mix(mix(incr_replaceText_nameSubstitution_color0, incr_replaceText_nameSubstitution_color1, smoothstep(0.0, 1.0, UV.x)), mix(incr_replaceText_nameSubstitution_color3,incr_replaceText_nameSubstitution_color2, smoothstep(0.0, 1.0, UV.x)), UV.y);\n\
        vec3 incr_replaceText_nameSubstitution_standardColor = mix(fragment.rgb, incr_replaceText_nameSubstitution_col.rgb * fragment.a * incr_replaceText_nameSubstitution_col.a, incr_replaceText_nameSubstitution_col.a);\n\
        vec3 incr_replaceText_nameSubstitution_addColor = fragment.rgb + incr_replaceText_nameSubstitution_col.rgb * incr_replaceText_nameSubstitution_col.a * fragment.a;\n\
        vec3 incr_replaceText_nameSubstitution_screenColor = mix(fragment.rgb, (vec3(1.0) - (vec3(1.0) - fragment.rgb) * (vec3(1.0) - incr_replaceText_nameSubstitution_col.rgb)) * fragment.a, incr_replaceText_nameSubstitution_col.a);\n\
        vec3 incr_replaceText_nameSubstitution_multiplyColor = mix(fragment.rgb, fragment.rgb * incr_replaceText_nameSubstitution_col.rgb, incr_replaceText_nameSubstitution_col.a);\n\
        fragment.rgb = incr_replaceText_nameSubstitution_standardColor * incr_replaceText_nameSubstitution_mode.x + incr_replaceText_nameSubstitution_addColor * incr_replaceText_nameSubstitution_mode.y + incr_replaceText_nameSubstitution_multiplyColor * incr_replaceText_nameSubstitution_mode.z + incr_replaceText_nameSubstitution_screenColor * incr_replaceText_nameSubstitution_mode.w;",
        [incr_replaceText_nameSubstitution_color0_def,incr_replaceText_nameSubstitution_color1_def,incr_replaceText_nameSubstitution_color2_def,incr_replaceText_nameSubstitution_color3_def,incr_replaceText_nameSubstitution_mode_def],
        undefined, undefined, undefined, undefined,
        "Applies a four-color bilinear gradient across the Material using UV coordinates, with one color at each corner and support for standard, additive, multiply, and screen blending modes."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 24: Effect Nodes/GradientThreeColors
----------------------------------------------------------


Title: GradientThreeColors
Template Library Path: Effect Nodes/GradientThreeColors
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/GradientThreeColors:
Applies a three-color linear gradient across the Material.

Center position, angle, and scale are all controllable, with standard, additive, multiply, and screen blending against the underlying color.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/GradientThreeColors:
// Incisor Template Library - GradientThreeColors: running a three-color gradient across an image.
// Requires Template Library items: GradientThreeColors

let picture = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Picture");
picture.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.GradientThreeColors,nc.effectNodes.ColorMultiply]);

// Same placement as GradientTwoColors - center and angle aim the gradient, scale sets how far it takes to cross.
// The extra color sits in the middle of the run rather than at either end.
picture.materialMaster.gradientThreeColors.centerX = 0;
picture.materialMaster.gradientThreeColors.centerY = 0;
picture.materialMaster.gradientThreeColors.angle = 90;
picture.materialMaster.gradientThreeColors.scale = 100;

picture.materialMaster.gradientThreeColors_color0.red = 1;
picture.materialMaster.gradientThreeColors_color0.green = .2;
picture.materialMaster.gradientThreeColors_color0.blue = .2;
picture.materialMaster.gradientThreeColors_color1.red = 1;
picture.materialMaster.gradientThreeColors_color1.green = 1;
picture.materialMaster.gradientThreeColors_color1.blue = .4;
picture.materialMaster.gradientThreeColors_color2.red = .2;
picture.materialMaster.gradientThreeColors_color2.green = .5;
picture.materialMaster.gradientThreeColors_color2.blue = 1;

// The mode components work as a set of switches - exactly one of them should be 1 at a time.
picture.materialMaster.gradientThreeColors_mode.standard = 0;
picture.materialMaster.gradientThreeColors_mode.multiplication = 1;

// Slide the middle color along the run by moving the gradient under the image.
nc.swoopValue(picture.materialMaster.gradientThreeColors,"centerY",120,6,nc.tweenTypes.Ease);

Content of Effect Nodes/GradientThreeColors, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode lays a three-color linear gradient over an object.

The middle color sits at the center of the gradient with the other two at either end, so this is the one to reach for
when a band of color needs to pass through an object rather than across it.

The gradient is positioned in the object's own space rather than across its UVs, so it has a center, an angle and a
scale of its own and can be swept across the object independently of the artwork underneath.

This is a fragment-stage node as far as color goes - the vertex stage below only hands the fragment stage each pixel's
position. It needs no subdivision and works on any object.

Once the node is on an object, its controllers are reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution', '..._color0' through '..._color2' and '..._mode'.
*/


CODE.runBeforeInit___begin;
    // Where the gradient sits and which way it runs. 'scale' is the distance the gradient takes to travel end to end,
    // and a negative scale flips which end is which.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution","Vector4",["centerX", "centerY", "angle","scale"],[0,0,0,100],nc.constants.effectControllerMixModes.addition,[[0,500],[0,500],[0,180],[0,100]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 3 color linear gradient to the fragments (pixels) on the Material it is applied to.",["The x value of the center of the gradient","The y value of the center of the gradient","The angle of the gradient","The scale of the gradient"]);

    // The three stops, in order along the gradient - color1 is the middle one and lands on the center. Their alpha is
    // how strongly the gradient takes over at that stop rather than the opacity of the object.
    let incr_replaceText_nameSubstitution_color0_def = nc.defineEffectController("incr_replaceText_nameSubstitution_color0","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 3 color linear gradient to the fragments (pixels) on the Material it is applied to.",["The red value of this gradient color.","The green value of this gradient color.","The blue value of this gradient color.","The alpha value of this gradient color."]);
    let incr_replaceText_nameSubstitution_color1_def = nc.defineEffectController("incr_replaceText_nameSubstitution_color1","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 3 color linear gradient to the fragments (pixels) on the Material it is applied to.",["The red value of this gradient color.","The green value of this gradient color.","The blue value of this gradient color.","The alpha value of this gradient color."]);
    let incr_replaceText_nameSubstitution_color2_def = nc.defineEffectController("incr_replaceText_nameSubstitution_color2","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 3 color linear gradient to the fragments (pixels) on the Material it is applied to.",["The red value of this gradient color.","The green value of this gradient color.","The blue value of this gradient color.","The alpha value of this gradient color."]);

    // These four are weights rather than a choice of one mode - every mode is calculated and then summed in these
    // proportions, so a mode can be swooped into another one. They are not normalized, so weights totaling more than 1
    // will blow the color out.
    let incr_replaceText_nameSubstitution_mode_def = nc.defineEffectController("incr_replaceText_nameSubstitution_mode","Vector4",["standard", "add", "multiplication", "screen"],[1, 0, 0, 0],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 3 color linear gradient to the fragments (pixels) on the Material it is applied to.",["The contribution to the resulting color as calculated by standard blending.","The contribution to the resulting color as calculated by additive blending.","The contribution to the resulting color as calculated by multiply blending.","The contribution to the resulting color as calculated by screen blending."]);

    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        // The vertex stage exists only to hand each pixel its position in the object's own space, which is what lets
        // the gradient be placed and angled independently of the object's UVs.
        ["varying vec2 pos;"],
        "pos = vertex.xy;",
        ["varying vec2 pos;", "uniform vec4 incr_replaceText_nameSubstitution;","uniform vec4 incr_replaceText_nameSubstitution_color0;", "uniform vec4 incr_replaceText_nameSubstitution_color1;", "uniform vec4 incr_replaceText_nameSubstitution_color2;", "uniform vec4 incr_replaceText_nameSubstitution_mode;"],
        // Three stops are handled as two separate two-color gradients that meet at the center - one running color0 to
        // color1 over the first half and one running color1 to color2 over the second. The step() at the end picks
        // whichever half the pixel falls in, which is why both are calculated even though only one is ever used.
        "float incr_replaceText_nameSubstitution_angle=incr_replaceText_nameSubstitution.z*3.14159/180.0;\n\
        vec2 incr_replaceText_nameSubstitution_center=incr_replaceText_nameSubstitution.xy;\n\
        float incr_replaceText_nameSubstitution_scale=max(0.001, abs(incr_replaceText_nameSubstitution.w)) * (incr_replaceText_nameSubstitution.w < 0.0 ? -1.0: 1.0);\n\
        vec2 incr_replaceText_nameSubstitution_axisOfTravel=vec2(cos(incr_replaceText_nameSubstitution_angle),sin(incr_replaceText_nameSubstitution_angle));\n\
        float incr_replaceText_nameSubstitution_newUV=dot(pos - incr_replaceText_nameSubstitution_center, incr_replaceText_nameSubstitution_axisOfTravel);\n\
        vec4 incr_replaceText_nameSubstitution_col1=mix(incr_replaceText_nameSubstitution_color0, incr_replaceText_nameSubstitution_color1, smoothstep(-0.5, 0.0, incr_replaceText_nameSubstitution_newUV / incr_replaceText_nameSubstitution_scale));\n\
        vec4 incr_replaceText_nameSubstitution_col2=mix(incr_replaceText_nameSubstitution_color1, incr_replaceText_nameSubstitution_color2, smoothstep(0.0, .5, incr_replaceText_nameSubstitution_newUV / incr_replaceText_nameSubstitution_scale));\n\
        vec4 incr_replaceText_nameSubstitution_col=mix(incr_replaceText_nameSubstitution_col1, incr_replaceText_nameSubstitution_col2, step(0.0, incr_replaceText_nameSubstitution_newUV / incr_replaceText_nameSubstitution_scale));\n\
        vec3 incr_replaceText_nameSubstitution_standardColor = mix(fragment.rgb, incr_replaceText_nameSubstitution_col.rgb * fragment.a * incr_replaceText_nameSubstitution_col.a, incr_replaceText_nameSubstitution_col.a);\n\
        vec3 incr_replaceText_nameSubstitution_addColor = fragment.rgb + incr_replaceText_nameSubstitution_col.rgb * incr_replaceText_nameSubstitution_col.a * fragment.a;\n\
        vec3 incr_replaceText_nameSubstitution_screenColor = mix(fragment.rgb, (vec3(1.0) - (vec3(1.0) - fragment.rgb) * (vec3(1.0) - incr_replaceText_nameSubstitution_col.rgb)) * fragment.a, incr_replaceText_nameSubstitution_col.a);\n\
        vec3 incr_replaceText_nameSubstitution_multiplyColor = mix(fragment.rgb, fragment.rgb * incr_replaceText_nameSubstitution_col.rgb, incr_replaceText_nameSubstitution_col.a);\n\
        fragment.rgb = incr_replaceText_nameSubstitution_standardColor * incr_replaceText_nameSubstitution_mode.x + incr_replaceText_nameSubstitution_addColor * incr_replaceText_nameSubstitution_mode.y + incr_replaceText_nameSubstitution_multiplyColor * incr_replaceText_nameSubstitution_mode.z + incr_replaceText_nameSubstitution_screenColor * incr_replaceText_nameSubstitution_mode.w;",
        [incr_replaceText_nameSubstitution_def,incr_replaceText_nameSubstitution_color0_def,incr_replaceText_nameSubstitution_color1_def,incr_replaceText_nameSubstitution_color2_def,incr_replaceText_nameSubstitution_mode_def],
        undefined, undefined, undefined, undefined,
        "Applies a three-color linear gradient across the Material, with configurable center position, angle, and scale, and support for standard, additive, multiply, and screen blending modes."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 25: Effect Nodes/GradientTwoColors
----------------------------------------------------------


Title: GradientTwoColors
Template Library Path: Effect Nodes/GradientTwoColors
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/GradientTwoColors:
Applies a two-color linear gradient across the Material.

Center position, angle, and scale are all controllable, with standard, additive, multiply, and screen blending against the underlying color. The simplest of the three gradient EffectNodes and the cheapest to evaluate.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/GradientTwoColors:
// Incisor Template Library - GradientTwoColors: sweeping a two-color gradient around over an image.
// Requires Template Library items: GradientTwoColors

let picture = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Picture");
picture.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.GradientTwoColors,nc.effectNodes.ColorMultiply]);

// The gradient is placed in the Material's own space - center and angle aim it, scale sets how far it takes to travel
// from the first color to the second.
picture.materialMaster.gradientTwoColors.centerX = 0;
picture.materialMaster.gradientTwoColors.centerY = 0;
picture.materialMaster.gradientTwoColors.angle = 0;
picture.materialMaster.gradientTwoColors.scale = 100;

picture.materialMaster.gradientTwoColors_color0.red = 1;
picture.materialMaster.gradientTwoColors_color0.green = .3;
picture.materialMaster.gradientTwoColors_color0.blue = 0;
picture.materialMaster.gradientTwoColors_color1.red = 0;
picture.materialMaster.gradientTwoColors_color1.green = .4;
picture.materialMaster.gradientTwoColors_color1.blue = 1;

// The mode components work as a set of switches - exactly one of them should be 1 at a time.
picture.materialMaster.gradientTwoColors_mode.standard = 0;
picture.materialMaster.gradientTwoColors_mode.multiplication = 1;

// Swing the gradient right around.
nc.swoopValue(picture.materialMaster.gradientTwoColors,"angle",360,12,nc.tweenTypes.Linear);

Content of Effect Nodes/GradientTwoColors, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode lays a two-color linear gradient over an object.

The gradient is positioned in the object's own space rather than across its UVs, so it has a center, an angle and a
scale of its own and can be swept across the object independently of the artwork underneath.

This is a fragment-stage node as far as color goes - the vertex stage below only hands the fragment stage each pixel's
position. It needs no subdivision and works on any object.

Once the node is on an object, its controllers are reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution', '..._color0', '..._color1' and '..._mode'.
*/


CODE.runBeforeInit___begin;
    // Where the gradient sits and which way it runs. 'scale' is the distance the gradient takes to travel from the
    // first color to the second, and a negative scale flips which end is which.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution","Vector4",["centerX", "centerY", "angle","scale"],[0,0,0,100],nc.constants.effectControllerMixModes.addition,[[0,500],[0,500],[0,180],[0,100]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 2 color gradient to the fragments (pixels) on the Material it is applied to.",["The x value of the center of the gradient","The y value of the center of the gradient","The angle of the gradient","The scale of the gradient"]);

    // The two ends of the gradient. Their alpha is how strongly the gradient takes over at that end rather than the
    // opacity of the object, so dropping it to 0 lets the artwork underneath through.
    let incr_replaceText_nameSubstitution_color0_def = nc.defineEffectController("incr_replaceText_nameSubstitution_color0","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 2 color gradient to the fragments (pixels) on the Material it is applied to.",["The red value of this gradient color.","The green value of this gradient color.","The blue value of this gradient color.","The alpha value of this gradient color."]);
    let incr_replaceText_nameSubstitution_color1_def = nc.defineEffectController("incr_replaceText_nameSubstitution_color1","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 2 color gradient to the fragments (pixels) on the Material it is applied to.",["The red value of this gradient color.","The green value of this gradient color.","The blue value of this gradient color.","The alpha value of this gradient color."]);

    // These four are weights rather than a choice of one mode - every mode is calculated and then summed in these
    // proportions, so a mode can be swooped into another one. They are not normalized, so weights totaling more than 1
    // will blow the color out.
    let incr_replaceText_nameSubstitution_mode_def = nc.defineEffectController("incr_replaceText_nameSubstitution_mode","Vector4",["standard", "add", "multiplication", "screen"],[1, 0, 0, 0],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which applies a 2 color gradient to the fragments (pixels) on the Material it is applied to.",["The contribution to the resulting color as calculated by standard blending.","The contribution to the resulting color as calculated by additive blending.","The contribution to the resulting color as calculated by multiply blending.","The contribution to the resulting color as calculated by screen blending."]);

    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        // The vertex stage exists only to hand each pixel its position in the object's own space, which is what lets
        // the gradient be placed and angled independently of the object's UVs.
        ["varying vec2 pos;"],
        "pos = vertex.xy;",
        ["varying vec2 pos;", "uniform vec4 incr_replaceText_nameSubstitution;","uniform vec4 incr_replaceText_nameSubstitution_color0;", "uniform vec4 incr_replaceText_nameSubstitution_color1;", "uniform vec4 incr_replaceText_nameSubstitution_mode;"],
        // The angle becomes a direction vector, and projecting each pixel onto it turns a two dimensional position into
        // one number - how far along the gradient that pixel sits. The max() keeps a scale of zero from dividing by
        // zero while the trailing sign preserves a negative scale, which is what flips the gradient end for end.
        "float incr_replaceText_nameSubstitution_angle=incr_replaceText_nameSubstitution.z*3.14159/180.0;\n\
        vec2 incr_replaceText_nameSubstitution_center=incr_replaceText_nameSubstitution.xy;\n\
        float incr_replaceText_nameSubstitution_scale=max(0.001, abs(incr_replaceText_nameSubstitution.w)) * (incr_replaceText_nameSubstitution.w < 0.0 ? -1.0: 1.0);\n\
        vec2 incr_replaceText_nameSubstitution_axisOfTravel=vec2(cos(incr_replaceText_nameSubstitution_angle),sin(incr_replaceText_nameSubstitution_angle));\n\
        float incr_replaceText_nameSubstitution_newUV=dot(pos - incr_replaceText_nameSubstitution_center, incr_replaceText_nameSubstitution_axisOfTravel);\n\
        vec4 incr_replaceText_nameSubstitution_col=mix(incr_replaceText_nameSubstitution_color0, incr_replaceText_nameSubstitution_color1, smoothstep(-0.5, 0.5, incr_replaceText_nameSubstitution_newUV / incr_replaceText_nameSubstitution_scale));\n\
        vec3 incr_replaceText_nameSubstitution_standardColor = mix(fragment.rgb, incr_replaceText_nameSubstitution_col.rgb * fragment.a * incr_replaceText_nameSubstitution_col.a, incr_replaceText_nameSubstitution_col.a);\n\
        vec3 incr_replaceText_nameSubstitution_addColor = fragment.rgb + incr_replaceText_nameSubstitution_col.rgb * incr_replaceText_nameSubstitution_col.a * fragment.a;\n\
        vec3 incr_replaceText_nameSubstitution_screenColor = mix(fragment.rgb, (vec3(1.0) - (vec3(1.0) - fragment.rgb) * (vec3(1.0) - incr_replaceText_nameSubstitution_col.rgb)) * fragment.a, incr_replaceText_nameSubstitution_col.a);\n\
        vec3 incr_replaceText_nameSubstitution_multiplyColor = mix(fragment.rgb, fragment.rgb * incr_replaceText_nameSubstitution_col.rgb, incr_replaceText_nameSubstitution_col.a);\n\
        fragment.rgb = incr_replaceText_nameSubstitution_standardColor * incr_replaceText_nameSubstitution_mode.x + incr_replaceText_nameSubstitution_addColor * incr_replaceText_nameSubstitution_mode.y + incr_replaceText_nameSubstitution_multiplyColor * incr_replaceText_nameSubstitution_mode.z + incr_replaceText_nameSubstitution_screenColor * incr_replaceText_nameSubstitution_mode.w;",
        [incr_replaceText_nameSubstitution_def,incr_replaceText_nameSubstitution_color0_def,incr_replaceText_nameSubstitution_color1_def,incr_replaceText_nameSubstitution_mode_def],
        undefined, undefined, undefined, undefined,
        "Applies a two-color linear gradient across the Material, with configurable center position, angle, and scale, and support for standard, additive, multiply, and screen blending modes."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 26: Effect Nodes/HueSaturationValue
----------------------------------------------------------


Title: HueSaturationValue
Template Library Path: Effect Nodes/HueSaturationValue
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/HueSaturationValue:
Adjusts the hue, saturation, and brightness of the fragments on the Material it is applied to.

The general-purpose color grading node. Animate the hue shift on a Timeline for cycling color effects.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/HueSaturationValue:
// Incisor Template Library - HueSaturationValue: turning an image's hue the whole way around.
// Requires Template Library items: HueSaturationValue

// This one shades fragments and moves no vertices, so the image's own Geometry is all it needs.
let picture = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Picture");
picture.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.HueSaturationValue,nc.effectNodes.ColorMultiply]);

// All three components are added to what the image already has, so zero leaves it untouched.
picture.materialMaster.hueSaturationValue.hue = 0;
picture.materialMaster.hueSaturationValue.saturation = 0;
picture.materialMaster.hueSaturationValue.value = 0;

// Hue wraps, so turning it a whole way around arrives back at the color it started on.
nc.swoopValue(picture.materialMaster.hueSaturationValue,"hue",1,9,nc.tweenTypes.Linear);

Content of Effect Nodes/HueSaturationValue, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode shifts the hue, saturation and brightness of an object's pixels.

Each control is an offset applied to what is already there rather than a value replacing it, so this grades an image
the way a color correction pass does - all three default to 0, which leaves it untouched.

This is a fragment-stage node, so it recolors what has already been drawn and never moves geometry. It needs no
subdivision and works on any object.

Once the node is on an object, its controller is reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution'.
*/


CODE.runBeforeInit___begin;
    // Hue is an angle around the color wheel, so its shift wraps - .5 lands on the opposite hue and 1 comes back around
    // to where it started. Saturation and value are clamped instead, since they have real floors and ceilings.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution", "Vector3", ["hue", "saturation", "value"], [0, 0, 0], nc.constants.effectControllerMixModes.addition, [[0, 1], [0,1], [0,1]], "EffectController for the incr_replaceText_NameSubstitution EffectNode, which adjusts the hue and saturation of the fragments (pixels) on the Material it is applied to.", ["The amount to shift the hue", "The amount to shift the saturation", "The amount to shift the value"]);

    // The empty vertex arguments below are what makes this a fragment-only node.
    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        [],
        "",
        // Hue and saturation are not something RGB can be adjusted in directly, so these two convert a color into hue,
        // saturation and value and back again. They deliberately carry no node name - support code is shared across
        // every node on a material and matched exactly, so any node declaring these identically shares one copy.
        ["vec3 incr_rgbToHsv(vec3 c)\
        {\
            vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\
            vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\
            vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\
            float d = q.x - min(q.w, q.y);\
            float e = 1.0e-10;\
            return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\
        }",
        "vec3 incr_hsvToRgb(vec3 c)\
        {\
            vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\
            vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\
            return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\
        }",
        "uniform vec3 incr_replaceText_nameSubstitution;"],
        // All three offsets are added at once, then saturation and value are clamped back into range while hue is left
        // to wrap on its own. A fully gray pixel has no hue to shift, so it only responds to the value offset until
        // saturation lifts it off gray.
        "fragment.rgb /= max(fragment.a, .001);\n\
        vec3 incr_replaceText_nameSubstitution_hsvHueSaturationValue = incr_rgbToHsv(fragment.rgb) + incr_replaceText_nameSubstitution;\n\
        incr_replaceText_nameSubstitution_hsvHueSaturationValue.yz = clamp(incr_replaceText_nameSubstitution_hsvHueSaturationValue.yz, 0.0, 1.0);\n\
        fragment.rgb = incr_hsvToRgb(incr_replaceText_nameSubstitution_hsvHueSaturationValue);\n\
        fragment.rgb *= fragment.a;",
        [incr_replaceText_nameSubstitution_def],
        undefined, undefined, undefined, undefined,
        "Adjusts the hue, saturation, and brightness (value) of the fragments on the Material it is applied to."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 27: Effect Nodes/MatCap
----------------------------------------------------------


Title: MatCap
Template Library Path: Effect Nodes/MatCap
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/MatCap:
Applies a MatCap texture using view-space normals.

Fakes complex material response with a single lookup texture, at a fraction of the cost of real lighting. Supports both multiplicative and additive blending with the existing fragment color.

The shading is read from the direction each part of a surface faces, so a flat object comes out a flat color - every pixel of a quad faces the same way and samples the same single point of the MatCap. Use it on geometry that has real shape, or put a NormalMap ahead of it to give a flat surface something to vary.

Because the lighting belongs to the viewer rather than to the object, a MatCap does not turn with what it is applied to. That is what sells chrome and polished metal, and what makes it the wrong choice for a light that has to stay put in a scene.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/MatCap:
// Incisor Template Library - MatCap: shading an object with a captured material.
// Requires Template Library items: MatCap

// A MatCap is an image of a sphere finished and lit the way a surface should look. The shading is read out of it by the
// direction each part of the object faces, so a whole material - chrome here - costs one texture lookup and no lights.
let coin = new GraphicObject(nc.graphicAssets.Coin,nc.mainScene,"Coin");
coin.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.MatCap,nc.effectNodes.ColorMultiply]);

// A Texture EffectController is material only - it is not passed down the way the numeric ones are, so it has to be
// set on each of the object's Materials rather than through materialMaster.
let materials = coin.getMaterials();
for(let i=0; i<materials.length; i++)
{
    materials[i].matCap_texture = nc.textures.matcap_chrome;
}

// additive is a single number rather than a set of components. At 0 the chrome multiplies into the coin's own coloring
// and keeps its detail, and at 1 it is added on top and the metal blows out bright.
coin.materialMaster.matCap_additive = 0;

// A MatCap's lighting belongs to the viewer rather than to the object, so turning the coin does not turn the reflection
// with it - the surface travels through highlights that stay where they are, the way real chrome behaves.
// Rotation is in degrees.
coin.rotation.swoop.y(360,9,nc.tweenTypes.Linear);
nc.swoopValue(coin.materialMaster,"matCap_additive",1,4.5,nc.tweenTypes.Ease);

Content of Effect Nodes/MatCap, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode shades an object using a MatCap - a single image of a sphere lit
however you like, which is then wrapped onto the object to give it that same material.

It is a way to get chrome, wax, clay or brushed metal without any lights in the scene at all. The lighting is baked into
the image, so it costs one texture lookup rather than a lighting calculation, and it never changes as the object moves.

The shading is driven entirely by which way each pixel faces, which means a flat object gets a flat result - every pixel
of a plain quad faces the same direction and samples the same spot of the MatCap. Use it on geometry that has real
shape, or put a NormalMap node ahead of it to give a flat surface something to catch the light with.

Once the node is on an object, its controllers are single values reachable directly by name on that object's material,
as 'incr_replaceText_nameSubstitution_texture' and 'incr_replaceText_nameSubstitution_additive'.
*/


CODE.runBeforeInit___begin;
    // The sphere image to wrap onto the object. Whatever is in the middle of this image lands on the parts facing the
    // camera, and its edges land on the parts turning away.
    nc.defineEffectController("incr_replaceText_nameSubstitution_texture", nc.constants.effectControllerBaseTypes.Texture, ["incr_replaceText_nameSubstitution_texture"], nc.textures.WhiteBox, "addition");

    // Multiplying keeps the object's own coloring and lets the MatCap shade it, which suits painted or textured
    // surfaces. Adding ignores what is underneath and piles light on top, which is what gives chrome and glass.
    nc.defineEffectController("incr_replaceText_nameSubstitution_additive", nc.constants.effectControllerBaseTypes.number, ["incr_replaceText_nameSubstitution_additive"], [0], "addition", [[0, 1]], "Controls how the MatCap color is combined with the existing color.  0 multiplies the two colors, and 1 adds the two colors.");

    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        // The direction from the camera to each pixel, which is what the shading is measured against. An orthographic
        // camera has no single viewpoint for rays to spread from, so the camera's own axis is used for every pixel.
        ["varying vec3 camToFrag;"],
        "camToFrag = isOrthographic ? cameraModelMatrix[2].xyz : (modelMatrix * vec4(vertex, 1.0)).xyz - cameraModelMatrix[3].xyz;",
        [
            // Builds a set of axes centered on the viewer, then measures the surface direction against them. The result
            // is where on the imaginary sphere this pixel would sit, which is the point of the MatCap image to sample.
            // The 'up' vector is swapped out when the view looks straight along it, since two parallel directions give
            // no sideways axis to build from.
            "vec2 matCapUV(vec3 eye, vec3 norm)\n\
            {\n\
                vec3 V = eye;\n\
                vec3 Z = -V;\n\
                vec3 up = vec3(0.0, 1.0, 0.0);\n\
                if (abs(dot(up, Z)) > 0.999)\n\
                    up = vec3(1.0, 0.0, 0.0);\n\
                vec3 X = normalize(cross(up, Z));\n\
                vec3 Y = cross(Z, X);\n\
                vec3 N = norm;\n\
                vec3 N_view = vec3(\n\
                    dot(N, X),\n\
                    dot(N, Y),\n\
                    dot(N, Z)\n\
                );\n\
                return N_view.xy * .5 + vec2(.5);\n\
            }",
            "varying vec3 camToFrag;",
            "uniform sampler2D incr_replaceText_nameSubstitution_texture;",
            "uniform float incr_replaceText_nameSubstitution_additive;"
        ],
        // Both the multiplied and the added result are worked out and then mixed between, so 'additive' can be swooped
        // to shift a surface from painted to polished while it is on screen.
        "vec2 matUV = matCapUV(normalize(camToFrag), normalize(NORMAL));\n\
        vec4 sample = texture2D(incr_replaceText_nameSubstitution_texture, matUV);\n\
        fragment = mix(fragment * sample, vec4(fragment.rgb + sample.rgb, fragment.a), incr_replaceText_nameSubstitution_additive);",
        [nc.effectControllers.incr_replaceText_nameSubstitution_texture, nc.effectControllers.incr_replaceText_nameSubstitution_additive],
        undefined, undefined, undefined, undefined,
        "Applies a MatCap (material capture) texture using view-space normals, with support for both multiplicative and additive blending with the existing fragment color."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 28: Effect Nodes/NormalMap
----------------------------------------------------------


Title: NormalMap
Template Library Path: Effect Nodes/NormalMap
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/NormalMap:
Perturbs surface normals using a normal map texture.

Affects the result of any lighting EffectNode applied after it, so ordering matters. Supports both the OpenGL and the DirectX left-handed normal map conventions, the latter via an inversion flag.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/NormalMap:
// Incisor Template Library - NormalMap: adding surface relief for a lighting EffectNode to catch.
// Requires Template Library items: NormalMap, ContourShading

// The coin in the sample assets ships with a normal map authored for it, so the relief lands exactly where the model's
// detail is rather than approximately.
let coin = new GraphicObject(nc.graphicAssets.Coin,nc.mainScene,"Coin");

// NormalMap changes the normals that later EffectNodes read, so it does nothing on its own - the lighting node that
// uses those normals has to come after it in the list. Reverse these two and the shading ignores the map entirely.
coin.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.NormalMap,nc.effectNodes.ContourShading,nc.effectNodes.ColorMultiply]);

// A Texture EffectController is material only - it is not passed down the way the numeric ones are, so it has to be
// set on each of the object's Materials rather than through materialMaster.
let materials = coin.getMaterials();
for(let i=0; i<materials.length; i++)
{
    materials[i].normalMap_texture = nc.textures.CoinNormals;
}

// The map only changes which way the surface faces, so there has to be a light for that change to show up in.
coin.materialMaster.contourShading_direction.x = -1;
coin.materialMaster.contourShading_direction.y = -1;
coin.materialMaster.contourShading_direction.z = -1;
coin.materialMaster.contourShading_lightColor.red = 1;
coin.materialMaster.contourShading_lightColor.green = .95;
coin.materialMaster.contourShading_lightColor.blue = .7;

// Both of these are single numbers rather than sets of components.
// Set isLeftHanded to 1 for a map authored to the DirectX convention, which has its green channel inverted.
coin.materialMaster.normalMap_strength = 0;
coin.materialMaster.normalMap_isLeftHanded = 0;

// Bringing the strength up from nothing is the clearest way to see what the map is adding, since the same coin under
// the same light is the before and the after. Rotation is in degrees.
coin.rotation.swoop.y(360,9,nc.tweenTypes.Linear);
nc.swoopValue(coin.materialMaster,"normalMap_strength",1,4.5,nc.tweenTypes.Ease);

Content of Effect Nodes/NormalMap, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode reads a normal map and uses it to change which way each pixel of a
surface appears to face, so a flat object picks up bumps, grain, dents and stitching without any extra geometry.

On its own this node changes nothing you can see. It only alters the direction each pixel faces, so it has to sit
BEFORE a node that lights the surface - ContourShading, MatCap or BlinnPhongLighting - and it is that later node whose
result changes. Put it after them in the list and nothing happens.

Once the node is on an object, its controllers are single values reachable directly by name on that object's material,
as 'incr_replaceText_nameSubstitution_texture', '..._strength' and '..._isLeftHanded'.
*/


CODE.runBeforeInit___begin;
    // The normal map itself. These are the flat blue-violet images where the color of each pixel is not a color at all
    // but a direction, and the blue cast is simply what "facing straight out" encodes as.
    nc.defineEffectController("incr_replaceText_nameSubstitution_texture", nc.constants.effectControllerBaseTypes.Texture, ["incr_replaceText_nameSubstitution_texture"], nc.textures.WhiteBox, "addition");

    // How far the map is allowed to tip each pixel, so 0 leaves the surface flat and 1 uses the map as authored. This
    // is the one to swoop when a surface should visibly roughen or smooth out.
    nc.defineEffectController("incr_replaceText_nameSubstitution_strength", "number", ["incr_replaceText_nameSubstitution_strength"], [1], "addition", [[0, 1]], "The strength of the per-fragment normal perturbation caused by the normal map.");

    // The two tools that author normal maps disagree about which way is up, so a map made for DirectX arrives with its
    // bumps reading as dents. Set this to 1 to flip them back.
    nc.defineEffectController("incr_replaceText_nameSubstitution_isLeftHanded", "number", ["incr_replaceText_nameSubstitution_isLeftHanded"], [0], "addition", [[0, 1]], "Normal maps created using the DirectX left handed convention will have inverted Y values. Set this value to 1 to correct this.");

    nc.defineEffectNode("incr_replaceText_NameSubstitution", ["varying vec3 vertPos;"], "vertPos = (modelMatrix * vec4(vertex, 1.0)).xyz;",
        [
            "uniform float incr_replaceText_nameSubstitution_strength;",
            "uniform float incr_replaceText_nameSubstitution_isLeftHanded;",
            "uniform sampler2D incr_replaceText_nameSubstitution_texture;",
            "varying vec3 vertPos;"
        ],
        // A normal map's directions are stored relative to the surface, so they mean nothing until there are axes to
        // read them against. Rather than requiring geometry authored with those axes, this works them out on the spot
        // by measuring how position and UV are changing across the screen - Q1 and Q2 against st1 and st2 give the two
        // directions the texture runs in, and those plus the existing normal build the frame the map is read through.
        "vec4 normalSample = texture2D(incr_replaceText_nameSubstitution_texture, UV);\n\
        vec3 Q1 = dFdx(vertPos);\n\
        vec3 Q2 = dFdy(vertPos);\n\
        vec2 st1 = dFdx(UV);\n\
        vec2 st2 = dFdy(UV);\n\
        vec3 N = normalize(NORMAL);\n\
        vec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n\
        vec3 B = -normalize(cross(N, T));\n\
        mat3 TBN = mat3(T, B, N);\n\
        vec3 n = normalSample.xyz;\n\
        n.xy = (n.xy * 2.0 - vec2(1.0)) * incr_replaceText_nameSubstitution_strength;\n\
        n.y = incr_replaceText_nameSubstitution_isLeftHanded > 0.5 ? -n.y : n.y;\n\
        n = gl_FrontFacing ? n : -n;\n\
        n = normalize(n);\n\
        NORMAL = normalize(TBN * n);",
        [nc.effectControllers.incr_replaceText_nameSubstitution_texture, nc.effectControllers.incr_replaceText_nameSubstitution_strength, nc.effectControllers.incr_replaceText_nameSubstitution_isLeftHanded], true,
        undefined, undefined, undefined,
        "Perturbs surface normals using a normal map texture, affecting the result of any subsequent lighting-based EffectNodes. Supports both OpenGL and DirectX (left-handed) normal map conventions."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 29: Effect Nodes/ShapifyStroke
----------------------------------------------------------


Title: ShapifyStroke
Template Library Path: Effect Nodes/ShapifyStroke
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/ShapifyStroke:
Converts edge data stored in a 'shapified' Texture into a sharp-edged image and adds a colored outer stroke.

Separate inner and outer colors, edge offset, feathering, and stroke thickness are all controllable. Requires a Texture that has been shapified, so it will not do anything useful on ordinary artwork.

A graphic is shapified when it is imported, not at runtime: select it in the Assets panel and check 'shapify' under Image Configurations. 'shapifyEdgeRange' is the largest distance the encoding can carry, and so the ceiling on how far edgeOffset and strokeThickness can reach, while 'shapifyOptimizationLevel' trades edge accuracy for a smaller download.

Checking 'shapify' also puts the plain Shapify EffectNode on every instance of the graphic - swap that for ShapifyStroke on the objects that should carry an outline.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/ShapifyStroke:
// Incisor Template Library - ShapifyStroke: putting a colored outline around a shapified icon.
// Requires Template Library items: ShapifyStroke

// ShapifyStroke reads edge data out of a shapified Texture, so it needs artwork that was shapified when it was imported -
// select the graphic in the Assets panel and check 'shapify' under Image Configurations. The sample icons already are,
// which is why this uses one - it would do nothing useful on an ordinary image.
let icon = new GraphicObject(nc.graphicAssets.icon_checkmark,nc.mainScene,"Icon");
icon.scale.scaleByFactor(6);
icon.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.ShapifyStroke,nc.effectNodes.ColorMultiply]);

// edgeOffset grows or shrinks the shape itself, edgeFeather softens its edge, and strokeThickness is the outline
// added outside it. The stroke is drawn outward, so a thick one needs room around the shape to land in.
icon.materialMaster.shapifyStroke.edgeOffset = 0;
icon.materialMaster.shapifyStroke.edgeFeather = .8;
icon.materialMaster.shapifyStroke.strokeThickness = 0;

icon.materialMaster.shapifyStroke_innerColor.red = 1;
icon.materialMaster.shapifyStroke_innerColor.green = 1;
icon.materialMaster.shapifyStroke_innerColor.blue = 1;
icon.materialMaster.shapifyStroke_outerColor.red = 1;
icon.materialMaster.shapifyStroke_outerColor.green = .2;
icon.materialMaster.shapifyStroke_outerColor.blue = .1;

// Grow the outline out from nothing.
nc.swoopValue(icon.materialMaster.shapifyStroke,"strokeThickness",.35,2.4,nc.tweenTypes.Ease);

Content of Effect Nodes/ShapifyStroke, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode draws a shapified Texture as a crisp shape with a colored stroke
around it.

A shapified Texture does not store a picture. It stores, for every pixel, how far that pixel is from the edge of the
shape, which is why one can be blown up to any size and keep a clean edge instead of going soft and blocky the way an
ordinary image does. This node turns that distance back into something visible - inside the shape, outside it, and a
band of stroke straddling the edge.

It replaces the fragment rather than adjusting it, so it needs no texture sampling node ahead of it and expects the
Texture it reads to have been shapified.

Once the node is on an object, its controllers are reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution', '..._innerColor' and '..._outerColor'.
*/


CODE.runBeforeInit___begin;
    // 'edgeOffset' slides the edge itself outward or inward, fattening or thinning the whole shape, and 'edgeFeather'
    // is how soft that edge is. 'strokeThickness' is how far the outer color reaches past the edge, and its sign
    // decides whether the stroke sits outside the shape or eats into it.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution", nc.constants.effectControllerBaseTypes.Vector3, ["edgeOffset", "edgeFeather", "strokeThickness"], [0, .8, .2], nc.constants.effectControllerMixModes.addition, [[0,1], [0,1], [0,1]], "The EffectController for the 'incr_replaceText_NameSubstitution' EffectNode. The incr_replaceText_NameSubstitution EffectNode converts edge data stored in a 'shapified' Texture into a presentable image with edges that stay sharp regardless of the scale of the associated GraphicObject, and adds a colored outer stroke around the edge.", ["This 'shapify' component determines how far to expand or contract the shape's edge from the position of the edge in the source image.", "This 'shapify' component determines the how many pixels the image's edge transition spans. For example, a value of 5 would lead to a soft edge, as the transition from inside the image's shape to outside the shape would take place over 5 pixels.", "The thickness of the outer stroke."]);

    // The fill and the stroke. Both are premultiplied by their own alpha as they are used, so dropping an alpha to 0
    // removes that part entirely rather than leaving a dark fringe behind it.
    let incr_replaceText_nameSubstitution_innerColor_def = nc.defineEffectController("incr_replaceText_nameSubstitution_innerColor", nc.constants.effectControllerBaseTypes.Vector4, ["red", "green", "blue", "alpha"], [1, 1, 1, 1], nc.constants.effectControllerMixModes.multiplication, [[0,1], [0,1], [0,1], [0,1]], "EffectController for inner color of the incr_replaceText_NameSubstitution EffectNode.", ["The red component of the inner color.", "The green component of the inner color.", "The blue component of the inner color.", "The alpha component of the inner color."]);
    let incr_replaceText_nameSubstitution_outerColor_def = nc.defineEffectController("incr_replaceText_nameSubstitution_outerColor", nc.constants.effectControllerBaseTypes.Vector4, ["red", "green", "blue", "alpha"], [1, 0, 0, 1], nc.constants.effectControllerMixModes.multiplication, [[0,1], [0,1], [0,1], [0,1]], "EffectController for outer color of the incr_replaceText_NameSubstitution EffectNode.", ["The red component of the outer color.", "The green component of the outer color.", "The blue component of the outer color.", "The alpha component of the outer color."]);

    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        [],
        "",
        ["uniform vec3 incr_replaceText_nameSubstitution;", "uniform vec4 incr_replaceText_nameSubstitution_innerColor;", "uniform vec4 incr_replaceText_nameSubstitution_outerColor;"],
        // Two edges are drawn from the same distance data - an inner one where the fill stops and an outer one where
        // the stroke stops - and the fill is laid over the stroke between them. Keeping the edge sharp at any scale is
        // what the derivatives are for - they measure how fast the distance is changing across the screen right here,
        // so the softness of the edge can be held to the same handful of pixels however far the object is zoomed in.
        "float incr_replaceText_nameSubstitution_dist = (-incr_replaceText_nameSubstitution.x + incr_replaceText_nameSubstitution.z) - (fragment.a * 2.0 - 1.0);\n\
        float incr_replaceText_nameSubstitution_d = length(vec2(dFdx(incr_replaceText_nameSubstitution_dist), dFdy(incr_replaceText_nameSubstitution_dist)));\n\
        float incr_replaceText_nameSubstitution_edgeFeatherSafe = max(0.0001, incr_replaceText_nameSubstitution.y * incr_replaceText_nameSubstitution_d);\n\
        float incr_replaceText_nameSubstitution_innerStrength = smoothstep(incr_replaceText_nameSubstitution.x + incr_replaceText_nameSubstitution_edgeFeatherSafe + min(incr_replaceText_nameSubstitution.z, 0.0), incr_replaceText_nameSubstitution.x - incr_replaceText_nameSubstitution_edgeFeatherSafe + min(incr_replaceText_nameSubstitution.z, 0.0), ((1.0 - fragment.a) - .5) * 2.0);\n\
        vec4 incr_replaceText_nameSubstitution_color = mix(vec4(incr_replaceText_nameSubstitution_outerColor.rgb * incr_replaceText_nameSubstitution_outerColor.a, incr_replaceText_nameSubstitution_outerColor.a), vec4(incr_replaceText_nameSubstitution_innerColor.rgb * incr_replaceText_nameSubstitution_innerColor.a, incr_replaceText_nameSubstitution_innerColor.a), incr_replaceText_nameSubstitution_innerStrength);\n\
        fragment = incr_replaceText_nameSubstitution_color * smoothstep(incr_replaceText_nameSubstitution.x + incr_replaceText_nameSubstitution_edgeFeatherSafe + max(incr_replaceText_nameSubstitution.z, 0.0), incr_replaceText_nameSubstitution.x - incr_replaceText_nameSubstitution_edgeFeatherSafe + max(incr_replaceText_nameSubstitution.z, 0.0), ((1.0 - fragment.a) - .5) * 2.0);",
        [incr_replaceText_nameSubstitution_def,incr_replaceText_nameSubstitution_innerColor_def,incr_replaceText_nameSubstitution_outerColor_def],
        true, undefined, undefined, undefined,
        "Converts edge data stored in a 'shapified' Texture into a sharp-edged image and adds a colored outer stroke. Supports separate inner and outer colors, edge offset, feathering, and stroke thickness."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 30: Effect Nodes/Shear
----------------------------------------------------------


Title: Shear
Template Library Path: Effect Nodes/Shear
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/Shear:
Distorts geometry by shearing it, rotating the X and Y axes independently.

Good for italicizing text assemblies and for cheap perspective fakes.

A vertex-stage effect, but a straight-line one: it moves the corners and everything between them follows exactly, so unlike Bulge and Arch it needs no subdivision.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/Shear:
// Incisor Template Library - Shear: leaning an image over into an italic slant.
// Requires Template Library items: Shear

// Shear moves the corners and everything between them follows exactly, so a plain quad is all it needs - no subdividing.
let picture = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Picture");
picture.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.Shear,nc.effectNodes.ColorMultiply]);

// preserveArea compensates the scale as the angles open up, so the image keeps its weight while it leans.
picture.materialMaster.shear.xAngle = 0;
picture.materialMaster.shear.yAngle = 0;
picture.materialMaster.shear.preserveArea = 1;

// The shear pivots around this point, in the object's own space.
picture.materialMaster.shear_center.x = 0;
picture.materialMaster.shear_center.y = 0;

// Lean it over.
nc.swoopValue(picture.materialMaster.shear,"xAngle",15,1.8,nc.tweenTypes.Ease);

Content of Effect Nodes/Shear, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode slants geometry by tipping its horizontal and vertical axes
independently, the way italic type leans or a flat shape suggests perspective.

This is a vertex-stage node, so it moves the vertices an object already has and never touches color. Unlike the curved
deformers it moves every vertex along a straight line, so it does not need a subdivided Geometry - a plain quad shears
correctly.

Once the node is on an object, its controllers are reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution' and 'materialMaster.incr_replaceText_nameSubstitution_center'.
*/


CODE.runBeforeInit___begin;
    // The two angles tip each axis away from square, so leaving both at 0 leaves the object alone. 'preserveArea'
    // decides what happens as the axes swing toward each other - at 1 the object keeps its area and simply slants, at 0
    // it is allowed to squash flat as the two axes converge.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution","Vector3",["xAngle","yAngle","preserveArea"],[0,0,1],nc.constants.effectControllerMixModes.addition,[[0,90],[0,90],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which distorts the shape to appear slanted or skewed.",["The amount in degrees to rotate the X axis.","The amount in degrees to rotate the Y axis.","How much to preserve the original area.  1 preserves area exactly.  0 allows the area to approach 0 as the axes approach each other."]);

    // The one point the shear leaves where it is - everything else moves relative to it, so this is the pivot to set
    // when the slant should hang off an edge rather than the middle.
    let incr_replaceText_nameSubstitution_center_def = nc.defineEffectController("incr_replaceText_nameSubstitution_center","Vector2",["x","y"],[0,0],nc.constants.effectControllerMixModes.addition,[[0,100],[0,100]],"EffectController for the Shear EffectNode, which distorts the shape to appear slanted or skewed.",["The X position of the center of the shear. This is the point that is not moved by the shear.","The Y position of the center of the shear.  This is the point that is not moved by the shear."]);

    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        ["uniform vec3 incr_replaceText_nameSubstitution;", "uniform vec2 incr_replaceText_nameSubstitution_center;"],
        // Both outcomes are built and then mixed between. Using the two tipped axes as they are gives the collapsing
        // version, since two unit axes swinging together enclose less and less area. Dividing each axis by its own
        // leading component stretches it back out so the object keeps its size, which is the true shear. The 90 degrees
        // added to the second angle is what makes the two axes start out square to each other.
        "float incr_replaceText_nameSubstitution_rx = incr_replaceText_nameSubstitution.x * 3.14159 / 180.0;\n\
        float incr_replaceText_nameSubstitution_ry = (incr_replaceText_nameSubstitution.y + 90.0) * 3.14159 / 180.0;\n\
        vec2 incr_replaceText_nameSubstitution_rotatedX = vec2(cos(incr_replaceText_nameSubstitution_rx), sin(incr_replaceText_nameSubstitution_rx));\n\
        vec2 incr_replaceText_nameSubstitution_rotatedY = vec2(cos(incr_replaceText_nameSubstitution_ry), sin(incr_replaceText_nameSubstitution_ry));\n\
        mat2 incr_replaceText_nameSubstitution_m = mat2(incr_replaceText_nameSubstitution_rotatedX, incr_replaceText_nameSubstitution_rotatedY);\n\
        vec2 incr_replaceText_nameSubstitution_collapseResult = incr_replaceText_nameSubstitution_m * (vertex.xy - incr_replaceText_nameSubstitution_center);\n\
        incr_replaceText_nameSubstitution_rotatedX /= max(incr_replaceText_nameSubstitution_rotatedX.x, 0.001);\n\
        incr_replaceText_nameSubstitution_rotatedY /= max(incr_replaceText_nameSubstitution_rotatedY.y, 0.001);\n\
        incr_replaceText_nameSubstitution_m = mat2(incr_replaceText_nameSubstitution_rotatedX, incr_replaceText_nameSubstitution_rotatedY);\n\
        vec2 incr_replaceText_nameSubstitution_shearResult = incr_replaceText_nameSubstitution_m * (vertex.xy - incr_replaceText_nameSubstitution_center);\n\
        vertex.xy = mix(incr_replaceText_nameSubstitution_collapseResult, incr_replaceText_nameSubstitution_shearResult, incr_replaceText_nameSubstitution.z) + incr_replaceText_nameSubstitution_center;",
        [],
        "",
        [incr_replaceText_nameSubstitution_def,incr_replaceText_nameSubstitution_center_def],
        undefined, undefined, undefined, undefined,
        "Distorts geometry by shearing (skewing) it — independently rotating the X and Y axes to create a slanted appearance."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 31: Effect Nodes/Sheen
----------------------------------------------------------


Title: Sheen
Template Library Path: Effect Nodes/Sheen
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/Sheen:
Adds a movable band of bright color over the Material, creating a highlight sweep.

Position, angle, thickness, feathering, color, and luminance are all controllable. Animate the position on a Timeline for the standard glint-across-a-surface effect.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Examples of Effect Nodes/Sheen:
// Incisor Template Library - Sheen: sweeping a glint of light across an image.
// Requires Template Library items: Sheen

let picture = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Picture");
picture.setEffectNodes([nc.effectNodes.SampleMainTexture,nc.effectNodes.Sheen,nc.effectNodes.ColorMultiply]);

// progress walks the band across the surface, angle tilts it, and thickness and feather set how wide and how soft it is.
picture.materialMaster.sheen.progress = 0;
picture.materialMaster.sheen.angle = 20;
picture.materialMaster.sheen.thickness = 60;
picture.materialMaster.sheen.feather = 120;

picture.materialMaster.sheen_color.red = 1;
picture.materialMaster.sheen_color.green = 1;
picture.materialMaster.sheen_color.blue = .8;

// luminance is a single number rather than a set of components, so it is set straight onto the Material.
picture.materialMaster.sheen_luminance = 1.4;

// Run the glint across. Animating progress on a Timeline instead is the usual way to time this to something else.
nc.swoopValue(picture.materialMaster.sheen,"progress",1,3.6,nc.tweenTypes.Ease);

Content of Effect Nodes/Sheen, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' EffectNode lays a soft band of bright color across an object, the highlight that
sweeps over glass or metal.

Sweeping it is the point - swoop 'progress' from one side of the object to the other and the band travels across it.
Because the band is placed in the object's own space, that sweep is independent of the artwork underneath.

This is a fragment-stage node as far as color goes - the vertex stage below only hands the fragment stage each pixel's
position. It needs no subdivision and works on any object.

Once the node is on an object, its controllers are reachable on that object's material as
'materialMaster.incr_replaceText_nameSubstitution', '..._color' and '..._luminance'.
*/


CODE.runBeforeInit___begin;
    // 'progress' is how far along its axis the band currently sits, so this is the one to swoop to make the highlight
    // travel. 'thickness' is the solid core of the band and 'feather' is the soft fade added onto each side of it.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution","Vector4",["progress","angle","thickness","feather"],[0,45,100,100],nc.constants.effectControllerMixModes.addition,[[0,500],[0,180],[0,100],[0,100]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which adds a movable band of bright color to the Material it is applied to.",["The offset of the bright band.","The angle of the bright band.","The thickness of the bright band.","The fuzziness of the edges of the bright band."]);

    // The color of the band. Its alpha is how strongly the band takes over rather than the opacity of the object.
    let incr_replaceText_nameSubstitution_color_def = nc.defineEffectController("incr_replaceText_nameSubstitution_color","Vector4",["red","green","blue","alpha"],[1,1,1,1],nc.constants.effectControllerMixModes.addition,[[0,1],[0,1],[0,1],[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which adds a movable band of bright color to the Material it is applied to.",["The red value of the incr_replaceText_NameSubstitution color.","The green value of the incr_replaceText_NameSubstitution color.","The blue value of the incr_replaceText_NameSubstitution color.","The alpha value of the incr_replaceText_NameSubstitution color."]);

    // How the band sits on the artwork rather than how bright it is - at 0 it paints over what is underneath, at 1 it
    // adds to it and blows out to white where the object is already light. It is a single number, so it is reachable
    // directly by name rather than through a component.
    let incr_replaceText_nameSubstitution_luminance_def = nc.defineEffectController("incr_replaceText_nameSubstitution_luminance","number",[""],[1],nc.constants.effectControllerMixModes.addition,[[0,1]],"EffectController for the incr_replaceText_NameSubstitution EffectNode, which adds a movable band of bright color to the Material it is applied to.","The luminance of the bright band.");

    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        // The vertex stage exists only to hand each pixel its position in the object's own space, which is what lets
        // the band be placed and angled independently of the object's UVs.
        ["varying vec2 pos;"],
        "pos = vertex.xy;",
        ["varying vec2 pos;", "uniform vec4 incr_replaceText_nameSubstitution;","uniform vec4 incr_replaceText_nameSubstitution_color;", "uniform float incr_replaceText_nameSubstitution_luminance;"],
        // The angle becomes a direction vector, and projecting each pixel onto it turns a two dimensional position into
        // one number - how far along the sweep that pixel sits. The band itself is two soft edges multiplied together,
        // one rising into it and one falling out of it, which leaves a feathered stripe between them.
        "float incr_replaceText_nameSubstitution_angle=incr_replaceText_nameSubstitution.y*3.14159/180.0;\n\
        float incr_replaceText_nameSubstitution_progress=incr_replaceText_nameSubstitution.x;\n\
        float incr_replaceText_nameSubstitution_thickness=incr_replaceText_nameSubstitution.z;\n\
        float incr_replaceText_nameSubstitution_feather=incr_replaceText_nameSubstitution.w;\n\
        vec2 incr_replaceText_nameSubstitution_axisOfTravel=vec2(cos(incr_replaceText_nameSubstitution_angle),sin(incr_replaceText_nameSubstitution_angle));\n\
        float incr_replaceText_nameSubstitution_newUV=dot(pos,incr_replaceText_nameSubstitution_axisOfTravel);\n\
        float incr_replaceText_nameSubstitution_sheenBand=smoothstep(incr_replaceText_nameSubstitution_progress-incr_replaceText_nameSubstitution_thickness*.5-incr_replaceText_nameSubstitution_feather,incr_replaceText_nameSubstitution_progress-incr_replaceText_nameSubstitution_thickness*.5,incr_replaceText_nameSubstitution_newUV)*smoothstep(incr_replaceText_nameSubstitution_progress+incr_replaceText_nameSubstitution_thickness*.5+incr_replaceText_nameSubstitution_feather,incr_replaceText_nameSubstitution_progress+incr_replaceText_nameSubstitution_thickness*.5,incr_replaceText_nameSubstitution_newUV);\n\
        vec3 incr_replaceText_nameSubstitution_addColor = fragment.rgb+incr_replaceText_nameSubstitution_sheenBand*fragment.a*incr_replaceText_nameSubstitution_color.rgb*incr_replaceText_nameSubstitution_color.a;\n\
        vec3 incr_replaceText_nameSubstitution_normalColor = mix(fragment.rgb, fragment.a*incr_replaceText_nameSubstitution_color.rgb, incr_replaceText_nameSubstitution_color.a * incr_replaceText_nameSubstitution_sheenBand);\n\
        fragment.rgb = mix(incr_replaceText_nameSubstitution_normalColor, incr_replaceText_nameSubstitution_addColor, incr_replaceText_nameSubstitution_luminance);",
        [incr_replaceText_nameSubstitution_def,incr_replaceText_nameSubstitution_color_def,incr_replaceText_nameSubstitution_luminance_def],
        undefined, undefined, undefined, undefined,
        "Adds a movable band of bright color over the Material, creating a sheen or highlight sweep effect. The band's position, angle, thickness, feathering, color, and luminance are all configurable."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 32: Effect Nodes/blank template
----------------------------------------------------------


Title: blank template
Template Library Path: Effect Nodes/blank template
Type: EffectNode
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Effect Nodes/blank template:
An empty EffectNode definition with one EffectController wired up, ready to be filled in.

Define the vertex and fragment support strings and bodies, and declare any EffectControllers the shader code reads. The controller defined here shows the required shape and can be renamed or removed.

EffectNodes run on the GPU, assembled into a single shader in the order they are listed, so any of them can be combined in any order - each one works from what the ones before it left.

Content of Effect Nodes/blank template, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
A starting point for writing your own EffectNode.

An EffectNode is a piece of shader code spliced into the program that draws an object. Every object with this node on it
runs that code on the graphics card - once per vertex to move geometry around, once per pixel to decide a color, or
both. Nothing here runs on the CPU, so an effect costs the same whether it touches one object or a thousand.

The two things it works on are 'vertex', the position of the point being processed in the object's own space, and
'fragment', the color of the pixel being drawn as a vec4. Read them, change them, and what is on screen changes.
'UV' and 'NORMAL' are also available, along with the usual matrices.

EffectControllers are how the shader is steered from project code. Each one becomes a uniform in the shader and a
property on the material, so it can be set and swooped like anything else. Vector types surface as
'materialMaster.<controllerName>.<componentName>', and single numbers and Textures surface directly by name.

To fill this in: declare what the shader needs in the support arrays, write the body strings, and list the controllers.
Leave a stage's two arguments empty and the node simply does not take part in that stage.
*/


CODE.runBeforeInit___begin;
    // The controller's arguments, in order - the name it is reached by, its base type, the names of its components,
    // the value each starts at, how two of these combine when several nodes use the same controller, the range each
    // component is expected to sit in, a description of the whole controller, then one per component.
    let incr_replaceText_nameSubstitution_def = nc.defineEffectController("incr_replaceText_nameSubstitution", "number", [""], [0, 0], nc.constants.effectControllerMixModes.addition, [[0, 1], [0, 1]], "EffectController for the incr_replaceText_NameSubstitution EffectNode");

    nc.defineEffectNode("incr_replaceText_NameSubstitution",
        // Vertex stage. The first array declares what this stage needs - uniforms matching the controllers, varyings to
        // hand values on to the fragment stage, and any helper functions. The string below it is the body, and it runs
        // once for every vertex, where writing to 'vertex' moves the geometry.
        [],
        "",
        // Fragment stage. Declared the same way, and the body below runs once for every pixel being drawn, where
        // writing to 'fragment' sets the color. Any varying written in the vertex stage has to be declared in both.
        [],
        "",
        // Every controller the shader above refers to has to be listed here, or its uniform will not be connected.
        [incr_replaceText_nameSubstitution_def]
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 33: Global Extensions/CustomMenu
----------------------------------------------------------


Title: CustomMenu
Template Library Path: Global Extensions/CustomMenu
Type: GlobalExtension
Placement: incr_applicationSupport/Global Extensions

Description of Global Extensions/CustomMenu:
Adds a custom menu to the Incisor top bar for every project on this machine.

The global counterpart to the project extension of the same name. Use this where the tooling is yours rather than the project's.

An item is a path and a callback - nce.addInspectorMenuItem(["Reports","Weekly","Export CSV"], owner, "exportCsv") nests one three levels deep, and Incisor creates any menu on that path that does not exist yet. Depth is unlimited, and a fourth argument passes callback arguments, so one method can serve a whole menu.

The callback itself is unrestricted: anything extension code can reach, including the running project through 'nce.projectPR'.

A GlobalExtension is code that runs in the Incisor inspector rather than inside your project - it lives in the Application Support directory and applies to every project on this machine, stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Global Extensions/CustomMenu, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Global Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to all Incisor projects.
Keep in mind that code placed in this 'Global Extensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the method that will be invoked by the custom menu...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}


    performMenuCallback()
    {
        nce.alert("Custom Menu Functionality","The 'incr_replaceText_NameSubstitution' functionality is happening!");
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Global Extensions Scope - This code executes when the Inspector first opens, before any project extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a new custom menu item that calls 'functionalityClassInstance.performMenuCallback'...
    nce.addInspectorMenuItem(["Example Menu", "incr_replaceText_NameSubstitution"],functionalityClassInstance,"performMenuCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 34: Global Extensions/CustomPanel
----------------------------------------------------------


Title: CustomPanel
Template Library Path: Global Extensions/CustomPanel
Type: GlobalExtension
Placement: incr_applicationSupport/Global Extensions

Description of Global Extensions/CustomPanel:
Defines a custom inspector panel available in every project on this machine.

The global counterpart to the project extension of the same name.

A GlobalExtension is code that runs in the Incisor inspector rather than inside your project - it lives in the Application Support directory and applies to every project on this machine, stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Global Extensions/CustomPanel, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Global Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to all Incisor projects.
Keep in mind that code placed in this 'Global Extensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// Custom InspectorPanels can be defined for use within the Incisor GUI. Just define a class that extends InspectorPanel, then call 'nce.registerInspectorPanelDefinition'.
class incr_replaceText_nameSubstitution_panelClass extends InspectorPanel
{
    constructor()
    {
        // Call the super constructor
        super("incr_replaceText_NameSubstitution");

        // Add a sample title to the header ScrollingPanel
        let titleText = new UiText(this,"TitleText");
        titleText.string = "incr_replaceText_NameSubstitution:";
        titleText.textFormat = nce.uiStyle.textFormat_subHeading.clone();
        titleText.layoutObject.topBuffer = nce.uiStyle.spacer_small;
        titleText.layoutObject.leftBuffer = nce.uiStyle.spacer_small*2;
        this.headerScrollingPanel.bodyStack.addElements(titleText);

        // Add text to the panel body
        let bodyText = new UiText(this,"BodyText");
        bodyText.string = "...panel content";
        bodyText.layoutObject.topBuffer = nce.uiStyle.spacer_small;
        bodyText.layoutObject.leftBuffer = nce.uiStyle.spacer_small*2;
        this.bodyScrollingPanel.bodyStack.addElements(bodyText);
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Global Extensions Scope - This code executes when the Inspector first opens, before any project extensions code

    // Register a the custom InspectorPanel 'incr_replaceText_NameSubstitution' with Incisor.
    nce.registerInspectorPanelDefinition("incr_replaceText_NameSubstitution",incr_replaceText_nameSubstitution_panelClass);   
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 35: Global Extensions/FileIoExample
----------------------------------------------------------


Title: FileIoExample
Template Library Path: Global Extensions/FileIoExample
Type: GlobalExtension
Placement: incr_applicationSupport/Global Extensions

Description of Global Extensions/FileIoExample:
Demonstrates reading and writing files from global extension code through nce.

Covers the file IO calls and the sandbox rules that govern them.

A GlobalExtension is code that runs in the Incisor inspector rather than inside your project - it lives in the Application Support directory and applies to every project on this machine, stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Global Extensions/FileIoExample, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Global Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to all Incisor projects.
Keep in mind that code placed in this 'Global Extensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the extensions functionality...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}

    performCallback()
    {
        // Write a text file to the project directory.
        let fileName = "TextFileFromExtensions-"+nce.timeStamp.getTimeStamp()+".txt";
        // Using 'nce.fileIO' to write a text file. Check out the documentation for 'nce.fileIO', which has a bunch of helpful functionality.
        nce.fileIO.writeTextFile(fileName,"This file was brought to you by Incisor extensions!");
        nce.alert("FileIO","A text file named '" + fileName + "' has been written to the project directory.");
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Global Extensions Scope - This code executes when the Inspector first opens, before any project extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a new custom menu item that calls 'functionalityClassInstance.performCallback'...
    nce.addInspectorMenuItem(["Example Menu", "incr_replaceText_NameSubstitution"],functionalityClassInstance,"performCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 36: Global Extensions/PopupExample
----------------------------------------------------------


Title: PopupExample
Template Library Path: Global Extensions/PopupExample
Type: GlobalExtension
Placement: incr_applicationSupport/Global Extensions

Description of Global Extensions/PopupExample:
Demonstrates the standard popup windows available to global extension code, including the text query popup and alerts.

A GlobalExtension is code that runs in the Incisor inspector rather than inside your project - it lives in the Application Support directory and applies to every project on this machine, stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Global Extensions/PopupExample, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Global Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to all Incisor projects.
Keep in mind that code placed in this 'Global Extensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the extensions functionality...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}

    async performCallback()
    {
        // show the text query popup and asynchronously await feedback
        let userText = await nce.showTextQueryPopup("Standard Text Query Popup","The user can provide text feedback here.","text:","your feedback here...");
        // display the text result - await feedback
        await nce.alert("User Text","The user text provided was '" + userText + "'.");
        // show the text query popup and asynchronously await feedback
        let userYesNo = await nce.showYesNoQueryPopup("Standard Yes/No Query Popup","The user can provide yes/no feedback here.");
        // display the yes/no result - await feedback
        await nce.alert("User Text","The user text provided was '" + userYesNo +"'.");
        // Create an instance of the custom popup if it hasn't been made yet
        if(this.incr_replaceText_nameSubstitution_customPopup===undefined)
        {
            this.incr_replaceText_nameSubstitution_customPopup = new incr_replaceText_nameSubstitution_customPopupClass(nce.mainScene,"incr_replaceText_nameSubstitution_customPopup");
        }
        // Open the custom popup
        this.incr_replaceText_nameSubstitution_customPopup.isOpen = true;
    }
}

// The class defining a custom popup
class incr_replaceText_nameSubstitution_customPopupClass extends UiPopupWindow
{
    constructor(parent,name)
    {
        // Call the super constructor
        super(parent,name);

        // Change the title 
        this.titleText.string = "incr_replaceText_NameSubstitution";
        this.titleText.colorMultiply.addMotion.red(0,1);

        // Add body text
        this.bodyText = new UiText(this.bodyStack,"bodyText");
        this.bodyText.string = "...custom popup content";
        this.bodyStack.addElements(this.bodyText);

        // Set the 'Decision Buttons'
        this.setDecisionButtons(["Custom","Decision","Buttons"]);

        // Add DecisionButton callback
        this.addDecisionButtonTriggerCallback(this,"decisionButtonTriggerCallback");
    }

    async decisionButtonTriggerCallback(decisionString,decisionButton)
    {
        await nce.alert("Popup Decision Button Pressed","The '" + decisionString + "' Button was pressed.");
        this.isOpen = false;
    }
}

// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Global Extensions Scope - This code executes when the Inspector first opens, before any project extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a new custom menu item that calls 'functionalityClassInstance.performCallback'...
    nce.addInspectorMenuItem(["Example Menu", "incr_replaceText_NameSubstitution"],functionalityClassInstance,"performCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 37: Global Extensions/ProjectConnectionActions
----------------------------------------------------------


Title: ProjectConnectionActions
Template Library Path: Global Extensions/ProjectConnectionActions
Type: GlobalExtension
Placement: incr_applicationSupport/Global Extensions

Description of Global Extensions/ProjectConnectionActions:
Hooks code to project connection events across every project on this machine.

Useful for per-session setup that should apply regardless of which project is open.

A GlobalExtension is code that runs in the Incisor inspector rather than inside your project - it lives in the Application Support directory and applies to every project on this machine, stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Global Extensions/ProjectConnectionActions, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Global Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to all Incisor projects.
Keep in mind that code placed in this 'Global Extensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the method that will be invoked every time the project connects to the inspector...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}


    async performConnectionCallback()
    {
        await nce.alert("Project Connecting","Performing the 'incr_replaceText_NameSubstitution' project connection action.");
    }


    async performDisconnectionCallback()
    {
        await nce.alert("Project Disconnecting","Performing the 'incr_replaceText_NameSubstitution' project disconnection action.");
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Global Extensions Scope - This code executes when the Inspector first opens, before any project extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a callback that happens whenever the project connects to the inspector
    nce.addProjectConnectionCallback(functionalityClassInstance,"performConnectionCallback");

    // Add a callback that happens whenever the project connects to the inspector
    nce.addProjectDisconnectionCallback(functionalityClassInstance,"performDisconnectionCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 38: Global Extensions/PublishActions
----------------------------------------------------------


Title: PublishActions
Template Library Path: Global Extensions/PublishActions
Type: GlobalExtension
Placement: incr_applicationSupport/Global Extensions

Description of Global Extensions/PublishActions:
Hooks code to run before and after publishing, for every project on this machine.

Use for machine-level build steps such as copying artifacts to a local server or stamping local build information.

A GlobalExtension is code that runs in the Incisor inspector rather than inside your project - it lives in the Application Support directory and applies to every project on this machine, stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Global Extensions/PublishActions, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Global Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to all Incisor projects.
Keep in mind that code placed in this 'Global Extensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the method that will be invoked right before the project is published...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}

    /** Function called prior to publishing.
     * @param {PrePublishInfoObject} prePublishInfoObject 
     */
    async performPrePublishCallback(prePublishInfoObject)
    {
        await nce.alert("Pre-Publish Action","Performing the 'PublishActions' action before publishing with the '" + prePublishInfoObject.configurationName + "' configuration.");
    }

    /** Function called after publishing.
     * @param {PostPublishInfoObject} postPublishInfoObject 
     */
    async performPostPublishCallback(postPublishInfoObject)
    {
        await nce.alert("Post-Publish Action","Performing the 'PublishActions' action after publishing with the '" + postPublishInfoObject.configurationName + "' configuration.");
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Global Extensions Scope - This code executes when the Inspector first opens, before any project extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a callback that happens right before the project is published
    nce.addPrePublishCallback(functionalityClassInstance,"performPrePublishCallback");
    // Add a callback that happens right after the project is published
    nce.addPostPublishCallback(functionalityClassInstance,"performPostPublishCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 39: Global Extensions/UiComponentsExample
----------------------------------------------------------


Title: UiComponentsExample
Template Library Path: Global Extensions/UiComponentsExample
Type: GlobalExtension
Placement: incr_applicationSupport/Global Extensions

Description of Global Extensions/UiComponentsExample:
A gallery of the Incisor UI components available to global extension code, with each one wired to a working callback.

A GlobalExtension is code that runs in the Incisor inspector rather than inside your project - it lives in the Application Support directory and applies to every project on this machine, stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Global Extensions/UiComponentsExample, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Global Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to all Incisor projects.
Keep in mind that code placed in this 'Global Extensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the extensions functionality...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}

    async performCallback()
    {
        // Create an instance of the custom popup if it hasn't been made yet
        if(this.incr_replaceText_nameSubstitution_customPopup===undefined)
        {
            this.incr_replaceText_nameSubstitution_customPopup = new incr_replaceText_nameSubstitution_customPopupClass(nce.mainScene,"incr_replaceText_nameSubstitution_customPopup");
        }
        // Open the custom popup
        this.incr_replaceText_nameSubstitution_customPopup.isOpen = true;
    }
}

// The class defining a custom popup
class incr_replaceText_nameSubstitution_customPopupClass extends UiPopupWindow
{
    constructor(parent,name)
    {
        // Call the super constructor
        super(parent,name);

        // Stash the 'DefaultFocusFallback' and set to this popup - management of the flow of the keyboard focus
        let previousDefaultFocusFallback = nce.defaultFocusFallback;
        nce.defaultFocusFallback = this;

        // Set the PopupWindow's Title
        this.titleText.string = "Incisor UI Components Example";

        // Add standard UiText examples 
        let standardUiText = new UiText(this.bodyStack,"standardUiText");
        standardUiText.textFormat = nce.uiStyle.textFormat_heading;
        standardUiText.string = "Heading text";
        this.bodyStack.addElements(standardUiText);
        standardUiText = new UiText(this.bodyStack,"standardUiText");
        standardUiText.textFormat = nce.uiStyle.textFormat_subHeading;
        standardUiText.string = "SubHeading text";
        this.bodyStack.addElements(standardUiText);
        standardUiText = new UiText(this.bodyStack,"standardUiText");
        standardUiText.textFormat = nce.uiStyle.textFormat_body;
        standardUiText.string = "Body text";
        this.bodyStack.addElements(standardUiText);
        standardUiText = new UiText(this.bodyStack,"standardUiText");
        standardUiText.textFormat = nce.uiStyle.textFormat_technical;
        standardUiText.string = "Technical text";
        this.bodyStack.addElements(standardUiText);
        standardUiText = new UiText(this.bodyStack,"standardUiText");
        standardUiText.textFormat = nce.uiStyle.textFormat_tiny;
        standardUiText.string = "Tiny text";
        this.bodyStack.addElements(standardUiText);

        // Add UiButton
        let standardUiButton = new UiButton(this.bodyStack,"standardUiButton");
        standardUiButton.displayLabel = true;
        standardUiButton.addTriggerCallback(this,"uiButtonPressedCallback");
        standardUiButton.layoutObject.topBuffer = nce.uiStyle.spacer_medium;
        this.bodyStack.addElements(standardUiButton);

        // Add UiLinkButton
        let standardUiLinkButton = new UiLinkButton(this.bodyStack,"standardUiLinkButton");
        standardUiLinkButton.displayLabel = true;
        standardUiLinkButton.addTriggerCallback(this,"uiLinkButtonPressedCallback");
        standardUiLinkButton.layoutObject.topBuffer = nce.uiStyle.spacer_medium;
        this.bodyStack.addElements(standardUiLinkButton);
    
        // Add UiTextField
        let standardUiTextField = new UiTextField(this.bodyStack,"standardUiTextField");
        standardUiTextField.displayLabel = true;
        standardUiTextField.layoutObject.topBuffer = nce.uiStyle.spacer_medium;
        this.bodyStack.addElements(standardUiTextField);

        // Add UiCollapsibleStack
        let standardUiCollapsibleStack = new UiCollapsibleStack(this.bodyStack,"standardUiCollapsibleStack");
        standardUiCollapsibleStack.layoutObject.topBuffer = nce.uiStyle.spacer_medium;
        for(let i=0; i<5; i++)
        {
            standardUiText = new UiText(standardUiCollapsibleStack.bodyStack,"standardUiText");
            standardUiText.string = "Item " + i + "...";
            standardUiCollapsibleStack.bodyStack.addElements(standardUiText);
        }
        this.bodyStack.addElements(standardUiCollapsibleStack);

        // Add ScrollingPanel
        let scrollingPanel  = new ScrollingPanel(this.bodyStack,"scrollingPanel");
        scrollingPanel.layoutObject.topBuffer = nce.uiStyle.spacer_medium;
        scrollingPanel.width = 500;
        scrollingPanel.height = 200;
        scrollingPanel.useNearestPixelRendering = true;
        this.bodyStack.addElements(scrollingPanel);

        // Add FileBrowser
        let fileBrowser = nce.addFileBrowser(scrollingPanel.bodyStack,"fileBrowser");
        fileBrowser.layoutObject.leftBuffer = nce.uiStyle.spacer_small;
        fileBrowser.allowRearrange = false;
        scrollingPanel.bodyStack.addElements(fileBrowser);

        // Add decision button callback
        this.addDecisionButtonTriggerCallback(this,"decisionButtonTriggerCallback");

        // Restore default focus fallback
        nce.defaultFocusFallback = previousDefaultFocusFallback;
    }

    uiButtonPressedCallback()
    {
        nce.alert("UiButton Pressed","The UiButton was pressed.");
    }

    uiLinkButtonPressedCallback()
    {
        nce.alert("UiLinkButton Pressed","The UiLinkButton was pressed.");
    }

    decisionButtonTriggerCallback()
    {
        this.isOpen = false;;
    }
}

// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Global Extensions Scope - This code executes when the Inspector first opens, before any project extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a new custom menu item that calls 'functionalityClassInstance.performCallback'...
    nce.addInspectorMenuItem(["Example Menu", "incr_replaceText_NameSubstitution"], functionalityClassInstance,"performCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 40: Global Extensions/blank template
----------------------------------------------------------


Title: blank template
Template Library Path: Global Extensions/blank template
Type: GlobalExtension
Placement: incr_applicationSupport/Global Extensions

Description of Global Extensions/blank template:
An empty global extension file with the class scope and the runBeforeInit block laid out, plus a header explaining how extensions work.

A GlobalExtension is code that runs in the Incisor inspector rather than inside your project - it lives in the Application Support directory and applies to every project on this machine, stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Global Extensions/blank template, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Global Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to all Incisor projects.
Keep in mind that code placed in this 'Global Extensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// This is where you can declare class definitions...


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Global Extensions Scope - This code executes when the Inspector first opens, before any project extensions code

    // This is where you put runtime code to register actions etc...

CODE.runBeforeInit___end;










----------------------------------------------------------
Section 41: Motion Types/Bounce
----------------------------------------------------------


Title: Bounce
Template Library Path: Motion Types/Bounce
Type: MotionType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Motion Types/Bounce:
Bounces off the lower bounds and falls from the upper bounds.

A continuous gravity-style bounce driven by the Motion's progress rather than a physics simulation, so it stays perfectly periodic.

This MotionType defines no controllers of its own - what shapes it are the arguments to addMotion, object.position.addMotion.y(0,300,1,nc.motionTypes.Bounce), and motionSpeed is progress per second. The lower bound is the floor it bounces off and the upper bound is the height it falls from, one full bounce to a unit of progress - so a motionSpeed of 1 is a bounce a second.

Examples of Motion Types/Bounce:
// Incisor Template Library - Bounce: dropping an object onto a floor and letting it bounce.
// Requires Template Library items: Bounce

// A MotionType is only legible next to something to compare it against, so this drives two objects between the same
// two heights at the same speed and changes nothing between them but the MotionType. Pendulum is the built-in one.
let swinging = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Swinging");
swinging.scale.scaleByFactor(3);
swinging.position.x = -150;

let bouncing = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Bouncing");
bouncing.scale.scaleByFactor(3);
bouncing.position.x = 150;

// The left one eases into both ends of its swing. The right one falls from the upper bound and meets the lower one at
// a point rather than easing into it, which is what reads as a bounce.
// One full bounce takes a unit of progress and motionSpeed is progress per second, so this is a bounce a second.
swinging.position.addMotion.y(-200,200,1,nc.motionTypes.Pendulum);
bouncing.position.addMotion.y(-200,200,1,nc.motionTypes.Bounce);

Content of Motion Types/Bounce, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' MotionType bounces off the lower bounds and falls from the upper bounds.

The lower bound is the floor it bounces off and the upper bound is the height it falls from, one full bounce to a unit of progress. It is driven by progress rather than by a physics simulation, so it stays perfectly periodic and never loses height.

A MotionType may define controllers of its own, given to nc.defineMotionType as a list of names and a matching list of defaults and read back as 'motion.controllers.incr_replaceText_NameSubstitution.<name>'. This one defines none, which is what the two undefined arguments below say.

A MotionType is handed to addMotion and is asked for a value on every fixed update, for as long as the Motion lives. It is given the Motion, and is responsible for writing every entry of 'currentValues' from 'lowerBounds', 'upperBounds' and 'progress'. Unlike a TweenType, it has no end to reach - progress climbs without limit at motionSpeed per second, and it is up to the function to decide what that means.
*/


CODE.runBeforeInit___begin;
    /** Define the motion function.
    * @param {Motion} motion
    */
    var incr_replaceText_nameSubstitution_motionTypeFunction = function(motion)
    {
    // The absolute value of a sine is a run of arcs that meet the floor at a point rather than easing into
    // it, which is what reads as a bounce. Its period is one unit of progress, so motionSpeed is bounces
    // per second.
        for (let i = 0; i < motion.numProperties; ++i)
        {
            motion.currentValues[i] = motion.lowerBounds[i] + Math.abs(Math.sin(motion.progress*Math.PI) * (motion.upperBounds[i]-motion.lowerBounds[i]));
        }
    };

// The name, the function, then the controller names and their defaults - both undefined here, since this MotionType
// takes everything it needs from the bounds. The last argument is the description that reaches the Code API.
    nc.defineMotionType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_motionTypeFunction,
        undefined,
        undefined,
        "This MotionType bounces off of the lower bounds and falls from the upper bounds."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 42: Motion Types/InfiniteAdd
----------------------------------------------------------


Title: InfiniteAdd
Template Library Path: Motion Types/InfiniteAdd
Type: MotionType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Motion Types/InfiniteAdd:
Adds to the values indefinitely, without ever wrapping or reversing.

Useful for continuous rotation, scrolling offsets, and anything that should accumulate forever.

This MotionType defines no controllers of its own - what shapes it are the arguments to addMotion, object.position.addMotion.z(0,360,.5,nc.motionTypes.InfiniteAdd), and motionSpeed is progress per second. The value starts at the lower bound and gains the distance between the bounds every unit of progress, so the example above turns a full circle every two seconds and keeps going.

The upper bound does not mean here what it means everywhere else. Every other MotionType treats the bounds as a range to stay inside; this one reads them as an amount to add, so nothing holds the value back and it passes the upper bound almost immediately. Give it the distance to cover per unit of progress rather than the largest value wanted - bounds of 0 and 360 do not keep a rotation within one turn, they add a turn every unit of progress forever.

Examples of Motion Types/InfiniteAdd:
// Incisor Template Library - InfiniteAdd: spinning objects that never stop or wrap.
// Requires Template Library items: InfiniteAdd

let slow = new GraphicObject(nc.graphicAssets.icon_play,nc.mainScene,"Slow");
slow.scale.scaleByFactor(3);
slow.position.x = -200;

let fast = new GraphicObject(nc.graphicAssets.icon_play,nc.mainScene,"Fast");
fast.scale.scaleByFactor(3);
fast.position.x = 200;

// InfiniteAdd reads its bounds as an amount to add per unit of progress rather than as a range to stay inside, so the
// value leaves them immediately and keeps climbing. rotation is in degrees.
// Both of these run at the same motionSpeed - the bounds alone are what makes one turn twice as fast as the other.
slow.rotation.addMotion.z(0,360,.5,nc.motionTypes.InfiniteAdd);
fast.rotation.addMotion.z(0,720,.5,nc.motionTypes.InfiniteAdd);

Content of Motion Types/InfiniteAdd, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' MotionType adds to the values indefinitely, without ever wrapping or reversing.

The value starts at the lower bound and gains the distance between the bounds every unit of progress, so the bounds set a starting point and a rate rather than a ceiling. Bounds of 0 and 360 at a motionSpeed of .5 turn a full circle every two seconds and keep going.

A MotionType may define controllers of its own, given to nc.defineMotionType as a list of names and a matching list of defaults and read back as 'motion.controllers.incr_replaceText_NameSubstitution.<name>'. This one defines none, which is what the two undefined arguments below say.

A MotionType is handed to addMotion and is asked for a value on every fixed update, for as long as the Motion lives. It is given the Motion, and is responsible for writing every entry of 'currentValues' from 'lowerBounds', 'upperBounds' and 'progress'. Unlike a TweenType, it has no end to reach - progress climbs without limit at motionSpeed per second, and it is up to the function to decide what that means.
*/


CODE.runBeforeInit___begin;
    /** Define the motion function.
    * @param {Motion} motion
    */
    var incr_replaceText_nameSubstitution_motionTypeFunction = function(motion)
    {
    // Progress is never wrapped or clamped, so this is the one MotionType where the value leaves its bounds
    // immediately and keeps climbing - the range is read as an amount to add rather than a place to stop.
        for (let i = 0; i < motion.numProperties; ++i)
        {
            motion.currentValues[i] = motion.lowerBounds[i] + motion.progress * (motion.upperBounds[i] - motion.lowerBounds[i] );
        }
    };

// The name, the function, then the controller names and their defaults - both undefined here, since this MotionType
// takes everything it needs from the bounds. The last argument is the description that reaches the Code API.
    nc.defineMotionType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_motionTypeFunction,
        undefined,
        undefined,
        "This MotionType adds to the value/values indefinitely."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 43: Motion Types/Modulo
----------------------------------------------------------


Title: Modulo
Template Library Path: Motion Types/Modulo
Type: MotionType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Motion Types/Modulo:
Adds linearly from the lower bound to the upper bound, then snaps back to the lower bound and repeats.

A sawtooth. The standard choice for looping scrolls and repeating sweeps where the reset should be instant.

This MotionType defines no controllers of its own - what shapes it are the arguments to addMotion, object.position.addMotion.x(-400,400,1,nc.motionTypes.Modulo), and motionSpeed is progress per second. The value sweeps from the lower bound to the upper bound over one unit of progress and then snaps back, so motionSpeed is also sweeps per second.

Examples of Motion Types/Modulo:
// Incisor Template Library - Modulo: sweeping across and snapping back to the start.
// Requires Template Library items: Modulo

// A MotionType is only legible next to something to compare it against, so this drives two objects between the same
// two points at the same speed and changes nothing between them but the MotionType. Pendulum is the built-in one.
let returning = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Returning");
returning.scale.scaleByFactor(3);
returning.position.y = 100;

let snapping = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Snapping");
snapping.scale.scaleByFactor(3);
snapping.position.y = -100;

// The top one travels back the way it came. The bottom one runs the sweep once and jumps to the start, which is what
// suits a looping scroll - one sweep to a unit of progress, and motionSpeed is progress per second.
returning.position.addMotion.x(-400,400,.5,nc.motionTypes.Pendulum);
snapping.position.addMotion.x(-400,400,.5,nc.motionTypes.Modulo);

Content of Motion Types/Modulo, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' MotionType adds linearly from the lower bound to the upper bound, then snaps back to the lower bound and repeats.

A sawtooth. One full sweep to a unit of progress, so motionSpeed is also sweeps per second. The reset is instant, which is what suits it to looping scrolls and repeating sweeps and what rules it out where the turn should be seen.

A MotionType may define controllers of its own, given to nc.defineMotionType as a list of names and a matching list of defaults and read back as 'motion.controllers.incr_replaceText_NameSubstitution.<name>'. This one defines none, which is what the two undefined arguments below say.

A MotionType is handed to addMotion and is asked for a value on every fixed update, for as long as the Motion lives. It is given the Motion, and is responsible for writing every entry of 'currentValues' from 'lowerBounds', 'upperBounds' and 'progress'. Unlike a TweenType, it has no end to reach - progress climbs without limit at motionSpeed per second, and it is up to the function to decide what that means.
*/


CODE.runBeforeInit___begin;
    /** Define the motion function.
    * @param {Motion} motion
    */
    var incr_replaceText_nameSubstitution_motionTypeFunction = function(motion)
    {
    // The remainder is what wraps the climb back to the lower bound. Bounds that are equal leave nothing to
    // divide by, so that case holds at the bound rather than dividing by zero.
        for (let i = 0; i < motion.numProperties; i++)
        {
            let range = motion.upperBounds[i] - motion.lowerBounds[i];
            if(range!==0){
                motion.currentValues[i] =  motion.lowerBounds[i] + (motion.progress * range) % range;
            }
            else{
                motion.currentValues[i] =  motion.lowerBounds[i];
            }
        }
    };

// The name, the function, then the controller names and their defaults - both undefined here, since this MotionType
// takes everything it needs from the bounds. The last argument is the description that reaches the Code API.
    nc.defineMotionType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_motionTypeFunction,
        undefined,
        undefined,
        "This MotionType will begin at the lower bound and linearly add until it reaches the upper bound. At that point it will reset to the lower bound and repeat."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 44: Motion Types/MoveInCircle
----------------------------------------------------------


Title: MoveInCircle
Template Library Path: Motion Types/MoveInCircle
Type: MotionType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Motion Types/MoveInCircle:
Moves the x and y components in a circle.

Only the first two components are driven, so it suits position and anything else read as a pair - a third component is held at 0 rather than left alone.

This MotionType defines no controllers of its own - what shapes it are the arguments to addMotion, object.position.addMotion.each([-200,-200,0],[200,200,0],1,nc.motionTypes.MoveInCircle), and motionSpeed is progress per second. The bounds are read as the box the circle is drawn inside - its center is their midpoint and its radii reach out to the upper bounds, so bounds that are not square give an ellipse. It writes the first two components as x and y and sets a third to 0 where there is one. A full turn takes one unit of progress, so motionSpeed reads directly as revolutions per second.

Examples of Motion Types/MoveInCircle:
// Incisor Template Library - MoveInCircle: orbiting one object in a circle and another in an ellipse.
// Requires Template Library items: MoveInCircle

let circling = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Circling");
circling.scale.scaleByFactor(3);

let ellipsing = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Ellipsing");
ellipsing.scale.scaleByFactor(3);

// MoveInCircle writes the first two components as x and y, so it needs the whole vector rather than one axis of it.
// The bounds are read as the box the circle is drawn inside - square bounds give a circle, uneven ones an ellipse.
// A full turn takes two units of progress, so at this motionSpeed both come round once every four seconds.
circling.position.addMotion.each([-200,-200,0],[200,200,0],.5,nc.motionTypes.MoveInCircle);
ellipsing.position.addMotion.each([-500,-100,0],[500,100,0],.5,nc.motionTypes.MoveInCircle);

Content of Motion Types/MoveInCircle, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' MotionType moves the x and y components in a circle.

The bounds are read as the box the circle is drawn inside - its center is their midpoint and its radii reach out to the upper bounds, so bounds that are not square give an ellipse. A full turn takes one unit of progress, so motionSpeed reads directly as revolutions per second.

Only the first two components are driven, so it suits position and anything else read as a pair. A third is held at 0 rather than left alone, which is worth knowing before putting one on a value whose z matters.

A MotionType may define controllers of its own, given to nc.defineMotionType as a list of names and a matching list of defaults and read back as 'motion.controllers.incr_replaceText_NameSubstitution.<name>'. This one defines none, which is what the two undefined arguments below say.

A MotionType is handed to addMotion and is asked for a value on every fixed update, for as long as the Motion lives. It is given the Motion, and is responsible for writing every entry of 'currentValues' from 'lowerBounds', 'upperBounds' and 'progress'. Unlike a TweenType, it has no end to reach - progress climbs without limit at motionSpeed per second, and it is up to the function to decide what that means.
*/


CODE.runBeforeInit___begin;
    /** Define the motion function.
    * @param {Motion} motion
    */
    var incr_replaceText_nameSubstitution_motionTypeFunction = function(motion)
    {
    // The bounds describe a box, so the circle is centered between them and reaches from that center out to
    // the upper bounds. Unequal bounds give unequal radii, which is an ellipse.
        let progress = motion.progress;
        let centerX = (motion.lowerBounds[0]+motion.upperBounds[0])*.5;
        let centerY = (motion.lowerBounds[1]+motion.upperBounds[1])*.5;
        let radiusX = motion.upperBounds[0]-centerX;
        let radiusY = motion.upperBounds[1]-centerY;
    // Cosine and sine of the same angle trace a circle. The angle advances by two pi per unit of progress, so
    // one unit is one whole turn and motionSpeed reads straight off as revolutions per second.
        motion.currentValues[0]=centerX+radiusX*Math.cos(progress*2*Math.PI);
        motion.currentValues[1]=centerY+radiusY*Math.sin(progress*2*Math.PI);
        motion.currentValues[2]=0;
    };

// The name, the function, then the controller names and their defaults - both undefined here, since this MotionType
// takes everything it needs from the bounds. The last argument is the description that reaches the Code API.
    nc.defineMotionType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_motionTypeFunction,
        undefined,
        undefined,
        "This MotionType moves x and y components in a circle."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 45: Motion Types/PingPong
----------------------------------------------------------


Title: PingPong
Template Library Path: Motion Types/PingPong
Type: MotionType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Motion Types/PingPong:
Travels back and forth between the lower and upper bounds at a constant rate.

A linear triangle wave. Use Sway or Pendulum instead where the reversal should feel eased rather than abrupt.

This MotionType defines no controllers of its own - what shapes it are the arguments to addMotion, object.position.addMotion.y(-200,200,1,nc.motionTypes.PingPong), and motionSpeed is progress per second. The value travels from one bound to the other and back over a unit of progress at a constant rate the whole way, so motionSpeed is also round trips per second. The bounds can be given in either order.

Examples of Motion Types/PingPong:
// Incisor Template Library - PingPong: traveling back and forth at one unchanging rate.
// Requires Template Library items: PingPong

// A MotionType is only legible next to something to compare it against, so this drives two objects between the same
// two points at the same speed and changes nothing between them but the MotionType. Pendulum is the built-in one.
let easing = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Easing");
easing.scale.scaleByFactor(3);
easing.position.y = 100;

let pingPonging = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"PingPonging");
pingPonging.scale.scaleByFactor(3);
pingPonging.position.y = -100;

// The top one slows into each end and gathers pace again. The bottom one holds one rate the whole way and reverses on
// the spot - a round trip to a unit of progress, and motionSpeed is progress per second.
easing.position.addMotion.x(-400,400,.5,nc.motionTypes.Pendulum);
pingPonging.position.addMotion.x(-400,400,.5,nc.motionTypes.PingPong);

Content of Motion Types/PingPong, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' MotionType travels back and forth between the lower and upper bounds at a constant rate.

A linear triangle wave - one round trip to a unit of progress, so motionSpeed is also round trips per second. The turn at each end is abrupt by design. Use Sway or the built-in Pendulum where the reversal should read as eased.

A MotionType may define controllers of its own, given to nc.defineMotionType as a list of names and a matching list of defaults and read back as 'motion.controllers.incr_replaceText_NameSubstitution.<name>'. This one defines none, which is what the two undefined arguments below say.

A MotionType is handed to addMotion and is asked for a value on every fixed update, for as long as the Motion lives. It is given the Motion, and is responsible for writing every entry of 'currentValues' from 'lowerBounds', 'upperBounds' and 'progress'. Unlike a TweenType, it has no end to reach - progress climbs without limit at motionSpeed per second, and it is up to the function to decide what that means.
*/


CODE.runBeforeInit___begin;
    /** Define the motion function.
    * @param {Motion} motion
    */
    var incr_replaceText_nameSubstitution_motionTypeFunction = function(motion)
    {
    // The bounds are sorted rather than trusted, so a Motion given them the other way round still runs.
        for (let i = 0; i < motion.numProperties; ++i)
        {
            let upperBound;
            let lowerBound;
            if(motion.upperBounds[i]>motion.lowerBounds[i])
            {
                upperBound = motion.upperBounds[i];
                lowerBound = motion.lowerBounds[i];
            }
            else
            {
                lowerBound = motion.upperBounds[i];
                upperBound = motion.lowerBounds[i];
            }
            let range = upperBound - lowerBound ;
            if(range!==0)
            {
            // wrapping over twice the range and folding the second half back is what makes the triangle -
            // the value climbs to the far bound, then retraces the same path home
                motion.currentValues[i] = lowerBound + Math.abs(((motion.progress * range * 2 + range ) % (range * 2)) - range);
            }
            else
            {
            // no range to travel, so the property is left reading as it did when the Motion was added
                motion.currentValues[i] = motion.baseValues[i];
            }
        }
    };

// The name, the function, then the controller names and their defaults - both undefined here, since this MotionType
// takes everything it needs from the bounds. The last argument is the description that reaches the Code API.
    nc.defineMotionType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_motionTypeFunction,
        undefined,
        undefined,
        "This MotionType bounces between the lower and upper bounds."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 46: Motion Types/Sway
----------------------------------------------------------


Title: Sway
Template Library Path: Motion Types/Sway
Type: MotionType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Motion Types/Sway:
Sways the values with a different randomness applied to each oscillation.

Because every value gets its own random offset, a group of objects driven by one Sway will drift out of phase with each other, which reads as organic. Use SwayUniform where they should stay in step.

This MotionType defines no controllers of its own - what shapes it are the arguments to addMotion, object.position.addMotion.each([-20,-20,0],[20,20,0],1,nc.motionTypes.Sway), and motionSpeed is progress per second. The bounds are the range each value wanders inside, and the randomness that separates them is drawn once, the first time the Motion updates, and kept in motion.workspace - so a Sway holds the same character for its lifetime rather than re-rolling as it runs.

Examples of Motion Types/Sway:
// Incisor Template Library - Sway: drifting a row of objects so they never fall into step.
// Requires Template Library items: Sway

// Every value driven by a Sway draws its own randomness, so three objects given the same bounds and the same speed
// still wander independently of one another - which is the whole reason to reach for it over SwayUniform.
for(let i = 0; i < 3; i++)
{
    let x = -250+(i*250);
    let drifting = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Drifting"+i);
    drifting.scale.scaleByFactor(3);
    drifting.position.x = x;
// The bounds are the range each value wanders inside, so the x pair is centered on where the object was placed.
// x and y draw separately too, which is what makes an object drift around its spot rather than along a line.
    drifting.position.addMotion.each([x-60,-60,0],[x+60,60,0],.4,nc.motionTypes.Sway);
}

Content of Motion Types/Sway, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' MotionType sways the values with a different randomness applied to each one.

The bounds are the range each value wanders inside, and motionSpeed sets the pace. Because every value gets its own speeds and offsets, a group driven by one Sway drifts out of phase, which reads as organic. Use SwayUniform where they should stay in step.

A MotionType may define controllers of its own, given to nc.defineMotionType as a list of names and a matching list of defaults and read back as 'motion.controllers.incr_replaceText_NameSubstitution.<name>'. This one defines none, which is what the two undefined arguments below say.

A MotionType is handed to addMotion and is asked for a value on every fixed update, for as long as the Motion lives. It is given the Motion, and is responsible for writing every entry of 'currentValues' from 'lowerBounds', 'upperBounds' and 'progress'. Unlike a TweenType, it has no end to reach - progress climbs without limit at motionSpeed per second, and it is up to the function to decide what that means.
*/


CODE.runBeforeInit___begin;
    /** Define the motion function.
    * @param {Motion} motion
    */
    var incr_replaceText_nameSubstitution_motionTypeFunction = function(motion)
    {
    // The randomness is drawn once, on the first update, and kept in the Motion's workspace - so a Sway holds
    // the same character for its lifetime rather than re-rolling as it runs.
        if(motion.workspace.speedRandomizer0 === undefined)
        {
            motion.workspace.speedRandomizer0 = [];
            motion.workspace.speedRandomizer1 = [];
            motion.workspace.offsetRandomizer0 = [];
            motion.workspace.offsetRandomizer1 = [];
            for (let i = 0; i < motion.numProperties; ++i)
            {
            // a set per property is what separates this from SwayUniform
                motion.workspace.speedRandomizer0[i] = Math.random() * .7 + .65;
                motion.workspace.speedRandomizer1[i] = Math.random() * .7 + .65;
                motion.workspace.offsetRandomizer0[i] = Math.random() * 100;
                motion.workspace.offsetRandomizer1[i] = Math.random() * 100;
            }
        }
    // Two sines of unrelated speeds multiplied together give a wave that never quite repeats, which is what
    // keeps a sway from reading as a metronome. The result is remapped to sit between the bounds.
        for (let i = 0; i < motion.numProperties; ++i)
        {
            let t = .5+(.5*(Math.sin(Math.PI * motion.progress * motion.workspace.speedRandomizer0[i] + motion.workspace.offsetRandomizer0[i]) * Math.sin(Math.PI * motion.progress * motion.workspace.speedRandomizer1[i] + motion.workspace.offsetRandomizer1[i])));
            motion.currentValues[i] = motion.lowerBounds[i] + (motion.upperBounds[i] - motion.lowerBounds[i]) * t;
        }
    };

// The name, the function, then the controller names and their defaults - both undefined here, since this MotionType
// takes everything it needs from the bounds. The last argument is the description that reaches the Code API.
    nc.defineMotionType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_motionTypeFunction,
        undefined,
        undefined,
        "This MotionType sways a value/all values with different randomness applied to each oscillation."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 47: Motion Types/SwayUniform
----------------------------------------------------------


Title: SwayUniform
Template Library Path: Motion Types/SwayUniform
Type: MotionType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Motion Types/SwayUniform:
Sways the values with a single randomness applied to the whole oscillation.

Every value shares the same oscillation, so multiple components stay in phase. Use Sway where the values should drift independently.

This MotionType defines no controllers of its own - what shapes it are the arguments to addMotion, object.position.addMotion.each([-20,-20,0],[20,20,0],1,nc.motionTypes.SwayUniform), and motionSpeed is progress per second. The bounds are the range the values wander inside, and the one set of randomness they share is drawn once, the first time the Motion updates, and kept in motion.workspace - so a SwayUniform holds the same character for its lifetime rather than re-rolling as it runs.

Examples of Motion Types/SwayUniform:
// Incisor Template Library - SwayUniform: swaying values that stay in step with each other.
// Requires Template Library items: SwayUniform

let sliding = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Sliding");
sliding.scale.scaleByFactor(3);

// One oscillation is shared by every value, so x and y reach their extremes together and the object travels a straight
// diagonal rather than wandering around its spot the way a Sway would.
sliding.position.addMotion.each([-300,150,0],[300,350,0],.4,nc.motionTypes.SwayUniform);

let pulsing = new GraphicObject(nc.graphicAssets.Parrot,nc.mainScene,"Pulsing");
pulsing.position.y = -250;

// That same property is what makes SwayUniform the one to reach for on a color - the components rise and fall
// together, so the picture dims and brightens instead of drifting through hues. Alpha is held still by equal bounds.
pulsing.colorMultiply.addMotion.each([.35,.35,.35,1],[1,1,1,1],.4,nc.motionTypes.SwayUniform);

Content of Motion Types/SwayUniform, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' MotionType sways the values with a single randomness applied to the whole oscillation.

The bounds are the range the values wander inside, and motionSpeed sets the pace. Every value shares one oscillation, so the components stay in phase with each other. Use Sway where they should drift independently.

A MotionType may define controllers of its own, given to nc.defineMotionType as a list of names and a matching list of defaults and read back as 'motion.controllers.incr_replaceText_NameSubstitution.<name>'. This one defines none, which is what the two undefined arguments below say.

A MotionType is handed to addMotion and is asked for a value on every fixed update, for as long as the Motion lives. It is given the Motion, and is responsible for writing every entry of 'currentValues' from 'lowerBounds', 'upperBounds' and 'progress'. Unlike a TweenType, it has no end to reach - progress climbs without limit at motionSpeed per second, and it is up to the function to decide what that means.
*/


CODE.runBeforeInit___begin;
    /** Define the motion function.
    * @param {Motion} motion
    */
    var incr_replaceText_nameSubstitution_motionTypeFunction = function(motion)
    {
    // The randomness is drawn once, on the first update, and kept in the Motion's workspace - one set rather
    // than one per property, which is the whole difference between this and Sway.
        if(motion.workspace.speedRandomizer0 === undefined)
        {
            motion.workspace.speedRandomizer0 = Math.random()*.7+.65;
            motion.workspace.speedRandomizer1 = Math.random()*.7+.65;
            motion.workspace.offsetRandomizer0 = Math.random()*100;
            motion.workspace.offsetRandomizer1 = Math.random()*100;
        }
    // Two sines of unrelated speeds multiplied together give a wave that never quite repeats. It is worked
    // out once and then remapped into each property's own bounds, so the components move together.
        let t = .5+(.5*(Math.sin(Math.PI * motion.progress * motion.workspace.speedRandomizer0 + motion.workspace.offsetRandomizer0) * Math.sin(Math.PI * motion.progress * motion.workspace.speedRandomizer1 + motion.workspace.offsetRandomizer1)));
        for (let i = 0; i < motion.numProperties; ++i)
        {
            motion.currentValues[i] = motion.lowerBounds[i] + (motion.upperBounds[i] - motion.lowerBounds[i]) * t;
        }
    };

// The name, the function, then the controller names and their defaults - both undefined here, since this MotionType
// takes everything it needs from the bounds. The last argument is the description that reaches the Code API.
    nc.defineMotionType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_motionTypeFunction,
        undefined,
        undefined,
        "This MotionType sways a value/all values with a randomness applied to the oscillation. Each value will use the same oscillation."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 48: Motion Types/blank template
----------------------------------------------------------


Title: blank template
Template Library Path: Motion Types/blank template
Type: MotionType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Motion Types/blank template:
An empty MotionType definition, ready to be filled in.

The motion function receives a Motion and is responsible for writing every entry of 'currentValues' from 'lowerBounds', 'upperBounds', and 'progress'. Unlike a TweenType, a MotionType runs continuously rather than from a start value to an end value.

A MotionType may define controllers of its own, given to nc.defineMotionType as a list of names and a matching list of defaults and read back inside the motion function as motion.controllers.<name>. Everything else it works from arrives with the addMotion call - object.position.addMotion.y(-200,200,1,nc.motionTypes.MyMotion) - where the bounds become 'lowerBounds' and 'upperBounds' and motionSpeed sets how fast 'progress' climbs, at one unit a second when it is 1.

Content of Motion Types/blank template, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' MotionType is an empty definition, ready to be filled in. As it stands it swings between the bounds like a pendulum.

A MotionType may define controllers of its own, given to nc.defineMotionType as a list of names and a matching list of defaults and read back as 'motion.controllers.incr_replaceText_NameSubstitution.<name>'. This one defines none, which is what the two undefined arguments below say.

A MotionType is handed to addMotion and is asked for a value on every fixed update, for as long as the Motion lives. It is given the Motion, and is responsible for writing every entry of 'currentValues' from 'lowerBounds', 'upperBounds' and 'progress'. Unlike a TweenType, it has no end to reach - progress climbs without limit at motionSpeed per second, and it is up to the function to decide what that means.
*/


CODE.runBeforeInit___begin;
    /** Define the motion function.
    * @param {Motion} motion
    */
    var incr_replaceText_nameSubstitution_motionTypeFunction = function(motion)
    {
    // Progress climbs forever, so a MotionType that should repeat has to fold it back itself - a sine does
    // that here, and remapping it from its own -1 to 1 into 0 to 1 is what keeps the swing inside the bounds.
        for(let i=0; i<motion.numProperties; i++)
        {
            motion.currentValues[i] = motion.lowerBounds[i]+(motion.upperBounds[i]-motion.lowerBounds[i])*(.5+.5*Math.sin(motion.progress*Math.PI*2));
        }
    };

// The name, the function, then the controller names and their defaults - both undefined here, since this MotionType
// takes everything it needs from the bounds. The last argument is the description that reaches the Code API.
    nc.defineMotionType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_motionTypeFunction,
        undefined,
        undefined,
        "This is a custom MotionType."
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 49: Project Extensions/CustomMenu
----------------------------------------------------------


Title: CustomMenu
Template Library Path: Project Extensions/CustomMenu
Type: ProjectExtension
Placement: Utilities/ProjectExtensions

Description of Project Extensions/CustomMenu:
Adds a custom menu to the Incisor top bar, with items that run your own code.

The starting point for team tooling: batch operations, project-specific checks, shortcuts to routines people run by hand today.

An item is a path and a callback - nce.addInspectorMenuItem(["Reports","Weekly","Export CSV"], owner, "exportCsv") nests one three levels deep, and Incisor creates any menu on that path that does not exist yet. Depth is unlimited, and a fourth argument passes callback arguments, so one method can serve a whole menu.

The callback itself is unrestricted: anything extension code can reach, including the running project through 'nce.projectPR'.

A ProjectExtension is code that runs in the Incisor inspector rather than inside your project - it lives in 'Utilities/ProjectExtensions', stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Project Extensions/CustomMenu, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Project Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to your project.
Keep in mind that code placed in this 'ProjectExtensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the method that will be invoked by the custom menu...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}


    performMenuCallback()
    {
        nce.alert("Custom Menu Functionality","The 'incr_replaceText_NameSubstitution' functionality is happening!");
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Project Extensions Scope - This code executes when the Inspector first opens, after any global extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var incr_replaceText_nameSubstitution_functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a new custom menu item that calls 'incr_replaceText_nameSubstitution_functionalityClassInstance.performMenuCallback'...
    nce.addInspectorMenuItem(["Example Menu", "incr_replaceText_NameSubstitution"],incr_replaceText_nameSubstitution_functionalityClassInstance,"performMenuCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 50: Project Extensions/CustomPanel
----------------------------------------------------------


Title: CustomPanel
Template Library Path: Project Extensions/CustomPanel
Type: ProjectExtension
Placement: Utilities/ProjectExtensions

Description of Project Extensions/CustomPanel:
Defines a custom inspector panel, dockable alongside the built-in panels.

Use when a workflow needs its own persistent surface rather than a menu item. Panels are built from the same Ui and Ux components the inspector itself uses.

A ProjectExtension is code that runs in the Incisor inspector rather than inside your project - it lives in 'Utilities/ProjectExtensions', stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Project Extensions/CustomPanel, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Project Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to your project.
Keep in mind that code placed in this 'ProjectExtensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// Custom InspectorPanels can be defined for use within the Incisor GUI. Just define a class that extends InspectorPanel, then call 'nce.registerInspectorPanelDefinition'.
class incr_replaceText_nameSubstitution_panelClass extends InspectorPanel
{
    constructor()
    {
        // Call the super constructor
        super("incr_replaceText_NameSubstitution");

        // Add a sample title to the header ScrollingPanel
        let titleText = new UiText(this,"TitleText");
        titleText.string = "incr_replaceText_NameSubstitution:";
        titleText.textFormat = nce.uiStyle.textFormat_subHeading.clone();
        titleText.layoutObject.topBuffer = nce.uiStyle.spacer_small;
        titleText.layoutObject.leftBuffer = nce.uiStyle.spacer_small*2;
        this.headerScrollingPanel.bodyStack.addElements(titleText);

        // Add text to the panel body
        let bodyText = new UiText(this,"BodyText");
        bodyText.string = "...panel content";
        bodyText.layoutObject.topBuffer = nce.uiStyle.spacer_small;
        bodyText.layoutObject.leftBuffer = nce.uiStyle.spacer_small*2;
        this.bodyScrollingPanel.bodyStack.addElements(bodyText);
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Project Extensions Scope - This code executes when the Inspector first opens, after any global extensions code

    // Register a the custom InspectorPanel 'incr_replaceText_NameSubstitution' with Incisor.
    nce.registerInspectorPanelDefinition("incr_replaceText_NameSubstitution",incr_replaceText_nameSubstitution_panelClass);   
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 51: Project Extensions/FileIoExample
----------------------------------------------------------


Title: FileIoExample
Template Library Path: Project Extensions/FileIoExample
Type: ProjectExtension
Placement: Utilities/ProjectExtensions

Description of Project Extensions/FileIoExample:
Demonstrates reading and writing files from extension code through nce.

Covers the file IO calls and the sandbox rules that govern them. A useful reference before writing any extension that touches disk.

A ProjectExtension is code that runs in the Incisor inspector rather than inside your project - it lives in 'Utilities/ProjectExtensions', stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Project Extensions/FileIoExample, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Project Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to your project.
Keep in mind that code placed in this 'ProjectExtensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the extensions functionality...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}

    performCallback()
    {
        // Write a text file to the project directory.
        let fileName = "TextFileFromExtensions-"+nce.timeStamp.getTimeStamp()+".txt";
        // Using 'nce.fileIO' to write a text file. Check out the documentation for 'nce.fileIO', which has a bunch of helpful functionality.
        nce.fileIO.writeTextFile(fileName,"This file was brought to you by Incisor extensions!");
        nce.alert("FileIO","A text file named '" + fileName + "' has been written to the project directory.");
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Project Extensions Scope - This code executes when the Inspector first opens, after any global extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var incr_replaceText_nameSubstitution_functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a new custom menu item that calls 'incr_replaceText_nameSubstitution_functionalityClassInstance.performCallback'...
    nce.addInspectorMenuItem(["Example Menu", "incr_replaceText_NameSubstitution"],incr_replaceText_nameSubstitution_functionalityClassInstance,"performCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 52: Project Extensions/PopupExample
----------------------------------------------------------


Title: PopupExample
Template Library Path: Project Extensions/PopupExample
Type: ProjectExtension
Placement: Utilities/ProjectExtensions

Description of Project Extensions/PopupExample:
Demonstrates the standard popup windows available to extension code, including the text query popup and alerts.

The quickest way to give an extension a usable interface without building a panel.

A ProjectExtension is code that runs in the Incisor inspector rather than inside your project - it lives in 'Utilities/ProjectExtensions', stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Project Extensions/PopupExample, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Project Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to your project.
Keep in mind that code placed in this 'ProjectExtensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the extensions functionality...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}

    async performCallback()
    {
        // show the text query popup and asynchronously await feedback
        let userText = await nce.showTextQueryPopup("Standard Text Query Popup","The user can provide text feedback here.","text:","your feedback here...");
        // display the text result - await feedback
        await nce.alert("User Text","The user text provided was '" + userText + "'.");
        // show the text query popup and asynchronously await feedback
        let userYesNo = await nce.showYesNoQueryPopup("Standard Yes/No Query Popup","The user can provide yes/no feedback here.");
        // display the yes/no result - await feedback
        await nce.alert("User Text","The user text provided was '" + userYesNo +"'.");
        // Create an instance of the custom popup if it hasn't been made yet
        if(this.incr_replaceText_nameSubstitution_customPopup===undefined)
        {
            this.incr_replaceText_nameSubstitution_customPopup = new incr_replaceText_nameSubstitution_customPopupClass(nce.mainScene,"incr_replaceText_nameSubstitution_customPopup");
        }
        // Open the custom popup
        this.incr_replaceText_nameSubstitution_customPopup.isOpen = true;
    }
}

// The class defining a custom popup
class incr_replaceText_nameSubstitution_customPopupClass extends UiPopupWindow
{
    constructor(parent,name)
    {
        // Call the super constructor
        super(parent,name);

        // Change the title 
        this.titleText.string = "incr_replaceText_NameSubstitution";
        this.titleText.colorMultiply.addMotion.red(0,1);

        // Add body text
        this.bodyText = new UiText(this.bodyStack,"bodyText");
        this.bodyText.string = "...custom popup content";
        this.bodyStack.addElements(this.bodyText);

        // Set the 'Decision Buttons'
        this.setDecisionButtons(["Custom","Decision","Buttons"]);

        // Add DecisionButton callback
        this.addDecisionButtonTriggerCallback(this,"decisionButtonTriggerCallback");
    }

    async decisionButtonTriggerCallback(decisionString,decisionButton)
    {
        await nce.alert("Popup Decision Button Pressed","The '" + decisionString + "' Button was pressed.");
        this.isOpen = false;
    }
}

// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Project Extensions Scope - This code executes when the Inspector first opens, after any global extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var incr_replaceText_nameSubstitution_functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a new custom menu item that calls 'incr_replaceText_nameSubstitution_functionalityClassInstance.performCallback'...
    nce.addInspectorMenuItem(["Example Menu", "incr_replaceText_NameSubstitution"],incr_replaceText_nameSubstitution_functionalityClassInstance,"performCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 53: Project Extensions/ProjectConnectionActions
----------------------------------------------------------


Title: ProjectConnectionActions
Template Library Path: Project Extensions/ProjectConnectionActions
Type: ProjectExtension
Placement: Utilities/ProjectExtensions

Description of Project Extensions/ProjectConnectionActions:
Hooks code to project connection events, so extensions can run when a project connects or disconnects.

Use for setup and teardown that should happen per session rather than per launch.

A ProjectExtension is code that runs in the Incisor inspector rather than inside your project - it lives in 'Utilities/ProjectExtensions', stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Project Extensions/ProjectConnectionActions, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Project Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to your project.
Keep in mind that code placed in this 'ProjectExtensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the method that will be invoked every time the project connects to the inspector...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}


    async performConnectionCallback()
    {
        await nce.alert("Project Connecting","Performing the 'incr_replaceText_NameSubstitution' project connection action.");
    }


    async performDisconnectionCallback()
    {
        await nce.alert("Project Disconnecting","Performing the 'incr_replaceText_NameSubstitution' project disconnection action.");
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Project Extensions Scope - This code executes when the Inspector first opens, after any global extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var incr_replaceText_nameSubstitution_functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a callback that happens whenever the project connects to the inspector
    nce.addProjectConnectionCallback(incr_replaceText_nameSubstitution_functionalityClassInstance,"performConnectionCallback");

    // Add a callback that happens whenever the project connects to the inspector
    nce.addProjectDisconnectionCallback(incr_replaceText_nameSubstitution_functionalityClassInstance,"performDisconnectionCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 54: Project Extensions/PublishActions
----------------------------------------------------------


Title: PublishActions
Template Library Path: Project Extensions/PublishActions
Type: ProjectExtension
Placement: Utilities/ProjectExtensions

Description of Project Extensions/PublishActions:
Hooks code to run before and after publishing, with access to the configuration being published.

The standard place for build-time steps: asset validation, copying artifacts, notifying a deploy pipeline, stamping version information.

A ProjectExtension is code that runs in the Incisor inspector rather than inside your project - it lives in 'Utilities/ProjectExtensions', stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Project Extensions/PublishActions, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Project Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to your project.
Keep in mind that code placed in this 'ProjectExtensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the method that will be invoked right before the project is published...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}

    /** Function called prior to publishing.
     * @param {PrePublishInfoObject} prePublishInfoObject 
     */
    async performPrePublishCallback(prePublishInfoObject)
    {
        await nce.alert("Pre-Publish Action","Performing the 'PublishActions' action before publishing with the '" + prePublishInfoObject.configurationName + "' configuration.");
    }

    /** Function called after publishing.
     * @param {PostPublishInfoObject} postPublishInfoObject 
     */
    async performPostPublishCallback(postPublishInfoObject)
    {
        await nce.alert("Post-Publish Action","Performing the 'PublishActions' action after publishing with the '" + postPublishInfoObject.configurationName + "' configuration.");
    }
}


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Project Extensions Scope - This code executes when the Inspector first opens, after any global extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var incr_replaceText_nameSubstitution_functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a callback that happens right before the project is published
    nce.addPrePublishCallback(incr_replaceText_nameSubstitution_functionalityClassInstance,"performPrePublishCallback");
    // Add a callback that happens right after the project is published
    nce.addPostPublishCallback(incr_replaceText_nameSubstitution_functionalityClassInstance,"performPostPublishCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 55: Project Extensions/Specialized Tools/ExtensionsBundleManager
----------------------------------------------------------


Title: ExtensionsBundleManager
Template Library Path: Project Extensions/Specialized Tools/ExtensionsBundleManager
Type: ProjectExtension
Placement: Utilities/ProjectExtensions

Description of Project Extensions/Specialized Tools/ExtensionsBundleManager:
A tool for compiling a set of extensions into a single bundle and publishing it to a central location, so a team can stay in sync.

Published bundles check for newer versions and update themselves, so teammates only install by hand once. Requires a dedicated project to hold the extension sources, and 'allowUniversalFileIO' enabled in Application Settings for everyone involved. Read the header comment before using it, as it needs configuring in several places.

A ProjectExtension is code that runs in the Incisor inspector rather than inside your project - it lives in 'Utilities/ProjectExtensions', stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Project Extensions/Specialized Tools/ExtensionsBundleManager, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/* This is a tool that compiles a set of extensions into a single file and publishes them to a central location.
* Published extensions include functionality to automatically check for newer bundles and enable users to update them easily.
* The ExtensionsBundleManager is meant to help teams keep shared extensions synced from a central source.
* To use the ExtensionsBundleManager:
* - Make a new project dedicated to managing a group of extensions.
* - Put this file into the 'Utilities/ProjectExtensions' directory of a project.
* - Create a directory in the project root where all of the source extensions will live (not in the ProjectExtensions).
* - Determine a central location (that everyone on the team can see) to publish the bundle to.
* - Modify the 'runBeforeInit' section of this file (below at the bottom) with the name of the bundle, 
*   the path to the extensions source directory, and the path to the central publish destination.
* - Options to test the bundle locally, and to publish centrally will appear in the menu.
* - Once published, other team members will need to download the bundled extensions file and place in their Global Extensions 
*   directory the first time, after that the auto-update will handle all of the subsequent file manipulation.
* - Everyone involved will need 'allowUniversalFileIO' in ApplicationSettings set to true for this functionality to work.
*/
class ExtensionsBundleManager
{
    constructor(bundleName,sourcePath,destinationPath,includeAutoUpdateFunctionality,bundledFileOrder)
    {
        this.bundleName = bundleName;
        this.sourcePath = sourcePath;
        this.destinationPath = destinationPath;
        
        // include an array with file names (including the extension), and the listed files will be included in the bundle in the specified order before unlisted files.
        this.bundledFileOrder = bundledFileOrder;
        if(includeAutoUpdateFunctionality===undefined){includeAutoUpdateFunctionality = true;}
        this.includeAutoUpdateFunctionality = includeAutoUpdateFunctionality;
    }


    async publishExtensionsBundle(isTestMode)
    {
        // create source location if needed
        if((await nce.fileIO.directoryExists(this.sourcePath,false)).payload === false)
        {
            console.log("Creating source directory for '" + this.bundleName + "' Extensions Bundle:\n" + this.sourcePath);
            await nce.fileIO.createDirectory(this.sourcePath,false);
        }

        // create destination location if needed
        if((await nce.fileIO.directoryExists(this.destinationPath,false)).payload === false)
        {
            console.log("Creating destination directory for '" + this.bundleName + "' Extensions Bundle:\n" + this.destinationPath);
            await nce.fileIO.createDirectory(this.destinationPath,false);
        }

        // get source contents
        let sourceContents = (await nce.fileIO.getDirectoryContents(this.sourcePath,false,true)).payload;

        // warn if no source contents
        if(sourceContents.length===0)
        {
            await nce.alert("Missing Source","There appears to be no extension files in the given source location:\n"+this.sourcePath);
            return;
        }

        // sort source contents if applicable
        if(this.bundledFileOrder!==undefined)
        {
            for(let i=0; i<sourceContents.length; i++)
            {
                let fileName = nce.paths.getFileName(sourceContents[i].path);
                if(this.bundledFileOrder.indexOf(fileName)===-1)
                {
                    sourceContents[i].order = Number.MAX_VALUE;
                }
                else
                {
                    sourceContents[i].order = this.bundledFileOrder.indexOf(fileName);
                }
            }
            sourceContents.sort(function(a,b){return(a.order-b.order);});
        }

        // bundle the extensions found in the source directory
        let bundledExtensions = [];
        let bundleTimestamp = nce.timeStamp.getTimeStamp();
        bundledExtensions.push("this.bundleTimeStamp_" + this.bundleName + " = '" + bundleTimestamp + "';");
        for(let i=0; i<sourceContents.length; i++)
        {
            let item = sourceContents[i];
            let path = item.path;
            item.fileName = nce.paths.getFileName(path);

            // require '.js' files...
            if(path.endsWith(".js"))
            {
                bundledExtensions.push( (await nce.fileIO.readTextFile(path,false)).payload );
            }
        }

        // include auto-update functionality
        if(this.includeAutoUpdateFunctionality===true)
        {
            let autoUpdateFunctionalityStringBuilder = [];
            let sb = autoUpdateFunctionalityStringBuilder;
            sb.push("// auto-update functionality");
            sb.push("CODE."+"runBeforeInit___begin;");
            sb.push("// function to acquire the path to the published '" + this.bundleName + " ' extensions directory.");
            sb.push("this.checkForExtensionsBundleUpdate_" + this.bundleName + " = async function()");
            sb.push("{");
            sb.push("   if(this.publishedExtensionsBundlePath_" + this.bundleName + " === undefined)");
            sb.push("   {");
            sb.push("       let pathPopupResult = await nce.showPathQueryPopup('Provide Extensions Bundle Path',\"The '"+this.bundleName+"' extensions bundle is attempting to perform an auto-update check but the path to the directory where that bundle is published is currently unknown. Provide the path to the directory where the '"+this.bundleName+"' extensions bundle is published.\",undefined,false,false,false,true);");
            sb.push("       let path;");  
            sb.push("       if(Array.isArray(pathPopupResult) && pathPopupResult.length>0){path = pathPopupResult[0].path;}");
            sb.push("       if(path!==undefined && path!=='')");
            sb.push("       {");
            sb.push("           let storedPathFileContents = 'CODE.'+'runBeforeInit___begin; this.publishedExtensionsBundlePath_" + this.bundleName + " = \"'+path+'\"; CODE.'+'runBeforeInit___end;';");
            sb.push("           let storedPathFilePath = await nce.paths.applicationSupportPath + '/Global Extensions/BundlePath_" + this.bundleName + ".js';" );
            sb.push("           await nce.fileIO.writeTextFile(storedPathFilePath,storedPathFileContents,false);" );
            sb.push("           this.publishedExtensionsBundlePath_" + this.bundleName + " = path;");
            sb.push("       }");
            sb.push("   }");
            sb.push("   let bundleDirectoryPath = this.publishedExtensionsBundlePath_" + this.bundleName + ";");
            sb.push("   if(bundleDirectoryPath !== undefined)");
            sb.push("   {");
            sb.push("       let directoryContents = (await nce.fileIO.getDirectoryContents(bundleDirectoryPath,false)).payload;");
            sb.push("       if(directoryContents===undefined || directoryContents.length===0)");
            sb.push("       {");
            sb.push("           await nce.alert('Bundle Auto-Update Problem',\"There is an issue with the auto-update for the '" + this.bundleName + "' extensions bundle. The path provided for the directory containing the published bundle either doesn't exist, or contains nothing:\\n\"+bundleDirectoryPath);");
            sb.push("           return;");
            sb.push("       }");
            sb.push("       else");
            sb.push("       {");
            sb.push("           let applicableItems = [];");
            sb.push("           for(let i=0; i<directoryContents.length; i++)");
            sb.push("           {");
            sb.push("               let path = nce.paths.getFileName(directoryContents[i].path);");
            sb.push("               if(directoryContents[i].type==='file' && path.startsWith('"+this.bundleName+"_')===true)");
            sb.push("               {");
            sb.push("                   directoryContents[i].date = path.split('_')[1];");
            sb.push("                   if(directoryContents[i].date !== undefined)");
            sb.push("                   {");
            sb.push("                       applicableItems.push(directoryContents[i]);");
            sb.push("                   }");
            sb.push("               }");
            sb.push("           }");
            sb.push("           if(applicableItems.length===0)");
            sb.push("           {");
            sb.push("               await nce.alert('Bundle Auto-Update Problem',\"There is an issue with the auto-update for the '" + this.bundleName + "' extensions bundle. The path provided for the directory containing the published bundle either doesn't exist, or contains nothing:\\n\"+bundleDirectoryPath);");
            sb.push("               return;");
            sb.push("           }");
            sb.push("           applicableItems.sort(function(a,b){if(a.date>b.date){return(-1);} return 1;});");
            sb.push("           let newestDate = applicableItems[0].date;");
            sb.push("           let currentDate = this.bundleTimeStamp_" + this.bundleName + " +  '.js';");
            sb.push("           if(currentDate<newestDate)");
            sb.push("           {");
            sb.push("               let updatedFileName = nce.paths.getFileName(applicableItems[0].path);");
            sb.push("               let currentFileDirectory = nce.paths.applicationSupportPath+'/Global Extensions/';");
            sb.push("               let currentBundleFilePath = currentFileDirectory + '"+this.bundleName+"_' + currentDate;");
            sb.push("               if((await nce.fileIO.fileExists(currentBundleFilePath,false)).payload)");
            sb.push("               {");
            sb.push("                   let yesOrNoResult = await nce.showYesNoQueryPopup('Extensions Bundle Update Found', 'An update to the \""+this.bundleName+"\" extensions bundle has been found:\\n'+updatedFileName+'\\n\\nWould you like to update now?')");
            sb.push("                   if(yesOrNoResult==='Yes')");
            sb.push("                   {");
            sb.push("                       await nce.fileIO.delete(currentBundleFilePath,false)");
            sb.push("                       await nce.fileIO.copyTo(applicableItems[0].path,currentFileDirectory,false)");
            sb.push("                       await nce.alert('Extensions Bundle Updated','The \""+this.bundleName+"\" extensions bundle has been updated:\\n'+currentFileDirectory+ updatedFileName +'\\n\\nThe Incisor client will now refresh.');");
            sb.push("                       location.reload();");
            sb.push("                   }");
            sb.push("               }");
            sb.push("               else");
            sb.push("               {");
            sb.push("                   await nce.alert('Auto-Update Issue',\"There was an issue updating the '" + this.bundleName + "' extensions bundle. The current extensions are not at the expected path:\\n\"+currentBundleFilePath);");
            sb.push("                   return;");
            sb.push("               }");
            sb.push("           }");
            sb.push("       }");
            sb.push("   }");
            sb.push("};");
            sb.push("// waiting to fetch the path to the published extensions so that it would be sure to load regardless of what order the extensions load in.");
            sb.push("nce.waitThen(2,this,'checkForExtensionsBundleUpdate_" + this.bundleName + "');");
            sb.push("CODE."+"runBeforeInit___end;");
            bundledExtensions.push(sb.join('\n'));
        }

        // if publish is 'public'
        if(isTestMode===false)
        {
            // write the bundled file to the destination folder
            let fileName = this.bundleName + "_" + bundleTimestamp + ".js";
            let filePath = this.destinationPath + "/" + fileName;
            await nce.fileIO.writeTextFile(filePath, bundledExtensions.join("\n"), false);

            // provide feedback for published extensions bundle
            await nce.alert("Extensions Bundle Published","The '" + this.bundleName + "' extensions bundle has been published:\n" + filePath + "\n\nThe Incisor client will now refresh.");
        }

        // if the publish is in 'testMode' 
        if(isTestMode===true)
        {
            // remove existing bundle file (if applicable)
            let directoryContents = (await nce.fileIO.getDirectoryContents(nce.paths.applicationSupportPath+"/Global Extensions",false,true,false)).payload;
            let currentBundlePath = "";
            for(let i=0; i<directoryContents.length; i++)
            {
                let fileName = nce.paths.getFileName(directoryContents[i].path);
                if(fileName.startsWith(this.bundleName+"_"))
                {
                    currentBundlePath = directoryContents[i].path;
                    break;
                }
            }
            if(currentBundlePath!=="")
            {
                nce.fileIO.delete(currentBundlePath,false);
            }

            // write the bundled file directly to the Global Extensions directory (since we're in test mode)
            let fileName = this.bundleName + "_" + bundleTimestamp + ".js";
            let filePath = nce.paths.applicationSupportPath + "/Global Extensions/" + fileName;
            await nce.fileIO.writeTextFile(filePath, bundledExtensions.join("\n"), false);

            // provide feedback for published extensions bundle
            await nce.alert("Bundle Updated Locally","The '" + this.bundleName + "' extensions bundle has been updated locally for testing:\n" + filePath + "\n\nThe Incisor client will now refresh.");
        }

        // refresh browser
        location.reload();
    }
}


CODE.runBeforeInit___begin;
    var extensionsBundleName = "SomeStudioExtensions";
    var extensionsBundleSourcePath = nce.paths.projectPath+"/ExtensionsSource";
    var extensionsBundlePublishDestinationPath = nce.paths.projectPath+"/PublishedExtensions";
    var bundledFileOrder = [];
    var extensionsBundleManager = new ExtensionsBundleManager(extensionsBundleName,extensionsBundleSourcePath,extensionsBundlePublishDestinationPath,true,bundledFileOrder);
    nce.addInspectorMenuItem(["Extensions Bundles", "Test "+extensionsBundleName],extensionsBundleManager,"publishExtensionsBundle",true);
    nce.addInspectorMenuItem(["Extensions Bundles", "Publish "+extensionsBundleName],extensionsBundleManager,"publishExtensionsBundle",false);
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 56: Project Extensions/UiComponentsExample
----------------------------------------------------------


Title: UiComponentsExample
Template Library Path: Project Extensions/UiComponentsExample
Type: ProjectExtension
Placement: Utilities/ProjectExtensions

Description of Project Extensions/UiComponentsExample:
A gallery of the Incisor UI components available to extension code, with each one wired to a working callback.

The fastest way to see what is available before building a custom panel.

A ProjectExtension is code that runs in the Incisor inspector rather than inside your project - it lives in 'Utilities/ProjectExtensions', stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Project Extensions/UiComponentsExample, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Project Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to your project.
Keep in mind that code placed in this 'ProjectExtensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// The class holding the extensions functionality...
class incr_replaceText_nameSubstitution_functionalityClass
{
    constructor(){}

    async performCallback()
    {
        // Create an instance of the custom popup if it hasn't been made yet
        if(this.incr_replaceText_nameSubstitution_customPopup===undefined)
        {
            this.incr_replaceText_nameSubstitution_customPopup = new incr_replaceText_nameSubstitution_customPopupClass(nce.mainScene,"incr_replaceText_nameSubstitution_customPopup");
        }
        // Open the custom popup
        this.incr_replaceText_nameSubstitution_customPopup.isOpen = true;
    }
}

// The class defining a custom popup
class incr_replaceText_nameSubstitution_customPopupClass extends UiPopupWindow
{
    constructor(parent,name)
    {
        // Call the super constructor
        super(parent,name);

        // Stash the 'DefaultFocusFallback' and set to this popup - management of the flow of the keyboard focus
        let previousDefaultFocusFallback = nce.defaultFocusFallback;
        nce.defaultFocusFallback = this;

        // Set the PopupWindow's Title
        this.titleText.string = "Incisor UI Components Example";

        // Add standard UiText examples 
        let standardUiText = new UiText(this.bodyStack,"standardUiText");
        standardUiText.textFormat = nce.uiStyle.textFormat_heading;
        standardUiText.string = "Heading text";
        this.bodyStack.addElements(standardUiText);
        standardUiText = new UiText(this.bodyStack,"standardUiText");
        standardUiText.textFormat = nce.uiStyle.textFormat_subHeading;
        standardUiText.string = "SubHeading text";
        this.bodyStack.addElements(standardUiText);
        standardUiText = new UiText(this.bodyStack,"standardUiText");
        standardUiText.textFormat = nce.uiStyle.textFormat_body;
        standardUiText.string = "Body text";
        this.bodyStack.addElements(standardUiText);
        standardUiText = new UiText(this.bodyStack,"standardUiText");
        standardUiText.textFormat = nce.uiStyle.textFormat_technical;
        standardUiText.string = "Technical text";
        this.bodyStack.addElements(standardUiText);
        standardUiText = new UiText(this.bodyStack,"standardUiText");
        standardUiText.textFormat = nce.uiStyle.textFormat_tiny;
        standardUiText.string = "Tiny text";
        this.bodyStack.addElements(standardUiText);

        // Add UiButton
        let standardUiButton = new UiButton(this.bodyStack,"standardUiButton");
        standardUiButton.displayLabel = true;
        standardUiButton.addTriggerCallback(this,"uiButtonPressedCallback");
        standardUiButton.layoutObject.topBuffer = nce.uiStyle.spacer_medium;
        this.bodyStack.addElements(standardUiButton);

        // Add UiLinkButton
        let standardUiLinkButton = new UiLinkButton(this.bodyStack,"standardUiLinkButton");
        standardUiLinkButton.displayLabel = true;
        standardUiLinkButton.addTriggerCallback(this,"uiLinkButtonPressedCallback");
        standardUiLinkButton.layoutObject.topBuffer = nce.uiStyle.spacer_medium;
        this.bodyStack.addElements(standardUiLinkButton);
    
        // Add UiTextField
        let standardUiTextField = new UiTextField(this.bodyStack,"standardUiTextField");
        standardUiTextField.displayLabel = true;
        standardUiTextField.layoutObject.topBuffer = nce.uiStyle.spacer_medium;
        this.bodyStack.addElements(standardUiTextField);

        // Add UiCollapsibleStack
        let standardUiCollapsibleStack = new UiCollapsibleStack(this.bodyStack,"standardUiCollapsibleStack");
        standardUiCollapsibleStack.layoutObject.topBuffer = nce.uiStyle.spacer_medium;
        for(let i=0; i<5; i++)
        {
            standardUiText = new UiText(standardUiCollapsibleStack.bodyStack,"standardUiText");
            standardUiText.string = "Item " + i + "...";
            standardUiCollapsibleStack.bodyStack.addElements(standardUiText);
        }
        this.bodyStack.addElements(standardUiCollapsibleStack);

        // Add ScrollingPanel
        let scrollingPanel  = new ScrollingPanel(this.bodyStack,"scrollingPanel");
        scrollingPanel.layoutObject.topBuffer = nce.uiStyle.spacer_medium;
        scrollingPanel.width = 500;
        scrollingPanel.height = 200;
        scrollingPanel.useNearestPixelRendering = true;
        this.bodyStack.addElements(scrollingPanel);

        // Add FileBrowser
        let fileBrowser = nce.addFileBrowser(scrollingPanel.bodyStack,"fileBrowser");
        fileBrowser.layoutObject.leftBuffer = nce.uiStyle.spacer_small;
        fileBrowser.allowRearrange = false;
        scrollingPanel.bodyStack.addElements(fileBrowser);

        // Add decision button callback
        this.addDecisionButtonTriggerCallback(this,"decisionButtonTriggerCallback");

        // Restore default focus fallback
        nce.defaultFocusFallback = previousDefaultFocusFallback;
    }

    uiButtonPressedCallback()
    {
        nce.alert("UiButton Pressed","The UiButton was pressed.");
    }

    uiLinkButtonPressedCallback()
    {
        nce.alert("UiLinkButton Pressed","The UiLinkButton was pressed.");
    }

    decisionButtonTriggerCallback()
    {
        this.isOpen = false;;
    }
}

// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Project Extensions Scope - This code executes when the Inspector first opens, after any global extensions code

    // Instantiate incr_replaceText_nameSubstitution_functionalityClass
    var incr_replaceText_nameSubstitution_functionalityClassInstance = new incr_replaceText_nameSubstitution_functionalityClass();

    // Add a new custom menu item that calls 'incr_replaceText_nameSubstitution_functionalityClassInstance.performCallback'...
    nce.addInspectorMenuItem(["Example Menu", "incr_replaceText_NameSubstitution"], incr_replaceText_nameSubstitution_functionalityClassInstance,"performCallback");
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 57: Project Extensions/blank template
----------------------------------------------------------


Title: blank template
Template Library Path: Project Extensions/blank template
Type: ProjectExtension
Placement: Utilities/ProjectExtensions

Description of Project Extensions/blank template:
An empty project extension file with the class scope and the runBeforeInit block laid out, plus a header explaining how extensions work.

A ProjectExtension is code that runs in the Incisor inspector rather than inside your project - it lives in 'Utilities/ProjectExtensions', stays out of published builds, and works through 'nce', the inspector's mirror of 'nc'. Extensions are a team's own tooling: workflow helpers, development scripting, testing harnesses, publishing customization, automation for any part of the process. Each is a starting point - drop it in, name it, rewrite the example into what you need.

Content of Project Extensions/blank template, file 'incr_replaceText_NameSubstitution.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
Welcome to Project Extensions! Place code in this file or in files contained in this directory to add customized Incisor functionality to your project.
Keep in mind that code placed in this 'ProjectExtensions' directory will not be included in published projects, and is instead meant
to provide a space for scripts and functionality to help in the development process. You can add custom menus, startup scripts, pre/post publish 
scripts, define custom inspector panels, and more. 

The examples below outline some of the key ways that Incisor extensions can help developers enhance productivity for their process and their team.

The 'nce' var is the primary accessor to Incisor extensions functionality, and largely mirrors the functionality that the 'nc' object has within normal project code.
*/


// This is where you can declare class definitions...


// Place code that should run in the 'init' phase within 'CODE.runBeforeInit' blocks. This scope will have access to 'nce', 
// and all user-created classes will be defined before this code executes.
CODE.runBeforeInit___begin;
    // Project Extensions Scope - This code executes when the Inspector first opens, after any global extensions code

    // This is where you put runtime code to register actions etc...

CODE.runBeforeInit___end;










----------------------------------------------------------
Section 58: Tween Types/AccelerateAndBounce
----------------------------------------------------------


Title: AccelerateAndBounce
Template Library Path: Tween Types/AccelerateAndBounce
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/AccelerateAndBounce:
Accelerates to the end value, then bounces away from it and back again.

The depth of the bounce and the point at which it begins are exposed as TweenControllers, so the same TweenType covers everything from a subtle settle to a pronounced rebound.

Its controllers live on the Swooper the swoop returns, under the tween's own name - swooper.controllers.AccelerateAndBounce. 'bounceHeight' (default .2) is how far back toward the start value the bounce travels, where 0 is no bounce and 1 returns the whole way. 'accelerateToBounceRatio' (default .7) is the share of the duration spent accelerating before the bounce begins, so lowering it shortens the approach and lengthens the bounce. Set them after starting the swoop, since a swoop that changes which tween a property is using resets them to the defaults given here.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.AccelerateAndBounce).

Examples of Tween Types/AccelerateAndBounce:
// Incisor Template Library - AccelerateAndBounce: dropping onto the mark and rebounding off it.
// Requires Template Library items: AccelerateAndBounce

// A TweenType is only legible next to something to compare it against, so this moves two objects the same distance over
// the same duration and changes nothing between them but the tween.
let reference = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Reference");
reference.scale.scaleByFactor(3);
reference.position.x = 100;
reference.position.y = 300;

let bouncing = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Bouncing");
bouncing.scale.scaleByFactor(3);
bouncing.position.x = -100;
bouncing.position.y = 300;

reference.position.swoop.y(-300,3,nc.tweenTypes.Linear);

// A swoop returns its Swooper, and a TweenType's controllers live on it under the tween's own name. They have to be set
// after the swoop is started, since starting one resets its controllers to the TweenType's defaults.
// bounceHeight is how far back toward the start the rebound carries, and accelerateToBounceRatio splits the duration
// between the fall and the bounce - all fall at 0, all bounce at 1.
let swooper = bouncing.position.swoop.y(-300,3,nc.tweenTypes.AccelerateAndBounce);
swooper.controllers.AccelerateAndBounce.bounceHeight = .35;
swooper.controllers.AccelerateAndBounce.accelerateToBounceRatio = .6;

Content of Tween Types/AccelerateAndBounce, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType accelerates to the end value, then bounces away from it and back again.

'bounceHeight' is how far back toward the start value the bounce travels, and 'accelerateToBounceRatio' is the share of the duration spent accelerating before the bounce begins. They are reached on the Swooper the swoop returns, as 'swooper.controllers.incr_replaceText_NameSubstitution.<name>', and are set after the swoop is started - a swoop that puts a different tween on a property puts its controllers back to the defaults below.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // The swoop is two curves end to end, and the ratio is where one hands over to the other.
        let progress = swooper.progress;
        let ratio = swooper.controllers.incr_replaceText_NameSubstitution.accelerateToBounceRatio;
        if (progress <= ratio)
        {
        // rescaled so the acceleration covers its whole share of the duration and arrives on the end value
            progress = progress / ratio;
            progress *= progress;
        }
        else
        {
        // a parabola centered on the remaining time, which dips below 1 and comes back - the bounce. Scaling
        // the dip rather than the whole curve is what keeps the end value arrived at whatever the height is.
            progress = ((progress - ratio - (1-ratio) * .5) * 2) / (1-ratio);
            progress *= progress;
            progress = 1 + (progress - 1) * swooper.controllers.incr_replaceText_NameSubstitution.bounceHeight;
        }
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        ["bounceHeight", "accelerateToBounceRatio"],
        [.2, .7],
        "This TweenType accelerates to the end value, then bounces away and back again.",
        ["The amount that the bounce moves toward the initial value. 0 means no bounce, and 1 means it returns all the way to the initial value.", "The ratio of the acceleration portion of the timing to the bounce portion. 0 means no bounce, and 1 means nothing but bounce."]
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 59: Tween Types/Arc
----------------------------------------------------------


Title: Arc
Template Library Path: Tween Types/Arc
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/Arc:
Adds an arced bend to the x, y, or z component of the swooped value.

Intended for position swoops where a straight line reads as mechanical. Each axis has its own arc controller, so the bend can be applied on one axis while the others interpolate normally.

Its controllers live on the Swooper the swoop returns, under the tween's own name - swooper.controllers.Arc. 'arcX', 'arcY' and 'arcZ' (defaults 0, 100 and 0) each add a sine-shaped bend to that component, at its widest halfway through the swoop and back to nothing at both ends, measured in the units of the value being swooped - so a negative value bends the other way. Only a component the swoop is actually carrying can bend, which is why these belong on a whole-vector swoop rather than a single-axis one. Set them after starting the swoop, since a swoop that changes which tween a property is using resets them to the defaults given here.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.Arc).

Examples of Tween Types/Arc:
// Incisor Template Library - Arc: bending a straight move into a curve.
// Requires Template Library items: Arc

// A TweenType is only legible next to something to compare it against, so this moves two objects between the same two
// points over the same duration and changes nothing between them but the tween.
let reference = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Reference");
reference.scale.scaleByFactor(3);
reference.position.x = -400;
reference.position.y = -200;

let arcing = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Arcing");
arcing.scale.scaleByFactor(3);
arcing.position.x = -400;
arcing.position.y = -200;

// Arc bends whichever components the swoop is carrying, so this swoops the position as a whole rather than one axis of
// it - a single-axis swoop has nothing for the bend to happen in.
reference.position.swoop.each([400,-200],2.5,nc.tweenTypes.Linear);

// A swoop returns its Swooper, and a TweenType's controllers live on it under the tween's own name. They have to be set
// after the swoop is started, since starting one resets its controllers to the TweenType's defaults.
// Each axis has its own arc, so the bend can be put on one while the others travel straight.
let swooper = arcing.position.swoop.each([400,-200],2.5,nc.tweenTypes.Arc);
swooper.controllers.Arc.arcX = 0;
swooper.controllers.Arc.arcY = 350;

Content of Tween Types/Arc, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType adds an arced bend to the x, y, or z component of the swooped value.

'arcX', 'arcY' and 'arcZ' each bend that one component, in the units of the value being swooped, so a negative value bends the other way. They are reached on the Swooper the swoop returns, as 'swooper.controllers.incr_replaceText_NameSubstitution.<name>', and are set after the swoop is started - a swoop that puts a different tween on a property puts its controllers back to the defaults below.

Only a component the swoop is actually carrying can bend, so this belongs on a whole-vector swoop rather than a single-axis one - a swoop of x alone has nothing to arc into.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // The straight line the bend is added to. Every TweenType has to write every property, so this runs
    // whether or not any of the arcs below are asked for.
        let progress = swooper.progress;
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    // A half sine over the swoop is zero at both ends and widest in the middle, so the bend leaves the start
    // and end values alone and only changes the path between them. Each axis carries its own.
        if(swooper.controllers.incr_replaceText_NameSubstitution.arcX!==0)
        {
            swooper.currentValues[0] += swooper.controllers.incr_replaceText_NameSubstitution.arcX * Math.sin(progress*Math.PI);
        }
        if(swooper.controllers.incr_replaceText_NameSubstitution.arcY!==0)
        {
            swooper.currentValues[1] += swooper.controllers.incr_replaceText_NameSubstitution.arcY * Math.sin(progress*Math.PI);
        }
        if(swooper.controllers.incr_replaceText_NameSubstitution.arcZ!==0)
        {
            swooper.currentValues[2] += swooper.controllers.incr_replaceText_NameSubstitution.arcZ * Math.sin(progress*Math.PI);
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        ["arcX","arcY","arcZ"],
        [0,100,0],
        "This TweenType adds an arced 'bend' in the x, y, or z component of the swooped value.",
        ["Adjusts the size of the arc of the X component.","Adjusts the size of the arc of the Y component.","Adjusts the size of the arc of the Z component."]
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 60: Tween Types/BulletTimeDoubleArc
----------------------------------------------------------


Title: BulletTimeDoubleArc
Template Library Path: Tween Types/BulletTimeDoubleArc
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/BulletTimeDoubleArc:
Arcs a position swoop toward an offset point while slowing the motion through the middle of the move.

Produces a dramatic 'bullet time' pass, where the object sweeps in fast, hangs briefly at the apex, and accelerates away. Built for position swoops specifically.

Its controllers live on the Swooper the swoop returns, under the tween's own name - swooper.controllers.BulletTimeDoubleArc. 'bulletTimeAmount' (default .5) is how far the middle of the move is slowed, where 0 is an even pace and 1 brings it almost to a standstill at the midpoint. 'x' and 'y' (both default 100) are the sine-shaped bends added to the first and second components, at their widest halfway through and back to nothing at both ends. Set them after starting the swoop, since a swoop that changes which tween a property is using resets them to the defaults given here.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.BulletTimeDoubleArc).

Examples of Tween Types/BulletTimeDoubleArc:
// Incisor Template Library - BulletTimeDoubleArc: sweeping in fast, hanging at the apex, then away.
// Requires Template Library items: BulletTimeDoubleArc

// A TweenType is only legible next to something to compare it against, so this moves two objects between the same two
// points over the same duration and changes nothing between them but the tween.
let reference = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Reference");
reference.scale.scaleByFactor(3);
reference.position.x = -500;
reference.position.y = -150;

let sweeping = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Sweeping");
sweeping.scale.scaleByFactor(3);
sweeping.position.x = -500;
sweeping.position.y = -150;

// This one is built for position swoops specifically, so it swoops the position as a whole rather than one axis of it.
reference.position.swoop.each([500,-150],3,nc.tweenTypes.Linear);

// A swoop returns its Swooper, and a TweenType's controllers live on it under the tween's own name. They have to be set
// after the swoop is started, since starting one resets its controllers to the TweenType's defaults.
// x and y place the point the pass arcs toward, and bulletTimeAmount is how much the middle of the move slows down -
// the hang at the apex is the whole effect, so it is the one worth pushing.
let swooper = sweeping.position.swoop.each([500,-150],3,nc.tweenTypes.BulletTimeDoubleArc);
swooper.controllers.BulletTimeDoubleArc.x = 0;
swooper.controllers.BulletTimeDoubleArc.y = 300;
swooper.controllers.BulletTimeDoubleArc.bulletTimeAmount = .75;

Content of Tween Types/BulletTimeDoubleArc, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType arcs a position swoop toward an offset point while slowing the motion through the middle of the move.

'bulletTimeAmount' is how far the middle of the move is slowed, and 'x' and 'y' are the bends added to the first and second components. They are reached on the Swooper the swoop returns, as 'swooper.controllers.incr_replaceText_NameSubstitution.<name>', and are set after the swoop is started - a swoop that puts a different tween on a property puts its controllers back to the defaults below.

Built for position swoops specifically, since it treats the first two properties as x and y.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // A fifth power centered on the halfway point is nearly flat through the middle and steep at both ends,
    // which is the hang. Mixing it against plain progress rather than replacing it is what makes the amount
    // a dial instead of a switch.
        let progress = swooper.progress;
        let params = swooper.controllers.incr_replaceText_NameSubstitution;
        progress = (.5*Math.pow((progress-.5)*2,5)+.5)*params.bulletTimeAmount+(1-params.bulletTimeAmount)*progress;
        var oneMinus = 1-progress;
    // The first two properties are read as x and y and get the same half sine bend Arc uses, zero at both
    // ends and widest in the middle. Anything past them travels straight.
        for(var i=0; i<swooper.startValues.length; i++)
        {
            if(i===0)       {swooper.currentValues[i] = swooper.startValues[i]*oneMinus+swooper.endValues[i]*progress+Math.sin(progress*Math.PI)*params.x;}
            else if(i===1)  {swooper.currentValues[i] = swooper.startValues[i]*oneMinus+swooper.endValues[i]*progress+Math.sin(progress*Math.PI)*params.y;}
            else{swooper.currentValues[i] = swooper.startValues[i]*oneMinus+swooper.endValues[i]*progress;}
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        ["bulletTimeAmount", "x", "y"],
        [.5, 100, 100],
        "This TweenType is intended for use with position swoops. It arcs the movement toward an offset position, and slows down the movement in the middle of the movement.",
        ["The amount to slow down the progression. 0 means no slow down, and 1 brings the progression to a standstill in the middle.", "The amount of X arc.", "The amount of Y arc."]
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 61: Tween Types/EaseIn
----------------------------------------------------------


Title: EaseIn
Template Library Path: Tween Types/EaseIn
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/EaseIn:
Changes quickly at first and slows toward the end value.

The standard choice for something arriving and settling. Pair with EaseOut on the reverse move for motion that reads as symmetrical.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.EaseIn).

Examples of Tween Types/EaseIn:
// Incisor Template Library - EaseIn: arriving quickly and settling into place.
// Requires Template Library items: EaseIn

// A TweenType is only legible next to something to compare it against, so this moves two objects the same distance over
// the same duration and changes nothing between them but the tween.
let reference = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Reference");
reference.scale.scaleByFactor(3);
reference.position.x = -400;
reference.position.y = 100;

let easing = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Easing");
easing.scale.scaleByFactor(3);
easing.position.x = -400;
easing.position.y = -100;

// The top one travels at a constant rate. The bottom one covers most of the distance early and creeps the last of it,
// which is what makes something read as arriving rather than as stopping.
reference.position.swoop.x(400,2,nc.tweenTypes.Linear);
easing.position.swoop.x(400,2,nc.tweenTypes.EaseIn);

Content of Tween Types/EaseIn, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType changes quickly at first and slows toward the end value.

It defines no controllers, so the swoop's duration is the only thing that shapes it - both empty lists below are what says so.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // The same square as Accelerate, mirrored - measuring the distance left rather than the distance covered
    // puts the fast part of the curve at the start and the slow part at the finish.
        let a = swooper.progress - 1;
        let progress = 1 - a * a;
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        [],
        [],
        "This TweenType changes quickly at first and slows down.",
        []
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 62: Tween Types/EaseOut
----------------------------------------------------------


Title: EaseOut
Template Library Path: Tween Types/EaseOut
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/EaseOut:
Changes slowly at first and speeds up toward the end value.

The standard choice for something departing. Pair with EaseIn on the reverse move for motion that reads as symmetrical.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.EaseOut).

Examples of Tween Types/EaseOut:
// Incisor Template Library - EaseOut: setting off gently and building speed.
// Requires Template Library items: EaseOut

// A TweenType is only legible next to something to compare it against, so this moves two objects the same distance over
// the same duration and changes nothing between them but the tween.
let reference = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Reference");
reference.scale.scaleByFactor(3);
reference.position.x = -400;
reference.position.y = 100;

let easing = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Easing");
easing.scale.scaleByFactor(3);
easing.position.x = -400;
easing.position.y = -100;

// The top one travels at a constant rate. The bottom one leaves slowly and is still gathering speed when it arrives,
// which is what makes something read as departing. Pair it with EaseIn on the return trip.
reference.position.swoop.x(400,2,nc.tweenTypes.Linear);
easing.position.swoop.x(400,2,nc.tweenTypes.EaseOut);

Content of Tween Types/EaseOut, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType changes slowly at first and speeds up toward the end value.

It defines no controllers, so the swoop's duration is the only thing that shapes it - both empty lists below are what says so.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // Squaring progress keeps the early frames close to the start value and packs the travel into the late
    // ones, which is the mirror of EaseIn and the pairing that makes a move and its reverse read alike.
        let x = swooper.progress;
        let progress = x * x;
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        [],
        [],
        "This TweenType changes slowly at first and speeds up.",
        []
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 63: Tween Types/ExtremeEaseIn
----------------------------------------------------------


Title: ExtremeEaseIn
Template Library Path: Tween Types/ExtremeEaseIn
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/ExtremeEaseIn:
Changes very quickly at first and slows sharply toward the end value.

A more aggressive EaseIn for snappy interface motion where the standard curve feels sluggish.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.ExtremeEaseIn).

Examples of Tween Types/ExtremeEaseIn:
// Incisor Template Library - ExtremeEaseIn: snapping most of the way there, then easing the rest.
// Requires Template Library items: ExtremeEaseIn, EaseIn

// This one is a sharper version of EaseIn, so the comparison worth seeing is against EaseIn itself rather than against
// a linear move.
let standard = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Standard");
standard.scale.scaleByFactor(3);
standard.position.x = -400;
standard.position.y = 100;

let extreme = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Extreme");
extreme.scale.scaleByFactor(3);
extreme.position.x = -400;
extreme.position.y = -100;

// Both settle rather than stop, but the bottom one covers almost the whole distance immediately and spends the rest of
// the duration on the last stretch. Reach for it where the standard curve feels sluggish for interface motion.
standard.position.swoop.x(400,2,nc.tweenTypes.EaseIn);
extreme.position.swoop.x(400,2,nc.tweenTypes.ExtremeEaseIn);

Content of Tween Types/ExtremeEaseIn, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType changes very quickly at first and slows sharply toward the end value.

It defines no controllers, so the swoop's duration is the only thing that shapes it - both empty lists below are what says so.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // A quarter sine already leaves at full speed and arrives at none. Raising it to a fraction pushes it
    // higher still early on, which is what separates this from EaseIn rather than any change of shape.
        let progress = Math.pow(Math.sin(.5*Math.PI*swooper.progress),.3);
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        [],
        [],
        "This TweenType changes very quickly at first and slows down.",
        []
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 64: Tween Types/ExtremeEaseOut
----------------------------------------------------------


Title: ExtremeEaseOut
Template Library Path: Tween Types/ExtremeEaseOut
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/ExtremeEaseOut:
Changes very slowly at first and accelerates sharply toward the end value.

A more aggressive EaseOut, useful for motion that should feel like it is being yanked away.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.ExtremeEaseOut).

Examples of Tween Types/ExtremeEaseOut:
// Incisor Template Library - ExtremeEaseOut: hanging still, then being yanked away.
// Requires Template Library items: ExtremeEaseOut, EaseOut

// This one is a sharper version of EaseOut, so the comparison worth seeing is against EaseOut itself rather than against
// a linear move.
let standard = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Standard");
standard.scale.scaleByFactor(3);
standard.position.x = -400;
standard.position.y = 100;

let extreme = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Extreme");
extreme.scale.scaleByFactor(3);
extreme.position.x = -400;
extreme.position.y = -100;

// The bottom one barely moves for most of the duration and then covers the whole distance at the end, which reads as
// being pulled away rather than as leaving under its own power.
standard.position.swoop.x(400,2,nc.tweenTypes.EaseOut);
extreme.position.swoop.x(400,2,nc.tweenTypes.ExtremeEaseOut);

Content of Tween Types/ExtremeEaseOut, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType changes very slowly at first and accelerates sharply toward the end value.

It defines no controllers, so the swoop's duration is the only thing that shapes it - both empty lists below are what says so.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // The mirror of ExtremeEaseIn - a quarter cosine leaves at no speed and arrives at full, and the power
    // above 1 flattens the early frames further so the move reads as being yanked away rather than eased.
        let progress = Math.pow(1-Math.cos(.5*Math.PI*swooper.progress),3.33);
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        [],
        [],
        "This TweenType changes very slowly at first and speeds up.",
        []
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 65: Tween Types/Oscillate
----------------------------------------------------------


Title: Oscillate
Template Library Path: Tween Types/Oscillate
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/Oscillate:
Applies a diminishing sine wave oscillation to the swooped values.

The values wobble around the target and settle into it. The number of oscillations is exposed as a TweenController, covering everything from a soft settle to a spring-like shudder.

Its controller lives on the Swooper the swoop returns, under the tween's own name - swooper.controllers.Oscillate.oscillations, default 3: the number of complete wobbles fitted into the duration of the swoop. How wide the wobble is cannot be set - it comes from the distance being swooped, and diminishes on its own as the swoop runs out. Set it after starting the swoop, since a swoop that changes which tween a property is using resets it to that default.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.Oscillate).

Examples of Tween Types/Oscillate:
// Incisor Template Library - Oscillate: wobbling around the target and settling into it.
// Requires Template Library items: Oscillate

// A TweenType is only legible next to something to compare it against, so this moves two objects the same distance over
// the same duration and changes nothing between them but the tween.
let reference = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Reference");
reference.scale.scaleByFactor(3);
reference.position.x = -400;
reference.position.y = 100;

let wobbling = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Wobbling");
wobbling.scale.scaleByFactor(3);
wobbling.position.x = -400;
wobbling.position.y = -100;

reference.position.swoop.x(400,3,nc.tweenTypes.Linear);

// A swoop returns its Swooper, and a TweenType's controllers live on it under the tween's own name. They have to be set
// after the swoop is started, since starting one resets its controllers to the TweenType's defaults.
let swooper = wobbling.position.swoop.x(400,3,nc.tweenTypes.Oscillate);
swooper.controllers.Oscillate.oscillations = 5;

Content of Tween Types/Oscillate, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType applies a diminishing sine wave oscillation to the swooped values, so they wobble around the target and settle into it.

'oscillations' is the number of complete wobbles fitted into the duration of the swoop. They are reached on the Swooper the swoop returns, as 'swooper.controllers.incr_replaceText_NameSubstitution.<name>', and are set after the swoop is started - a swoop that puts a different tween on a property puts its controllers back to the defaults below.

How wide the wobble is cannot be set - it comes from the distance being swooped, and the term that shrinks it is progress itself, so the wave is always spent by the time the swoop ends.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // A sine divided by the angle it was taken at is a wave whose height falls away as the swoop runs on,
    // and the remaining progress shrinks it the rest of the way so the end value is arrived at cleanly.
    // At zero oscillations the division has no angle to divide by, so that case interpolates straight.
        let a = swooper.progress * Math.PI * 2 * swooper.controllers.incr_replaceText_NameSubstitution.oscillations;
        let lerpFactor = a === 0 ? swooper.progress : 1 - Math.sin(a) * (1 - swooper.progress) / a;
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-lerpFactor) + swooper.endValues[i]*lerpFactor;
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        ["oscillations"],
        [3],
        "This TweenType applies a diminishing sine wave oscillation to the swooped values.",
        ["The number of oscillations to complete over the duration of the swoop."]
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 66: Tween Types/Overshoot
----------------------------------------------------------


Title: Overshoot
Template Library Path: Tween Types/Overshoot
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/Overshoot:
Moves past the end value and then returns to it.

The classic anticipation-free 'pop' finish. How far it runs past is fixed, so the duration of the swoop is what decides how sharp the pop reads.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.Overshoot).

Examples of Tween Types/Overshoot:
// Incisor Template Library - Overshoot: sliding an object into place past its mark and back.
// Requires Template Library items: Overshoot

// A TweenType is only legible next to something to compare it against, so this moves two objects the same distance over
// the same duration and changes nothing between them but the tween.
let reference = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Reference");
reference.scale.scaleByFactor(3);
reference.position.x = -400;
reference.position.y = 100;

let overshooting = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Overshooting");
overshooting.scale.scaleByFactor(3);
overshooting.position.x = -400;
overshooting.position.y = -100;

// The TweenType is the third argument to a swoop, and it is the only difference between these two moves - the top one
// travels at a constant rate, the bottom one runs past 400 and settles back onto it.
reference.position.swoop.x(400,2,nc.tweenTypes.Linear);
overshooting.position.swoop.x(400,2,nc.tweenTypes.Overshoot);

Content of Tween Types/Overshoot, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType moves past the end value and then returns to it.

It defines no controllers, so the swoop's duration is the only thing that shapes it - both empty lists below are what says so. How far it runs past is fixed, so the duration of the swoop is what decides how sharp the pop reads.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // A sine subtracted from the straight line bends it away and back. Starting a third of the way into the
    // wave and covering two thirds of one lands the dip past 1 and returns it, which is the overshoot -
    // the .39 is how far past, and the offsets are what keep both ends of the swoop on their own values.
        let progress = swooper.progress;
        progress = -.39*Math.sin((progress*.666666+.333333)*2*Math.PI)+(progress*.666666+.333333);
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        [],
        [],
        "This TweenType moves past the end value, then returns to it.",
        []
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 67: Tween Types/Windup
----------------------------------------------------------


Title: Windup
Template Library Path: Tween Types/Windup
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/Windup:
Moves away from the end value first, then travels toward it.

Gives motion a windup or anticipation beat before the main move, which reads as effort or intent.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.Windup).

Examples of Tween Types/Windup:
// Incisor Template Library - Windup: pulling back before the move, the way a throw does.
// Requires Template Library items: Windup

// A TweenType is only legible next to something to compare it against, so this moves two objects the same distance over
// the same duration and changes nothing between them but the tween.
let reference = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Reference");
reference.scale.scaleByFactor(3);
reference.position.x = -400;
reference.position.y = 100;

let winding = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Winding");
winding.scale.scaleByFactor(3);
winding.position.x = -400;
winding.position.y = -100;

// The bottom one travels the wrong way first. That beat of anticipation is what makes a move read as intended rather
// than as something that simply happened - it needs room behind the start point to wind into.
reference.position.swoop.x(400,3,nc.tweenTypes.Linear);
winding.position.swoop.x(400,3,nc.tweenTypes.Windup);

Content of Tween Types/Windup, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType moves away from the end value first, then travels toward it.

It defines no controllers, so the swoop's duration is the only thing that shapes it - both empty lists below are what says so.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // The same wave Overshoot uses, entered half a swoop earlier so the bend lands before the travel rather
    // than after it - the value backs away from its target first, which reads as effort or intent.
        let progress = swooper.progress;
        progress = -.39*Math.sin(((progress-.5)*.666666+.333333)*2*Math.PI)+((progress-.5)*.666666+.333333);
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        [],
        [],
        "This TweenType initially moves away from the end value, then moves toward it.",
        []
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 68: Tween Types/WindupOvershoot
----------------------------------------------------------


Title: WindupOvershoot
Template Library Path: Tween Types/WindupOvershoot
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/WindupOvershoot:
Winds up away from the end value, travels past it, then settles back onto it.

Combines anticipation and follow-through in a single curve. The most expressive of the stock TweenTypes, and the most likely to be too much for interface work.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.WindupOvershoot).

Examples of Tween Types/WindupOvershoot:
// Incisor Template Library - WindupOvershoot: pulling back, throwing past the mark, then settling onto it.
// Requires Template Library items: WindupOvershoot

// A TweenType is only legible next to something to compare it against, so this moves two objects the same distance over
// the same duration and changes nothing between them but the tween.
let reference = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Reference");
reference.scale.scaleByFactor(3);
reference.position.x = -400;
reference.position.y = 100;

let thrown = new GraphicObject(nc.graphicAssets.icon_plus,nc.mainScene,"Thrown");
thrown.scale.scaleByFactor(3);
thrown.position.x = -400;
thrown.position.y = -100;

// Anticipation and follow-through in one curve - back, past, and settle. It is the most expressive of the stock tweens
// and the easiest to overdo, so it wants a longer duration and room on both sides of the move.
reference.position.swoop.x(400,3,nc.tweenTypes.Linear);
thrown.position.swoop.x(400,3,nc.tweenTypes.WindupOvershoot);

Content of Tween Types/WindupOvershoot, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType winds up away from the end value, travels past it, then settles back onto it.

It defines no controllers, so the swoop's duration is the only thing that shapes it - both empty lists below are what says so.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // A whole sine over the whole swoop rather than the two thirds Windup and Overshoot each take, so both
    // bends are present - one before the travel and one after - for a single curve with anticipation and
    // follow-through in it.
        let progress = swooper.progress;
        progress = -.35*Math.sin(progress*2*Math.PI)+progress;
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        [],
        [],
        "This TweenType initially moves away from the end value, then moves past the end value, then reaches it.",
        []
    );
CODE.runBeforeInit___end;










----------------------------------------------------------
Section 69: Tween Types/blank template
----------------------------------------------------------


Title: blank template
Template Library Path: Tween Types/blank template
Type: TweenType
Placement: Assets/CodeAssets
TypeScript: This item also has a TypeScript version in the Template Library. Only the JavaScript is shown here.

Description of Tween Types/blank template:
An empty TweenType definition, ready to be filled in.

The tween function receives a Swooper and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues', and 'progress'. Start here when none of the stock curves fit.

A TweenType sets the pace of a swoop rather than where it goes, and is passed as the argument after the duration - object.position.swoop.x(400,2,nc.tweenTypes.TweenTypeName).

Content of Tween Types/blank template, file 'incr_replaceText_NameSubstitution.codeAsset.js'. Names that begin with 'incr_replaceText_' are replaced with the name the user gives the item:
/*
The 'incr_replaceText_NameSubstitution' TweenType is an empty definition, ready to be filled in. As it stands it interpolates straight from the start value to the end value.

A TweenType may define controllers of its own, given below as a list of names and a matching list of defaults and read back inside the function as 'swooper.controllers.incr_replaceText_NameSubstitution.<name>'. The two empty lists are what says this one has none.

A TweenType is handed to a swoop as the argument after the duration, and is asked for a value on every frame of that swoop. It is given the Swooper, and is responsible for writing every entry of 'currentValues' from 'startValues', 'endValues' and 'progress' - progress runs 0 to 1 over the duration, and reshaping it before the interpolation is what makes one curve differ from another.
*/


CODE.runBeforeInit___begin;
    /** Define the tween function.
    * @param {Swooper} swooper
    */
    var incr_replaceText_nameSubstitution_tweenTypeFunction = function(swooper)
    {
    // Reshaping progress before this loop is the whole job of a TweenType - left alone, as here, the value
    // travels at a constant rate.
        let progress = swooper.progress;
        for(let i=0; i<swooper.numProperties; i++)
        {
            swooper.currentValues[i] = swooper.startValues[i]*(1-progress) + swooper.endValues[i]*progress;
        }
    };

// The name, the function, the controller names and their defaults, then the descriptions that reach the Code API - the
// item's own description first, then one for each controller in the same order the names were given.
    nc.defineTweenType(
        "incr_replaceText_NameSubstitution",
        incr_replaceText_nameSubstitution_tweenTypeFunction,
        [],
        [],
        "This is a custom TweenType.",
        []
    );
CODE.runBeforeInit___end;

Incisor® Articles

IncisorArticles.txt

Incisor® Articles
This document is part of the compiled knowledge base for the Incisor® Software Development Platform.
Any use of this content is subject to the INCISOR® end user license and terms of use agreement.
https://www.incisordev.com/eultua
2026.11.05.12.18.12






----------------------------------------------------------
TABLE OF CONTENTS:
----------------------------------------------------------
Section 1: Incisor Articles Overview
Section 2: How can I have AI test my Incisor project?
Section 3: Controlling Incisor from the Command Line
Section 4: Can I debug my project from my code editor?
Section 5: Can particle emission follow a path?
Section 6: FlowControllers & FlowStates
Section 7: Incisor Optimization Checklist
Section 8: Lazy Loading Content in Incisor










----------------------------------------------------------
Section 1: Incisor Articles Overview
----------------------------------------------------------


The Incisor® website publishes articles in its FAQs & Tutorials section at https://www.incisordev.com/articles/index.html. A FAQ answers one question. A tutorial teaches a feature or a workflow. Each section after this one is the text of one article. Screenshots, images, and videos are not included.

The articles, newest first:
- How can I have AI test my Incisor project? (FAQ, 2026-11-05): Let an AI agent run, see, click, type in and check your project through the command line: screenshots to see, simulated cursor and keyboard input to act, and your project's own state to verify. Includes a briefing to paste into your agent.
- Controlling Incisor from the Command Line (Tutorial, 2026-11-04): The complete reference for the Incisor command line: turn it on, run commands on Mac and Windows, read the JSON answer, and use every command, exit code, error code and timeout. Written for people, scripts and AI agents.
- Can I debug my project from my code editor? (FAQ, 2026-10-27): Turn on editor debugging, attach VS Code or WebStorm to a running Incisor project, and step through your own TypeScript or JavaScript with breakpoints, variables, and the call stack.
- Can particle emission follow a path? (FAQ, 2026-10-02): Make particles trail along a path or behind a moving object with emitterPosition expressions and EffectControllers, without losing the speed of the GPU particle system. Includes two downloadable example projects.
- FlowControllers & FlowStates (Tutorial, 2026-09-29): Organize your game's phases (intro, idle, play, results) as timed FlowStates, wait on players and servers with pauses, and watch every step live in the Flows panel. Built around the Incisor Slot Template.
- Incisor Optimization Checklist (Tutorial, 2026-09-28): The final pass before you publish: fourteen quick checks for a smaller download, faster startup and smoother frames, from sprite sheets and font reduction to update loops and overdraw.
- Lazy Loading Content in Incisor (Tutorial, 2026-09-27): Split your assets into loading tiers so the first screen appears fast and everything else streams in behind it. Covers the concepts, Assets panel, Project Settings, the nc.loadTier API, the Loading Tiers panel, and proven patterns.










----------------------------------------------------------
Section 2: How can I have AI test my Incisor project?
----------------------------------------------------------


Title: How can I have AI test my Incisor project?
Type: FAQ
Published: 2026-11-05
URL: https://www.incisordev.com/articles/testing-your-project-with-ai/index.html
Tags: ai, testing, cli, automation
Keywords: AI agent, AI testing, automated testing, QA, Claude Code, LLM, command line, CLI, runNceScript, getProjectScreenShot, getInspectorScreenShot, getSessionInfo, nce.projectNC, nce.projectPR, nce.mainCamera, cursor simulation, keyboard simulation, setCursorViewPosition, simulateCursorPressEvent, simulateCursorReleaseEvent, simulateKeyPress, simulateKeyDown, simulateKeyUp, getViewPosition, getIntersections, getDescendants, run button, isRunning, enableCLI, Slot Template, knowledge base, MCP
Summary: Let an AI agent run, see, click, type in and check your project through the command line: screenshots to see, simulated cursor and keyboard input to act, and your project's own state to verify. Includes a briefing to paste into your agent.

Give an AI agent the Incisor command line and it can run your project, look at it, click and type in it, and check what happened. That's the same loop a human tester follows, without you at the keyboard.

Short answer:

Turn on `enableCLI` in Application Settings, then let your agent use three commands. `getProjectScreenShot` and `getInspectorScreenShot` let it see. `runNceScript` lets it act, by simulating the cursor and keyboard, and check, by reading your project's state. Every command answers in JSON, so the agent can verify its own work.

## How can I have AI test my Incisor project?: See it happen

Claude Code in VS Code (left) plays the Incisor Slot Template (right) using only the command line. It presses Run, clicks through the intro, spins, toggles the sound and opens the menu, and takes a screenshot after each step to see the result. Shown at 4× speed.

## How can I have AI test my Incisor project?: Before you start

#### Incisor 2026.11.05.00.00.00 or later

Earlier versions don't have `getProjectScreenShot` or keyboard simulation. Use Incisor menu → Check for Updates to update.

#### The command line turned on

In Application Settings, under security, tick `enableCLI`. It takes effect straight away.

#### Your project open in Incisor

The agent works on the project in the Incisor window you have open, so you can watch everything it does.

#### An agent that can run commands

Any AI agent that can run terminal commands and look at images works, such as Claude Code in VS Code.

`enableCLI` is in the security group of Application Settings.

Warning: Know the risk. With `enableCLI` on, any program on your computer can send commands to Incisor, and a script can click anything a person can. Turn it on only on a machine you trust, and tell your agent what it may and may not change.

Tip: Give your agent the manual. Connect it to the Incisor knowledge base, either through the public MCP server at `https://mcp.incisordev.com/mcp` or by downloading it from the Knowledge Base page at incisordev.com. Every command used here is described in full in the article Controlling Incisor from the Command Line.

## How can I have AI test my Incisor project?: How it works

A test is the same three moves, repeated. Each move is one command.

#### See

A screenshot command saves a PNG of the project, or of the whole Incisor tab. The agent opens the image and looks at it.

#### Act

`runNceScript` runs a short script that moves the cursor, clicks, or presses keys, exactly as a player would.

#### Check

The same script returns whatever the agent asks for, such as the current FlowState or the text in a meter. Another screenshot confirms it.

### Two worlds: the inspector and your project

A script from `runNceScript` runs inside the inspector, the Incisor window around your project. It gets one object, `nce`. Your running project is a separate world with its own `nc`, and `nce` has a doorway into it. Knowing which side you're on is the key to everything below.

In a script | What it is | Use it to
`nce.projectNC` | Your running project's `nc` | Do anything your own code does with `nc`: reach `mainCamera`, `mainScene` and `flows`, and simulate keys.
`nce.projectPR` | Your running project's `pr` | Read your own properties and call your own functions.
`nce.mainCamera` and `nce.mainScene` | The inspector's own camera and scene | Click inspector controls, such as the Run button in Live View.

So a click on your game goes through `nce.projectNC.mainCamera`, and a click on the inspector goes through `nce.mainCamera`. The same split applies to keys: `nce.projectNC.simulateKeyPress` types in your project, and `nce.simulateKeyPress` types in the inspector.

### Sending a script

The scripts in this article are plain JavaScript. To send one, it has to become the `script` text of a `runNceScript` command. On a Mac, save the script as a file and let `jq` build the command, so you never escape quotes by hand:

Mac terminal

```
jq -n --rawfile script click.js \
  '{command:"runNceScript", projectPath:"'"$HOME"'/Desktop/MyProject", script:$script}' > command.json
rm -f answer.json
/Applications/Incisor.app/Contents/MacOS/Incisor --cli-file command.json --output answer.json
```

The answer is printed, and also saved in `answer.json`. The value the script returned is in `result.value`. On Windows the commands are the same, and the command line article lists where the executable is.

## How can I have AI test my Incisor project?: 1. Run the project

Projects open stopped by default, and an agent can only see and click a project that's running. There's no command that runs a project, so the agent presses the Run button the way you do.
1. Send `getSessionInfo` and find your project in `openProjects`. If it isn't listed, send `openProject`. If its `isRunning` is `true`, skip to step 2.
2. Send `getInspectorScreenShot`. The answer gives the image's `path`, `width` and `height`. In the image, find the Run button: the play icon under the words “project stopped”, or the small one at the left of the Live View header.
A stopped project in Live View. Either play button runs it.
3. Click that spot with the inspector's camera. A camera's view runs from −0.5 to 0.5 in each direction, with −0.5 at the left and bottom, so the script turns the pixel into a view position first.
Script: press Run
```
// From the getInspectorScreenShot answer, and where the Run button is in that image.
const shot = { width: 1680, height: 1306 };
const runButton = { x: 1137, y: 492 };

const viewX = runButton.x / shot.width - 0.5;
const viewY = 0.5 - runButton.y / shot.height;

const camera = nce.mainCamera;   // the inspector's camera
camera.setCursorViewPosition(viewX, viewY, 0, true);
camera.simulateCursorPressEvent();
camera.simulateCursorReleaseEvent();
```
4. Send `getSessionInfo` again and confirm `isRunning` is now `true`.

Tip: Skip this step entirely. Turn on `runProjectOnOpen` in Application Settings and projects start running as soon as they open.

## How can I have AI test my Incisor project?: 2. See

There are two screenshot commands. Both save a PNG and answer with its `path`, `width` and `height`.

`getProjectScreenShot`: the project alone. Use it to judge what a player sees.

`getInspectorScreenShot`: the whole Incisor tab. Use it to find inspector controls and read panels.

Command: see the project

```
{ "command": "getProjectScreenShot", "projectPath": "/Users/you/Desktop/MyProject" }
```

Command: see the whole tab

```
{ "command": "getInspectorScreenShot", "projectPath": "/Users/you/Desktop/MyProject" }
```

`getProjectScreenShot` needs the project to be running. If it isn't, the command fails with the error code `notRunning`.

## How can I have AI test my Incisor project?: 3. Act

An agent could click by pixel position, but it doesn't have to guess. Your project's objects have names, and a script can ask any object where it is.

### Find what can be clicked

Script: list the Buttons

```
const game = nce.projectNC;
return game.mainScene.getDescendants()
  .filter(o => o.type === 'Button')
  .map(o => o.name);
```

Answer, from the Slot Template

```
{
  "ok": true,
  "command": "runNceScript",
  "result": { "value": ["MenuButton", "SoundButton", "SpinButton", "Autoplay Button"] }
}
```

`getDescendants()` lists only enabled objects, so this is what's clickable right now. Call `getDescendants(false)` to include disabled objects too.

### Click by name

Script: click the SpinButton

```
const game = nce.projectNC, camera = game.mainCamera;
const target = game.mainScene.getDescendants().find(o => o.name === 'SpinButton');
if (!target) return { clicked: false, reason: 'SpinButton not found, or disabled' };

const view = target.getViewPosition(camera);
camera.setCursorViewPosition(view.x, view.y, 0, true);
const under = [...new Set(camera.getIntersections().map(i => i.sceneObject.name))];
camera.simulateCursorPressEvent();
camera.simulateCursorReleaseEvent();
return { clicked: true, under };
```

Answer

```
{
  "ok": true,
  "command": "runNceScript",
  "result": { "value": {
    "clicked": true,
    "under": ["BackgroundShadow", "GameBackgroundPattern", "FallingStarMask", "SpinButton"]
  } }
}
```

- `getViewPosition(camera)` gives the object's position in that camera's view, ready to hand to `setCursorViewPosition`. It keeps working when the window is resized, which pixel positions don't.
- `getIntersections()` lists everything under the cursor. Returning it as `under` lets the agent confirm the click landed on the right thing, or spot that something is covering it.
- Keep move, press and release together in one script, with no waiting in between.

### Press keys

Keys are named the way the browser names them, such as `'a'`, `'Enter'`, `'ArrowLeft'`, or `' '` for the space bar.

Script: keys

```
const game = nce.projectNC;
game.simulateKeyPress(' ');        // press and release the space bar

game.simulateKeyDown('Shift');     // or hold a key down...
// ...do something while it's held...
game.simulateKeyUp('Shift');       // ...and let it go
```

These trigger your project's `keyDown`, `keyUp` and `keyboardEvent` AppEvents, and update `nc.keyDownStates`, just as a real key does.

### Scroll and right-click

After placing the cursor, a camera can also send `simulateCursorScrollEvent()` and `simulateContextMenuEvent()`. To fire one callback on one Button directly, every Button has functions such as `simulatePressCallback` and `simulateReleaseCallback`.

## How can I have AI test my Incisor project?: 4. Check

A screenshot shows what happened. A script can also say what happened, exactly, by returning your project's state. Scripts may use `await`, so one script can act, wait for the result, and report it.

Script: spin, wait, and report

```
const game = nce.projectNC, flow = game.flows.MainGameFlow;
const read = name => game.mainScene.getDescendants().find(o => o.name === name).string;
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
const before = read('BalanceMeter');

game.simulateKeyPress(' ');
await wait(500);
const spinning = () => ['StartGame', 'SpinReels'].includes(flow.currentFlowState.name);
while (spinning()) await wait(100);

return {
  state: flow.currentFlowState.name,
  before,
  balance: read('BalanceMeter'),
  win: read('WinMeter')
};
```

Answer

```
{
  "ok": true,
  "command": "runNceScript",
  "result": { "value": { "state": "GameIdle", "before": "$1,207.00", "balance": "$1,205.50", "win": "" } }
}
```

That one answer proves the space bar started a spin, the reels stopped, the game returned to `GameIdle`, and the $1.50 bet came off the balance. Things worth returning:
- FlowStates: `nce.projectNC.flows.MainGameFlow.currentFlowState.name` says which phase the project is in.
- What's on screen: a TextBox's `string`, or any object's `enabled`, `position` or `getViewPosition(camera)`.
- Your own code: anything on `nce.projectPR`. In the Slot Template, `nce.projectPR.symbolReels.length` returns 5.

Return plain values such as names, numbers and text, not the objects themselves, because the answer is sent as JSON. Every answer also carries `ok`, an `error` with a code and message when something failed, and `logs`, the lines Incisor logged while the command ran.

## How can I have AI test my Incisor project?: Example: playing a slot

Here is the whole loop on the Incisor Slot Template, which you can open from the Project Gallery. Every step is one command, and every image is a screenshot the agent took.
1. Run it. `getSessionInfo` shows `isRunning` is `false`, so the agent takes an inspector screenshot, finds the play button, and clicks it with `nce.mainCamera`.
2. See it. `getProjectScreenShot` shows the intro screen, and the Button list includes `GameIntroBackground`, a Button that covers the whole screen.
3. Click through. The agent clicks `GameIntroBackground` by name. A script reports the FlowState changed from `GameIntro` to `GameIdle`, with a balance of $1,000.00 and a bet of $1.50.
4. Spin. The agent clicks `SpinButton`, waits for the FlowState to leave `SpinReels`, and reads the meters. After a losing spin the balance is $998.50, exactly one bet lower.
5. Catch a win. When the FlowState lands on `WinCelebration`, the agent takes a screenshot and compares the number on screen with the `WinMeter` text.

Step 2: the intro.

Step 3: ready to spin.

Step 5: a win.

From here an agent can go wherever you point it: open the menu, try autoplay, hammer the spin button mid-spin, or play 200 spins and confirm the balance always adds up.

## How can I have AI test my Incisor project?: A briefing for your agent

Paste this into your agent, with your own paths, then tell it what to test.

Briefing

```
You can test my Incisor project through the Incisor command line (CLI).

SETUP
- Incisor executable: /Applications/Incisor.app/Contents/MacOS/Incisor
  Use the copy of Incisor that is already running. On a Mac, check with:
  pgrep -fl "Incisor.app/Contents/MacOS/Incisor"
- Project folder: /Users/you/Desktop/MyProject
- Reference: the article "Controlling Incisor from the Command Line" at
  https://www.incisordev.com/articles/incisor-command-line/index.html
  and the Incisor knowledge base (MCP server: https://mcp.incisordev.com/mcp).

RUNNING A COMMAND
- Write the command as JSON in a file, then run:
  <executable> --cli-file command.json --output answer.json
- In a VS Code or Claude Code terminal, put this in front: env -u ELECTRON_RUN_AS_NODE
- Run one command at a time. Delete answer.json before each command.
- Check "ok" and "error" in every answer. A script's return value is in result.value.

THE LOOP
1. Run: send getSessionInfo and find the project in openProjects. If isRunning is
   false, send getInspectorScreenShot, find the Run (play) button in Live View, and
   click that pixel with nce.mainCamera:
   viewX = pixelX / width - 0.5, viewY = 0.5 - pixelY / height.
2. See: send getProjectScreenShot (the project alone) or getInspectorScreenShot
   (the whole Incisor tab), then open the image and look at it.
3. Act: send runNceScript. In the script, nce.projectNC is the running project's nc
   and nce.projectPR is its pr. To click, find the object by name in
   nce.projectNC.mainScene.getDescendants(), get its position with
   getViewPosition(camera), then call camera.setCursorViewPosition(x, y, 0, true),
   camera.simulateCursorPressEvent() and camera.simulateCursorReleaseEvent() back
   to back, where camera is nce.projectNC.mainCamera.
   To press a key, call nce.projectNC.simulateKeyPress(key).
4. Check: return state from the script (FlowState names, TextBox strings, positions),
   read "logs", and take another screenshot.

RULES
- Never declare a variable named nc or pr in a script. Those names are taken.
- Find project objects by name, not by pixel position.
- Wait inside a script with await, and raise timeoutSeconds for long scripts.
- Return plain values (names, numbers, text), not objects.
- Tell me what you did, what you saw, and anything that looks wrong.
- Don't change any project files unless I ask.
```

## How can I have AI test my Incisor project?: Good to know
- `nc` and `pr` are taken. Inside a script those two names are reserved, so declaring `const pr = nce.projectPR` fails. Pick other names, such as `game`.
- Clicks aim at an object's position. `getViewPosition` returns where the object itself sits, which is normally the middle of a Button. If a Button's graphic is drawn away from its position, check `under` and adjust.
- Inspector controls go by pixel. The inspector's own objects have internal names that change between versions, so find inspector controls in a `getInspectorScreenShot` image and click by position. Take a new screenshot after the window is resized, because the positions move.
- Long waits need a longer timeout. `runNceScript` stops after 30 seconds unless the command includes a larger `timeoutSeconds`.
- A code change refreshes the project. If the agent edits your code, check `isRunning` again and look up objects again before the next step.
- Hidden tabs slow down. A project in a tab that isn't showing is throttled unless `runHiddenTabsUnthrottled` is on in Application Settings. Both screenshot commands bring the tab forward, and so does `focusTab`.

## How can I have AI test my Incisor project?: Troubleshooting

### A command hangs, or a second Incisor starts

The command went to a different copy of Incisor than the one that's open, for example `/Applications/Incisor.app` when the running copy is on the Desktop. Always use the executable inside the copy that's running. On a Mac, this shows which one that is:

Mac terminal

```
pgrep -fl "Incisor.app/Contents/MacOS/Incisor"
```

### The answer is from the previous command

An old answer file was still at the `--output` path. Delete it before each command, or use a new file name each time.

### notRunning

The project is stopped. Press Run as shown in step 1, or turn on `runProjectOnOpen`.

### Identifier 'pr' has already been declared

The script declared a variable named `pr` or `nc`. Rename it.

### The click did nothing
- Move, press and release are in the same script, with no `await` between them.
- The click used the right camera: `nce.projectNC.mainCamera` for your project, `nce.mainCamera` for the inspector.
- The target is in the `under` list, and nothing that takes clicks is covering it.
- The project is in a state that accepts the click. Return the FlowState to find out.

### timeout: command not found

macOS has no `timeout` command. Put `timeoutSeconds` in the command instead.

### bad option: --cli

The terminal has `ELECTRON_RUN_AS_NODE` set, which VS Code and Claude Code do. Put `env -u ELECTRON_RUN_AS_NODE` in front of the command on a Mac. The command line article covers Windows.










----------------------------------------------------------
Section 3: Controlling Incisor from the Command Line
----------------------------------------------------------


Title: Controlling Incisor from the Command Line
Type: Tutorial
Published: 2026-11-04
URL: https://www.incisordev.com/articles/incisor-command-line/index.html
Tags: cli, automation, publishing, settings, api
Keywords: command line, terminal, CLI, headless, build script, continuous integration, AI agent, enableCLI, --cli, --cli-file, --output, timeoutSeconds, getSessionInfo, publish, openProject, focusTab, getInspectorScreenShot, getProjectScreenShot, runNceScript, nce.saveProjectScreenShot, nce.saveInspectorScreenShot, nce.publishing.publishProject, prePublish, postPublish, exit codes, error codes, cliDisabled, badCommand, unknownCommand, missingArgument, notOpen, notRunning, alreadyOpen, notAProject, notVerified, projectBusy, publishFailed, openFailed, scriptError, actionFailed, timeout, noResponse, unavailable, notReady, internalError, ELECTRON_RUN_AS_NODE, jq
Summary: The complete reference for the Incisor command line: turn it on, run commands on Mac and Windows, read the JSON answer, and use every command, exit code, error code and timeout. Written for people, scripts and AI agents.

Publish a project, open it, take a screenshot, or run a script in the inspector, all from a terminal, a build script, or an AI agent. Each command gets one JSON answer and an exit code, so anything that can run a program can drive Incisor.

## Controlling Incisor from the Command Line: The short version

Incisor accepts one command at a time from the command line, whether it's open or closed. You run the Incisor executable with `--cli` and one JSON object. It waits until the command is done, prints one JSON answer on stdout, and exits with a code.

The command line isn't part of the Incisor API documentation, so this page is the full reference for it. There are seven commands:

Command | Does | Works with Incisor closed | Default timeout
`getSessionInfo` | Returns the application settings and the open projects. | Yes | 15 s
`publish` | Publishes a project with a named configuration. | Yes | 1800 s
`openProject` | Opens a project in a tab. | Yes, and Incisor stays open | 60 s
`focusTab` | Brings a project's tab and the window forward. | No | 10 s
`getInspectorScreenShot` | Saves an image of a project's whole tab. | No | 30 s
`getProjectScreenShot` | Saves an image of a running project. | No | 30 s
`runNceScript` | Runs a script inside an open project's inspector. | No | 30 s

A `publish` command on a Mac and its answer, filtered with `jq`. `ok` is true, and `result` holds the publish summary.

## Controlling Incisor from the Command Line: Before you start

#### Incisor 2026.11.05.00.00.00 or later

The command line isn't available in earlier versions. Use Incisor menu → Check for Updates to update.

#### A logged-in user

`publish` and `openProject` need a verified user, so Incisor must have been logged in and its key must still be valid.

Warning: Know the risk. Once the command line is on, any program on your computer, including programs run by other user accounts, can issue these commands. A script can do anything the open project can do. Turn it on only on a machine you trust.

## Controlling Incisor from the Command Line: 1 · Turn on the command line

The command line is off by default. It's controlled by one application setting, `enableCLI`, in the security group.
1. Open Incisor menu → Application Settings...
2. In the security group, turn on `enableCLI`.
`enableCLI` is in the security group, below `allowEditorDebugging`.
3. Confirm the prompt, which reads: "By enabling this feature, you agree to assume responsibility for all of the associated risks. Do you wish to continue?"

The setting takes effect immediately, with no restart. Every command is recorded in the Incisor log and in the shell log when it's received, whether or not it's then allowed to run.

## Controlling Incisor from the Command Line: 2 · Run a command

Run the Incisor executable with one of these flags:

Flag | Does
`--cli <json>` | Runs the command given as one JSON object.
`--cli-file <path>` | Runs the command held in a file. Best for long scripts, and on Windows.
`--output <path>` | Also writes the answer to a file.

The JSON object always has a `command` name, plus that command's arguments. Any command can also take `timeoutSeconds`.

### Running a command on a Mac

The default location is `/Applications/Incisor.app/Contents/MacOS/Incisor`. Incisor can be dragged anywhere, so if yours isn't in Applications, use the same path inside your own copy of `Incisor.app`. Run this executable directly, because `open` starts a second app instead.

Mac terminal

```
/Applications/Incisor.app/Contents/MacOS/Incisor --cli '{"command":"getSessionInfo"}'
```

### Running a command on Windows

The default location is `%LOCALAPPDATA%\Programs\Incisor\Crimson\Incisor.exe`. The `Crimson` folder is named after the version set. The installer also lets you pick another folder. If you did, right-click the Incisor Crimson Start Menu shortcut and choose Open file location.

Put the command in a file and read the answer from `--output`, since a desktop program's stdout isn't shown by every terminal.

command.json

```
{ "command": "getSessionInfo" }
```

Windows cmd

```
"%LOCALAPPDATA%\Programs\Incisor\Crimson\Incisor.exe" --cli-file command.json --output answer.json
```

Windows PowerShell

```
& "$env:LOCALAPPDATA\Programs\Incisor\Crimson\Incisor.exe" --cli-file command.json --output answer.json
```

Backslashes in a JSON file must be doubled, as in `"C:\\Users\\you\\Desktop\\MyProject"`.

### Project paths

`projectPath` is the folder of the project. Relative `projectPath` and `outputPath` values work, and are taken from the folder the command was issued in.

A `~` inside single quotes isn't expanded by the shell, so build a home-based path from `$HOME` instead. The quotes close around `"$HOME"` and then reopen:

Mac terminal

```
/Applications/Incisor.app/Contents/MacOS/Incisor --cli '{"command":"publish","projectPath":"'"$HOME"'/Desktop/MyProject","configName":"LocalDev"}'
```

## Controlling Incisor from the Command Line: 3 · Read the answer

Every command answers with one JSON object. The answer is only what's on stdout or in the `--output` file. Ignore stderr, which carries a `DevTools listening on ws://127.0.0.1:<port>/...` line whenever the editor debugging port is on.

Field | Holds
`docFormatVersion` | The version of this answer format, currently `1`.
`ok` | `true` if the command worked, `false` if it failed.
`command` | The name of the command.
`result` | What the command returned. Only present when `ok` is true.
`error` | An object with `code` and `message`. Only present when `ok` is false.
`logs` | Lines logged while the command ran. These can include lines from other activity.

A command that worked

```
{ "docFormatVersion": 1, "ok": true, "command": "focusTab", "result": { "focused": true }, "logs": [ "..." ] }
```

A command that failed

```
{ "docFormatVersion": 1, "ok": false, "command": "focusTab", "error": { "code": "notOpen", "message": "The project is not open: /Users/you/Desktop/MyProject" }, "logs": [ "..." ] }
```

Warning: Check `error`, not just `result`. On a failure, `error` replaces `result`, so a filter such as `jq '{ok, command, result}'` hides the reason. Include `error` in the filter.

A good everyday pattern on a Mac drops stderr and keeps the fields that matter:

Mac terminal

```
/Applications/Incisor.app/Contents/MacOS/Incisor --cli '{"command":"focusTab","projectPath":"'"$HOME"'/Desktop/MyProject"}' 2>/dev/null | jq '{ok, command, result, error}'
```

An `--output` file is written whole, so a script never reads half of an answer.

## Controlling Incisor from the Command Line: Exit codes

Code | Meaning | Error codes
`0` | The command worked. | None
`1` | The command failed. | Every code not listed in the rows below, including `timeout`
`2` | The command line is turned off. | `cliDisabled`
`3` | Incisor gave no answer or wasn't ready. | `noResponse`, `unavailable`, `notReady`

## Controlling Incisor from the Command Line: Error codes

When `ok` is false, `error.code` is one of these, and `error.message` gives the detail.

Code | Exit | Meaning | What to do
`cliDisabled` | 2 | `enableCLI` is off. | Turn it on in Application Settings.
`badCommand` | 1 | Invalid JSON, an unreadable command file, or no `command` name. | Fix the JSON or the file path.
`unknownCommand` | 1 | The name isn't one of the seven commands. | Check the spelling, which is case-sensitive.
`missingArgument` | 1 | A required argument is missing or empty. | `error.message` names it.
`notOpen` | 1 | The project isn't open, or Incisor is closed. | Run `openProject` first.
`notRunning` | 1 | `getProjectScreenShot` was run on a project that's open but not running. | Run the project, then try again.
`alreadyOpen` | 1 | `openProject` was run on an open project. | Carry on, since the project is ready. Use `focusTab` to bring it forward.
`notAProject` | 1 | `publish` was given a path that isn't a valid project. | Point `projectPath` at the project's folder.
`notVerified` | 1 | The user isn't verified. | Open Incisor and log in.
`projectBusy` | 1 | A publish of this project is underway, or assets were still processing when time ran out. | Wait, then try again, with a longer `timeoutSeconds` if needed.
`publishFailed` | 1 | The publish reported an error. | Read `error.message`.
`openFailed` | 1 | The project couldn't be opened. | Read `error.message`.
`scriptError` | 1 | A `runNceScript` script failed. | Read `error.message` and fix the script.
`actionFailed` | 1 | The window couldn't focus the tab or take the screenshot. | Read `error.message`.
`timeout` | 1 | `focusTab`, `getInspectorScreenShot`, `getProjectScreenShot` or `runNceScript` ran out of time. | It may still finish. Check before running it again.
`noResponse` | 3 | No answer arrived within `timeoutSeconds` plus 20 seconds. | It may still finish. Check before running it again.
`unavailable` | 3 | Incisor isn't running, or stopped before the command finished. | Try again.
`notReady` | 3 | Incisor didn't finish starting up within 120 seconds. | Try again.
`internalError` | 1 | The command failed unexpectedly. | Read `error.message` and `logs`.

## Controlling Incisor from the Command Line: Timeouts

Each command has its own time limit in seconds, shown in the table at the top of this page. Add `timeoutSeconds` to any command to change it:

command.json

```
{ "command": "runNceScript", "projectPath": "/Users/you/Desktop/MyProject", "script": "return 6 * 7;", "timeoutSeconds": 120 }
```

A command that times out may still finish in Incisor. Before you run it again, check whether the work was done.

## Controlling Incisor from the Command Line: Commands

Every command that names a project takes `projectPath`, the folder of the project. All examples use `/Users/you/Desktop/MyProject`. In the longer answers, `"..."` marks what was cut.

### getSessionInfo

Returns the application settings and the projects that are open.

Detail | Value
Arguments | None
Needs | Nothing. Works with Incisor open or closed.
Default timeout | 15 seconds
Result | `applicationSettings` and `openProjects`
Each open project | `projectPath`, `projectName`, `isRunning`, `projectSettings`

This answer is long. It holds the full `projectSettings` of every open project, about 450 lines each, so filter it before putting it in a prompt. See Common workflows below for a filter.

Command

```
{ "command": "getSessionInfo" }
```

Answer (abbreviated)

```
{
  "docFormatVersion": 1,
  "ok": true,
  "command": "getSessionInfo",
  "result": {
    "applicationSettings": {
      "docFormatVersion": 0,
      "incisorVersion": "2026.11.04.11.13.35",
      "language": "en",
      "logs": { "verbosity": "high", "entryCharLimit": 500 },
      "maxUndoStates": 500,
      "connectionPorts": [8000, 8001, 8002, "..."],
      "colorTheme": "Default",
      "customColorThemes": [{ "name": "...", "colors": "..." }, "..."],
      "maxThreads": 8,
      "refreshOnCodeChange": true,
      "runProjectOnOpen": false,
      "stopProjectOnException": true,
      "security": {
        "allowUniversalFileIO": true,
        "allowExternalExecutableProcesses": true,
        "allowEditorDebugging": true,
        "editorDebuggingPort": 9222,
        "enableCLI": true,
        "allowRemoteHosting": false
      },
      "...": "..."
    },
    "openProjects": [
      {
        "projectPath": "/Users/you/Desktop/MyProject",
        "projectName": "MyProject",
        "isRunning": false,
        "projectSettings": {
          "publicProjectName": "MyProject",
          "projectCodeName": "MyProject",
          "latestIncisorVersionSetUsed": "Crimson",
          "latestIncisorVersionUsed": "2026.11.04.11.13.35",
          "usingTypescript": true,
          "devModeConfiguration": "LocalDev",
          "configurations": {
            "LocalDev": { "publishIndexFile": true, "...": "..." },
            "EgmSingleScreenPublish": "...",
            "EgmDualScreenPublish": "..."
          },
          "screenShotDestination": "ScreenShots",
          "...": "..."
        }
      }
    ]
  },
  "logs": [
    "74 CLI: Command line command received: {\"command\":\"getSessionInfo\",\"timeoutSeconds\":15}",
    "75 CLI: Command line command 'getSessionInfo' succeeded."
  ]
}
```

The names under `configurations` are the values `publish` accepts for `configName`.

### publish

Publishes the project with the named configuration. It waits for any asset processing that's already underway.

Detail | Value
Arguments | `projectPath`, `configName`
Needs | A verified user. Works with Incisor open or closed, and with the project open or not.
Default timeout | 1800 seconds
Result | `result`, `hostedPort`, `publishTimeStamp`, `destinationDirectory`
Errors | `missingArgument`, `notVerified`, `notAProject`, `projectBusy`, `publishFailed`, `noResponse`

In the result, `hostedPort` is `-1` when nothing is hosted, and `destinationDirectory` is the folder holding the published build.

Command

```
{ "command": "publish", "projectPath": "/Users/you/Desktop/MyProject", "configName": "LocalDev" }
```

Answer (abbreviated)

```
{
  "docFormatVersion": 1,
  "ok": true,
  "command": "publish",
  "result": {
    "result": "project publishing complete.",
    "hostedPort": -1,
    "publishTimeStamp": "2026.11.04.11.51.42",
    "destinationDirectory": "/Users/you/Desktop/MyProject/Publishing/Builds/2026.11.04.11.51.42_LocalDev"
  },
  "logs": [
    "76 CLI: Command line command received: {\"command\":\"publish\",\"projectPath\":\"/Users/you/Desktop/MyProject\",\"configName\":\"LocalDev\",\"timeoutSeconds\":1800}",
    "...",
    "101 CLI: Command line command 'publish' succeeded."
  ]
}
```

If the project wasn't open, `publish` opens it without a tab, doesn't add it to your recent projects, and closes it again afterward.

Warning: `publish` skips two things. The `prePublish` and `postPublish` events that extensions listen for don't fire, because they belong to the inspector, and the published project isn't hosted. If you need the events, see Publishing with events below.

### openProject

Opens the project in a tab, starting Incisor if it's closed.

Detail | Value
Arguments | `projectPath`
Needs | A verified user. The project must not already be open.
Default timeout | 60 seconds
Result | `projectPath`, `pageUrl`
Errors | `missingArgument`, `notVerified`, `alreadyOpen`, `openFailed`, `noResponse`

Command

```
{ "command": "openProject", "projectPath": "/Users/you/Desktop/MyProject" }
```

### focusTab

Brings the project's tab and the window forward.

Detail | Value
Arguments | `projectPath`
Needs | Incisor open, and the project open.
Default timeout | 10 seconds
Result | `focused`, which is `true`
Errors | `missingArgument`, `notOpen`, `actionFailed`, `timeout`

Command

```
{ "command": "focusTab", "projectPath": "/Users/you/Desktop/MyProject" }
```

### getInspectorScreenShot

Focuses the project's tab and saves an image of the whole tab as a PNG.

Detail | Value
Arguments | `projectPath`, and optionally `outputPath`
Needs | Incisor open, and the project open.
Default timeout | 30 seconds
Result | `path`, `width`, `height`
Errors | `missingArgument`, `notOpen`, `actionFailed`, `timeout`

With no `outputPath`, the image goes in a temporary folder. Read `path` in the result to find it.

Command

```
{ "command": "getInspectorScreenShot", "projectPath": "/Users/you/Desktop/MyProject", "outputPath": "/Users/you/Desktop/inspector.png" }
```

### getProjectScreenShot

Brings the project's tab and the window forward, then saves an image of the project's main render target as a PNG.

Detail | Value
Arguments | `projectPath`, and optionally `outputPath`
Needs | Incisor open, and the project open and running.
Default timeout | 30 seconds
Result | `path`, which is absolute, plus `width` and `height`
Errors | `missingArgument`, `notOpen`, `notRunning`, `actionFailed`, `scriptError`, `timeout`

With no `outputPath`, the image goes to the folder set by `screenShotDestination` in Project Settings, which is `ScreenShots` in the example above. An `outputPath` outside the project's folders needs `allowUniversalFileIO`, since the project's own file rules apply.

Command

```
{ "command": "getProjectScreenShot", "projectPath": "/Users/you/Desktop/MyProject" }
```

### runNceScript

Runs a script inside the open project's inspector, with `nce` available as it is in extensions. The script may use `await`, and may `return` a value.

Detail | Value
Arguments | `projectPath`, `script`
Needs | Incisor open, and the project open.
Default timeout | 30 seconds. Raise it for anything slow.
Result | `value` if the script returns a value. Otherwise `result` is empty.
Errors | `missingArgument`, `notOpen`, `scriptError`, `timeout`
- `nc` and `pr` aren't available, the same as in extensions. Those two names are reserved, so a script can't declare variables called `nc` or `pr` either.
- To reach the running project, use `nce.projectNC` (the project's `nc`) and `nce.projectPR` (the project's `pr`).
- The script is limited by the same settings that limit extensions, such as `allowUniversalFileIO` and `allowExternalExecutableProcesses`.
- Inside JSON, a script's double quotes must be written `\"` and its line breaks `\n`, so `--cli-file` is easier for long scripts.

Command

```
{ "command": "runNceScript", "projectPath": "/Users/you/Desktop/MyProject", "script": "return 6 * 7;" }
```

Answer

```
{ "docFormatVersion": 1, "ok": true, "command": "runNceScript", "result": { "value": 42 }, "logs": [ "..." ] }
```

Answer when the script returns nothing

```
{ "docFormatVersion": 1, "ok": true, "command": "runNceScript", "result": { }, "logs": [ "..." ] }
```

## Controlling Incisor from the Command Line: Publishing with events

To publish an open project and fire the `prePublish` and `postPublish` events, use `runNceScript` and trigger them around `nce.publishing.publishProject`, which is what the inspector does itself. Replace `"Web"` with the name of your configuration.

Script

```
const info = { configurationName: "Web", proceedWithPublishing: true, hostPublishedProject: false };
await nce.appEvents.prePublish.asyncTrigger(info);
let summary;
if(info.proceedWithPublishing)
{
    const response = await nce.publishing.publishProject(info.configurationName, info.hostPublishedProject);
    summary = response.payload;
    await nce.appEvents.postPublish.asyncTrigger({ configurationName: info.configurationName, publishTimeStamp: summary.publishTimeStamp, destinationDirectory: summary.destinationDirectory, hostedPort: summary.hostedPort });
}
return summary;
```

- Give it a long `timeoutSeconds`. The default for a script is only 30 seconds.
- Keep the `proceedWithPublishing` check. A `prePublish` callback can set it to false to stop the publish. The script then returns nothing, so `result` is empty.
- Read the summary from `result.value`. It holds the same fields as the `publish` result.

Here's the same script as a complete command, ready for `--cli-file`:

command.json

```
{
  "command": "runNceScript",
  "projectPath": "/Users/you/Desktop/MyProject",
  "timeoutSeconds": 1800,
  "script": "const info = { configurationName: \"Web\", proceedWithPublishing: true, hostPublishedProject: false };\nawait nce.appEvents.prePublish.asyncTrigger(info);\nlet summary;\nif(info.proceedWithPublishing)\n{\n    const response = await nce.publishing.publishProject(info.configurationName, info.hostPublishedProject);\n    summary = response.payload;\n    await nce.appEvents.postPublish.asyncTrigger({ configurationName: info.configurationName, publishTimeStamp: summary.publishTimeStamp, destinationDirectory: summary.destinationDirectory, hostedPort: summary.hostedPort });\n}\nreturn summary;"
}
```

## Controlling Incisor from the Command Line: Screenshots from a script

For a plain image of a running project, `getProjectScreenShot` is the simplest choice, and `getInspectorScreenShot` captures the whole tab. For camera renderings, or to save screenshots as part of a larger script, use `runNceScript` with these functions. The project has to be running.

Function | Saves
`nce.saveProjectScreenShot(path, isPathRelative)` | A screenshot of the project.
`nce.saveInspectorScreenShot(path, isPathRelative)` | A screenshot of the entire inspector.
- `path` is optional. If you leave it out, the `screenShotDestination` value in Project Settings is used.
- `isPathRelative` is optional. Set it to `true` if `path` is relative to the project.
- Both functions return the path of the screenshot, so return that from your script to get it back as `value`.

Command

```
{ "command": "runNceScript", "projectPath": "/Users/you/Desktop/MyProject", "script": "return await nce.saveProjectScreenShot(\"ScreenShots/title.png\", true);" }
```

## Controlling Incisor from the Command Line: Common workflows

### Using the command line from an AI agent or a script
1. Run `getSessionInfo`, and filter the answer. If it fails with `cliDisabled`, ask the user to turn on `enableCLI`.
2. Find the project in `openProjects`. If it's not there, run `openProject`.
3. Run the commands you need, one at a time.
4. After each one, check `ok` and the exit code, and read `error` on a failure.
5. After a `timeout` or `noResponse`, check whether the work was done before you run the command again.

To have an agent run, see, click, type in and check a project, read the FAQ How can I have AI test my Incisor project? in FAQs & Tutorials at incisordev.com.

### Listing open projects and their configurations

This filter cuts `getSessionInfo` down to what a prompt needs, and keeps `error`:

Mac terminal

```
/Applications/Incisor.app/Contents/MacOS/Incisor --cli '{"command":"getSessionInfo"}' 2>/dev/null | jq '{ok, error, projects: [.result.openProjects[]? | {projectPath, isRunning, configurations: (.projectSettings.configurations // {} | keys)}]}'
```

### What happens when Incisor is closed
- `focusTab`, `getInspectorScreenShot`, `getProjectScreenShot` and `runNceScript` need a window, so they fail with `notOpen`.
- `openProject` starts Incisor and leaves it open.
- `getSessionInfo` and `publish` start Incisor with no window, and it quits when the command is done.

## Controlling Incisor from the Command Line: Troubleshooting

### bad option: --cli, with exit code 9

The `ELECTRON_RUN_AS_NODE` environment variable is set, which makes the executable behave as Node instead of Incisor. VS Code's terminal and anything launched from a program built on Electron set it, including Claude Code in VS Code. Remove it for the command:

Mac terminal

```
env -u ELECTRON_RUN_AS_NODE /Applications/Incisor.app/Contents/MacOS/Incisor --cli '{"command":"getSessionInfo"}'
```

Windows cmd

```
set ELECTRON_RUN_AS_NODE=
```

Windows PowerShell

```
Remove-Item Env:ELECTRON_RUN_AS_NODE
```

### A command hangs, or a second Incisor starts

The command went to a different copy of Incisor than the one that's open, for example `/Applications/Incisor.app` when the running copy is on the Desktop. Always use the executable inside the copy that's running. On a Mac, this shows which one that is:

Mac terminal

```
pgrep -fl "Incisor.app/Contents/MacOS/Incisor"
```

### The answer is from the previous command

An old answer file was still at the `--output` path. Delete it before each command, or use a new file name each time.

### cliDisabled, with exit code 2

Turn on `enableCLI` in the security group of Application Settings.

### ok is false and result is missing

That's expected on a failure. Read `error` instead, and if you're filtering with `jq`, add `error` to the filter.

### A DevTools line appears in the output

That line is on stderr, and it appears whenever the editor debugging port is on. Ignore it, or drop it with `2>/dev/null` on a Mac.

### A path starting with ~ isn't found

A `~` inside single quotes isn't expanded. Build the path from `$HOME`, as shown in Project paths above.

For the `nce` functions you can call from a script, see the Incisor documentation at incisordev.com, under Documentation.










----------------------------------------------------------
Section 4: Can I debug my project from my code editor?
----------------------------------------------------------


Title: Can I debug my project from my code editor?
Type: FAQ
Published: 2026-10-27
URL: https://www.incisordev.com/articles/debugging-from-your-code-editor/index.html
Tags: debugging, vs code, webstorm, typescript, settings
Keywords: debugger, breakpoint, attach, launch.json, tasks.json, allowEditorDebugging, editorDebuggingPort, 9222, source maps, WebStorm, call stack, stopProjectOnException, runProjectOnOpen, TypeScript check, problems panel
Summary: Turn on editor debugging, attach VS Code or WebStorm to a running Incisor project, and step through your own TypeScript or JavaScript with breakpoints, variables, and the call stack.

Set a breakpoint in your own TypeScript or JavaScript, press a key in your game, and land right on that line with your variables and call stack in front of you, all without leaving your editor.

Short answer:

Yes. Incisor can open a debugging port on your computer. Turn on `allowEditorDebugging` in Application Settings, restart Incisor, and attach your editor to that port. For VS Code, Incisor even writes the attach configuration for you.

## Can I debug my project from my code editor?: Before you start

#### Incisor 2026.10.26.15.33.40 or later

Editor debugging isn't available in earlier versions. Use Incisor menu → Check for Updates to update.

#### Source maps on

Your breakpoints map to your own files through source maps. In Project Settings, keep `generateSourceMaps` on, and turn `removeComments` and `removeWhiteSpace` off for the configuration you're running.

Whitespace removal must be off for now. Soon, whitespace removal will only happen when you publish, and this requirement will go away.

Warning: Know the risk. The debugging port is only open to your own computer, but any program on that computer, including programs run by other user accounts, can connect to it and run code inside your projects. Turn it on only on a machine you trust, and turn it off when you're done debugging.

## Can I debug my project from my code editor?: 1. Turn on editor debugging

This step is the same whichever editor you use.

Incisor menu → Application Settings...

The security group holds both debugging settings.
1. Open Application Settings from the Incisor menu (the logo at the far left of the menu bar).
2. Under security, tick `allowEditorDebugging`. Incisor asks you to confirm that you accept the risks. Choose Yes.
3. Leave `editorDebuggingPort` at 9222 unless another program on your computer already uses that port. Any whole number from 1024 to 65535 works.
4. Press Save and Restart. Both settings take effect only when Incisor starts. Save and Refresh keeps Incisor running and applies them the next time it starts.

## Can I debug my project from my code editor?: 2. Connect your editor

Every editor connects to the same port. Only the setup is different.

### VS Code

When you open a project with editor debugging on, Incisor adds an Attach to Incisor configuration to the project's `.vscode/launch.json`. All you have to do is start it.
1. Open the project folder in VS Code (the folder itself, not a parent folder), so VS Code finds the project's `.vscode` folder.
2. Go to Run and Debug, choose Attach to Incisor from the dropdown, and press the green play button (or F5).
3. VS Code lists the open Incisor tabs. Pick your project, not the Control Center.
4. Click in the gutter to set a breakpoint in one of your files, then run the code that reaches it.

Paused on a breakpoint in `ProjectMain.ts`. The Variables and Call Stack panels show your own TypeScript, not compiled output.

### What Incisor writes for you

- launch.json: the Attach to Incisor entry is kept current by Incisor, including your port and the source-map paths for your files. Any other configurations you add are left alone.
- tasks.json (TypeScript projects): an Incisor TypeScript Check task runs when you open the folder and keeps watching your files. Type errors appear in the Problems panel as you work. Your own tasks are left alone too.

The TypeScript Check task catches a typo before you even run the project.

### WebStorm

WebStorm attaches with its built-in Attach to Node.js/Chrome configuration. You set it up once per project.
1. Open the project folder in WebStorm.
2. Choose Run → Edit Configurations...
3. Press + and choose Attach to Node.js/Chrome. Give it a name such as Incisor, leave Host as `localhost`, and set Port to your `editorDebuggingPort` (9222 by default). Leave everything else as it is and press OK.
4. Select Incisor in the run configuration dropdown and press the Debug button (the bug), or choose Run → Debug 'Incisor'. WebStorm lists the Incisor pages. Pick your project, not the Control Center or the tab bar.
5. Click in the gutter to set a breakpoint in one of your files, then run the code that reaches it.

Paused on a breakpoint in `ProjectMain.ts`, with the call stack and variables in Threads & Variables.

Incisor doesn't write this configuration for you, as it does for VS Code. If you change `editorDebuggingPort`, update the port here too.

### Incisor's console, in WebStorm

While attached, the Console tab of the Debug window shows your project's console output, including the TypeScript errors Incisor reports.

## Can I debug my project from my code editor?: Good to know

### Projects open stopped (by default), so press Run

Nothing runs until you press Run in Live View, which gives you time to attach and set breakpoints before your startup code runs. To have projects start running as soon as they open, turn on `runProjectOnOpen` in Application Settings.

### Choosing `stopProjectOnException`

This Application Setting decides what happens when your code throws an error:

#### On

Incisor stops the project at the error. This keeps the Incisor inspector running smoothly, so it's a good everyday setting.

#### Off

The project keeps running past the error, so you can watch what happens next in your debugger. Use this to track down the trickier bugs.

## Can I debug my project from my code editor?: Troubleshooting

### “Editor debugging port in use”

Incisor shows this when another program already holds the port. Your editor can't attach until Incisor opens its own port. Pick a different `editorDebuggingPort` in Application Settings and restart Incisor. In VS Code, the Attach to Incisor configuration picks up the new port automatically.

### No “Attach to Incisor” in VS Code
- You're on Incisor 2026.10.26.15.33.40 or later.
- `allowEditorDebugging` is on and Incisor has been restarted since you turned it on.
- Source maps are on: `generateSourceMaps` on, `removeComments` and `removeWhiteSpace` off.
- You've opened the project in Incisor since then (that's when the configuration is written), and VS Code has the project folder itself open.

### Breakpoints don't get hit
- You picked your project's tab, not the Control Center.
- The project is running (press Run in Live View).
- Source maps are on, as above.

### My port setting was ignored

The port must be a whole number from 1024 to 65535. Anything else falls back to 9222.










----------------------------------------------------------
Section 5: Can particle emission follow a path?
----------------------------------------------------------


Title: Can particle emission follow a path?
Type: FAQ
Published: 2026-10-02
URL: https://www.incisordev.com/articles/particle-emission-that-follows-a-path/index.html
Tags: particles, expressions, effects, downloads
Keywords: particle system, emitterPosition, trail, follow object, track, trajectory, emission, GLSL, EffectController, EffectNode, uniform, emissionTime, comet, sparkle trail
Summary: Make particles trail along a path or behind a moving object with emitterPosition expressions and EffectControllers, without losing the speed of the GPU particle system. Includes two downloadable example projects.

Say you want sparkles trailing a coin as it flies across the screen, or a comet tail behind a moving object. Here's how to do it with Incisor's GPU particle system, plus two example projects you can download.

Short answer:

Yes. Don't move the ParticleSystem itself. Move the emitter, by giving the definition's `emitterPosition` an expression that describes the path over time. To change that path at runtime, feed the expression its values through an EffectController.

## Can particle emission follow a path?: Why it works this way

Incisor's particle system runs entirely on the GPU. That's what makes it so fast:

#### Thousands, cheaply

Every particle is calculated on the graphics card, so the CPU never touches individual particles.

#### Shared definitions

Many ParticleSystems can use one definition, which saves memory and setup time.

#### Driven by time

Each particle's state is worked out from time, so a system plays back the same way every time and can be scrubbed on its timeline.

The trade-off is that most of a definition's settings are locked in when the system is built. Changing one at runtime triggers a costly rebuild, and the result looks as if the system always had the new value. It doesn't animate from the old value to the new one.

What you can do is make a setting an expression: a small piece of GLSL that the GPU evaluates for each particle. An expression can depend on time, which is all you need to move the emitter along a path.

## Can particle emission follow a path?: The tempting approach (and why it fails)

The obvious move is to put the ParticleSystem on the moving object, or swoop it along the path. But every particle lives in its ParticleSystem's space, so moving the system drags along every particle it has already emitted. Instead of a trail you get a cloud that slides around with the object:

Moving the system:
The ParticleSystem is swooped along with the logo. No trail forms.

Moving the emitter:
The emitter moves along the path, and particles stay where they were emitted.

## Can particle emission follow a path?: 1. A fixed path

In the Particle System panel, open Emission → emitterPosition, set its type to Expression, and write the path as a function of `emissionTime`, the moment each particle is emitted. Assign the result to `value`.

The Static example: a double S drawn top to bottom over 3 seconds.

emitterPosition expression

```
// 0 to 1 over the 3-second emission
float sT = clamp(emissionTime / 3.0, 0.0, 1.0);

// x: two full side-to-side swings (4π)   y: top of the screen to the bottom
value = vec2(sin(sT * 12.56637061) * 260.0, mix(380.0, -380.0, sT));
```

Because the GPU works out each particle's start point from its own emission time, earlier particles stay exactly where they were emitted, and the trail forms naturally.

### Keeping another object on the emitter

The example's logo rides the emitter by running the same formula in JavaScript, driven by the ParticleSystem's own clock so the two can't drift apart:

ProjectMain.js (excerpt)

```
this.particles.playbackController.addTimeUpdateCallback(this, "moveLogoToEmitter");

moveLogoToEmitter(time) {
    let t = Math.min(Math.max(time / 3, 0), 1);
    this.logo.position.x = Math.sin(t * 2 * 2 * Math.PI) * 260;
    this.logo.position.y = 380 - (t * 2 * 380);
}
```

Tip: The expression and the JavaScript are two copies of the same path, so if you change one, change the other.

## Can particle emission follow a path?: 2. A path you set at runtime

A fixed path is great until the start and end points depend on gameplay. Editing `emitterPosition` at runtime would trigger a rebuild, so instead give the expression a value it can read: a shader uniform, supplied by an EffectController. Writing to an EffectController is cheap, because it only updates the uniform.

The Dynamic example: change the start and end points, press Go, and the next stroke follows the new path.

### 1. Define a controller and a node that declares it

SCurvePath.codeAsset.js (trimmed)

```
let sCurvePath_def = nc.defineEffectController(
    "sCurvePath",
    nc.constants.effectControllerBaseTypes.Vector4,
    ["startX", "startY", "endX", "endY"],
    [0, 0, 0, 0],
    nc.constants.effectControllerMixModes.addition
    // ...ranges and descriptions
);

// Only declares the uniform, so the emitterPosition expression can read it
nc.defineEffectNode("SCurvePath", ["uniform vec4 sCurvePath;"], "", "", "", [sCurvePath_def]);
```

### 2. Read it in the expression

emitterPosition expression

```
float t = clamp(emissionTime / 3.0, 0.0, 1.0);
vec2 a = sCurvePath.xy;   // start point
vec2 b = sCurvePath.zw;   // end point
vec2 along = b - a;
float len = length(along);
vec2 perp = len > 0.0001 ? vec2(-along.y, along.x) / len : vec2(1.0, 0.0);

// Walk from a to b, bowing either side of the line to make the S
value = mix(a, b, t) + perp * sin(t * 12.56637061) * len * 0.3;
```

The example's expression uses longer variable names (`sCurveT`, `sCurveA`…), so they won't collide with anything else in the shader. Do the same in your own projects.

### 3. Attach it and set the values

ProjectMain.js (excerpt)

```
const def = nc.particleSystemDefs.MyNewParticleSystemDefinition;
this.particles = nc.addParticleSystem(def, nc.mainScene, "MovingEmitterParticles");

// addEffectNodes, not setEffectNodes, so the particle node stays in place
this.particles.addEffectNodes(nc.effectNodes.SCurvePath);

// Each new stroke: write the endpoints, then play
this.particles.sCurvePath.startX = startX;
this.particles.sCurvePath.startY = startY;
this.particles.sCurvePath.endX = endX;
this.particles.sCurvePath.endY = endY;
this.particles.playbackController.playOnce();
```

The SCurvePath node and its sCurvePath controller in the Object panel.

Select the ParticleSystem and you can inspect the values live in the Object panel, under Material Info → EffectControllers → sCurvePath.

Warning: Set the path, then leave it alone. The expression runs for every particle, every frame, so changing the uniform mid-stroke moves particles that are already in flight. That's why the example copies the fields into the controller only when you press Go.

## Can particle emission follow a path?: Coming soon

### New particle system functionality is on the roadmap
- Direct object tracking: emission that follows other objects directly, with no path expressions needed.
- Expanded 3D particle capability.
- Sprite-animated particles.

Until then, the expression approach above works today, and keeps all the speed of the GPU system.

## Can particle emission follow a path?: Downloads

Both examples are complete Incisor projects. Unzip one and open the folder in Incisor.
- Static path example: An `emitterPosition` expression draws a fixed double S, with a logo riding the emitter. (download: ParticleSystemEmissionExpressionExample-Static.zip)
- Dynamic path example: Adds an EffectNode and EffectController, so you can set the start and end points at runtime. (download: ParticleSystemEmissionExpressionExample-Dynamic.zip)










----------------------------------------------------------
Section 6: FlowControllers & FlowStates
----------------------------------------------------------


Title: FlowControllers & FlowStates
Type: Tutorial
Published: 2026-09-29
URL: https://www.incisordev.com/articles/flowcontrollers-and-flowstates/index.html
Tags: flow, api, gui, architecture, debugging
Keywords: FlowController, FlowState, FlowStateElement, defineFlowController, nc.flows, addElement, addPause, setToCurrentState, currentFlowState, state machine, game loop, Flows panel, slot template, server wait
Summary: Organize your game's phases (intro, idle, play, results) as timed FlowStates, wait on players and servers with pauses, and watch every step live in the Flows panel. Built around the Incisor Slot Template.

Every game moves through phases: intro, idle, play, results. A FlowController is a good way to organize those phases. It keeps track of which one you're in, and runs each one as a FlowState: a timed sequence of steps that you can watch live in the Flows panel.

## FlowControllers & FlowStates: The short version

The Incisor Slot Template is a complete, working slot game that you can open from the Project Gallery inside Incisor and build your own game on. It's also a good example of FlowControllers in action, so in this article we'll be examining how the Slot Template uses them. For another example, open Botched Together, a demo game that's also in the Project Gallery.

The Slot Template runs its whole game on one FlowController, `MainGameFlow`, with five FlowStates. At any moment exactly one of them is current:
The Slot Template's game loop
`nc.flows.MainGameFlow`
- GameIntro: Title, then "press to continue"
- GameIdle: Waiting for a spin
- StartGame: Place the bet
- SpinReels: Spin, wait for the outcome, stop
- WinCelebration: Show the wins
then back to GameIdle

Each state is a small class with a list of timed steps. When a state finishes its job, it makes the next state current. The result is the game's whole flow, readable from a folder of files and visible play by play in the GUI.

## FlowControllers & FlowStates: Core concepts

#### FlowController

A named manager that holds FlowStates and knows which one is current. Most games can use one, and you can make as many as you like.

#### FlowState

A class that extends `FlowState`. It has its own clock, which starts at 0 every time the state becomes current.

#### Elements

Timed calls to the state's own methods: "at 0.2 seconds, run `highlightWin`".

#### Pauses

A special element that holds the clock until its method returns `true`. Use one for player input, server replies, anything you have to wait for.

There are no transition tables to maintain. A state moves the game on by calling `setToCurrentState()` on the next state, from one of its own elements or from anywhere else in your code.

## FlowControllers & FlowStates: 1. Set up a flow

Define the controller, add each FlowState class (not an instance), then pick the starting state. This is the Slot Template's `ProjectMain.init`:

ProjectMain.js

```
nc.defineFlowController("MainGameFlow");
nc.flows.MainGameFlow.addFlowState(GameIntro);
nc.flows.MainGameFlow.addFlowState(GameIdle);
nc.flows.MainGameFlow.addFlowState(StartGame);
nc.flows.MainGameFlow.addFlowState(SpinReels);
nc.flows.MainGameFlow.addFlowState(WinCelebration);
nc.flows.MainGameFlow.GameIntro.setToCurrentState(true);
```

Each state is then available by its class name: `nc.flows.MainGameFlow.SpinReels`. Autocomplete knows about them, and so does the Flows panel.

Tip: Keep one state per file in a `ProjectCode/FlowStates/` folder, numbered in play order (`00 GameIntro.js`, `01 GameIdle.js`…). The folder then reads like a table of contents for your game.

## FlowControllers & FlowStates: 2. Write a FlowState

Add elements in the constructor, and write the methods they call. Here's the template's intro screen, lightly trimmed:

FlowStates/00 GameIntro.js

```
class GameIntro extends FlowState {
    constructor() {
        super();
        this.userTouchedScreen = false;
        this.addElement(0, "startGameIntro");   // at 0s: show the title
        this.addPause(1, "waitForUserToTouchScreen");   // at 1s: hold until touched
        this.addElement(1.05, "playIntroOutro");   // then: fade out, move on
    }
    startGameIntro() {
        const layout = pr.gameLayout.descendantsByName;
        layout.GameIntroBackground.addReleaseCallback(this, "userTouchedScreenCallback");
        layout.GameIntroAnimation.enable();
        layout.GameIntroAnimation.timelines.Intro.playOnce();
    }
    userTouchedScreenCallback() {
        this.userTouchedScreen = true;
    }
    waitForUserToTouchScreen() {
        return this.userTouchedScreen;   // true lets the clock move again
    }
    playIntroOutro() {
        nc.flows.MainGameFlow.GameIdle.setToCurrentState();   // hand off to the next state
    }
}
```

Try it: press play and watch the clock stop at the pause until you "touch the screen".
startGameIntro 0.00
waitForUserToTouchScreen 1.00 · pause
playIntroOutro 1.05

## FlowControllers & FlowStates: 3. Wait for anything

Pauses are what make flows so handy for games that talk to a server. In the Slot Template, `SpinReels` starts the reels one after another, waits for the game outcome, then stops them one by one:

FlowStates/03 SpinReels.js (constructor)

```
this.addElement(0, "startSpin");
for (let i = 0; i < pr.symbolReels.length; i++) {
    this.addElement(.01 + .05 * i, "spinReel", i);   // start reels 0.05s apart
}
this.addPause(1.5, "waitForGameOutcome");   // hold here until the server replies
for (let i = 0; i < pr.symbolReels.length; i++) {
    this.addElement(1.51 + .2 * i, "stopReel", i);   // stop reels 0.2s apart
}
```

A slow server just means a longer hold at 1.5 seconds. The staggered starts and stops look the same every time, however long the reply takes.

The third argument to `addElement` is passed to the method, so each element calls `spinReel(i)` or `stopReel(i)` for its own reel.

### Shift groups of elements with variable offsets

Element times are fixed when you add them. To adjust timing while the game runs, give elements a variable offset: the name of a number property, passed as the fourth argument to `addElement` or `addPause`.
- Incisor adds a property with that name to the FlowState, starting at `0`.
- Each element runs at its base time plus the current value of its offsets. That total is the element's `netTime`.
- Change the property and every element that uses it moves together. Elements without it stay where they are.
- An element can use several offsets (pass an array of names), and their values add up.

The Slot Template doesn't use offsets, but its reel stops are a natural fit. Tag them with an offset called `stopDelay`:

A variation on SpinReels

```
for (let i = 0; i < pr.symbolReels.length; i++) {
    this.addElement(1.51 + .2 * i, "stopReel", i, "stopDelay");
}

// Later, for example in startSpin() when a big win is coming:
this.stopDelay = 1;   // every reel stop happens 1 second later, still 0.2s apart
```

The pause at 1.5 isn't tagged, so it doesn't move. Once the outcome arrives, the reels keep spinning for an extra second before they start to stop. Set `this.stopDelay = 0` to put the stops back at their base times.

## FlowControllers & FlowStates: 4. Watch it live

Open any panel's Panel Type menu and choose Flows. Every FlowController is listed with all its elements, in time order.

- Name - Controller rowThe controller's name, its current state and that state's clock.
- → - PointerShows where the current state's clock is. Rows in other states are dimmed.
- - FiredTicks when an element runs, then fades.
- - PauseMarks a pause element.
- ☑ - isActive / auto-scrollFreeze the controller, or keep the pointer in view.

### Where is it stuck?

When a sequence stalls, the pointer shows you where. Here the game is sitting on the intro's pause, waiting for a touch:

GameIntro 1.00: holding on `waitForUserToTouchScreen` while the game shows "Press to continue".

SpinReels 0.63: every reel has started, and the pointer is heading for the outcome pause.

Mid-spin, the reel starts have ticked and the pointer is moving toward `waitForGameOutcome`. If the server never replies, this is where it stops, and you'll see it right away.

WinCelebration, looping through the wins (more on that below).

## FlowControllers & FlowStates: More control

### React to player input by state

In the Slot Template, one spin button has three meanings. `currentFlowState` tells you which one applies:

Simplified from ProjectMain.js · mainPlayerInput()

```
const flow = nc.flows.MainGameFlow;
switch (flow.currentFlowState.name) {
    case "GameIdle":       flow.StartGame.setToCurrentState(true); break;   // spin
    case "SpinReels":      this.slamReels(); break;   // stop early
    case "WinCelebration": flow.StartGame.setToCurrentState(true); break;   // skip ahead
}
```

### Loop inside a state

In the Slot Template, `WinCelebration` cycles through the winning lines by jumping its own clock back:

FlowStates/05 WinCelebration.js

```
this.addElement(0,   "startWinCelebration");
this.addElement(.2,  "highlightWin");
this.addElement(1.1, "unhighlightWinSymbols");
this.addElement(1.2, "goToNextWin");

goToNextWin() {
    this.setTime(.1, true);   // back to just before highlightWin, for the next line
}
```

### About `performFollowupEvaluation`

`setToCurrentState()` and `setTime()` both take an optional `true`. Include `true` to evaluate the new state's elements immediately, so anything due at the new time runs right away. Otherwise, the evaluation happens on the next fixed update.

### Handy extras

On a FlowController (`nc.flows.MainGameFlow`):

Use | To
`addFlowStateChangeCallback(owner, name)` | Hear about every state change. You get the new state and the previous one. Great for analytics and logging.
`playbackRate` | Run the controller's clock faster or slower. `2` is double speed, which makes testing quicker.
`pauseImmunity` / `speedControl` | Set how the flow responds to PauseEvents and SpeedControls. You can also pass them to `nc.defineFlowController`.
`isActive` | Stop the controller's clock entirely. It's also a checkbox in the Flows panel.

On a FlowState (`nc.flows.MainGameFlow.SpinReels`, or `this` inside the state):

Use | To
`getElements()` | List the state's elements in time order. You can change an element's `time` to reorder the sequence.
`owner` | Get the FlowController the state belongs to.

## FlowControllers & FlowStates: When to use them

GAME PHASES

#### Intro, menu, play, results

The classic use. One controller, one state per phase, and the whole structure is visible at a glance.

ROUNDS

#### Bet → spin → reveal

Anything that repeats in a fixed rhythm: slot spins, card deals, turns, waves.

WAITING

#### Server and player

Pauses turn "wait for the reply" or "wait for a tap" into one line, with the timing kept on either side.

SEQUENCES

#### Celebrations and tutorials

Step-by-step presentation, such as big-win reveals, onboarding or attract loops, where timing matters and players may skip ahead.

### Tips
- Keep states focused. One phase each. If a state keeps growing, it's probably actually multiple states.
- Use a pause, not a timer, for anything asynchronous. Then the Flows panel shows exactly what you're waiting on.
- Reset in the time-0 element. The clock restarts on every entry, but your own flags (like `userTouchedScreen`) don't. Clear them in the first element.
- Leave simple animation to Timelines. A flow decides what happens next. A Construct Timeline is better for animating it.
- Keep the module in. `flowControllers` is an optional code module, so don't exclude it in Project Settings if you use flows.

## FlowControllers & FlowStates: Cheat sheet

API | Does
`nc.defineFlowController(name)` | Creates a controller, reached at `nc.flows[name]`.
`controller.addFlowState(StateClass)` | Adds a state. Its class name becomes its name.
`controller.currentFlowState` | The state that's running now.
`state.setToCurrentState(true)` | Makes this state current, and its clock restarts at 0. Include `true` for an immediate evaluation, otherwise it happens on the next fixed update.
`state.addElement(time, method, args, offsets)` | Calls `method` at `time`, plus any variable offsets.
`state.addPause(time, method, args, offsets)` | Holds the clock at `time` until `method` returns `true`.
`state.time` / `state.setTime(t, true)` | Reads or jumps the state's clock.

For full signatures, see the documentation (search `FlowController`). To see it all running, open the Incisor Slot Template and look in `ProjectCode/FlowStates/`.










----------------------------------------------------------
Section 7: Incisor Optimization Checklist
----------------------------------------------------------


Title: Incisor Optimization Checklist
Type: Tutorial
Published: 2026-09-28
URL: https://www.incisordev.com/articles/incisor-optimization-checklist/index.html
Tags: optimization, publishing, assets, performance, checklist
Keywords: download size, graphic summary, resolution scale, sprite sheet, font reduction, minification, optional code modules, assetPackageScale, soundQuality, autoRender, timelines, overdraw, masking, frame rate
Summary: The final pass before you publish: fourteen quick checks for a smaller download, faster startup and smoother frames, from sprite sheets and font reduction to update loops and overdraw.

A final pass for a smaller download, faster startup and smoother frames. Most items take a few minutes. Work from top to bottom and tick things off as you go. This page remembers your ticks.

Download, smaller and faster to start Runtime, smoother while it plays Open How on any item for the details.

Pass 1 · Assets

## Incisor Optimization Checklist: Trim the download

Make sure every graphic you ship is needed, sized right and packed well.

### 01. Review the Graphic Summary
Helps: Download, Runtime

Publish, then open Publishing Analysis → Graphic Summary… to see every graphic the build will load, grouped by loading tier.

How:

What to look for, and what to do about it:
- Graphics that aren't used: delete them, or turn off `includeWhenBuilt` in the Assets panel if you want to keep them in the project.
- Graphics larger than they ever appear on screen: lower their `resolutionScale` (03). Roll over a graphic to see its dimensions.
- Near-duplicates: keep one and reuse it, for example by flipping, tinting or scaling it in place of a second copy. Incisor already removes exact duplicates for you.
- Related graphics on the same tier that aren't on a sprite sheet: give them the same `spriteSheet` name (04).
- Large areas that never appear on screen: clear those areas to transparent in the source art. Automatic trimming then cuts them out of the shipped texture.

Roll over any graphic to see its name, dimensions and download size.

### 02. Split assets into loading tiers
Helps: Download

Move anything the first screen doesn't need into a later tier, so players can start sooner.

How:

In the Assets panel, select a folder and set Asset → loadingTier. Everything inside the folder goes to that tier. One folder per tier keeps it easy to follow.

`loadingTier` is the first setting in the Asset section.

Publishing Analysis → Asset Summary then shows what each tier contains. The first tier is the one every player waits for.

Full guide: Lazy Loading Content in Incisor →

### 03. Scale down oversized graphics at publish time
Helps: Download

Your source art stays full size. Set `resolutionScale` on an image or a folder, and the published build downloads a smaller copy instead.

How:

In the Assets panel, open Resolution → resolutionScale. A value of `0.7` ships the image at 70% of its size. Leave `applyAssetPackageScaling` on so the per-device scale from 08 still applies.

### 04. Put related graphics on sprite sheets
Helps: Download

Packing related images into one sheet lets them share a single palette, which multiplies the savings from paletted compression.

How:

In the Assets panel, open Sprite Sheet → spriteSheet and pick an existing sheet or New Sprite Sheet…. Every image with the same sheet name is packed together. Set it on a folder to pack the whole folder.

Group images that share a loading tier (this is required). Images with similar colors make the best sheets, because they share the palette well.

Pass 2 · Build settings

## Incisor Optimization Checklist: Ship only what the player needs

Most of these are checkboxes in Project Settings, under the configuration you publish.

### 05. Exclude unused code modules
Helps: Download

Optional parts of Incisor, such as sounds, particles, Spine, reels and video, only need to ship if you use them.

How:

In Project Settings → configurations → your configuration → codeInclusion → optionalCodeModulesExcluded, tick every module the project doesn't use.

Modules on the right. The tags on the left are for 06.

### 06. Keep dev-only code out of the build
Helps: Download, Runtime

Testing code, cheats and debug logging shouldn't ship to players.

How:

Put code that only you need between `CODE.includeIf___unpublished` and `CODE.includeEnd___unpublished`. For code that belongs only in some configurations, define a conditional code tag and tick it under `conditionalCodeTagsIncluded` (see the screenshot in 05).

Code that stays out of published builds

```
CODE.includeIf___unpublished;
    // testing info: never published
    console.log("TEST: spin result", this.outcome.totalWin, "lines won:", this.outcome.wins.length);
CODE.includeEnd___unpublished;

CODE.includeIf___LocalDev;
    // only in configurations with the LocalDev tag ticked
    nc.appEvents.keyboardEvent.addCallback(this, "cheatKeys");
CODE.includeEnd___LocalDev;
```

### 07. Minify and strip the source
Helps: Download, IP protection

This makes the published code smaller and harder to read.

How:

Under the configuration's publishing settings, turn on `removeComments`, `removeWhitespace` and `minification → enableMinification`. These only affect published builds. Your code in development stays exactly as you wrote it.
- Whitespace removal needs semicolons at the end of every statement. Only turn it on if every statement in your code ends with one.
- Exclude names from minification if outside code relies on them, such as RGS calls and other external integration names. Minification renames identifiers, which would break those connections. List them in `Utilities/MinificationLists/DoNotMinifyLists/DoNotMinifyList.json`, or name them with a do-not-minify prefix or suffix (`doNotMinify_` and `_doNotMinify` by default; you can change both in the `minification` settings). To protect a whole block, wrap it in `CODE.preserve___begin` and `CODE.preserve___end`.
- Keep a running do-not-minify list. Every time you use an external API (RGS, analytics, platform SDKs and so on), add its names to `DoNotMinifyList.json` right away, and carry the list from project to project. Then minification is ready to go when you publish.
- Prefer to opt in? The usual approach minifies everything and excludes a few names. For the reverse, turn off `automaticallyMinifyAllKeywords`. Then only names listed in `MinifyList.json`, or named with the minify prefix or suffix (`minify_` / `_minify` by default), get minified. It's less common, but it makes preparing for minification easier.

Warning: Minification touches almost all of your code, so test the published, minified build thoroughly. Play through the whole project and check every external integration.

### 08. Match media quality to the device
Helps: Download, Runtime

Phones don't need desktop-sized art or top-quality sound.

How:

First, list the values you want to offer in Project Settings → assetConfigurationDefinitions, separated by commas. For example, add `35` to `assetPackageScale` for a lower-resolution package.

Then, in the configuration you publish, add one `supportedAssetConfigurations` entry for each device class, picking its `assetPackageScale` and `soundQuality` from those values. The first entry is the default.

Then pick one at startup in `ProjectCode/PreloadConfiguration/PreloadConfiguration.js`. Incisor doesn't detect device classes, so that check is yours to write:

PreloadConfiguration.js

```
function preloadConfiguration(projectConfiguration)
{
    // ...keep the template's code...

    // Your own device check. The result must match an entry in supportedAssetConfigurations.
    const isSmallScreen = Math.min(screen.width, screen.height) < 500;
    if (isSmallScreen) {
        projectConfiguration.assetConfiguration.assetPackageScale = "50";
        projectConfiguration.assetConfiguration.soundQuality = "mono_55";
    }
}
```

### 09. Use phrases, then reduce fonts
Helps: Download, Localization

Fonts can ship with only the characters your text uses, for each language.

How:
1. Give each TextBox and TextAssembly a `phraseID` from the Transcript instead of a plain string.
2. In Project Settings → fontReduction, turn off `includeStandardCharactersWhenPublished`, and keep `includeTranscriptCharacters` on.
3. For characters that only appear in code-built text, like numbers and currency, add them to that font's `alwaysIncludeTheseCharacters`.

To check the result, click Font Reduction… in the Transcript panel. It lists the exact characters kept for each font in each language.

Pass 3 · Runtime

## Incisor Optimization Checklist: Keep every frame light

Anything that runs every frame adds up fast. Make sure only what the player can see, or is waiting on, is doing any work.

### 10. Audit and manage update-loop callbacks
Helps: Runtime, CPU

Every callback on `fixedUpdate` or `screenUpdate` runs every frame, whether it's needed or not.

How:

Who's listening on each frame?

```
// Every AppEvent and its active callbacks. Look for unusually long lists.
console.log(nc.getAllEventRecipients());

// The per-frame events in detail
for (const name of ["fixedUpdate", "lateFixedUpdate", "screenUpdate", "lateScreenUpdate"]) {
    console.log(name, nc.appEvents[name].getRecipients().map(r => r.callbackName));
}
```

If something is still running after its job is done, remove it with `removeCallback`.

#### Best practice: tie callbacks to the enabled state

Rather than tracking by hand when an object should be updating, let its enabled state decide. Add an enabled-state-change callback that adds or removes the object's per-frame callbacks:

The manageCallbacks pattern

```
class Sparkles extends SceneObject {
    constructor(parent, name) {
        super(parent, name);
        this.addEnabledStateChangeCallback(this, "manageCallbacks");
        this.manageCallbacks(this.isEnabledWithInheritance);   // set up for the current state
    }
    manageCallbacks(isEnabled) {
        if (isEnabled) nc.appEvents.fixedUpdate.addCallback(this, "update");
        else nc.appEvents.fixedUpdate.removeCallback(this, "update");
    }
    update() {
        // per-frame work, which only runs while Sparkles is enabled
    }
}
```

The callback fires however the enabled state changes, including when an ancestor is disabled or enabled. It receives the overall state, ancestors included. So disabling a whole screen automatically stops every object inside it that uses this pattern.

### 11. Disable what's off-screen
Helps: Runtime, CPU, GPU

Every enabled SceneObject costs CPU time on every frame, even when it can't be seen.

How:

Count the enabled objects

```
// true = count enabled objects only
console.log(nc.mainScene.getDescendants(true).length);
```

Check every Scene the game uses. Where the count is high, `disable()` whole branches that aren't visible, and `enable()` them when they are.

### 12. Stop Construct Timelines when they finish
Helps: Runtime, CPU, GPU

A Timeline left playing keeps working. If its Construct generates a Precomp, that Precomp keeps re-rendering too.

How:

Check each Timeline's `autoplayMode`: `loop` means it never stops. When an animation is done, call `stop()` or `pause()`, or use `playOnce()` for animations that should play once.

Let it rest

```
this.intro.timelines.Idle.stop();
```

### 13. Don't re-render cameras that aren't changing
Helps: Runtime, GPU

A camera with `autoRender` on renders every frame, even when nothing it sees has changed.

How:

For extra cameras and Precomps whose content rarely changes, set `autoRender` to `false` in code, then call `render()` yourself whenever the content changes. Leave it on for the main camera.

Render on demand

```
// A secondary camera whose view rarely changes
this.minimapCamera.autoRender = false;
this.minimapCamera.render();   // call again only when something changes

// Precomps take autoRender as a constructor argument.
// With false, it renders once when its content loads.
this.menu = new Precomp("MenuPrecomp", 1024, 1024, false);
this.menu.camera.render();   // re-render after the menu changes
```

To try it out while the project runs, toggle `autoRender` in the Object panel under Camera Info. The change isn't saved, so make it permanent in code.

### 14. Cut large areas of overdraw
Helps: Runtime, GPU

Pixels hidden under other pixels still cost texture lookups.

How:

Where large graphics overlap, mask away the part that's covered. You'll find `masking` in the Object panel, and Manage → MaskGroups in the menu. Keep `trimMode` on `hugged` (the default) so transparent areas are never drawn.

Final review

## Incisor Optimization Checklist: Before you ship

### Publish a fresh build and review the analysis.

### Test first-play startup on the slowest device you target.

### Play through every scene while watching CPU and GPU use.

### Retest after turning on minification or font reduction.










----------------------------------------------------------
Section 8: Lazy Loading Content in Incisor
----------------------------------------------------------


Title: Lazy Loading Content in Incisor
Type: Tutorial
Published: 2026-09-27
URL: https://www.incisordev.com/articles/lazy-loading-content-in-incisor/index.html
Tags: loading tiers, assets, optimization, api, gui, publishing
Keywords: lazy loading, loadTier, addTierLoadedCallback, awaitLoadedTiers, loadingProgress, loading screen, loading bar, isAutoLoaded, incrementalContentProcessing, duplicate removal, streaming, download size
Summary: Split your assets into loading tiers so the first screen appears fast and everything else streams in behind it. Covers the concepts, Assets panel, Project Settings, the nc.loadTier API, the Loading Tiers panel, and proven patterns.

Get the first playable moment on screen fast, then bring in everything else only when it's actually needed.
LOAD NOW: Startup and the first interaction
LOAD NEXT: The likely next screen or feature
LOAD LATER: Bonus, paytable, deep content

## Lazy Loading Content in Incisor: Loading tiers are downloadable content groups

Every asset belongs to a numbered loading tier. Incisor publishes each tier as a separately loadable group, so your project doesn't have to download everything before gameplay begins.

A tier is either auto-loaded at startup or left for your code to request later. The tier number labels the group and sets the order auto-loaded tiers load in. Your loading strategy comes from which tiers auto-load, when you call `loadTier()`, and whether you prioritize a request.

A good mental model Organize around moments of need, not file type. A level may need textures, sounds, animations and fonts together, so put everything that moment needs in the same tier.

## Lazy Loading Content in Incisor: Assign assets to tiers

Set the tier on an asset, or set it once on a folder and let everything inside inherit it.

Pick any defined tier from an asset's loadingTier field. Manage Loading Tiers… jumps to Project Settings, where you define additional tiers.

The Assets panel shows the tier next to the asset's other build settings.

### Use inheritance for whole content groups

Folder inheritance is the fastest way to keep a large project manageable. Put each feature, level or screen in its own folder, set the loading tier on the folder, and let the assets inside inherit it. Override only the exceptions.
inherited setting local override

## Lazy Loading Content in Incisor: Configure how each tier behaves

Tier definitions live in Project Settings → loadingTierDefinitions and control how each tier loads at startup and at runtime.

### `isAutoLoaded`

Loads the tier automatically at startup. Auto-loaded tiers load one at a time in ascending numerical order, so give the tiers the player needs first the lowest numbers.

### `incrementalContentProcessing`

Spreads asset processing across several frames. Turn it on for tiers that stream in while the player is already playing, so their arrival doesn't cause a hitch. Leave it off for tiers that load before the experience starts or behind a loading screen, so they finish as fast as possible. You can also switch it off while a tier is loading, if the player suddenly needs that tier right away.

### `assetDataFileSizeLimitKB`

A soft limit that splits the tier's published asset data into smaller files. Very large files can cause a hitch when they arrive, so use a lower limit for tiers that stream in during play. Tiers that load behind a loading screen can use a higher one. A single oversized asset can still exceed the limit.

### `performDuplicateRemoval`

Identical assets across eligible tiers are downloaded only once. Be careful with on-demand tiers: a tier can end up waiting on a duplicate held by a tier that isn't loaded yet.
How it plays out: one tier at a time
- Tier 100 First visible · auto
- Tier 100.5 Base game · auto
- Tier 110 Music · auto
- Tier 103 Level 3 · on demand
- Tier 120 Feature tease · auto
- Tiers 150–700 Bonus, paytable… · auto
First frame, Playable, Level 3 ready, All loaded
Auto-loaded, in ascending order Incremental processing Player picks Level 3 Requested with `prioritize = true`

An example game. The first two tiers load behind the loading screen as fast as they can. After that, the rest stream in during play with incremental processing, so nothing hitches. When the player picks Level 3, the tier that's already loading (110) finishes first, then the prioritized request jumps ahead of everything still queued.

## Lazy Loading Content in Incisor: Load tiers from code

Incisor gives you direct loading, async waiting, callbacks, and runtime status.

Load a tier

```
// Queue a tier behind anything already loading.
nc.loadTier(150);

// Pass true to send it to the front of the queue instead.
nc.loadTier(103, true);
```

Wait for content before continuing

```
async openBonus() {
    nc.loadTier(600, true);
    await nc.awaitLoadedTiers(600);

    this.showBonusScreen();
}
```

Use a callback

```
nc.addTierLoadedCallback(
    600,
    this,
    "showBonusScreen"
);
nc.loadTier(600, true);
```

Show a loading screen only when needed

```
async openBonus() {
    const tier = nc.projectConfiguration.loadingTierDefinitions[600];

    if (!tier.isLoaded) {
        this.showLoadingScreen();   // tier.loadingProgress (0 to 1) can drive its progress bar
        tier.incrementalContentProcessing = false;     // it's urgent now, so process it all at once
        if (!tier.isLoading) nc.loadTier(600, true);   // a tier can only be requested once
        await nc.awaitLoadedTiers(600);
        this.hideLoadingScreen();
    }
    this.showBonusScreen();
}
```

### Need everything a SceneObject requires?
`nc.assessCumulativeLoadingTierRequirements(sceneObject)` returns every tier that the object, its descendants, and their textures and geometries need. It's useful when a complex screen spans more than one tier.

Load and wait for a whole screen

```
const tiers = nc.assessCumulativeLoadingTierRequirements(nextScreen);

for (const t of tiers) {
    const def = nc.projectConfiguration.loadingTierDefinitions[t];
    if (!def.isLoaded && !def.isLoading) nc.loadTier(t);
}
await nc.awaitLoadedTiers(tiers);
```

## Lazy Loading Content in Incisor: Test the loading experience, not just the final result

The Loading Tiers panel shows what's loaded, loading or still waiting, and lets you hold tiers back or slow them down to see how your project handles late content.

Turn on auto-block tiers so content can't arrive before you've tested the unloaded state. Release or load tiers by hand when you're ready.

Expand a tier to check exactly which assets ended up inside it.

Tip: A useful test: add an artificial tier delay, move through the game quickly, and try every interaction that could need content that hasn't loaded yet. Anything that appears blank, pops in, or breaks is a spot your loading plan doesn't cover yet.

## Lazy Loading Content in Incisor: Verify the published package

After you publish, Publishing Analysis → Graphic Summary shows your tier strategy in practice.

Look for an early tier that's unexpectedly large, content in the wrong tier, and graphics that could be resized, trimmed, compressed or sprite-sheeted.

## Lazy Loading Content in Incisor: Patterns that work well

The best lazy loading is usually invisible to the player.
First playable

Auto-load only the shell, the first screen, and the assets the first interaction needs.
Look-ahead prefetch

Start loading the next likely destination while the player is still busy with the current one.
Feature on demand

Keep bonus games, help and paytable content, and rare features out of the startup download.
Level streaming

Keep each level's art and audio together, and start the next level's tier during the current level or the transition.
Background queue

Request non-critical tiers normally so they wait at the back of the queue. Pass `prioritize = true` only for what the player needs now.
Configurations + tiers

Use loading tiers for when content arrives, and asset configurations for which version suits the device.

## Lazy Loading Content in Incisor: Practical rules
- Load before the click. If a button opens a heavy screen, start loading while the player is heading toward that choice, not after they press it.
- Keep shared assets early. Common UI, fonts, symbols and audio used everywhere don't belong in a late feature tier.
- Group by experience. A tier should be a meaningful chunk of gameplay, not a random mix of file types.
- Watch download and processing. Even small files can cause work at runtime. Use incremental processing for any tier that arrives during active play.
- Test the failure case. Block tiers, add a delay, and check that the UI still behaves well while content is unavailable.

The goal: make the first useful moment small, then stay one step ahead of the player.