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
2025.12.18.13.09.02






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










----------------------------------------------------------
Section 1: 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 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: 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 4: 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 5: 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 6: 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 7: 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 8: 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 9: 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 10: 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 11: 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 12: 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 13: 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 14: 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 15: 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 16: 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 17: 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 18: 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 19: 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.



















----------------------------------------------------------
Section 20: 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 21: 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 22: 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 23: 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 24: 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 25: 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 26: 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 27: 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 28: 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 29: 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 30: 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 31: 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.

