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.09.25.12.50.58
----------------------------------------------------------
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.09.25.12.50.58
----------------------------------------------------------
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. If you've developed with Incisor using JavaScript, you know that saving your code will automatically update Live View. However, with TypeScript, there are some additional steps required. After you saved your TypeScript code. It must then be compiled into JavaScript and distributed into the project code: TypeScript generated js directory.
We first must make sure TypeScript is available to us within our project. We will use the node package manager or npm to do this. Execute the following npm install command. NPM install TypeScript. Dash dash. Save dev. Next we will execute npm run build. This will execute a prebuilt script to remove all of the previously generated TypeScript from your last build.
It will then compile your TypeScript into JavaScript and distribute it as JavaScript into the project code. TypeScript generated JS directory. Notice that after completing npm run build, the live view is automatically reloaded. To avoid needing multiple steps before a live view update. We can use a simple macro. There are a number of powerful free macro extensions for VS code, but most editors will have the ability to add macros and bind them to a single key.
For this example, I will create a VS code task and bind it to the F5 function key. First in the top menu I will select Code Settings Tasks. Here you can see in the task dot Json file that I've added two tasks: save and compile and save all files. Save all files saves everything. Save and compile depends on save all files, then it runs our npm build command.
Next I will go back to the top menu and select: code > Settings > Keyboard shortcuts. In the top right click the file icon to open Keybindings dot Json. Here you can see that I have bound the F5 key to the Save and Complete run task. Now let's add a few exclamation points. Press the F5 key 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. Press F5 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→browser": "Settings for the browser used to view the Incisor GUI and inspector."
"Application Settings→browserClient": "This field determines which browser is used for the Incisor front-end GUI and inspector. Type the name of the desired browser. Please be aware that different OSs refer to browsers differnetly (ei 'Google Chrome' vs 'Chrome')"
"Application Settings→browserClientAdditionalOpeningArgs:": "This field is used to feed the OS additional parameters when opening the given browser."
"Application Settings→connectionPorts:": "This is a list of ports that Incisor can use to connect to the front-end browser. Incisor does it's best to determine when ports are in use by other processes, but in some cases different ports must be used to enable Incisor to communicate properly."
"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→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→refreshOnAssetChange": "Setting determining if changing assets on disk causes the given project to automatically refresh."
"Application Settings→clearConsoleOnProjectRefresh": "Setting determining if refreshing the project clears the browser console."
"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 Tiers 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 Tiers 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 Tiers 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→object search": "Use this field to search for a particular asset by name."
"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'."
"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."
"": ""
"": ""
"": ""
"": ""
"": ""
"": ""
"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."
"": ""
"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."
"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→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→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→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→targetOS": "The target OS for the ElectronBuild"
"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→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.09.25.12.50.59
----------------------------------------------------------
TABLE OF CONTENTS:
----------------------------------------------------------
Section 1: 2026.09.25.00.00.00
Section 2: 2026.09.24.00.00.00
Section 3: 2026.09.22.00.00.00
Section 4: 2026.09.14.00.00.00
Section 5: 2026.09.10.00.00.00
Section 6: 2026.08.26.00.00.00
Section 7: 2026.08.22.00.00.00
Section 8: 2026.08.13.00.00.00
Section 9: 2026.08.07.00.00.00
Section 10: 2026.08.06.00.00.00
Section 11: 2026.08.05.00.00.00
Section 12: 2026.08.04.00.00.00
Section 13: 2026.08.03.00.00.00
Section 14: 2026.07.27.00.00.00
Section 15: 2026.07.25.00.00.00
Section 16: 2026.07.24.00.00.00
Section 17: 2026.07.21.00.00.00
Section 18: 2026.07.15.00.00.00
Section 19: 2026.07.09.00.00.00
Section 20: 2026.07.06.00.00.00
Section 21: 2026.06.30.00.00.00
Section 22: 2026.06.15.00.00.00
Section 23: 2026.05.21.00.00.00
Section 24: 2026.05.18.00.00.00
Section 25: 2026.05.14.00.00.00
Section 26: 2026.05.12.00.00.00
Section 27: 2026.05.09.00.00.00
Section 28: 2026.05.04.00.00.00
Section 29: 2026.05.03.00.00.00
Section 30: 2026.04.30.00.00.00
Section 31: 2026.04.29.00.00.00
Section 32: 2026.04.23.00.00.00
Section 33: 2026.04.21.00.00.00
Section 34: 2026.04.19.00.00.00
Section 35: 2026.04.17.00.00.00
Section 36: 2026.04.15.00.00.00
Section 37: 2026.04.03.00.00.00
Section 38: 2026.03.25.00.00.00
Section 39: 2026.03.20.00.00.00
Section 40: 2026.03.19.00.00.00
Section 41: 2026.03.17.00.00.00
Section 42: 2026.03.14.00.00.00
Section 43: 2026.03.11.00.00.00
Section 44: 2026.03.05.00.00.00
Section 45: 2026.03.03.00.00.00
Section 46: 2026.02.26.00.00.00
Section 47: 2026.02.23.00.00.00
Section 48: 2026.02.20.00.00.00
Section 49: 2026.02.19.00.00.00
Section 50: 2026.02.18.00.00.00
Section 51: 2026.02.16.00.00.00
Section 52: 2026.02.12.00.00.00
Section 53: 2026.02.10.00.00.00
Section 54: 2026.02.05.00.00.00
Section 55: 2026.02.02.00.00.00
Section 56: 2026.02.01.00.00.00
Section 57: 2026.01.31.00.00.00
Section 58: 2026.01.30.00.00.00
Section 59: 2026.01.29.00.00.00
Section 60: 2026.01.28.00.00.00
Section 61: 2026.01.27.00.00.00
Section 62: 2026.01.12.00.00.00
Section 63: 2026.01.11.00.00.00
Section 64: 2026.01.08.00.00.00
Section 65: 2026.01.05.00.00.00
Section 66: 2026.01.04.00.00.00
Section 67: 2025.12.08.00.00.00
Section 68: 2025.12.01.00.00.00
Section 69: 2025.11.30.00.00.00
Section 70: 2025.11.26.00.00.00
Section 71: 2025.11.12.00.00.00
Section 72: 2025.10.28.00.00.00
Section 73: 2025.10.25.00.00.00
Section 74: 2025.10.24.00.00.00
Section 75: 2025.10.23.00.00.00
Section 76: 2025.10.18.00.00.00
Section 77: 2025.10.15.00.00.00
Section 78: 2025.10.03.00.00.00
Section 79: 2025.10.01.00.00.00
Section 80: 2025.09.29.00.00.00
Section 81: 2025.09.27.00.00.00
Section 82: 2025.09.25.00.00.00
Section 83: 2025.09.24.00.00.00
Section 84: 2025.09.26.00.00.00
Section 85: 2025.09.20.00.00.00
Section 86: 2025.09.19.00.00.00
Section 87: 2025.09.15.00.00.00
Section 88: 2025.09.10.00.00.00
Section 89: 2025.09.08.00.00.00
Section 90: 2025.09.04.00.00.00
Section 91: 2025.09.02.00.00.00
Section 92: 2025.08.28.00.00.00
Section 93: 2025.08.27.00.00.00
Section 94: 2025.08.24.00.00.00
Section 95: 2025.08.16.00.00.00
Section 96: 2025.08.10.00.00.00
Section 97: 2025.07.09.00.00.00
Section 98: 2025.07.08.00.00.00
Section 99: 2025.06.29.00.00.00
Section 100: 2025.06.28.00.00.00
Section 101: 2025.06.13.00.00.00
Section 102: 2025.06.11.00.00.00
Section 103: 2025.06.10.00.00.00
Section 104: 2025.06.07.00.00.00
Section 105: 2025.06.06.00.00.00
Section 106: 2025.05.30.00.00.00
Section 107: 2025.05.29.00.00.00
Section 108: 2025.05.27.00.00.00
Section 109: 2025.05.20.00.00.00
Section 110: 2025.05.13.00.00.00
Section 111: 2025.05.05.00.00.00
Section 112: 2025.04.30.00.00.00
Section 113: 2025.04.29.00.00.00
Section 114: 2025.04.25.00.00.00
Section 115: 2025.04.23.00.00.00
Section 116: 2025.04.22.00.00.00
Section 117: 2025.04.21.01.00.00
Section 118: 2025.04.21.00.00.00
Section 119: 2025.04.17.00.00.00
Section 120: 2025.04.16.00.00.00
Section 121: 2025.04.09.00.00.00
Section 122: 2025.04.04.00.00.00
Section 123: 2025.04.02.00.00.00
Section 124: 2025.03.31.00.00.00
Section 125: 2025.03.27.00.00.00
Section 126: 2025.03.26.00.00.00
Section 127: 2025.03.25.00.00.00
Section 128: 2025.03.21.00.00.00
Section 129: 2025.03.20.00.00.00
Section 130: 2025.03.14.00.00.00
Section 131: 2025.03.12.00.00.00
Section 132: 2025.03.08.00.00.00
Section 133: 2025.03.05.00.00.00
Section 134: 2025.03.04.00.00.00
Section 135: 2025.02.27.12.29.02
Section 136: 0000.00.00.00
----------------------------------------------------------
Section 1: 2026.09.25.00.00.00
----------------------------------------------------------
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.
----------------------------------------------------------
Section 2: 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 3: 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 4: 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 5: 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 6: 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 7: 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 8: 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 9: 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 10: 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 11: 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 12: 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 13: 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 14: 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 15: 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 16: 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 17: 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 18: 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 19: 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 20: 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 21: 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 22: 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 23: 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 24: 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 25: 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 26: 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 27: 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 28: 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 29: 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 30: 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 31: 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 32: 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 33: 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 34: 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 35: 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 36: 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 37: 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 38: 2026.03.25.00.00.00
----------------------------------------------------------
TITLE:
Further Bug Fixes to UxListSupervisor
DESCRIPTION:
More edge cases producing visual duplicates are fixed.
----------------------------------------------------------
Section 39: 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 40: 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 41: 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 42: 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 43: 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 44: 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 45: 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 46: 2026.02.26.00.00.00
----------------------------------------------------------
TITLE:
Introducing UxListSupervisor
DESCRIPTION:
Object for laying out dynamic lists in the GUI for extensions.
TITLE:
Latent Hierarchy Bug Fixed
DESCRIPTION:
There was a bug that allowed old disposed hierarchies to be visible after a project refreshed - this has been fixed.
TITLE:
Dynamic Cursor Changing
DESCRIPTION:
The cursor now changes based on what it's hovering over.
TITLE:
Added Default Inspector Panel Layout Preset
DESCRIPTION:
The same layout as a brand new project is now available within the presets as 'Default'.
----------------------------------------------------------
Section 47: 2026.02.23.00.00.00
----------------------------------------------------------
TITLE:
Open Project Popup Location is now Persistent
DESCRIPTION:
For ease of use.
TITLE:
ParticleSystem Trailing Comma Issue Fix
DESCRIPTION:
A trailing comma found at the end of a list of parameters in a function call was causing problems for the UC Browser. This has been fixed.
TITLE:
Introducing Panel Layout Presets
DESCRIPTION:
Now you can save the layout of the inspector panel and recall it easily from within the 'View' menu. The data is stored within the ApplicationSettings.json file.
----------------------------------------------------------
Section 48: 2026.02.20.00.00.00
----------------------------------------------------------
TITLE:
Timeline.influence Edge Case Fixed
DESCRIPTION:
An edge case has been fixed where changing the influence of a Timeline would cause the influence of other timelines' influences to become NaN.
----------------------------------------------------------
Section 49: 2026.02.19.00.00.00
----------------------------------------------------------
TITLE:
Improved fileIO.delete Validation
DESCRIPTION:
Empty quotes are no longer an acceptable path to provide 'fileIO.delete'.
TITLE:
FileIO.delete Behavior Changed
DESCRIPTION:
If the item to be deleted is not present, a 'blue error' will no longer be generated in the client, and the message explaining that the item wasn't present has been moved to the payload property of the returned response instead of the original error member.
----------------------------------------------------------
Section 50: 2026.02.18.00.00.00
----------------------------------------------------------
TITLE:
Improved Pivot Point Adjuster Validation
DESCRIPTION:
PivotPointAdjusters are not supported on TextBoxes, but previously there was no logging or validation to prevent it.
----------------------------------------------------------
Section 51: 2026.02.16.00.00.00
----------------------------------------------------------
TITLE:
Fixed UiDropDown Positioning Bug
DESCRIPTION:
In certain instances UiDropDown menu positioning was off, this has been fixed.
TITLE:
More Robust Error Feedback for Electron Publishing
DESCRIPTION:
We are now looking through the stdOut from the 'electron-builder' process for errors and logging them for the user. Also the publishing output is now dumped to a PublishingLog.txt file in the publishing workspace.
TITLE:
Changed the 'Open Project' Keyboard Shortcut
DESCRIPTION:
It is now [Cmd/Ctrl][Alt][O], since some browsers are already using [Cmd/Ctrl][O] to open a new window.
----------------------------------------------------------
Section 52: 2026.02.12.00.00.00
----------------------------------------------------------
TITLE:
Items in Publishing Popup Made Persistent
DESCRIPTION:
The current configuration and the other checkboxes are now persistent in the publishing popup window.
TITLE:
Added Keyboard Shortcuts for the Publishing Popup, the ProjectSettings Popup, and the Application Settings Popup
DESCRIPTION:
For quick access...
----------------------------------------------------------
Section 53: 2026.02.10.00.00.00
----------------------------------------------------------
TITLE:
Improved Duplicate Asset Name Messaging
DESCRIPTION:
Now if you have more than one asset with the same name in your project, Incisor gives you their paths in the associated red error.
----------------------------------------------------------
Section 54: 2026.02.05.00.00.00
----------------------------------------------------------
TITLE:
Introducing AuxiliaryPublishingPackages in ProjectSettings
DESCRIPTION:
You can now define extra publishing options such as Electron publishing packages and tie them to configurations.
TITLE:
Restructuring Electron Publishing
DESCRIPTION:
Whenever the given Electron publishing package is defined and used during publishing, a directory is created under the package's name in the project at Utilities/AuxiliaryPublishingSupport, and that directory is where the components for the given package are collected for publishing.
----------------------------------------------------------
Section 55: 2026.02.02.00.00.00
----------------------------------------------------------
TITLE:
Timeline.playOnce_swoopInfluence Timing Bug Fix
DESCRIPTION:
The related fix on 2026.01.29 contained an edge case issue.
----------------------------------------------------------
Section 56: 2026.02.01.00.00.00
----------------------------------------------------------
TITLE:
Asset Configuration Bug Fix
DESCRIPTION:
Applying asset configuration filters to images was causing red errors in some scenarios. This has been fixed.
----------------------------------------------------------
Section 57: 2026.01.31.00.00.00
----------------------------------------------------------
TITLE:
GUI: EffectController Color Vector Supervisor Bug Fix
DESCRIPTION:
In some cases the color picker box on color supervisors in the GUI were displaying the wrong color. This has been fixed.
----------------------------------------------------------
Section 58: 2026.01.30.00.00.00
----------------------------------------------------------
TITLE:
Number Format Bug Fix
DESCRIPTION:
Incisor was experiencing a collection of visual bugs when it was running on machines that have default number formatting other than the 'en-US' formatting.
TITLE:
Spine Glitchiness Bug Fix
DESCRIPTION:
A small defect in the Spine bezier curve evaluation was creating some glitchiness in certain imported Spine animations. Animations should not need to be re-imported to be improved.
TITLE:
Better Defaulting for 'nc.mainModifierKey'
DESCRIPTION:
Incisor was doing a bad job at detecting when it was running on OSX and was therefore making nc.mainModifierKey = 'Control' in most cases. This is fixed now.
----------------------------------------------------------
Section 59: 2026.01.29.00.00.00
----------------------------------------------------------
TITLE:
Timeline.playOnce_swoopInfluence Bug Fix
DESCRIPTION:
Timeline.playOnce_swoopInfluence was not properly taking the playbackRate of the given timeline into account when doing its return swoop.
TITLE:
Refactored the Internal Storage of Installation Support
DESCRIPTION:
In order to fix a bug that was limiting the ability to add more JS to Incisor.
----------------------------------------------------------
Section 60: 2026.01.28.00.00.00
----------------------------------------------------------
TITLE:
Matrix4 and Matrix4Array EffectController Fixes
DESCRIPTION:
These two EffectController types were not working properly with regards to their placement onto MaterialMaster and CharacterMaterial objects. Also, defaults for the types were not properly being applied in general.
TITLE:
FlowController/FlowState Dynamic Documentation Bug Fixed
DESCRIPTION:
The user choosing to omit the 'flowController' optional code module was causing replacement tags to be left in the IncisorAPI dynamic documentation. This has been fixed.
----------------------------------------------------------
Section 61: 2026.01.27.00.00.00
----------------------------------------------------------
TITLE:
JS Keyword Removal Bug Fixed
DESCRIPTION:
The 'default' keyword was being removed erroneously.
TITLE:
Internal Incisor Publishing Pipeline Refactored
DESCRIPTION:
For faster, more reliable, publishing of Incisor app with better flow for codesigning.
----------------------------------------------------------
Section 62: 2026.01.12.00.00.00
----------------------------------------------------------
TITLE:
GUI: Focused TextBoxes and UiTextFields Ignore Panel Hot Zones
DESCRIPTION:
Previously, rolling over a panel would steal focus from TextBoxes and UiTextFields, which created issues with usability. Now the user has to exit text editing entirely (via a click or by pressing enter etc...) for panel focus zones to have any effect.
----------------------------------------------------------
Section 63: 2026.01.11.00.00.00
----------------------------------------------------------
TITLE:
New SceneObject EffectController Inheritance Bug Fix
DESCRIPTION:
Fixed an issue where new children added (post-init) failed to inherit effect controller values.
TITLE:
GUI: EffectController Supervisors - Live Updating
DESCRIPTION:
Now the EffectControllers available in the Object panel for any SceneObject or Material are correctly reflected, even if they changed live in code.
TITLE:
Object Panel: PerspectiveCamera
DESCRIPTION:
Supervisors have been added to the Object panel for PerspectiveCameras.
----------------------------------------------------------
Section 64: 2026.01.08.00.00.00
----------------------------------------------------------
TITLE:
DropDown Menu Overflow Adjustments
DESCRIPTION:
Improving the behavior of menus that are too big for the window. This is still a bit of a patch... a menu overhaul is on the roadmap.
TITLE:
Keyboard Navigation Outline Bug Fix
DESCRIPTION:
An issue with keyboard navigation outlines not being properly displayed has been fixed.
----------------------------------------------------------
Section 65: 2026.01.05.00.00.00
----------------------------------------------------------
TITLE:
Added 'perspective' Option for 'mainCameraType' to ProjectSettings Popup
DESCRIPTION:
To be able to change the main camera type from the ProjectSettings window.
----------------------------------------------------------
Section 66: 2026.01.04.00.00.00
----------------------------------------------------------
TITLE:
Introducing PerspectiveCamera (experimental)
DESCRIPTION:
New Camera with a perspective frustum.
TITLE:
Runtime Project Memory Footprint Improvements
DESCRIPTION:
An overlooked feature of Incisor object class inheritance was causing some EffectController getters and setters to be added at the instance level instead of at the prototype level. This has been fixed.
TITLE:
Camera vs OrthographicCamera Reorganization
DESCRIPTION:
To prepare for PerspectiveCamera some restructuring of Camera and OrthographicCamera was required.
TITLE:
Spine Initialization Bug Fixed
DESCRIPTION:
A race condition allowed for a sporadic issue with Spine animations. This has been fixed.
TITLE:
New AdaptiveCameraModes: preserveViewAngleVertical and preserveViewAngleHorizontal
DESCRIPTION:
Values used with the new PerspectiveCamera.
----------------------------------------------------------
Section 67: 2025.12.08.00.00.00
----------------------------------------------------------
TITLE:
Introducing Support for Compressed Video (experimental)
DESCRIPTION:
Now you can include '.mp4' and '.webm' assets in your project and have the associated video content appear on GraphicObjects within Incisor. This functionality is not universally supported on all browsers, and special considerations must be taken when using this functionality.
TITLE:
Timeline Panel: Shift-Lock for Keyframe Dragging in Graph Editor
DESCRIPTION:
Now you can hold shift while dragging keyframes in the Graph Editor to lock to the nearest axis.
TITLE:
Timeline Panel: New Ease Standards
DESCRIPTION:
Now when selecting one of the built-in ease options, the ease handle is located at 30% of the span instead of 40% of the span.
TITLE:
Added 'nc.cursorMode' and Deprecated 'nc.isTouchCursor'
DESCRIPTION:
The determination of which mode (touch or mouse) a given project is in, automatically defaults to the first type of event received, but can be changed via 'nc.cursorMode'.
----------------------------------------------------------
Section 68: 2025.12.01.00.00.00
----------------------------------------------------------
TITLE:
Added x, y, and z Axes to the HUD in the Incisor Inspector
DESCRIPTION:
A clear indication of where the origin is...
----------------------------------------------------------
Section 69: 2025.11.30.00.00.00
----------------------------------------------------------
TITLE:
Added Material.depthTest, Material.depthWrite, and Material.faceCulling.
DESCRIPTION:
Exposing these material properties for use in conjunction with OBJs.
TITLE:
Added ContourShading to the TemplateLibrary
DESCRIPTION:
A basic shading EffectNode to make OBJ contour visible.
TITLE:
Added RegisteredProperty.displayInGui
DESCRIPTION:
Flag determining if a given registered property will be displayed with a Supervisor in the GUI.
----------------------------------------------------------
Section 70: 2025.11.26.00.00.00
----------------------------------------------------------
TITLE:
Fixed Bug with Empty-Quote-Named Construct Objects
DESCRIPTION:
Fixed a superficial, red-error generating bug related to making the name for items equal to empty quotes.
TITLE:
Introducing preliminary OBJ support (experimental)
DESCRIPTION:
You can now include OBJ files in the Assets directory of your project and they will automatically appear in the nc.GraphicAssets, and nc.Geometries dictionaries in the project.
TITLE:
Many Documentation Fixes
DESCRIPTION:
In the process of reworking the Incisor Documentation site, and creating the pipeline for the Incisor Raw Knowledge Base, many small issues were found in the documentation and corrected - too numerous to enumerate.
----------------------------------------------------------
Section 71: 2025.11.12.00.00.00
----------------------------------------------------------
TITLE:
Added TextBox.addStartEditCallback
DESCRIPTION:
A new callback that can be created whenever a TextBox's editingMode changes to 'editing'.
TITLE:
Added TextBox.htmlBacking
DESCRIPTION:
A means to allow keyboard input from mobile devices by creating a hidden text element that accepts mobile keyboard entry.
----------------------------------------------------------
Section 72: 2025.10.28.00.00.00
----------------------------------------------------------
TITLE:
Added 'ProcessConfiguration' for runProcess, runCmd, and runBash
DESCRIPTION:
A new class with properties pertaining to the running of processes.
TITLE:
Cleared many unnecessary documentation classes.
DESCRIPTION:
Several classes were converted to object expressions in the documentation to reduce clutter.
----------------------------------------------------------
Section 73: 2025.10.25.00.00.00
----------------------------------------------------------
TITLE:
Template Library Generated Extensions Bug Fix
DESCRIPTION:
Some of the names within the exported extensions from the template library weren't being substituted correctly.
----------------------------------------------------------
Section 74: 2025.10.24.00.00.00
----------------------------------------------------------
TITLE:
Fixed Bug with Gradient2Color, Gradient3Color, Gradient4Color
DESCRIPTION:
Those EffectNodes had effect controllers that attempted to use a disallowed component name. They have been fixed and validation has been added to clarify what is happening when this issue is encountered in the future.
----------------------------------------------------------
Section 75: 2025.10.23.00.00.00
----------------------------------------------------------
TITLE:
Fix to the PingPong Motion Type
DESCRIPTION:
Prior to this fix, if the upper bounds weren't larger than the lower bounds, there were issues.
TITLE:
Spine Import Fixes
DESCRIPTION:
Too numerous to itemize, many are related how multiple constraint-style spine features work together.
----------------------------------------------------------
Section 76: 2025.10.18.00.00.00
----------------------------------------------------------
TITLE:
Template Library Effect Nodes Made Safer
DESCRIPTION:
All of the variables declared in the open fragment and vertex shader scopes are now prepended with the user-specified effect node name. Also, associated EffectControllers are now made to be lowercase if they are not already.
TITLE:
Added the ShapifyStroke EffectNode to the TemplateLibrary
DESCRIPTION:
Add a built-in stroke to a shapified GraphicObject.
TITLE:
Added nc.definePrecomp
DESCRIPTION:
Allowing the for the creation of a Precomp in the target software from within extensions via 'nce.projectNC.definePrecomp'.
TITLE:
Fixed EffectNode Default Values Bug
DESCRIPTION:
In certain scenarios the default values were not being applied to the material when a new EffectNode was being added.
----------------------------------------------------------
Section 77: 2025.10.15.00.00.00
----------------------------------------------------------
TITLE:
Added SlotReel.numSymbols
DESCRIPTION:
... for quick reference
TITLE:
SlotReels can now accept a CustomObjectDefinition for the 'symbolDefinition' parameter.
DESCRIPTION:
To make the interface between the SlotReel and its symbols more intuitive and less verbose.
TITLE:
Added SlotReels.symbolPathOverrideMode.
DESCRIPTION:
Now the positioning of the symbols along the reel path can be completely overriden.
----------------------------------------------------------
Section 78: 2025.10.03.00.00.00
----------------------------------------------------------
TITLE:
Added nce.runBash and nce.runCmd
DESCRIPTION:
For the ability to run terminal commands easily through extensions without having to specify the process location.
TITLE:
Introducing Electron Integration
DESCRIPTION:
Look for options to publish native apps in the 'Publish Project' popup window.
TITLE:
Fixed SlotReel.getSymbols Bug
DESCRIPTION:
It previously wasn't returning correctly.
----------------------------------------------------------
Section 79: 2025.10.01.00.00.00
----------------------------------------------------------
TITLE:
Added the nc.addScene
DESCRIPTION:
Exposing the factory function which can be used in addition to the standard constructor.
----------------------------------------------------------
Section 80: 2025.09.29.00.00.00
----------------------------------------------------------
TITLE:
Added the 'StretchBetween2D' CustomAddOn to the TemplateLibrary.
DESCRIPTION:
Stretch any GraphicObject in the middle such that it reaches between the two points you provide.
----------------------------------------------------------
Section 81: 2025.09.27.00.00.00
----------------------------------------------------------
TITLE:
Added 'numHorizontalGridSegments' and 'numVerticalGridSegments' to the Object panel, and also made those items Construct-savable.
DESCRIPTION:
To be able to manipulate the number of grid segments from within the GUI.
----------------------------------------------------------
Section 82: 2025.09.25.00.00.00
----------------------------------------------------------
TITLE:
Fixed Post Publish Bugs
DESCRIPTION:
There was a race condition that caused the inspector to need to be refreshed after publishing projects.
TITLE:
Fixed ParticleSystem.stopEmitting Documentation Issue
DESCRIPTION:
Fixed the parameter type.
----------------------------------------------------------
Section 83: 2025.09.24.00.00.00
----------------------------------------------------------
TITLE:
Introducing SlotReel
DESCRIPTION:
To create spinning reels for a casino slot game with ease.
TITLE:
Introducing Matrix4, SceneObject.worldMatrixOverrideMode, SceneObject.localMatrixOverrideMode, SceneObject.worldMatrix, and SceneObject.localMatrix
DESCRIPTION:
Unlocking the ability for the user to work around the built-in 'arrangement' properties and manipulate the rendering matrices directly for custom effects.
TITLE:
Introducing Spine Import (Experimental)
DESCRIPTION:
Users can now import Spine animations.
TITLE:
Added GraphicObject.frustumCulling
DESCRIPTION:
Boolean determining if the GraphicObject is automatically omitted from rendering when it is entirely outside of the Camera's viewing area (its frustum).
TITLE:
Added WaitThen.duration
DESCRIPTION:
Read-only property indicating the current duration of the WaitThen.
----------------------------------------------------------
Section 84: 2025.09.26.00.00.00
----------------------------------------------------------
TITLE:
Added nc.defineFlowController, FlowController, FlowState, FlowStateElement, and the 'Flows' panel.
DESCRIPTION:
For implementing and visualizing state flows within the project...
TITLE:
Hierachy Panel: Hold 'Alt' to Reparent while Maintaining Global Position
DESCRIPTION:
This feature was accidentally removed in an earlier version.
----------------------------------------------------------
Section 85: 2025.09.20.00.00.00
----------------------------------------------------------
TITLE:
Added New Color Themes, Including a new Default Color Theme
DESCRIPTION:
If you have already been using Incisor, you may need to wipe out your ApplicationSettings.json to see the new colors.
TITLE:
Fixed copy/paste TextBox Bug in ConstructEditor
DESCRIPTION:
Now a freshly pasted TextBox will display properly immediately in the ConstructEditor.
TITLE:
Fixed Error in nc.defineEffectNode and nc.definedEffectController Documentation
DESCRIPTION:
These documentation errors were resulting in misleading TypeScript compilation errors.
TITLE:
Fixed Bug Related to Layers Changing In Construct
DESCRIPTION:
Now if a construct item's layer disappears, nothing bad happens (except the requisite warnings).
----------------------------------------------------------
Section 86: 2025.09.19.00.00.00
----------------------------------------------------------
TITLE:
Runtime Memory Usage Reduction
DESCRIPTION:
Several changes have been made to reduce runtime memory including removing the 'asset data stash', freeing asset list 'bulk' data, and making internal EffectNode support objects be generated on an 'as-needed' basis.
TITLE:
Removed 'SampleGlobalExtensions' and 'SampleProjectExtensions'
DESCRIPTION:
All of these examples have been moved to the 'TemplateLibrary' menu.
----------------------------------------------------------
Section 87: 2025.09.15.00.00.00
----------------------------------------------------------
TITLE:
Live View Cursor Input Bug Fixed
DESCRIPTION:
Now cursor input is only sent through the Live View panel if it is in focus.
TITLE:
Missing Sub-Construct Bug Fixed
DESCRIPTION:
Incisor was failing in an unrecoverable way when attempting to place a non-existent Construct within a Construct, no you just get the standard warning.
----------------------------------------------------------
Section 88: 2025.09.10.00.00.00
----------------------------------------------------------
TITLE:
Added 'nc.canvasElement'
DESCRIPTION:
For direct access to the project canvas element.
TITLE:
Added FontReduction Window
DESCRIPTION:
Accessible via a new button in the Transcript Panel. In this you window can see which characters will be included with each font when the project is published. You can also export an informational JSON file for external use if needed.
----------------------------------------------------------
Section 89: 2025.09.08.00.00.00
----------------------------------------------------------
TITLE:
Added builtInHeaderMenus to Custom Color Themes
DESCRIPTION:
For increased flexability.
TITLE:
Fixed Publishing Bug: Font Character Assets split out by Language
DESCRIPTION:
There was an issue font characters were not being split into language-specific asset data files.
TITLE:
Added Header to Live View Panel
DESCRIPTION:
Now all of the control buttons are in the header.
TITLE:
Live View Panel: Added Full Scren Toggle
DESCRIPTION:
Now you can toggle fullscreen for Live View.
TITLE:
Live View Panel: Added View Modes
DESCRIPTION:
Modes allow you to specify the aspect ratio of the live view. You can include additional view modes in ProjectSettings.
TITLE:
Live View Paused Bug Fixes
DESCRIPTION:
Pausing the Live View was causing some bugs, including issues with the Construct Editor, and issues with stepping a single frame.
----------------------------------------------------------
Section 90: 2025.09.04.00.00.00
----------------------------------------------------------
TITLE:
Added nce.reloadProject
DESCRIPTION:
Functionality for reloading the project (same as pressing the refresh button in the live view) from within extensions.
----------------------------------------------------------
Section 91: 2025.09.02.00.00.00
----------------------------------------------------------
TITLE:
Added ApplicationSettings.colorTheme, and ApplicationSettings.customColorThemes
DESCRIPTION:
Now you can create custom color themes for Incisor.
TITLE:
Timeline Keyframe Scaling Bug Fixed
DESCRIPTION:
Fixed bugs with keyframe handle scaling related to uiZoom
TITLE:
Upgraded Incisor/Browser Protocol
DESCRIPTION:
Optimized communications protocol between Incisor and the client browser, elminating multiple Cson/Json interpretations per communication and reducing the overall size of communications.
----------------------------------------------------------
Section 92: 2025.08.28.00.00.00
----------------------------------------------------------
TITLE:
Added FileBrowser.refresh
DESCRIPTION:
Method to refresh the FileBrowser so it can reflect file system changes.
TITLE:
Added Color Supervisor Button and Color Window
DESCRIPTION:
Now you can see a swatch of a given color next to its EffectController. Clicking the swatch opens a window that allows you to visually choose a color.
TITLE:
Added UiPopupWindow.isMovable
DESCRIPTION:
Windows can now now be moved by dragging the header.
TITLE:
Added nc.visualFocusDimmerAmount
DESCRIPTION:
The strength of the dimmer can now be changed dynamically.
TITLE:
Rebuilt 'Layers' Manager
DESCRIPTION:
The LayersManager has been visually reconstructed and is now accessable from the layers menu in the Object panel, in its own panel, and from within the 'Manage' menu. Keystroke shortcuts have also been added.
TITLE:
Rebuilt 'Masks' Manager
DESCRIPTION:
The MasksManager has been visually reconstructed and is now accessable from the masking menu in the Object panel, and also from within the 'Manage' menu. Keystroke shortcuts have also been added.
----------------------------------------------------------
Section 93: 2025.08.27.00.00.00
----------------------------------------------------------
TITLE:
Upgraded Project File System
DESCRIPTION:
Changes made to project files while a project is open are now reflected in the Incisor project and are part of the 'undo/redo' stack.
----------------------------------------------------------
Section 94: 2025.08.24.00.00.00
----------------------------------------------------------
TITLE:
Added nce.runProcess
DESCRIPTION:
A means to run external executable processes from within extensions code.
TITLE:
Fixed Asset Package Scale Bug with SpriteSheets
DESCRIPTION:
When publishing with multiple asset package scales, images in sprite sheets were reusing geometry from other asset packages erroneously.
TITLE:
Rebuilt the Hierarchy Inspector
DESCRIPTION:
The hierarchy inspector has been rebuilt visually, and now uses the 'ItemRepStack' method that the file browser uses.
TITLE:
Asset Browser and Asset Settings have been combined
DESCRIPTION:
Now the inspector has a single 'Assets' panel, which makes for easier access.
----------------------------------------------------------
Section 95: 2025.08.16.00.00.00
----------------------------------------------------------
TITLE:
Added 'nce.addFileBrowser'
DESCRIPTION:
A new tool for file system viewing within extensions.
TITLE:
Added 'nce.showPathQueryPopup'
DESCRIPTION:
Another standardized popup for acquiring a path from the user via visual interface.
TITLE:
Added a root selector to the Open Project and New Project popup windows.
DESCRIPTION:
Now you can change the root to different locations and drives from within the popup window.
TITLE:
AssetBrowser panel and AssetSettings panel have been combined into the 'Assets' panel.
DESCRIPTION:
Easier access in one, split panel. A searchbar has also been added.
TITLE:
Added nc.incisorApp.pauseProjectDirectoryWatcher and nc.incisorApp.resumeProjectDirectoryWatcher
DESCRIPTION:
A way to pause and resume the auto-reload-on-file-change functionality.
TITLE:
Fixed Issue with TextBox.BoxHeight and TextAssembly.BoxHeight
DESCRIPTION:
In some situations, with wrapToFit=false, the box size properties were not having the desired effect on the text layout.
TITLE:
Added More Detection for Project Minification Reservations
DESCRIPTION:
Added auto-detection of asset names and other keywords referenced in Constructs, Layers, ParticleSystems, Masks, and Transcripts.
----------------------------------------------------------
Section 96: 2025.08.10.00.00.00
----------------------------------------------------------
TITLE:
SoftwareSpeed Sound PlaybackRate Bug Fixed
DESCRIPTION:
Incisor was failing to adjust the PlaybackRate of sounds when SoftwareSpeed was adjusted in some scenarios.
TITLE:
Inspector Live View Aspect Ratio Slippage Fixed
DESCRIPTION:
Within the inspector, the LiveView was sending the previous aspect ratio to the target software instead of the current aspect ratio.
----------------------------------------------------------
Section 97: 2025.07.09.00.00.00
----------------------------------------------------------
TITLE:
Added Info-Object Parameters to Publish Actions
DESCRIPTION:
nce.addPrePublishCallback, and nce.addPostPublishCallback now sends info objects (PrePublishInfoObject and PostPublishInfoObject) to the callbacks.
----------------------------------------------------------
Section 98: 2025.07.08.00.00.00
----------------------------------------------------------
TITLE:
Added nc.appEvents.visibilityChange
DESCRIPTION:
Event associated with a change in the visibility of the browser/app running Incisor.
TITLE:
Added SceneObject.addUiZoomCallback and SceneObject.removeUiZoomCallback
DESCRIPTION:
Provides a new way to get a callback from a uiZoomChange event, such that callbacks associated with SceneObjects with higher 'hierarchy depth' values occur earlier.
TITLE:
Inspector Optimizations
DESCRIPTION:
Many of the UI objects have been optimized to not populate certain components unless needed. Also recursion has been removed from several internal processes.
TITLE:
HierarhcyPanel Rework
DESCRIPTION:
SceneObject representatives are now populated asynchronously to avoid performance issues with large Scenes. A search bar has also been added, as well as an 'expand/collapse all' button.
TITLE:
Added nc.maxReconciliationTime, and nc.maxHiddenReconciliationTime
DESCRIPTION:
Values to limit 'computational pile-ups' for projects with heavy computational tasks.
----------------------------------------------------------
Section 99: 2025.06.29.00.00.00
----------------------------------------------------------
TITLE:
Added SceneObject.excludeChildrenFromBlueprint
DESCRIPTION:
A way to ensure that automatically populated children are accidentally duplicated in Constructs.
----------------------------------------------------------
Section 100: 2025.06.28.00.00.00
----------------------------------------------------------
TITLE:
Introducing Transcript Panel
DESCRIPTION:
Now you can add, edit, and remove transcript phrases from within the new 'Transcript' panel.
----------------------------------------------------------
Section 101: 2025.06.13.00.00.00
----------------------------------------------------------
TITLE:
AppEvent Rework
DESCRIPTION:
AppEvents have been reworked and unified internally in Incisor. New features include ordered AppEvents, as well as 'consumable callback' AppEvents. It should be noted that the parameters for AppEvent.addCallback have been changed in a way that may not be backwards compatible.
----------------------------------------------------------
Section 102: 2025.06.11.00.00.00
----------------------------------------------------------
TITLE:
TypeScript Generation: Remove Previously Generated TypeScript Bug Fixed
DESCRIPTION:
There was an issue with the package.json file that was causing the removal of old files to fail.
TITLE:
HUD Scroll Selection Stability
DESCRIPTION:
New scroll-select algorithm produces a more stable and usable interface.
TITLE:
Auto_Select Timeline on Open
DESCRIPTION:
Now when you open a new Timeline panel it opens the Timeline that is currently open in any other Construct panels, if applicable.
TITLE:
Alphabetized Construct Menu, Construct-Timeline Menu
DESCRIPTION:
For increased usability...
----------------------------------------------------------
Section 103: 2025.06.10.00.00.00
----------------------------------------------------------
TITLE:
Fixed Issue with New-Member Signup
DESCRIPTION:
Issue related to email confirmation resolved.
----------------------------------------------------------
Section 104: 2025.06.07.00.00.00
----------------------------------------------------------
TITLE:
Added nc.appEvents.start and nc.addLateStartCallback
DESCRIPTION:
These AppEvents/callbacks are useful within CustomAddOns that are used in Constructs to be able to ensure that everything is 'set up' before the code in question runs.
----------------------------------------------------------
Section 105: 2025.06.06.00.00.00
----------------------------------------------------------
TITLE:
Template Library Rework
DESCRIPTION:
Library items are now built as templates, with the user determining the name when they add them to the project. Also, templates for extensions, CustomAddOns, and CustomObjects.
TITLE:
CodeAssets Now Available in TypeScript
DESCRIPTION:
You can now have a '.codeAsset.ts' file in your Assets directory, and the resulting code asset will be converted into an associated JavaScript when the TypeScript is compiled.
TITLE:
Construct 'Sub-Name' Bug Fix
DESCRIPTION:
There was a bug that caused one Construct to overwrite another Construct upon saving changes if their names ended in the same characters. This bug has been fixed.
----------------------------------------------------------
Section 106: 2025.05.30.00.00.00
----------------------------------------------------------
TITLE:
Button.addReleaseCallback bug fix
DESCRIPTION:
When published and run on touch devices, Button.addReleaseCallback was experiencing issues.
----------------------------------------------------------
Section 107: 2025.05.29.00.00.00
----------------------------------------------------------
TITLE:
Added Sound.swoopVolume
DESCRIPTION:
...Interpolates the volume over the designated period of time.
----------------------------------------------------------
Section 108: 2025.05.27.00.00.00
----------------------------------------------------------
TITLE:
Introducing CustomObjects
DESCRIPTION:
CustomObjects have been added... Define a new class that inherits from any of the standard hierarchy-bound objects (such as SceneObject, GraphicObject, etc...) and then register that object with Incisor to enable your custom object to be added to Constructs within the GUI.
----------------------------------------------------------
Section 109: 2025.05.20.00.00.00
----------------------------------------------------------
TITLE:
Bug Fix: Post-Enabled EffectController Reset
DESCRIPTION:
In certain situations, enabling objects would cause effect controllers to have 'stuck' values. Effect controller values are now 'dirtied' upon an object being enabled
TITLE:
Bug Fix: 'Number' Effect Controllers Getter Wrong at Instantiation
DESCRIPTION:
Efforts made to sync the primary and passdown controller values for 'number' typed controllers were previously broken, causing issues in some situations.
TITLE:
Bug Fix: Minification Combined with 'RunBeforeInit' Sections
DESCRIPTION:
Such sections weren't being pulled through into the compiled file when minification was turned on.
TITLE:
Default TypeScript Compilation Target Changed to ES2017
DESCRIPTION:
This cleans up the typescript generated code for asynchronous functions a lot without raising serious compatibility concerns.
TITLE:
PlaybackController.autoplay is becoming PlaybackController.autoplayWhenInConstruct
DESCRIPTION:
For clarity.
----------------------------------------------------------
Section 110: 2025.05.13.00.00.00
----------------------------------------------------------
TITLE:
ProjectSettings: UiTextField Focus Fallback Bugs Fixed
DESCRIPTION:
Certain UiTextFields in the ProjectSettings popup were causing focus issues when they were edited.
TITLE:
Introducing CustomAddOns
DESCRIPTION:
CustomAddOns can now be defined in code assets and added to various SceneObjects using the inspector.
TITLE:
Restored Undo/Redo Functionality for TextBoxes
DESCRIPTION:
While typing in a TextBox, you can undo and redo. This functionality was accidentally disabled in January and has been restored.
TITLE:
TextBoxes: 'Hold Shift for New Line'
DESCRIPTION:
Now, if a TextBox's 'returnEndsEditing' property is true, you can still hold 'shift' to get a new line.
TITLE:
Added TextAssembly.getCharacters
DESCRIPTION:
Returns an array of GraphicObjects...
----------------------------------------------------------
Section 111: 2025.05.05.00.00.00
----------------------------------------------------------
TITLE:
Added: nc.useNearestPixelRenderingForAllUiItems
DESCRIPTION:
A way to set the default value of 'useNearestPixelRendering' for all of the 'UI' objects at once.
TITLE:
Project Settings Popup: Loading Tier Removal Bug Fix
DESCRIPTION:
A bug related to removing loadingTiers in the ProjectSettings is fixed.
TITLE:
SpriteSetter: Key GraphicAsset Selection Updated
DESCRIPTION:
Now uses the improved GraphicAsset selection popup...
TITLE:
Constructs: Buttons can now be added Directly to Constructs
DESCRIPTION:
The option to add Buttons is now in the GUI, and Constructs will reproduce the Buttons correctly.
----------------------------------------------------------
Section 112: 2025.04.30.00.00.00
----------------------------------------------------------
TITLE:
LiveViewPanel: Single Step 'screenUpdate'
DESCRIPTION:
To ensure that all of the callbacks associated with a given live-view-single-step (when the user presses the single step button) Incisor now forces a screen update in the target project with each step.
TITLE:
MaskGroup Predefinition Files
DESCRIPTION:
MaskGroup definitions can now be stored in the 'main.maskGroups' file within the Assets directory.
TITLE:
MaskGroups Management in GUI
DESCRIPTION:
MaskGroups can now be managed from within the GUI via ObjectPanel->masking->maskGroups.
TITLE:
JavaScript Strict Mode No Longer Enforced
DESCRIPTION:
In previous versions, Incisor enforced JavaScript 'strict mode'. Now the user can add that restriction if they want.
----------------------------------------------------------
Section 113: 2025.04.29.00.00.00
----------------------------------------------------------
TITLE:
GraphicObject: Masking API Change
DESCRIPTION:
Masking-related items are now accessible through GraphicObject.masking. See updated documentation for more information.
TITLE:
Timelines Panel: Stray Keyframe Dropping Bug Fix
DESCRIPTION:
In some scenarios, scrubbing the playhead could cause a random keyframe to drop. This has been fixed.
TITLE:
AssetSettings Panel: Erroneous Red Error Removed
DESCRIPTION:
Projects with more assets would produce a red error on load if the AssetSettings panel was open. This has been fixed.
----------------------------------------------------------
Section 114: 2025.04.25.00.00.00
----------------------------------------------------------
TITLE:
Pdfs: Added PdfSection.setMargins
DESCRIPTION:
For ease of use.
TITLE:
Pdfs: Added the ability to add Tables to TextFrames.
DESCRIPTION:
New functionality...
TITLE:
ParticleSytems: Added the '.particleSysDef' asset format.
DESCRIPTION:
ParticleSystemDefinitions are no longer meant to be solely stored as '.codeAsset' files (but they still can be). Now you can use the 'create new' button in the GUI to create a new ParticleSystemDefinition (based on any existing ParticleSystemDefinition or one of several templates), which is stored in an associated 'particleSysDef' file in the project's 'Assets' directory. Any ParticleSystemDefinition backed by a '.particleSysDef' file has full undo/redo functionality in the GUI.
TITLE:
Object Panel: Timeline Editor Scene Objects Blocked from Editing
DESCRIPTION:
Most of the functionality in the Object panel has no permanent affect on objects inside of a Timeline Editor Scene, so to help users avoid what has been a super common mistake, we've blocked the Object panel entirely when such an object is selected, and added a 'go to NeutralState' button, which is where the associated changes can be made correctly.
TITLE:
Deprecation Schedule Actions Taken
DESCRIPTION:
Deprecations made current through to today, with the next round scheduled for 2025.06.01. See the 'DeprecationSchedule' for more information.
----------------------------------------------------------
Section 115: 2025.04.23.00.00.00
----------------------------------------------------------
TITLE:
nc.loadingTiers auto-complete bug fixed
DESCRIPTION:
Auto-complete for 'nc.loadingTiers' was connected to the index values of the loading tiers instead of being connected to the numeric tier designations themselves. This has been fixed.
----------------------------------------------------------
Section 116: 2025.04.22.00.00.00
----------------------------------------------------------
TITLE:
ProjectSettings Popup Window: Font Definitions
DESCRIPTION:
Fonts definitions can now be edited from within the project settings popup window.
TITLE:
ProjectSettings Popup Window: Loading Tier Definitions
DESCRIPTION:
Loading Tier definitions can now be edited from within the project settings popup window.
TITLE:
ProjectSettings Popup Window: Font Reduction Settings
DESCRIPTION:
Font reduction settings can now be edited from within the project settings popup window.
----------------------------------------------------------
Section 117: 2025.04.21.01.00.00
----------------------------------------------------------
TITLE:
Re-open Control Center Feature Removed
DESCRIPTION:
Now, as soon as all Incisor tabs are closed, the app closes...
----------------------------------------------------------
Section 118: 2025.04.21.00.00.00
----------------------------------------------------------
TITLE:
TimelinePanel: Graph Editor Alignment Bug Fix
DESCRIPTION:
Bug fixed: the graph editor was mis-aligned with the keyframe graphic objects.
----------------------------------------------------------
Section 119: 2025.04.17.00.00.00
----------------------------------------------------------
TITLE:
Timeline: Double Tap Timescale
DESCRIPTION:
Now you can double tap the time scale bar to zoom the timeline into full visibility within the timeline editor.
----------------------------------------------------------
Section 120: 2025.04.16.00.00.00
----------------------------------------------------------
TITLE:
Application Settings GUI Rework
DESCRIPTION:
Completely new panel - streamlined look and improved usability.
TITLE:
Project Settings GUI Rework
DESCRIPTION:
Completely new panel - streamlined look and improved usability.
TITLE:
Switching Timelines in Construct Panel Changes Selected SceneObject
DESCRIPTION:
Now if you choose a different Timeline in the Construct panel or choose to add a new Timeline the Construct instance in the associated editor is automatically selected.
TITLE:
Timeline Panel: Default Filtering Off
DESCRIPTION:
An issue where the filtering button may be left on when creating a new Timeline was thought to have been fixed but persisted in some scenarios. This has been fixed now.
TITLE:
ApplicationSettings: maxUndoStates bug fixed
DESCRIPTION:
It is now functioning correctly.
TITLE:
LayoutStack.border Documentation Fix
DESCRIPTION:
It was listed twice, which was affecting the TypeScript API.
TITLE:
nc.phrases and nc.phraseIDs Restored in TypeScript
DESCRIPTION:
These members were missing from autocomplete in TypeScript and are no longer missing.
TITLE:
ProjectSettings: 'usingTypeScript' indicator set correctly
DESCRIPTION:
The indicator erroneously always displayed as true. This has been fixed.
TITLE:
ProjectSettings: New Configuration Name Bug
DESCRIPTION:
If the auto-generated name already existed, no new configuration was created. This has been fixed.
TITLE:
ProjectSettings: 'limitPublishedBuildsKept' is now a Project-Wide Setting
DESCRIPTION:
Previously it was a per-configuration setting. Now you can set the value and it just manages the total number of published builds
----------------------------------------------------------
Section 121: 2025.04.09.00.00.00
----------------------------------------------------------
TITLE:
Timeline Management Popup Added to Construct Panel
DESCRIPTION:
Now you can add timelines, remove timelines, duplicate timelines, and set the default timeline for a given Construct by clicking 'Manage Timelines'
TITLE:
TextBox Drag, Double Click, and Triple Click Bug
DESCRIPTION:
There were several associated bugs with TextBoxes caused by a low level malfunction in button drag functionality related to removing the requirement for drag threshold. This has been fixed.
TITLE:
TextBox Copy Paste Bug Fixed
DESCRIPTION:
In Windows, there were issues with copying and pasting with TextBoxes. This has been fixed.
TITLE:
Timeline Panel Playhead and Column Divider Bug Fix
DESCRIPTION:
Some of the organizational graphics were getting cut off and no longer are.
TITLE:
Timeline Panel Persistence Bugs Fixed
DESCRIPTION:
Open Close SceneObject, Graph Editor Open, and the zoom and location of the timescale weren't always properly persisting and now they are.
----------------------------------------------------------
Section 122: 2025.04.04.00.00.00
----------------------------------------------------------
TITLE:
Keyframes and Curve Handles Have Larger Button Areas and Rollover Animations
DESCRIPTION:
...for ease of use...
TITLE:
Editing Project Extensions Refreshes Browser
DESCRIPTION:
Every time a file change is detected within the project extensions directory, the browser will reload.
TITLE:
Timeline Panel State Persistence Improved
DESCRIPTION:
The open/close states of SceneObjects listed in the timeline panel are working now, along with the open/close state of graph editors.
----------------------------------------------------------
Section 123: 2025.04.02.00.00.00
----------------------------------------------------------
TITLE:
GUI Blank Tab Bug Fixed
DESCRIPTION:
There was a bug that resulted in the browser opening blank tabs while attempting to show the Incisor GUI. This has been fixed.
TITLE:
'Run as Administrator' no longer required for Windows
DESCRIPTION:
Port acquisition has been reworked so administration mode is no longer required.
----------------------------------------------------------
Section 124: 2025.03.31.00.00.00
----------------------------------------------------------
TITLE:
GraphicAsset Selection PopupWindow Added
DESCRIPTION:
For ease of use when selecting from a larger number of GraphicAssets.
TITLE:
Timeline Filter Button No Longer Defaults On
DESCRIPTION:
The default view is unfiltered.
TITLE:
Delete Items From Anywhere Bug Fixed
DESCRIPTION:
The keyboard input for deleting an object from the Hierarchy panel was lacking a singular focus requirement, and so keyboard commands were affecting selected items from anywhere. This has been fixed.
----------------------------------------------------------
Section 125: 2025.03.27.00.00.00
----------------------------------------------------------
TITLE:
Timeline Display Functionality Updates
DESCRIPTION:
In the Timeline panel: Added expand/collapse all button, 'show' button, and 'sort' button. Also made the state of those buttons, as well as the expanded/collapsed state of SceneObjects persistent.
----------------------------------------------------------
Section 126: 2025.03.26.00.00.00
----------------------------------------------------------
TITLE:
ProjectTranscript and PhraseID Functionality Added
DESCRIPTION:
Added nc.phraseIDs, nc.phrases, and nc.getPhrase, as well as TextBox.phraseID and TextAssembly.phraseID. In addition, phraseID is now 'capturable' via Constructs.
----------------------------------------------------------
Section 127: 2025.03.25.00.00.00
----------------------------------------------------------
TITLE:
Incisor Extensions Fleshed out and Documented
DESCRIPTION:
Added IncisorExtensions object and functionality. Also, Incisor now includes the 'SampleProjectExtensions.js' file in new projects, and the 'SampleGlobalExtensions.js' in the Incisor application support directory.
----------------------------------------------------------
Section 128: 2025.03.21.00.00.00
----------------------------------------------------------
TITLE:
Item Drag Extends Outside of Inspector Panels
DESCRIPTION:
Now if you are dragging a supervisor in the GUI to affect its value, you can continue to drag outside of the panel that contains it without the drag being interrupted.
TITLE:
Added 'CursorInputOverrideButton.allowExtendedDrag'
DESCRIPTION:
Flag determining if items within the inner scene associated with a CursorInputOverrideButton can be dragged outside of the bounds of the viewing camera.
TITLE:
Inspector KeyboardEvent Bug Fix
DESCRIPTION:
The 'Incisor Panel Refactor' fix introduced a bug that didn't allow keyboard input through the inspector to the project. This has been fixed.
----------------------------------------------------------
Section 129: 2025.03.20.00.00.00
----------------------------------------------------------
TITLE:
Windows Installation Bug Fixed
DESCRIPTION:
In some situations, installation was failing on Windows causing Incisor to not be able to find the WMPL executable.
TITLE:
Incisor Panel Refactor
DESCRIPTION:
Inspector panels have been reworked in the Incisor GUI to better prepare for making them available for customization in Incisor Extensions.
----------------------------------------------------------
Section 130: 2025.03.14.00.00.00
----------------------------------------------------------
TITLE:
TypeScript Critical Error Fixed
DESCRIPTION:
TypeScript projects entirely failed to open. Now fixed!
TITLE:
Construct Component Minification
DESCRIPTION:
Minification has been reworked to provide more robust detection and matching of tokens between Construct files and project code.
----------------------------------------------------------
Section 131: 2025.03.12.00.00.00
----------------------------------------------------------
TITLE:
fileIO.copyTo bug fixed
DESCRIPTION:
This was failing to default the 'rename' option internally... now fixed.
TITLE:
UiPoppWindow.setDecisionButtons layering issue fix.
DESCRIPTION:
There was an issue when calling 'setDecisionButtons' after changing the layers of a UiPopupWindow. Layers for decision buttons are now defaulted to the background of the given UiPopupWindow.
----------------------------------------------------------
Section 132: 2025.03.08.00.00.00
----------------------------------------------------------
TITLE:
Incisor Extensions Added!
DESCRIPTION:
Include javascript files in the 'Utilities/ProjectExtensions' in the project or '(ApplicationSupportDirectory)/Global Extensions' to extend the Incisor inspector with custom functionality.
TITLE:
nc.recreateObjectFromBlueprint returns root object
DESCRIPTION:
Previously, this function was returning an array with a single object in error. Now, the appropriate SceneObject is returned.
TITLE:
'includeDescendants' parameter included in nc.gatherObjectBlueprint
DESCRIPTION:
Now you can decide if you want to recurse into the descendants or not.
TITLE:
added 'nc.duplicateViaBlueprint'
DESCRIPTION:
The user can use the same system that is used by Constructs to duplicate SceneObjects or collections of SceneObjects by calling 'nc.duplicateViaBlueprint'
----------------------------------------------------------
Section 133: 2025.03.05.00.00.00
----------------------------------------------------------
TITLE:
Layers Bug Fix
DESCRIPTION:
The 'subLayers' calculation for GraphicObjects had a bug that allowed for subLayers to push GraphicObjects outside of the bounds of their layers. This bug has been fixed.
TITLE:
CodeAsset Format Update
DESCRIPTION:
The code asset file format has changed. The file extension has changed from '.codeAsset' to '.codeAsset.js'. In addition code that is meant to be run 'on init' must now be marked with the 'CODE.runBeforeInit___begin' and 'CODE.runBeforeInit___end' tags, otherwise, code in code asset files will be placed in the 'class' scope, so that classes can be accessible in ProjectCode classes. Code assets using the older format will be updated and tags will be automatically added.
TITLE:
CODE.preserveStart -> CODE.preserve___begin, CODE.preserveEnd -> CODE.preserve___end
DESCRIPTION:
Change made for consistency and clarity.
----------------------------------------------------------
Section 134: 2025.03.04.00.00.00
----------------------------------------------------------
TITLE:
GraphicExpander: ExpandableWidth duplicate reference in documentation fix
DESCRIPTION:
GraphicExpander.expandableHeight was mis-labeled as GraphicExpander.expandableWidth
TITLE:
TypeScript Code Iteration Bug Fixed
DESCRIPTION:
There was an issue in typescript projects where 'npm run build' was sporadically causing multiple refresh messages to go to the Incisor client, which was causing issues.
----------------------------------------------------------
Section 135: 2025.02.27.12.29.02
----------------------------------------------------------
TITLE:
Timelines: New numeric-type AnimatedProperties available
DESCRIPTION:
The following numeric properties can now be animated in Construct Timelines: all GraphicExpander components; GraphicObject.subLayer; PlaybackController.time, PlaybackController.value, PlaybackController.playbackRate, for Timelines, SpriteSetters, and ParticleSystems; Timeline.influence
TITLE:
Timelines: New boolean-type AnimatedProperties available
DESCRIPTION:
The following booleans can now be animated in Construct Timelines: the 'enabled' flag on all SceneObjects; the 'visible' flag on GraphicObjects; 'useAdditiveBlendingMode' on GraphicObjects.
TITLE:
Timelines: New function-invocation-type AnimatedProperties available
DESCRIPTION:
The following functions are now Timeline-Keyframe-invocable: play, pause, stop, and playOnce can be called on Timelines, SpriteSetters, and ParticleSystems; playOnceWithInfluence and playOnceAsEvent can also be called on Timelines
TITLE:
Timelines: SwoopInfluence, PlayOnceAsEvent, PlayOnceWithInfluence, PlayWithInfluence methods added
DESCRIPTION:
New helper functions to play and manipulate influence on Construct Timelines.
TITLE:
PlaybackControllers: autoplay and initialTime added
DESCRIPTION:
All PlaybackControllers including Timelines, SpriteSetters, and Particle systems now have 'autoplay' and 'initialTime' properties. These new properties make it easier to explicitly determine the initial time of Timelines in newly instantiated Constructs, as well as their playback state.
TITLE:
Inspector Hierarchy Panel: Inappropriate changes blocked
DESCRIPTION:
In the GUI, certain changes to SceneObjects in the TimelineEditorScene have been blocked. Blocked changes include reparenting, renaming, removing objects, and adding objects. These changes should only happen in the NeutralState of a Construct.
TITLE:
Publishing Analytics Panel Updated
DESCRIPTION:
Reworked for stability... Also, a 'Current Configuration' mode has been introduced so that users can see what it will look like if they publish in the current configuration.
TITLE:
Incisor failing to open in Windows bug mitigated
DESCRIPTION:
Some Windows defender configurations (in Windows 11) were preventing Incisor from hosting the HttpListeners and WebSockets it depends on. As a result, we've had to make running Incisor as 'an administrator' a requirement. Our intent is to investigate ways to remove this requirement in the future.
TITLE:
Intermitant graphic locking up bug fixed
DESCRIPTION:
On some systems, the Incisor inspector would cause Chrome and Safari garbage collection to become overwhelmed over time. In some cases this was causing significant freezing/locking of the browser. This has been fixed by implementing low-level systemic memory reuse.
TITLE:
GraphicExpander: API Reworked
DESCRIPTION:
GraphicExpanders have been reworked to have a more intuitive interface, they are now either in 'symmetric' mode, or not. When in symmetric mode you deal with width and height, otherwise you determine all of the bounds. Everything should be entirely backward compatible with clear deprecation messaging.
TITLE:
Construct: SceneObject-descendant duplication bug fixed
DESCRIPTION:
In certain circumstances, duplicating SceneObjects (or copying and pasting them) would result in multiple SceneObjects having the same UID, which led to all kinds of issues with Timeline keyframes disappearing etc... This bug has been fixed.
TITLE:
Buttons: Default PauseImmunity bug fixed
DESCRIPTION:
The default pauseImmunity of Buttons was not being set to nc.defaultPauseImmunity, and now it is.
TITLE:
Layers: Move to Scene without layers bug fixed
DESCRIPTION:
There was a bug where reparenting a GraphicObject into a Scene without its Layer was causing it to disappear. Now, the given GraphicObject's layer is remapped to DefaultLayer in this case.
----------------------------------------------------------
Section 136: 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.09.25.12.50.59
----------------------------------------------------------
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 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
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.09.25.12.50.58
----------------------------------------------------------
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: ProjectSettingsElectronWebPreferences
Section 84: GraphicObject
Section 85: Masking
Section 86: MaskGroup
Section 87: SpriteSetter
Section 88: UxTable
Section 89: Camera
Section 90: OrthographicCamera
Section 91: PerspectiveCamera
Section 92: Intersection
Section 93: LoadingTierDefinition
Section 94: IncisorExtensions
Section 95: ProcessResult
Section 96: InspectorPanel
Section 97: FileBrowser
Section 98: PrePublishInfoObject
Section 99: PostPublishInfoObject
Section 100: ProcessConfiguration
Section 101: ColorSupervisorButton
Section 102: PixelsObject
Section 103: PixelsObjects
Section 104: UiGraphicButton
Section 105: Scene
Section 106: Layer
Section 107: LayersByScene
Section 108: TimeStamp
Section 109: UxStringSupervisorTextField
Section 110: UxNumberSupervisorTextField
Section 111: UxBooleanSupervisorCheckbox
Section 112: AncillaryDevInfo
Section 113: ScrollingPanel
Section 114: Material
Section 115: ConstructDefinition
Section 116: Blueprint
Section 117: Construct
Section 118: UrlParameterIterator
Section 119: UiLinkButton
Section 120: TimePlaybackController
Section 121: ValuePlaybackController
Section 122: PlaybackController
Section 123: UiBooleanSupervisor_checkbox
Section 124: Publishing
Section 125: Precomp
Section 126: AnimatedProperty
Section 127: CustomBlendingMode
Section 128: UiTextField
Section 129: WaitThen
Section 130: UiStringSupervisor_menu
Section 131: GraphicAsset
Section 132: MaterialPreset
Section 133: CustomAddOnDefinition
Section 134: RegisteredProperty
Section 135: CustomAddOnBase
Section 136: CustomAddOn_SceneObject
Section 137: CustomAddOn_GraphicObject
Section 138: CustomAddOn_Button
Section 139: CustomAddOn_TextBox
Section 140: CustomAddOn_TextAssembly
Section 141: CustomAddOn_ParticleSystem
Section 142: CustomAddOn_Construct
Section 143: RenderTarget
Section 144: ApplicationSettings
Section 145: ApplicationColorTheme
Section 146: LayoutStack
Section 147: UxStringSupervisorMenu
Section 148: UiStringSupervisor_textField
Section 149: UiNumberSupervisor_textField
Section 150: LazyUpdater
Section 151: KeyframedValue
Section 152: ValueKeyframe
Section 153: Code
Section 154: Timeline
Section 155: CustomObjectDefinition
Section 156: TextFormat
Section 157: CharacterMaterial
Section 158: IncisorApp
Section 159: IncisorAppBasic
Section 160: Swooper
Section 161: TweenType
Section 162: TweenControllers
Section 163: Curve
Section 164: CurvePoint
Section 165: Vector1Swoop
Section 166: Vector2Swoop
Section 167: Vector3Swoop
Section 168: Vector4Swoop
Section 169: ColorSwoop
Section 170: Vector1AddMotion
Section 171: Vector2AddMotion
Section 172: Vector3AddMotion
Section 173: Vector4AddMotion
Section 174: ColorAddMotion
Section 175: Vector4Base
Section 176: Vector4
Section 177: Color
Section 178: Vector3Base
Section 179: Vector3
Section 180: Vector2Base
Section 181: Vector2
Section 182: VectorBase
Section 183: Vector1
Section 184: Geometry
Section 185: SymbolReel
Section 186: UxVectorSupervisorTextField
Section 187: TextBox
Section 188: HtmlBacking
Section 189: RangeInfo
Section 190: Pdf
Section 191: PdfSection
Section 192: PdfParagraph
Section 193: PdfHeader
Section 194: PdfFooter
Section 195: PdfImage
Section 196: PdfTable
Section 197: PdfRow
Section 198: PdfCell
Section 199: PdfTextFrame
Section 200: CursorInputOverrideButton
Section 201: UiMenu
Section 202: UiMenuItem
Section 203: Constants
Section 204: UiPopupWindow
Section 205: INCISOR
Section 206: Supervisor
Section 207: 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. Use 'setSkin' to apply one or more of these skins.
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.
----------------------------------------------------------
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 Sound belongs too. 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.
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.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.os
[type: string] [default: "--win --x64"]
Target OS / architecture argument string for the Electron build.
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: 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 84: 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 85: 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.
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).
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 86: 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 87: 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 88: 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 89: 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 90: 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 91: 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 92: 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 93: 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.
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 94: 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.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.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.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 95: 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 96: 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 97: 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 98: 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 99: 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 100: 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 101: 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 102: 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 103: 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 104: 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 105: 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 106: 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 107: 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 108: 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 109: 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 110: 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 111: 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 112: 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 113: 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 114: 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 115: 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 116: 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 117: 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 118: 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 119: 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 120: 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 121: 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 122: 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 123: 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 124: 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 125: 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 126: 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 127: 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 128: 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 129: 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 130: 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 131: 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 132: 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 133: 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 134: 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 135: 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 136: 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 137: 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 138: 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 139: 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 140: 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 141: 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 142: 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 143: 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 144: 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.browserClient
[type: string] [default: ""]
This field determines which browser is used for the Incisor® front-end GUI and inspector. Type the browser name as expected by the operating system. Please be aware that different OSs refer to browsers differently (for example "Google Chrome" vs "Chrome").
example:
// Example values mentioned in Incisor documentation:
// Windows: "Chrome", "msedge", "firefox"
// macOS: "Google Chrome", "Safari", "Firefox"
ApplicationSettings.browserClientAdditionalOpeningArgs
[type: string] [default: ""]
Additional command-line style arguments supplied to the OS when opening the selected browser.
example:
// Example:
// "--auto-open-devtools-for-tabs"
ApplicationSettings.heartbeatTimeoutInterval
[type: number] [default: 2.0]
Internal timeout interval related to the application's communication / heartbeat behavior. This value is persisted in ApplicationSettings.json even though it is not typically a primary user-facing setting in the popup.
ApplicationSettings.connectionPorts
[type: [number]]
A list of ports that Incisor® can use to connect to the front-end browser. Incisor® does its best to determine when ports are in use by other processes, but in some cases different ports must be used to enable Incisor® to communicate properly.
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.refreshOnAssetChange
[type: boolean] [default: true]
Setting determining if changing assets on disk causes the current project to automatically refresh.
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.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 145: 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 146: 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 147: 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 148: 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 149: 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 150: 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 151: 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 152: 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 153: 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 154: 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 155: 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 156: 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 157: 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 158: 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 159: 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 160: 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 161: 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 162: TweenControllers
----------------------------------------------------------
TweenControllers
[type: class] [NON-INSTANTIABLE]
Dictionary of all registered TweenControllers.
----------------------------------------------------------
Section 163: 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 164: 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 165: 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 166: 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 167: 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 168: 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 169: 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 170: 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 171: 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 172: 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 173: 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 174: 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 175: 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 176: 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 177: 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 178: 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 179: 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 180: 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 181: 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 182: 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 183: 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 184: 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 185: 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 186: 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 187: 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 188: 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 189: 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 190: 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 191: 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 192: 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 193: 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 194: 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 195: 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 196: 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 197: 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 198: 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 199: 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 200: 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 201: 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 202: 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 203: 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 204: 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 205: 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.renderTargets.incr_saveThumbnailRenderTarget
[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)
[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.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: true] [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.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 206: 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 207: 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® 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.09.25.12.50.58
----------------------------------------------------------
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-09-25T19:48:46.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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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":{
"autoplay":false,
"initialTime":0,
"playbackRate":1,
"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":37.00000000000023},
{"time":0.35000000000000003,"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.6833333333333336,"value":0},
{"time":3,"value":37.00000000000023},
{"time":3.35,"value":-38.59999999999988},
{"time":3.5,"value":-46.999999999999886},
{"time":3.6833333333333336,"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}
]
},
{
"sceneObject":[2,0,2,0],
"sceneObjectUid":"9868125099917119",
"propertyPath":["rotation","z"],
"keyframes":[
{"time":0,"value":13.999999999999432},
{"time":0.35000000000000003,"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.8333333333333335,"value":-4},
{"time":2,"value":13.999999999999432},
{"time":2.35,"value":-15.700000000000568},
{"time":2.5,"value":-19.00000000000057},
{"time":2.6833333333333336,"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.6833333333333336,"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.833333333333334,"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.833333333333334,"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.833333333333334,"value":-4},
{"time":8,"value":13.999999999999432}
]
},
{
"sceneObject":[2,0,2,0,0],
"sceneObjectUid":"1001230710194815",
"propertyPath":["rotation","z"],
"keyframes":[
{"time":0,"value":30.080087455487593},
{"time":0.18333333333333335,"value":2.6800874554870706},
{"time":0.35000000000000003,"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.1833333333333336,"value":2.6800874554870706},
{"time":2.35,"value":3.0000874554872157},
{"time":2.5,"value":3.080087455487252},
{"time":2.6833333333333336,"value":0},
{"time":3,"value":30.080087455487593},
{"time":3.1833333333333336,"value":2.6800874554870706},
{"time":3.35,"value":3.0000874554872157},
{"time":3.5,"value":3.080087455487252},
{"time":3.6833333333333336,"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}
]
},
{
"sceneObject":[2,0,3],
"sceneObjectUid":"2333391500121242",
"propertyPath":["rotation","z"],
"keyframes":[
{"time":-0.49999999999999994,"value":37},
{"time":-0.1499999999999999,"value":-38},
{"time":0,"value":-47},
{"time":0.18333333333333335,"value":0},
{"time":0.4999999999999999,"value":37},
{"time":0.5,"value":37},
{"time":0.8500000000000001,"value":-38},
{"time":1,"value":-47},
{"time":1.1833333333333333,"value":0},
{"time":1.5,"value":37},
{"time":1.85,"value":-38},
{"time":2,"value":-47},
{"time":2.1833333333333336,"value":0},
{"time":2.5,"value":37},
{"time":2.85,"value":-38},
{"time":3,"value":-47},
{"time":3.1833333333333336,"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}
]
},
{
"sceneObject":[2,0,3,0],
"sceneObjectUid":"0520431315092932",
"propertyPath":["rotation","z"],
"keyframes":[
{"time":-0.49999999999999994,"value":14},
{"time":-0.1499999999999999,"value":-15.7},
{"time":0,"value":-19},
{"time":0.18333333333333335,"value":0},
{"time":0.33333333333333337,"value":-4},
{"time":0.4999999999999999,"value":14},
{"time":0.5,"value":14},
{"time":0.8500000000000001,"value":-15.7},
{"time":1,"value":-19},
{"time":1.1833333333333333,"value":0},
{"time":1.3333333333333335,"value":-4},
{"time":1.5,"value":14},
{"time":1.85,"value":-15.7},
{"time":2,"value":-19},
{"time":2.1833333333333336,"value":0},
{"time":2.3333333333333335,"value":-4},
{"time":2.5,"value":14},
{"time":2.85,"value":-15.7},
{"time":3,"value":-19},
{"time":3.1833333333333336,"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.333333333333334,"value":-4},
{"time":5.5,"value":14}
]
},
{
"sceneObject":[2,0,3,0,0],
"sceneObjectUid":"3249685385429677",
"propertyPath":["rotation","z"],
"keyframes":[
{"time":-0.49999999999999994,"value":30},
{"time":-0.3166666666666666,"value":2.6},
{"time":-0.1499999999999999,"value":3},
{"time":0,"value":3},
{"time":0.18333333333333335,"value":0},
{"time":0.4999999999999999,"value":30},
{"time":0.5,"value":30},
{"time":0.6833333333333333,"value":2.6},
{"time":0.8500000000000001,"value":3},
{"time":1,"value":3},
{"time":1.1833333333333333,"value":0},
{"time":1.5,"value":30},
{"time":1.6833333333333333,"value":2.6},
{"time":1.85,"value":3},
{"time":2,"value":3},
{"time":2.1833333333333336,"value":0},
{"time":2.5,"value":30},
{"time":2.6833333333333336,"value":2.6},
{"time":2.85,"value":3},
{"time":3,"value":3},
{"time":3.1833333333333336,"value":0},
{"time":3.5,"value":30},
{"time":3.6833333333333336,"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}
]
},
{
"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.5,
"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,
"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":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":-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}
]
},
{
"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":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}
]
},
{
"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":28},
{"time":0.35000000000000003,"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.8333333333333335,"value":28},
{"time":2,"value":28},
{"time":2.35,"value":-6.199999999999896},
{"time":2.5,"value":-9.999999999999886},
{"time":2.6833333333333336,"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.6833333333333336,"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.833333333333334,"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.833333333333334,"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.833333333333334,"value":28},
{"time":8,"value":28}
]
},
{
"sceneObject":[2,0,2],
"sceneObjectUid":"6331146838850387",
"propertyPath":["position","y"],
"keyframes":[
{"time":0,"value":-76},
{"time":0.18333333333333335,"value":-57},
{"time":0.35000000000000003,"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.8333333333333335,"value":-76},
{"time":2,"value":-76},
{"time":2.1833333333333336,"value":-57},
{"time":2.35,"value":-72.2},
{"time":2.5,"value":-76},
{"time":2.6833333333333336,"value":-56},
{"time":2.8333333333333335,"value":-76},
{"time":3,"value":-76},
{"time":3.1833333333333336,"value":-57},
{"time":3.35,"value":-72.2},
{"time":3.5,"value":-76},
{"time":3.6833333333333336,"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.833333333333334,"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.833333333333334,"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.833333333333334,"value":-76},
{"time":8,"value":-76}
]
},
{
"sceneObject":[2,0,2,0],
"sceneObjectUid":"9868125099917119",
"propertyPath":["position","x"],
"keyframes":[
{"time":0,"value":0},
{"time":0.8333333333333334,"value":0},
{"time":1,"value":0},
{"time":1.8333333333333335,"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.833333333333334,"value":0},
{"time":6,"value":0},
{"time":6.833333333333334,"value":0},
{"time":7,"value":0},
{"time":7.833333333333334,"value":0},
{"time":8,"value":0}
]
},
{
"sceneObject":[2,0,2,0],
"sceneObjectUid":"9868125099917119",
"propertyPath":["position","y"],
"keyframes":[
{"time":0,"value":-19},
{"time":0.8333333333333334,"value":-19},
{"time":1,"value":-19},
{"time":1.8333333333333335,"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.833333333333334,"value":-19},
{"time":6,"value":-19},
{"time":6.833333333333334,"value":-19},
{"time":7,"value":-19},
{"time":7.833333333333334,"value":-19},
{"time":8,"value":-19}
]
},
{
"sceneObject":[2,0,3],
"sceneObjectUid":"2333391500121242",
"propertyPath":["position","x"],
"keyframes":[
{"time":-0.5,"value":16.000000000000227},
{"time":0.18333333333333332,"value":-14},
{"time":0.33333333333333337,"value":8.000000000000167},
{"time":0.4999999999999999,"value":16.000000000000227},
{"time":0.5,"value":16.000000000000227},
{"time":1.1833333333333333,"value":-14},
{"time":1.3333333333333335,"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.1833333333333336,"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.333333333333334,"value":8.000000000000167},
{"time":5.5,"value":16.000000000000227}
]
},
{
"sceneObject":[2,0,3],
"sceneObjectUid":"2333391500121242",
"propertyPath":["position","y"],
"keyframes":[
{"time":-0.49999999999999994,"value":-64},
{"time":-0.31666666666666665,"value":-48},
{"time":-0.15000000000000002,"value":-64},
{"time":0.18333333333333335,"value":-44},
{"time":0.33333333333333337,"value":-64},
{"time":0.4999999999999999,"value":-64},
{"time":0.5,"value":-64},
{"time":0.6833333333333333,"value":-48},
{"time":0.8500000000000001,"value":-64},
{"time":1.1833333333333333,"value":-44},
{"time":1.3333333333333335,"value":-64},
{"time":1.5,"value":-64},
{"time":1.6833333333333333,"value":-48},
{"time":1.85,"value":-64},
{"time":2.1833333333333336,"value":-44},
{"time":2.3333333333333335,"value":-64},
{"time":2.5,"value":-64},
{"time":2.6833333333333336,"value":-48},
{"time":2.85,"value":-64},
{"time":3.1833333333333336,"value":-44},
{"time":3.3333333333333335,"value":-64},
{"time":3.5,"value":-64},
{"time":3.6833333333333336,"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.333333333333334,"value":-64},
{"time":5.5,"value":-64}
]
},
{
"sceneObject":[2,0,3,0],
"sceneObjectUid":"0520431315092932",
"propertyPath":["position","x"],
"keyframes":[
{"time":-0.49999999999999994,"value":-2},
{"time":0.18333333333333335,"value":-2},
{"time":0.33333333333333337,"value":-2},
{"time":0.4999999999999999,"value":-2},
{"time":0.5,"value":-2},
{"time":1.1833333333333333,"value":-2},
{"time":1.3333333333333335,"value":-2},
{"time":1.5,"value":-2},
{"time":2.1833333333333336,"value":-2},
{"time":2.3333333333333335,"value":-2},
{"time":2.5,"value":-2},
{"time":3.1833333333333336,"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.333333333333334,"value":-2},
{"time":5.5,"value":-2}
]
},
{
"sceneObject":[2,0,3,0],
"sceneObjectUid":"0520431315092932",
"propertyPath":["position","y"],
"keyframes":[
{"time":-0.49999999999999994,"value":-13},
{"time":0.18333333333333335,"value":-13},
{"time":0.33333333333333337,"value":-13},
{"time":0.4999999999999999,"value":-13},
{"time":0.5,"value":-13},
{"time":1.1833333333333333,"value":-13},
{"time":1.3333333333333335,"value":-13},
{"time":1.5,"value":-13},
{"time":2.1833333333333336,"value":-13},
{"time":2.3333333333333335,"value":-13},
{"time":2.5,"value":-13},
{"time":3.1833333333333336,"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.333333333333334,"value":-13},
{"time":5.5,"value":-13}
]
},
{
"sceneObject":[2,0,2,0,0],
"sceneObjectUid":"1001230710194815",
"propertyPath":["position","x"],
"keyframes":[
{"time":0,"value":12},
{"time":0.8333333333333334,"value":12},
{"time":1,"value":12},
{"time":1.8333333333333335,"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.833333333333334,"value":12},
{"time":6,"value":12},
{"time":6.833333333333334,"value":12},
{"time":7,"value":12},
{"time":7.833333333333334,"value":12},
{"time":8,"value":12}
]
},
{
"sceneObject":[2,0,2,0,0],
"sceneObjectUid":"1001230710194815",
"propertyPath":["position","y"],
"keyframes":[
{"time":0,"value":-56},
{"time":0.8333333333333334,"value":-56},
{"time":1,"value":-56},
{"time":1.8333333333333335,"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.833333333333334,"value":-56},
{"time":6,"value":-56},
{"time":6.833333333333334,"value":-56},
{"time":7,"value":-56},
{"time":7.833333333333334,"value":-56},
{"time":8,"value":-56}
]
},
{
"sceneObject":[2,0,3,0,0],
"sceneObjectUid":"3249685385429677",
"propertyPath":["position","x"],
"keyframes":[
{"time":-0.49999999999999994,"value":14},
{"time":0.18333333333333335,"value":14},
{"time":0.33333333333333337,"value":14},
{"time":0.4999999999999999,"value":14},
{"time":0.5,"value":14},
{"time":1.1833333333333333,"value":14},
{"time":1.3333333333333335,"value":14},
{"time":1.5,"value":14},
{"time":2.1833333333333336,"value":14},
{"time":2.3333333333333335,"value":14},
{"time":2.5,"value":14},
{"time":3.1833333333333336,"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.333333333333334,"value":14},
{"time":5.5,"value":14}
]
},
{
"sceneObject":[2,0,3,0,0],
"sceneObjectUid":"3249685385429677",
"propertyPath":["position","y"],
"keyframes":[
{"time":-0.49999999999999994,"value":-60},
{"time":0.18333333333333335,"value":-60},
{"time":0.33333333333333337,"value":-60},
{"time":0.4999999999999999,"value":-60},
{"time":0.5,"value":-60},
{"time":1.1833333333333333,"value":-60},
{"time":1.3333333333333335,"value":-60},
{"time":1.5,"value":-60},
{"time":2.1833333333333336,"value":-60},
{"time":2.3333333333333335,"value":-60},
{"time":2.5,"value":-60},
{"time":3.1833333333333336,"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.333333333333334,"value":-60},
{"time":5.5,"value":-60}
]
},
{
"sceneObject":[2,0],
"sceneObjectUid":"8391582935630722",
"propertyPath":["position","y"],
"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.6833333333333336,"value":-40.99999999999971},
{"time":3,"value":28.999999999999943},
{"time":3.1833333333333336,"value":-40.99999999999971},
{"time":3.5,"value":28.999999999999943},
{"time":3.6833333333333336,"value":-40.99999999999971},
{"time":4,"value":28.999999999999943}
]
},
{
"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,"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}
]
},
{
"sceneObject":[2,0,4],
"sceneObjectUid":"7554277963686835",
"propertyPath":["position","y"],
"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}
]
},
{
"sceneObject":[2,0,4,0,0],
"sceneObjectUid":"6553804298258501",
"propertyPath":["position","x"],
"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}
]
},
{
"sceneObject":[2,0,4,0,0],
"sceneObjectUid":"6553804298258501",
"propertyPath":["position","y"],
"keyframes":[
{"time":0,"value":-11},
{"time":1.5,"value":-11},
{"time":3.5,"value":-11},
{"time":4,"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":2.333333333333321,"value":false}
]
},
{
"sceneObject":[3],
"sceneObjectUid":"3201523667536051",
"propertyPath":["scale","y"],
"keyframes":[
{"time":0,"value":1}
]
},
{"sceneObject":[2],"sceneObjectUid":"6320565315338379","propertyPath":["position","y"],"keyframes":[]},
{
"sceneObject":[2],
"sceneObjectUid":"6320565315338379",
"propertyPath":["scale","y"],
"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.6833333333333336,"value":0.9},
{"time":3,"value":1.1},
{"time":3.183333333333333,"value":0.9},
{"time":3.5,"value":1.1},
{"time":3.6833333333333336,"value":0.9},
{"time":4,"value":1.1}
]
},
{"sceneObject":[2],"sceneObjectUid":"6320565315338379","propertyPath":["scale","x"],"keyframes":[]},
{
"sceneObject":[2,0],
"sceneObjectUid":"8391582935630722",
"propertyPath":["rotation","z"],
"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.166666666666667,"value":-0.8991862025184969},
{"time":2.5,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4},
{"time":2.666666666666667,"value":-0.8991862025184969},
{"time":3,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4},
{"time":3.166666666666667,"value":-0.8991862025184969},
{"time":3.5,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4},
{"time":3.666666666666667,"value":-0.8991862025184969},
{"time":4,"value":16.999999999999943,"leftHandleValue":0,"leftHandleSpan":0.4}
]
},
{
"sceneObject":[2,0],
"sceneObjectUid":"8391582935630722",
"propertyPath":["position","x"],
"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.6833333333333336,"value":24.999999999999943},
{"time":3,"value":0},
{"time":3.183333333333333,"value":24.999999999999943},
{"time":3.5,"value":0},
{"time":3.6833333333333336,"value":24.999999999999943},
{"time":4,"value":0}
]
}
]
}
},
"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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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 influence of the timeline we want to manipulate.
// If no influence is set, calling playback controller functions won't result in any visual changes.
this.incisorSaurus.timelines.Idle.influence = 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 _swoopInfluence functions to play and swoop the influnence of a new timeline without having to set the influence seperately.
// Swooping the timeline influence will interpolate the animated values of objects within the construct from one timeline to another.
// Play_swoopInfluence will tween to the designated timeline over a given duration, then continuously loop it.
this.incisorSaurus.timelines.Walk.play_swoopInfluence(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.play_swoopInfluence(.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() {
// PlayOnce_swoopInfluence will tween to the designated timeline and play it once, then return to a designated timeline.
// If returnToTimeline is left undefined, it will return to the timeline that was playing before PlayOnce_swoopInfluence was called.
this.incisorSaurus.timelines.Growl.playOnce_swoopInfluence(.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.play_swoopInfluence(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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
class IncisorExample extends SceneObject {
constructor(parent, name) {
super(parent, name);
}
}
ProjectCode/ProjectMain.js
------------------------------------------------------------
"use strict";
// 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":["[[-1,\"Timeline Editor Scene: Incisorsaurus→Run\"],[0,\"Incisorsaurus\"],[2,\"Controller\"],[0,\"Incisorsaurus_0015_Body\"]]"]},"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,enterprise","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-09-25T19:48:49.659Z
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
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
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
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
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
/** 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"
}
]
}
},
"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"
}
]
}
},
"layers":[],
"constructSettings":{"targetScene":"MainScene","defaultTimeline":"BaseLayout_Mobile"}
}
Assets/GameLayout/GameLayout.construct.ncData
------------------------------------------------------------
default ncData file
Assets/GameLayout/GameTitle.png.ncData
------------------------------------------------------------
default ncData file
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
------------------------------------------------------------
default ncData file
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/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/SymbolImages.ncData
------------------------------------------------------------
default ncData file
ProjectCode/FlowStates/00 GameIntro.js
------------------------------------------------------------
"use strict";
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;
}
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
------------------------------------------------------------
"use strict";
class GameIdle extends FlowState {
constructor() {
super();
this.addElement(0, "startIdle");
}
startIdle() {
}
}
ProjectCode/FlowStates/02 StartGame.js
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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() {
// check to see that all reels have spun and stopped...
if (this.allReelsHaveStarted === true) {
let allReelsAreStopped = true;
for (let i = 0; i < pr.symbolReels.length; i++) {
if (pr.symbolReels[i].reelState !== "stopped" && pr.symbolReels[i].reelState !== "bounce") {
allReelsAreStopped = false;
break;
}
}
if (allReelsAreStopped === true) {
nc.sounds.ReelSpinSound.pause();
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) {
pr.symbolReels[reelIdx].beginStop(true);
}
}
ProjectCode/FlowStates/05 WinCelebration.js
------------------------------------------------------------
"use strict";
class WinCelebration extends FlowState {
constructor() {
super();
this.centerWinMeter = pr.gameLayout.descendantsByName.CenterWinMeter;
this.winRollupAmount = 0;
this.addElement(0, "startWinCelebration");
this.addElement(.2, "highlightWin");
this.addElement(1.1, "unhighlightWinSymbols");
this.addElement(1.2, "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.scale.swoop.all(1.2, 2, nc.tweenTypes.ExtremeEaseIn);
symbol.layer = nc.layers.WinningSymbols;
}
else {
symbol.scale.swoop.all(1, .5, nc.tweenTypes.Ease);
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() {
for (let i = 0; i < pr.symbolReels.length; i++) {
for (let j = 0; j < pr.symbolReels[i].numMainSymbols; j++) {
pr.symbolReels[i].getSymbol(j).scale.swoop.all(1, .5, nc.tweenTypes.Ease);
pr.symbolReels[i].getSymbol(j).brightnessContrast.swoop.brightness(0, 1, nc.tweenTypes.Ease);
}
}
}
goToNextWin() {
this.setTime(.1, true);
}
cleanUpWinCelebration() {
this.unhighlightWinSymbols();
pr.gameLayout.descendantsByName.ReelBackground.brightnessContrast.swoop.brightness(0, .25);
pr.gameLayout.descendantsByName.GameBackgroundPattern.brightnessContrast.swoop.brightness(0, .35);
}
}
ProjectCode/PreloadConfiguration/PreloadConfiguration.js
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
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
------------------------------------------------------------
"use strict";
/** 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
------------------------------------------------------------
"use strict";
// 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, "adjustGameLayoutAspectRatio");
this.adjustGameLayoutAspectRatio();
// 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);
}
adjustGameLayoutAspectRatio() {
// acquire aspect ratio
let canvasResolution = nc.getCanvasPixelResolution();
let aspectRatio = canvasResolution.x / canvasResolution.y;
// set GameLayout construct's time based on aspect ratio
if (aspectRatio <= 1) {
this.gameLayout.timelines.BaseLayout_Mobile.time = -1 / aspectRatio;
}
else {
this.gameLayout.timelines.BaseLayout_Mobile.time = aspectRatio;
}
}
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
------------------------------------------------------------
"use strict";
/** 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/ProjectState.json
------------------------------------------------------------
{"docFormatVersion":0,"panelLayout":{"subPanels":[{"subPanels":[{"subPanels":[],"panelType":"Tool Tips","isColumns":true,"divisionLocation":0.5,"stateInfo":""},{"subPanels":[{"subPanels":[{"subPanels":[],"panelType":"Object","isColumns":true,"divisionLocation":0.5,"stateInfo":""},{"subPanels":[],"panelType":"Hierarchy","isColumns":true,"divisionLocation":0.5,"stateInfo":""}],"isColumns":false,"divisionLocation":0.5,"stateInfo":""},{"subPanels":[],"panelType":"Flows","isColumns":true,"divisionLocation":0.5,"stateInfo":""}],"isColumns":true,"divisionLocation":0.4659931794086369,"stateInfo":""}],"isColumns":false,"divisionLocation":0.12,"stateInfo":""},{"subPanels":[],"panelType":"Live View","isColumns":true,"divisionLocation":0.5,"stateInfo":""}],"isColumns":true,"divisionLocation":0.41349433641404976,"stateInfo":""},"selectionState":{"sceneObject":["[[-1,\"MainScene\"],[1,\"GameLayout\"],[1,\"GameTitleContainer\"],[0,\"GameTitle\"]]"]},"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\"]]"]},"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,enterprise","publishingPopupStateInfo":{"currentConfiguration":"LocalDev","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":"Red","latestIncisorVersionUsed":"2026.08.12.10.20.44","requiredPermissions":"proGaming","usingTypescript":false,"assetConfigurationDefinitions":{"assetPackageScale":["100","50"],"soundQuality":["stereo_115","mono_55"],"language":["en","es"]},"assetConfigurationDataOrder":["assetPackageScale","soundQuality","language"],"conditionalCodeTagDefinitions":["LocalDev","WebPublish","EgmPublish"],"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":[]},"EgmPublish":{"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"]}},"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.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-09-25T19:48:48.483Z
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
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
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
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
ProjectState.json
ProjectTranscript.json
Assets.ncData
package.json
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"
}
]
}
},
"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"
}
]
}
},
"layers":[],
"constructSettings":{"targetScene":"MainScene","defaultTimeline":"BaseLayout_Mobile"}
}
Assets/GameLayout/GameLayout.construct.ncData
------------------------------------------------------------
default ncData file
Assets/GameLayout/GameTitle.png.ncData
------------------------------------------------------------
default ncData file
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
------------------------------------------------------------
default ncData file
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/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/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;
}
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()
{
// check to see that all reels have spun and stopped...
if(this.allReelsHaveStarted===true)
{
let allReelsAreStopped = true;
for(let i=0; i<pr.symbolReels.length; i++)
{
if(pr.symbolReels[i].reelState!=="stopped" && pr.symbolReels[i].reelState!=="bounce")
{
allReelsAreStopped=false;
break;
}
}
if(allReelsAreStopped===true)
{
nc.sounds.ReelSpinSound.pause();
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)
{
pr.symbolReels[reelIdx].beginStop(true);
}
}
TypescriptProjectCode/FlowStates/05 WinCelebration.ts
------------------------------------------------------------
class WinCelebration extends FlowState
{
winRollupAmount:number;
centerWinMeter:TextBox;
winHighlightIndex:number;
constructor()
{
super()
this.centerWinMeter = pr.gameLayout.descendantsByName.CenterWinMeter;
this.winRollupAmount = 0;
this.addElement(0,"startWinCelebration");
this.addElement(.2,"highlightWin");
this.addElement(1.1,"unhighlightWinSymbols");
this.addElement(1.2,"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.scale.swoop.all(1.2,2,nc.tweenTypes.ExtremeEaseIn);
symbol.layer = nc.layers.WinningSymbols;
}
else
{
symbol.scale.swoop.all(1,.5,nc.tweenTypes.Ease);
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()
{
for(let i=0; i<pr.symbolReels.length; i++)
{
for(let j=0; j<pr.symbolReels[i].numMainSymbols; j++)
{
pr.symbolReels[i].getSymbol(j).scale.swoop.all(1,.5,nc.tweenTypes.Ease);
pr.symbolReels[i].getSymbol(j).brightnessContrast.swoop.brightness(0,1,nc.tweenTypes.Ease);
}
}
}
goToNextWin()
{
this.setTime(.1,true);
}
cleanUpWinCelebration()
{
this.unhighlightWinSymbols();
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,"adjustGameLayoutAspectRatio");
this.adjustGameLayoutAspectRatio();
// 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);
}
adjustGameLayoutAspectRatio()
{
// acquire aspect ratio
let canvasResolution = nc.getCanvasPixelResolution();
let aspectRatio = canvasResolution.x/canvasResolution.y;
// set GameLayout construct's time based on aspect ratio
if(aspectRatio<=1)
{
this.gameLayout.timelines.BaseLayout_Mobile.time=-1/aspectRatio;
}
else
{
this.gameLayout.timelines.BaseLayout_Mobile.time=aspectRatio;
}
}
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/ProjectState.json
------------------------------------------------------------
{"docFormatVersion":0,"panelLayout":{"subPanels":[{"subPanels":[{"subPanels":[],"panelType":"Tool Tips","isColumns":true,"divisionLocation":0.5,"stateInfo":""},{"subPanels":[{"subPanels":[{"subPanels":[],"panelType":"Object","isColumns":true,"divisionLocation":0.5,"stateInfo":""},{"subPanels":[],"panelType":"Hierarchy","isColumns":true,"divisionLocation":0.5,"stateInfo":""}],"isColumns":false,"divisionLocation":0.5,"stateInfo":""},{"subPanels":[],"panelType":"Flows","isColumns":true,"divisionLocation":0.5,"stateInfo":""}],"isColumns":true,"divisionLocation":0.4659931794086369,"stateInfo":""}],"isColumns":false,"divisionLocation":0.12,"stateInfo":""},{"subPanels":[],"panelType":"Live View","isColumns":true,"divisionLocation":0.5,"stateInfo":""}],"isColumns":true,"divisionLocation":0.41349433641404976,"stateInfo":""},"selectionState":{"sceneObject":["[[-1,\"MainScene\"],[1,\"GameLayout\"],[1,\"GameTitleContainer\"],[0,\"GameTitle\"]]"]},"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\"]]"]},"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,enterprise","publishingPopupStateInfo":{"currentConfiguration":"LocalDev","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.
package.json
------------------------------------------------------------
{
"name": "incisortypescript",
"version": "1.0.0",
"main": "ProjectMain.js",
"scripts": {
"prebuild": "npx rimraf ./ProjectCode/TypescriptGeneratedJS",
"build": "tsc"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}
ProjectSettings.json
------------------------------------------------------------
{"docFormatVersion":0,"publicProjectName":"Incisor Slot Template TS","projectCodeName":"IncisorSlotTemplateTS","latestIncisorVersionSetUsed":"Red","latestIncisorVersionUsed":"2026.08.12.10.20.44","requiredPermissions":"proGaming","usingTypescript":true,"assetConfigurationDefinitions":{"assetPackageScale":["100","50"],"soundQuality":["stereo_115","mono_55"],"language":["en","es"]},"assetConfigurationDataOrder":["assetPackageScale","soundQuality","language"],"conditionalCodeTagDefinitions":["LocalDev","WebPublish","EgmPublish"],"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":[]},"EgmPublish":{"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"]}},"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.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"]
}