Navigation for the ZIM JavaScript Canvas Framework

Here are some terms that we use in our world of ZIM.

  • ZIM JavaScript Canvas Framework to code creativity - adds conveniences, components and controls to CreateJS.
  • JavaScript a very popular object oriented programming language (currently ES6) to code the Browswer DOM, canvas, and server. See JAVASCRIPT.
  • Canvas a new HTML 5 tag that supports dynamic drawing with JavaScript. ZIM Frame will make the Canvas tag for you.
  • Framework a term for code that helps coders code code. More all-encompassing than a code library. ZIM has a Frame class that makes the canvas, sets the stage and handles scaling. See FRAME.
  • Stage the base container where we add our display objects. The metaphor was used in Macromedia (Adobe) Director and Flash.
  • Zapp! something made with ZIM like a game, app, puzzle, art, interactive logo, gadget, etc.
  • Distill the system to minify only the code the app uses to reduce the size of the ZIM library (known as Tree Shaking). See Distill.
  • DUO provide parameters as normal or as a single configuration object with property names that match the parameter names. Introduced in ZIM DUO (2). See CONFIGURATION.
  • VEE some function and class parameters accept dynamic values that can be picked randomly, in series, in ranges or results of functions. See DYNAMIC.
  • Chaining when we dot multiple methods onto an object. See CHAINING.
  • alp One of a dozen short (three letter) chainable methods: alp()-alpha, loc()-locate, pos()-position, sca()-scale, rot()-rotate, ske()-skew, etc.
  • zog One of a half dozen short helper functions starting with Z - this one is short for console.log(). See ZOG and also the bottom of the docs for more.
  • Dr Abstract ZIM Founder - Canadian New Media Awards Programmer and Educator, Dan Zen's new personna with illustration by Antonio Caggiano.
  • Pragma Dr Abstract's side-kick and muse representing the more empethatic side of ZIM.
  • Slack a forum tool, for community with channels for questions, examples, release information, bugs, requests, etc. Join us at ZIM Slack.
Complete changes to ZIM code can be found on the Updates page linked to from the top of the Docs. There are about 7,000 updates listed for the different versions of ZIM.
  • BREAKS - are highlighted in yellow for changes of parameter order, etc.
  • IMPROVEMENTS - are hightlighted in green may make your code better!
  • SEARCH with ctrl/command F to find updates to specific commands.
  • PATCHES - list changes that happen after the version has launched.
The ZIM About section lists features for the Versions. The Bubbling videos demonstrate over 200 new features over the last 5 years.

REMEMBER, videos and examples age and it is always best to try to keep up and code with the lastest features and formats. Here is our rough policy for updates:
  • DOCS, TIPS & INTRO - always up-to-date - tell is if something is old
  • CODE TEMPLATES on Code Page and CodePen - always up-to-date
  • GITHUB - latest version posted - but may be missing PATCHES
  • NPM - delayed by a couple months after releases - waiting for patches
  • BUBBLING VIDS - within a week or two from version launch
  • ZIM KIDS, SKOOL & BITS - updated every few versions
  • EXAMPLES - NOT updated in general - they keep their original version
Generally, try and code with the lastest version of ZIM. Once your app is done and tested, probably just leave the version as is - it works! Keep an eye on IMPROVEMENTS and PATCHES for things that may help your apps but usually, once an app is made, just leave it.

Here are some things to watch for when bringing older code into current code.
  • The lastest template uses F, S, W, H rather than frame, stage, stageW and stageH
  • See the FRAME tip for an easy solution with ready(frame, stage, stageW, stageH)
  • Watch for parameter order updates - see BREAK in UPDATES
  • ZIM ZIM 01 for instance, just changed Button parameter order to include down states
  • ZIM CAT changed all time to seconds.
  • ZIM TEN integrated physics and made all sorts of component parameter updates
  • ZIM OCT added loc() and changed how pos() works and added STYLE
  • ZIM VEE made the namespace unnecessary - so no need to use zim.Frame, etc.
  • ZIM 4TH provided methods ball.drag() for what were functions zim.drag(ball)
  • BEWARE of any code older than 4TH - ZIM now needs only half the code
  • In general, check for errors in the CONSOLE (F12)
Follow us on Social Media - see the footer of any page. TWITTER is usually first. and of course on SLACK and DISCORD.

Finally... check the TIPS - half its purpose is to keep you up to date.
ZIM has a set of constants that represent string versions. These can be easier to type and recognize. For example, for positioning a circle 100 pixels from the right and bottom of the stage use:

circle.pos(100, 100, RIGHT, BOTTOM);
// or strings works too and are the same
circle.pos(100, 100, "right", "bottom");

Here are scaling, positoning and orientation constants:


Others are:

TIME is a constant introduced in ZIM Cat that defaults to "seconds". Earlier ZIM examples and videos use "milliseconds" for animate(), wiggle(), timeout(), interval() and others.

new Circle().center().amimate({scale:2}, 1000); // nothing appears to happen!

Above will now take 1000 SECONDS and give a console warning. You want:

new Circle().center().amimate({scale:2}, 1);

To go back to Milliseconds use
TIME = "milliseconds";
TIME = "ms";
Older ZIM examples and videos use the zim namespace - for instance:

const circle = new zim.Circle();

This is no longer required so you can just use:

const circle = new Circle();

Another example is
can now be just
. See the news post.
You can chain almost all ZIM methods. For example:

new Circle()

Note the semi-colon is at the end. Putting these on multiple lines allows you to comment out individual commands for testing. Do NOT chain the CreateJS
method for events and do NOT chain properties. ZIM provides a number of equivalent chainable methods like:

pos(), loc(), mov(), sca(), alp(), hov(), rot(), reg(), siz(),
ske(), tap(), hov(), cur(), top(), bot(), ord(), sha()

Other methods can be chained too such as

center(), centerReg(), cache(), setMask(), etc.

Do NOT use
as it conflicts with CreateJS 1.0 but rather use
. See the Bubbling video.

In general, to confirm that a ZIM method returns the object, check at the bottom of the docs for that method under the RETURNS section. If it says returns obj for chaining, then you are good to chain!
Configuration Objects are object literals { } that hold properties that match the parameter names for classes and functions. The ZIM DUO technique allows us to pass in parameters individually or as a single parameter that is a configuration object. For example:

// traditional parameters in order:
const rect = new Rectangle(100, 100, red, null, null, 20);

// or as a configuration object:
const rect = new Rectangle({width:100, height:100, color:red, corner:20})

Configuration Objects can be clearer and can be considerably shorter. Also, the order of the properties in the configuration object does not matter. On the other hand, if you are using only the first couple parameters, configuration objects could take longer to type.

RECOMMENDATION: switch between the two depending on the situation. If you need a parameter that is many parameters along, then a configuration object will be better. If you are using a few parameters in order, then traditional parameters are fine.

See the Parameter sections of the ZIM Docs to see if a class or function accepts ZIM DUO. You can also make your own classes and functions work with configuration objects by using zob.
In ZIM VEE (version 5) ZIM launched a system of dynamic parameters. These are values that can be be passed to parameters and then picked later by the function, method or class. In the docs, they are refered to as ZIM VEE values. The formats are:
  1. a random selection: ["blue", "green", "yellow"] - array format
  2. a random range: {min:10, max:30} - range object format
  3. a series: series(10,20,30) - series format also Pick.series()
  4. a function result: function(){return new Date().minutes} - function format
  5. a normal value: 7 or "hello" - single-value format
  6. a noPick object: {noPick:["real", "array"]} - escape format
  7. a combination: [{min:10, max:20}, 30, 40] - combination format (recursive)
You can use them to make tile a series of objects, to emit different particles each time. To make an interval go at a range of times, etc. Here is an example:

new Tile(new Circle({min:20,max:50}, [red,green,blue])).center();

You can also use ZIM VEE values in STYLE to apply styles in order or randomly. See the STYLE tip. See also SERIES for options like reverse(), bounce(), constrain(), step(), every() and jump(). See PICK to use dynamic parameters in your custom methods, functions or classes.
We usually work in a single Frame and add and remove ZIM Container objects to the stage if we want different pages. Rarely, will we load new HTML pages. Due to people not thinking of using a Container, in ZIM CAT, we added a Page object which is just a Container with two color parameters for making a quick Gradient.

// here we use Container(), we could have used Page()
const page1 = new Container(stageW, stageH).addTo();
page1.content = new Circle(200,blue).center(page1);
// page1 now has a circle on it

const page2 = new Container(stageW, stageH);
page2.content = new Rectangle(400,400,purple).center(page2);
// page2 is not added to the stage yet and holds a rectangle 

// when we press page1 content, show page2
    S.update(); // global variable S is the stage

// when we press page2 content, show page1
    S.update(); // global variable S is the stage

This is okay for a couple pages but can be annoying when there are many pages. So ZIM has a Pages class to handle going from one page to another including swiping, transitions and more! See the examples in the docs.

Aside from Container, Page and Pages, ZIM also has Pane, Panel and Window:

  • Container holds objects to add, remove, animate, fade, etc.
  • Page a container with a backing and optional gradient color
  • Pages to control multiple pages with swipe, transitions, etc.
  • Pane for a pop-up window with show() and hide()
  • Panel for a collection of components with title bar, etc.
  • Window for scrollable content including Wrapper
There are a variety of ways to add and position objects. See You can also use x, y, regX and regY properties - but generally, we use the following chainable methods:
  1. addTo(container, index, localToLocal)
    • use to add to a container at current x and y
    • note: objects, when created, have an x and y of 0
    • default container is stage - can set index
    • keeps visual positon when changing containers
    • unless localToLocal is set to false

  2. center(container, index, add)
    • use to center on and add to container
    • default container is stage - can set index
    • can choose not to add

  3. centerReg(container, index, add)
    • use to center registration, center on and add to container
    • default container is stage - can set index
    • can choose not to add

  4. loc(target|x, y, container, index, add, localToLocal)
    • use to place object at the location of a target object
    • or use to locate the registration at an x and y
    • default container is stage - can set index
    • can choose not to add
    • if target is in another container will still place on target
    • unless localToLocal is false

  5. pos(x, y, horizontal, vertical, container, index, add, reg, regX, regY)
    • NOTE: updated in ZIM 10.6.0 to use horizontal and vertical parameters
    • horizontal can be LEFT (default), CENTER / MIDDLE, RIGHT constants
    • vertical can be TOP (default), CENTER / MIDDLE, BOTTOM constants
    • use to add to container and to easily position around edges or from center
    • setting RIGHT will position right side of bounding box from right side of container
    • setting BOTTOM will position bottom side of bounding box from bottom of container
    • setting CENTER will center object then move the amount specified in x or y
    • default container is stage - can set index
    • can choose not to add
    • set reg to true to position the registration point
    • ** many examples use the old registration point pos()
    • ** the new pos() will work the same way for reg(0,0) objects
    • ** but will work differently for other registrations or rotated objects
    • setting POSREG = true; will default all pos() to reg based
    • but would recommend using loc(x,y) for registration positioning

  6. mov(x, y)
    • use mov() to set relative position
    • does NOT add to a container

  7. reg(x, y)
    • use reg() to change the registration point
    • the object will appear to shift
    • yet its x and y values will remain the same
    • does NOT add to a container

The following code tools are available to help position objects:

  1. place(id)
    • use place() to pick up object and place
    • you can also use key arrows and shift key arrows
    • the console (F12) will show location
    • hard code with loc() in code and delete place()

  2. placeReg(id)
    • use placeReg() to set registration point
    • the console (F12) will show location
    • hard code with reg() in code and delete placeReg()

  3. new Grid(obj, color, percent)
    • tool to see absolute location
    • add a Grid to a container obj (default stage)
    • use the cursor to find x and y values
    • use pos() in code to apply distance
    • set percent to false to see pixels
    • or press the p key to toggle
    • remove the Grid when done

  4. new Guide(obj, vertical, percent)
    • tool to see relative location
    • add a Guide to a container obj (default stage)
    • can use vertical and horizontal
    • use the cursor to find x and y values
    • at a distance from the guide
    • use mov() in code to apply distance
    • set percent to false to see pixels
    • or press the p key to toggle
    • remove the Guide when done
The traditional way to scale an object is with scaleX and scaleY properties. CreateJS added a scale property as well to do both - yay. ZIM has added chainable

// to scale circle twice as big in x and y
new Circle().sca(2).center(); 
// to scale circle twice as big in x and leave y scale:
new Circle().sca(2,1).center(); 

// scale circle to fit within stage bounds - without stretching
new Circle().scaleTo(stage,100,100).center(); 
// this is the same as FIT is the default type
new Circle().scaleTo(stage,100,100,FIT).center();

// fill the stage with the circle - without stretching
new Circle().scaleTo(stage,100,100,FILL).center(); 

// stretch the circle to the stage width and stage height
new Circle().scaleTo(stage,100,100,FULL).center();

There is also a
method to fit an object and center it inside a rectangular boundary. See RESPONSIVE below for more involved scaling techniques.
For basic scaling see SCALE above.

ZIM has a Layout() class to layout pages in a responsive way to handle different screen sizes imporant for mobile.

Layout is similar to FlexBox but with a subtle difference. Layout scales regions that generally have fixed aspect ratios. This allows for easier design yet still have scaling - it is called FLEXIVE design. Here are the general steps:
  1. Make dimensioned containers called regions
  2. Give the containers a type property of "Region"
  3. Add interface and content to the regions
  4. Add the regions to the Layout class
  5. Specify margins, alignment, sizes and colors
  6. Add all layouts to a resize Manager
  7. Handle different pages with ZIM Pages()
  8. Handle different orientations with multiple Pages
  9. Resize the manager in a Frame resize event
See the Docs for more details. These steps can be found in the following examples:


Each DisplayObject (Circle, Button, Container, etc.) is placed in its container at a certain level (layer) starting with 0 at the back and increasing in index number to the front. This is similar to layers in Photoshop or Flash and to z-index in CSS. When things are added they are placed on top but a specific level can also be given as follows:

new Circle().addTo(container, level);
new Circle().loc(x, y, level);
new Circle().pos(x, y, horizontal, vertical, level);
new Circle().center(container, level);
new Circle().centerReg(container, level);

Note - objects behind other objects might not be seen.

The following methods and properties are available to set levels:

  1. top()
    • moves object to top of container
    • chainable zim method

  2. bot()
    • moves object to bottom of container
    • chainable zim method

  3. ord(num)
    • moves object relatively up or down
    • ord(-1) moves down a level, ord(-3) down three
    • ord(1) moves up a level, ord(2) moves up two
    • chainable zim method

  4. parent.addChildAt(obj, level)
    • CreateJS method, not chainable
    • note this is on the parent

  5. parent.setChildIndex(obj, level)
    • CreateJS method, not chainable
    • note this is on the parent

  6. parent.getChildIndex(obj)
    • CreateJS method, not chainable
    • note this is on the parent

  7. parent.swapChildren(obj1, obj2)
    • swaps the location of two children
    • note this is on the parent

  8. parent.swapChildrenAt(index1, index2)
    • swaps two children based on index
    • note this is on the parent

  9. parent.removeChildAt(index)
    • removes a child at an index
    • note this is on the parent

  10. parent.sortChildren(sortFunction)
    • sorts children of a container
    • make a function that returns 1,-1 or 0

  11. obj.numChildren
    • read only to find the number of children in container

JavaScript 6 (ES6) is now being used in the ZIM Template, ZIM Skool, CodePen examples, etc. However the earlier examples are ES5 based. Here are the common differences. Also see ZIM ES6.

// In ES5 we need to write the following:
new Frame({ready:ready}); // property name and value
// In ES6 an object literal property can be written once
// if it is the same as the variable name for its value                
new Frame({ready}); 
function ready() {

    // Instead of var we use const or let
    // const is for always holding the same object
    // let is for variables that may change objects
    const circle = new Circle().center().drag(); // always the same circle
    // ES6 Arrow Function - short for function(){}
    F.on("resize", e=>{ // arrow functions with one param do not need () and F is global variable frame;


ZIM Frame creates a canvas tag, the stage and scales these in a variety of ways. We recommend that you use the frame available on the CODE page - just copy the tempate! See the FRAME page for more templates like Full window, Fit to the window, fitting in an existing HTML tag and act just like an image - except an interactive image!

In ZIM ZIM 01, a ready callback parameter has been added to Frame() after the outerColor and before the assets parameter. This means that many previous examples will have a slightly different parameter order. We also simplified the template to below:

new Frame(FIT, 1024, 768, light, dark, ready);
function ready() { // can also receive ready(frame, stage, width, height) parameters  
    // given F, S, W, H, M globals for frame, stage, width, height, mobile
    new Circle().center().drag();
    // stage update is automatic at end of ready

The old way with the "ready" event still works too.

const frame = new Frame(FIT, 1024, 768, light, dark);
frame.on("ready", ()=>{ 
    // given F, S, W, H, M globals for frame, stage, width, height, mobile
    new Circle().center().drag();
    // stage update is automatic at end of ready event

Frame can be used to load assets in its assets parameter:

const assets = ["asset.jpg", "sound.mp3"];
const path = "assets/"; // an assets folder in the same directory as the file

// pass optional assets and path into the Frame call
// the next parameter is either a new Waiter() or new ProgressBar() for showing loading
new Frame(FIT, 1024, 768, light, dark, ready, assets, path);
function ready() {
    const pic = new Pic("asset.jpg").center();
    // play a sound on click (note see TIP on SOUND for important sound info)
    pic.on("click", ()=>{
        new Aud("sound.mp3").play();


OR at any time in your code with F.loadAssets():

// inside your frame "ready" event function
// at any specific time you want to load assets - also see 8. IMAGES below.

    F.loadAssets(["pic.png", "sound.mp3"], "path/"); // F is global variable frame

    F.on("complete", () => {
        new Pic("pic.png").center();

There are more options (such as techniques for multiple loadings) and events when loading - see the ZIM Docs.


You can use multiple frames on the same page and even overlap frames. We might want to do this if the first frame has lots of animation. Anything that does not need constant updating, like components and text, we put in the second frame. This way, we do not have to constantly redraw the interface.

There are things we need to watch out for when using two frames!

  • Use the nextFrame parameter of Frame to pass along interactivity
  • center(), loc(), pos(), etc, add automatically to the default (first) frame stage
  • Either pass in the second frame's stage - center(stage2), loc(10,10,stage2), etc.
  • Or set the second frame to default using frame2.setDefault();
  • Ticker() also will update the default stage unless Ticker.add(function, stage2) is used.
  • Just leave the top frame's color as null and to see through to underneath frames
// The first frame
let circle; // if need access to circle in both frame ready functions
const frame = new Frame(FIT, 1024, 768, light, dark, ready);
function ready() {
    circle = new Circle(100, red).center().tap(()=>{
} // end ready

// The second frame
// use color:clear to see through the second frame to the first
// use ready:ready2 NOT ready:ready
// use nextFrame:frame to provide interactivity to first frame 
// or if first frame is only animation, for instance,
// then we would not need need the nextFrame parameter 
new Frame({
function ready2(F2, S2, W2, H2) { // or whatever names are desired  

    // F, S, W, H, M will be globals for the first frame 
    // and loc() will loc() on the first frame's stage
    // unless F2.setDefault() is called, then they all shift to this frame and stage
    new Button({label:"RESET"})
        // S2 is needed to locate on second frame's stage 
        // unless F2.setDefault() is used
            S.update(); // note we update the first frame's stage
} // end ready2


You can put ZIM above or below other HTML or Canvas tags or other ZIM Frames. See OVERLAY example. Here is a VIDEO about overlaying ThreeJS and ZIM. Unfortunately, only the canvas or the HTML can have the interactivity. Two or more ZIM frames can overlap with interactivity on all using the nextFrame (or nextStage) parameter of the frames.

Here are some tips on overlaying on HTML like the ZIM SNOW or ZIM TEN.

// to overlay ZIM with no interactivity on HTML

new Frame({
    scaling:FULL, // or other scaling options
    allowDefault:true // let HTML scroll, page up, wheel, etc.

// styles can also be used to do just about anything you want with the canvas = "absolute";  // F is global variable frame = -1; // or 5 for above, etc. = "none";

// these also could help = "fixed";
F.allowDefault = true; // alternative to Frame parameter - to activate scrolls

ZIM FIT FILL and FULL stop the window from scrolling which may not be desired if loaded into an iFrame. If ZIM is in an iFrame loaded from the same site then the wheel scrolling can be re-activated by adding the following code in your script (thanks Michael Perez for the tip):

window.addEventListener("wheel",function(e) {

Images can be loaded with Frame - see FRAME above. When you view images from the Web LOCALLY in a Browser on the Canvas, there is a security error that mentions CORS (cross origin resource sharing). The issue will go away when on a SERVER. This is a general (not just ZIM) JavaScript Canvas security for local viewing.

To solve the issue, you can use the Live Server extension in VS Code or a Browser package in Atom or Sublime. Or start your favourite Browser as follows:

type: about:config into your Browser URL bar
search for security.fileuri.strict_origin_policy and double click it to set it to false

To test locally, find your Chrome icon or shortcut, right click and choose properties
then under Target, adjust your target to include --allow-file-access-from-files (after the quotes)
eg. "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files
** You must always start your first Chrome window from this shortcut

open your terminal anywhere, make sure Google Chrome is currently not running
copy paste this line and hit enter:
open -a "Google Chrome" --args --allow-file-access-from-files

Open the Safari browser and click on Develop in the upper menu 
From the drop-down menu select Disable Local File Restrictions 

Frame can be used to load assets with its assets parameter and optional path parameter. Loading will be complete on the frame "ready" event. The Pic() object can be used to show the image.

// use an array for multiple assets ["asset.png", "asset2.png", etc.]
// if there are many assets, consider using the progress parameter
// to show a new Waiter() or new ProgressBar()

new Frame(FIT, 1024, 768, light, dark, ready, "asset.png", "path/");
function ready() {
    new Pic("asset.png").center();    


Note: when loading an absolute URL use https:// as http:// is NOT supported.

  • new Pic() is the new way to show images as of ZIM 00
  • the former way was asset() which can still be used
  • new Pic() is a Container that has a Bitmap inside and is type Pic
  • asset() is a Bitmap and is of type Bitmap unless
    it is lazy-loaded then it is a Container and is type Image
  • to get a copy of the same image use new Pic()
  • to get a second asset() of the same image use asset().clone()
  • both can be lazy-loaded - see Lazy Loading below
Lazy-loading or automatic loading is when the asset is not preloaded. Tile(), Sprite(), Scroller() do NOT work with Lazy-loaded images.

new Frame(FIT, 1024, 768, light, dark, ready); // no preloading
function ready() {
    PATH = "path/"; // optional global PATH variable
    new Pic("asset.png").center();    


Note: if using a path parameter in Frame() or loadAssets() then the PATH global variable will be initially set to the value of the path parameter.

Frame also has a loadAssets() method that can be used to preload assets at any time and provide a "complete" event. For instance, assets can be loaded when going to a different section of the app.

new Frame(FIT, 1024, 768, light, dark, ready); 
function ready() {

    // given F, S, W, H, M globals for frame, stage, width, height, mobile
    // at some point in the app more assets can be loaded
    const pics = F.loadAssets("asset.png", "path/");
    pics.on("complete", ()=>{
        new Pic("asset.png").center();  

Cross-origin resource sharing (CORS) is put in place to help content creators have more control over who uses their assets. By default, assets cannot be shared across different domains. In emergencies... CORS may be bypassed as follows - this may not always work:

See this example

// use the noCORSonImage property of the ZIM asset object when loading the image:

// Then load assets in the Frame() or in loadAssets()
new Frame(1024, 768, light, dark, ready, assets);
// If you have multiple assets use an array - see FRAME above.

There are many more ways to load assets - please see the Docs under Pic and information on SOUND below.

Sounds can be preloaded inside the Frame assets parameter or later with the Frame loadAssets().

Warning! When you load assets from the Web LOCALLY in a Browser on the Canvas, there is a security error that mentions CORS (cross origin resource sharing). See the IMAGES section above as to how to deal with that locally.

Warning! Sound cannot be played before the user interacts with the page - this is a general Browswer rule to stop being bombarded with sounds. It means that you will have to make a start button or a splash page that the user interacts with before a background sound can be played.

Sound can be held in an Aud() object and played with the play() method. Parameters for volume, loop, loopCount, offset and pan are available plus a couple others.

The return value of the play() can be stored in a variable and can be used to set a "complete" event to find when the sound finishes. It also has volume, pan, duration and paused properties.

new Frame(FIT, 1024, 768, light, dark, ready, "backing.mp3", "path/");
function ready() {

    // given F, S, W, H, M globals for frame, stage, width, height, mobile
    S.on("stagemousedown", ()=>{
        // note sounds cannot be played until there is a first interaction 
        // with a mousedown/click/tap/change        
        new Aud("backing.mp3").play({volume:.2, loop:true});
    }, null, true); // true for remove the event after first occurence     

Note: SEE Docs under Aud() for examples of:
  • Using Toggle() for background sound
  • Using Pane() to start a game with sound
  • Getting the "complete" event of the sound
What happens when a sound is played more than once can be controlled with the interrupt and maxNum parameters.

new Frame(FIT, 1024, 768, light, dark, ready, "beep.mp3", "path/");
function ready() {

    const beep = new Aud({
        interrupt:"any", // see the docs for more options
    // pressing the button will stop any beep sound 
    // and play the sound from the start
    new Button({label:"BEEP"}).center().tap(()=>{;}
} // end ready

Make sure that if you are loading an absolute URL to use https:// as https:// is NOT supported

There are many more ways to load assets - please see the Docs under Sounds and information on IMAGES above.

Video is held in a Vid() object. This creates and HTML video tag and provides control from within ZIM. Video can be scaled as FIT, FILL, FULL into its dimensioned container as follows:
  • FIT - scales video to fit inside width and height keeping aspect ratio - also see align and valign
  • FILL - scales video to surround width and height keeping aspect ratio - also see align and valign
  • FULL - scales video width to width and video height to height possibly stretching aspect ratio
new Frame(FIT, 1024, 768, light, dark, ready);
function ready() {
    // given F, S, W, H, M globals for frame, stage, width, height, mobile
    // video is a container that will have a width of 800 and height of 600
    // The video will be FIT inside these dimensions and centered by default
    // Also see align and valign parameters
    // At the start, it will have a type of "AC" once it loads it will be "Vid"
    const video = new Vid("video.mp4", 800, 600, FIT) // FIT is default
       .center() // using 800x600
    S.on("stagemousedown", () => { // must interact before playing video;

Video can be loaded without dimensions too:

new Frame(FIT, 1024, 768, light, dark, ready);
function ready() {
    // given F, S, W, H, M globals for frame, stage, width, height, mobile
    // video is a container with no width and height to start
    // once the video is loaded the container will take the dimensions of the video
    // and the center() will be called again to properly center the container
    // just like lazy loading Pic().
    const video = new Vid("video.mp4")
       .center() // will automatically be re-centered after loading
    S.on("stagemousedown", () => {;

Font can be set on Label and other component objects with labels.

new Label("Hello", 24, "courier").center();

Custom fonts can be loaded into the Frame() call or in loadAssets() in the assets parameter. As of ZIM ZIM 02, just the font file can be used - no longer is a ZIM font object {} needed.

const assets = "urlToFont.ttf"; // or put in array with other assets
const path = "assets/"; // optional path

new Frame({ready, assets, path}); // in es6.  In es5 {ready:ready, assets:assets, path:path}
function ready() {
    new Label("Hello", 24, "fontName").center(); // do not put the file extension here

Most Google fonts will work as well - the name in this case is passed into the google font:

 const assets = ""

Please see the Docs under Fonts for more information.

Often the app must be interacted with before the keyboard keys can be used - for instance arrows for a game. To solve this, we use a Pane() at the start of a game that makes the users interact.

WARNING: if the app is in an iFrame clicking on the canvas will not activate the keys so we have added a keyboardMessage() method for the Frame that will handle this. Or set the keyboardActive parameter of Pane() to true which is probably the best solution. It calls a blank keyboardMessage() in the background.

// if app is in iFrame like CodePen or the ZIM editor 
// add the keyboardAccess:true parameter to the Pane() 
// if not in an iFrame then just use the Pane() like normal
new Pane({content:"START", keyboardAccess:true}).show(); 

ZIM has a couple more helpful features for keyboards:
  • ZIM Keyboard() soft keyboard that works with ZIM Label objects and has many settings.
  • For mobile we have added a feature that shifts the stage - see KEYBOARD STAGE SHIFT
  • Use the TextInput() for letting the user type text - this is part of the canvas
  • If multiline text is needed then use a TextArea but it is an HTML overlay
  • The ZIM TextEditor may solve the overlay issue by giving an editor popup
As of ZIM Cat 04, ZIM Frame has fullscreen() built in. The stage can also be transfered from a tag mode to a fit mode (or full mode). Here are examples:


// as of ZIM ZIM 01, frame is stored in F global variable
F.on("keydown", e=>{	
    if (e.keyCode==77) F.fullscreen(); // M key is pressed for magnify

Frame also has an isFullscreen property and "fullscreenenter" / "fullscreenexit" events.

ZIM started off with special colors stored on the Frame -,, etc. These have become very well used and there are times the colors are needed before the Frame loads. So, now the colors are available on the ZIM namespace or GLOBALLY if the namespace is not required.

green, orange, blue, pink, brown, yellow, purple, red

As well as shades such as:

dark, darker, light, lighter, grey, tin, silver,
fog, mist, moon, white, black, faint, clear

We tend to use these in ZIM examples but any HTML/CSS string color will do such as:

"red", "#CC0000", "#333", "rgba(0,0,0,.2)", etc.

You can also use color lighten(), darken(), toColor(), toAlpha() methods or convert colors and animate between colors:

new Rectangle(100, 100, red.darken(.5));
F.color = purple.lighten(.1); // global variable F is the frame
const faintBlue = blue.toAlpha(.1);
const circle = new Circle(100, red).center().animate({color:faintBlue}, 1);
timeout(2, ()=>{
    circle.color = blue.toColor(pink, .5); // blue half way to pink

COLOR CHANGES: as of ZIM OCT (8) color parameters across the components have changed:
  • color and rollColor now refer to text color
  • backgroundColor and rollBackgroundColor refer to the component color
In many of the earlier ZIM examples and videos, color was the background color and the text color could only be set through a custom Label. This has changed many of the parameter names and the order of the parameters in some places. All changes can be found in the ZIM Docs Updates Page

ZIM DisplayObjects now accept GradientColor(), RadialColor() and BitmapColor() objects - take a look in the docs for how to use these.
In general, use the on() method to capture events such as:

"click", "dblclick", "mousedown/pressdown", "pressmove", "pressup",
"mousemove", "stagemousemove", "mouseover", "mouseout"
"ready", "complete", "change", "keydown", "keyup"

This is like the traditional JavaScript addEventListener() but shorter and with a few extra features:

const button = new Button().center();
// the type of event as a string and the function to call
button.on("click", ()=>{
    zgo("", "_blank");

// alternatively, using a named function
button.on("click", doClick);
function doClick() {
    zgo("", "_blank");

const tile = new Tile(new Rectangle(), 5, 5, 2, 2).center();
tile.on("mousedown", e=>{ // collect the event object in parameter e
    // is the object that caused the event (one of the rectangles) = 0;
    // e.currentTarget is the object on which the event is placed (the tile);
    // do not forget to update stage in events if needed!
    S.update(); // global variable S is the stage

let keyEvent = F.on("keydown", e=>{  // F is global variable frame
    zog(e.keyCode); // will tell code for key pressed
    // etc.
timeout(2, ()=>{ // time in seconds as of ZIM Cat
    // remove the keyEvent"keydown", keyEvent);

timeout(4, ()=>{
    // add the keyEvent back again
    // note - the event must be re-assigned to use again
    // this leads to a tricky bug if not careful!
    keyEvent = F.on("keydown", keyEvent);
timeout(6, ()=>{
    // remove the keyEvent again
    // this only works if we re-assigned the latest event to keyEvent
    // which is why we used let rather than const"keydown", keyEvent);

// call this function only once when mousing over the stage
// note: "mousemove" would only trigger if moving over an object on the stage
S.on("stagemousemove", ()=>{
    pauseAnimate(false); // unpause all animations
}, null, true); // this true means remove the event after calling it once

// a remove() method is available on the event object
const circle = new Circle();
circle.on("mouseover", e=>{
    circle.alpha -= .1;
    if (circle.alpha <= .5) e.remove();

The on() method should NOT be chained. ZIM provides several chainable methods as alternatives:

// TAP
// tap() is like a "click" but the mouse needs to stay in the same area
new Rectangle().center().tap(e=>{ += 5;
    S.update(); // global variable S is the stage

// all objects that have a "change" event have a change() method
new Slider().center().change(e=>{

// There is NO "mousemove" event on a DisplayObject other than on the stage
// To get movement anywhere on the stage (even off objects) use "stagemousemove"
// For movement on an object put the "mousemove" event on the stage
// and use to test for the object you want
// OR use the chainable movement() method with callback:
new Circle().center().movement(()=>{
    circle.alpha -= .01;
    S.update(); // global variable S is the stage

// HOV
// hov() can be applied to any DisplayObject
// this is like "mouseover" and "mouseout" events
// most components like a Button already handle this
// alpha if number and color if string
new Circle().alp(.5).center().hov(1); // full alpha on hover

// a press and hold
new Triangle().center().hold(e=>{;
    S.update(); // global variable S is the stage
When you are coding, sometimes things do not show up. Here are some reasons why that might happen:
  • The Internet is down - the console (F12) will say Frame is not a function
  • You have an error - see console and look for message in red
  • If have images or sound and the error says "CORS..." then see IMAGES
  • You forgot to add object to the stage - use addTo(), center(), centerReg()
  • You forgot to update the stage - use stage.update()
  • You forgot to put stage.update() at the end of an event function
  • When adding to a container, remember to add the container to the stage
  • The thing that is missing might be underneath something else - see LEVELS.
  • You are animating something in and using milliseconds rather than seconds - see TIME.
  • You are viewing the wrong file - use zog() to detect this mistake
This last tip is the ZEN FIVE MINUTE rule of debugging. If you have been trying to fix something for more than five minutes - no matter what - confirm that you are viewing the file that you are updating.
Indenting is very important - it is how we organize our code. Imagine taking a book and making paragraphs from every four sentences. You can still read the book, but you will be left puzzled quite often.

Indenting is equivalent of putting things in boxes - boxes within boxes. This lets us see the code at multiple levels when we are planning or debugging. We can easily skip over whole sections just by looking at the indenting. Indenting is the product of hierarchy - of abstraction - a key concept in coding and in life.

There are very easy and consistent rules for indenting. These are somewhat clouded by chaining but here they are:
  1. Indent inside { } when on multiple lines - think of these as a box.
  2. Indent using a single tab (not two or three - not spaces)
There... not so hard! Here are some extras:
  1. Indent when chaining on a new line but stop indenting at the end of the statement;
  2. If your indents are too small, change them in your preferences
Look at the code examples on this page. Or look at every single example on the ZIM site - over 1,000,000 lines of code. You will not find a single indent out of place. That is the importance of indenting. "You will code more efficiently by perfecting indentation" - Dr. Abstract.

This code was received in Slack. In general, the indenting is not that bad. The first line could have been a copy and paste error into Slack. And the different number of characters for the indents come from copying from different files - but would highly recommend fixing.

Below are the areas of concern. These will undoubtedly be fixed at some point - but the sooner the better. As a rule - do not go forward until your indenting is fixed. EVER. Once again, not too bad... certainly seen worse. But even the few indent errors here make the code hard to read.

  1. To fix a different indent size, select the lines and shift tab until they hit the edge then tab into the right position.
  2. When copying (or cutting) and pasting, paste at the same tab indent as when copying or cutting. If you cut from the very left, paste at the very left. If you cut 4 tabs in then paste 4 tabs in.
  3. In many editors (like Atom and Sublime) sitting at a bracket will show you the matching bracket.
  4. Some editors will draw lines connecting tabs and some will provide collapsible blocks.
  5. Remember to set your tab indent to at least 4 characters. The default 2 characters is too small which encourages double tabbing or adding spaces - bad habbits!
As of ZIM OCT (8) STYLE can be used to define default values for DisplayObject (shapes, components, etc.) parameters:

STYLE = {corner:0, backgroundColor:yellow};

All DisplayObjects will have these styles. You can style a type of object and these will override the general styles:

STYLE.type = {Button:{corner:20, scale:2, bacgkroundColor:"ignore"}};

Now, Buttons will have corners of 20 and be scaled twice as big. The Buttons will also ignore any previous backgroundColor style so they will be the original default (orange).

You can style a group of components and these styles will override the earier styles: = {customize:{center:true, transform:true}};

new Button({group:"customize"});

The Button will have transform tools applied along with the other styles. You can add any number of objects to a group and objects can be part of more than one group with a comma separated string. Other functions can be applied with styles too, read the STYLE Docs for more features.

As of ZIM Cat, there is a Style class that has helper methods for organizing STYLE:

Style.add(); Style.addType(); Style.addGroup();

Style.remove(); Style.removeType(); Style.removeGroup();

Style.clear(); Style.clearTypes(); Style.clearGroups();

Style.remember(); Style.recall(); Style.clearRemembered();

Any values applied through parameters of the component will override the previous styles. You can also set ignoreStyles to true to ignore all styles for the component.

We recommend that you turn off your STYLE when you are finished with your section. It depends on how widespread you want your styles.

STYLE = {}; // or STYLE = null; or Style.clear();

// you can also turn off certain styles:

STYLE.type.Button = {}; // or Style.removeType("Button");

// starting new styles will also stop using old styles
// previous styles will not be applied to up-coming objects
// but they will remain on previously made objects

STYLE = {color:red}

// you can remember current STYLES and recall them latter

STYLE = {color:blue};
new Circle().center();

You can animate, wiggle, move, add, centerReg and more with style. You can also provide ZIM VEE values such as an array of options to pick:

color:[red, purple, green], // random
x:series(100,200,300) // applied in order

The above styles would probably be written all in one assignment:

    color:[red, purple, green],
        Slider:{step:1, useTicks:true, alpha:.5}
        customize:{center:true, transform:true},
        homePage:{outline:true} // apply outline() to all members of this group
Dragging in ZIM can be done in several ways:
  • obj.drag() - the most common basic way
  • obj.transform() - addes transform box with other transforms
  • obj.gesture() - works with pinch and rotate too
  • obj.animate({props:{path:new Blob()}, drag:true}) - drag on path
  • MotionController(target, "pressmove") - jumps to and eases to location
  • MotionController(target, "pressdrag") - eases to location
  • Swiper(swipeOn, target)
Note: Squiggle() and Blob() objects get their own drag.

Here are tips for drag(). Please see the docs for the others.

// basic drag - will add pointer cursor:
new Circle().center().drag();

// drag object and keep animation of object animating:
// note - the default drag removes animation Tweens
new Circle()
    .animate({props:{scale:2}, rewind:true, loop:true})
    .drag({removeTweens:false}); // good for Sprites too!

// with boundary of stage:
// as of ZIM Cat - boundary can now be any Display Object
// and the dragging object will be kept within its bounds
new Rectangle(w,h).center().drag(stage);

// prior to ZIM Cat - we had to calculate the bounds:
const w = 100;
const h = 100;
const boundary = new Boundary(0,0,stageW-w,stageH-h);
new Rectangle(w,h).center().drag(boundary);

// with boundary for object with center reg:
const r = 50;
const boundary = new Boundary(r,r,stageW-r*2,stageH-r*2);
new Circle(r).center().drag(boundary);

// with boundary for 200 pixels horizontal only (no vertical height):
const boundary = new Boundary(stageW/2-100,stageH/2,200,0);
new Circle().center().drag(boundary);

// drag items in a Container (a Tile is a Container):
const tile = new Tile(new Circle(30,[blue,green,orange]),20,10)
    .drag(); // will drag individual circles

// drag items above without item coming to top:
// note: the default drag brings object to top of its container
    .drag({onTop:false}); // will leave level order same

// drag all items above - not each individual item:
    .drag({all:true}); // will drag whole container

// to stop dragging:

Mouse Events can still be applied while dragging:

const circle = new Circle().center().drag();

// circle.on("mousedown", ()=>{ // as of ZIM Cat, "pressdown" does the same as "mousedown"
circle.on("pressdown", ()=>{
    circle.startX = circle.x;
    circle.startY = circle.y;
circle.on("pressmove", ()=>{
    circle.alpha = 1-Math.abs(circle.x-stageW/2)/(stageW/2);
circle.on("pressup", ()=>{
    // could use circle.noDrag()
    // but that would record the incorrect start position
    // so do not record user press on object
        props:{x:circle.startX, y:circle.startY, alpha:1},
        call:()=>{circle.mouse();} // let user press on object

See ZIM Bits Drag Copy dragging a copy and ZIM Bits Snapping for snapping to objects.

See CodePen Unscramble for dragging and shifting tiles. Etc.

See ZIM Scrambler - now the Unscramble example is built into ZIM Cat!

See ZIM NIO and Groovity for dragging on paths.
ZIM loop is an easier format than a traditional
for(var i=0; i<10; i++){}
loop. Here is the format - which matches the familiar event call:

loop(10, i=>{
    zog(i); // 0-9

// same as ES5:

loop(10, function(i) {
    zog(i); // 0-9

There are lots of extra features too. Here are ways to loop through arrays, objects and containers. In the container example we loop through backwards which is important when removing children:

const letters = ["A", "B", "C"];
loop(letters, letter=>{
    zog(letter); // "A", "B", "C"

const person = {age:20, job:"farmer", greeting:"yo"};
loop(person, (property, value)=>{
    zog(property, value); // age 10, job farmer, greetings yo

const monsters = new Container(); // then fill with monster Bitmaps, etc.
loop(monsters, monster=>{
    if (monster.growl) monster.removeFrom(monsters);
}, true); // true loops backwards

See ZIM Docs for more details including start and end values, continuing or breaking from a loop, more parameters, etc.
ZIM animate() is one of the most feature-full of ZIM methods. The Animation Example shows the basic types.

ZIM animate() is powered by CreateJS TweenJS here are some differences:
  1. animate chains to ZIM objects - not get(), to(), wait(), etc. chained to Tween()
  2. animate uses ZIM DUO with parameters in order or a configuration object
  3. animate adds features and is SIX times the size of CreateJS Tween
A good read over the Docs is well worth the time.


Note: DRAG MAY STOP X and Y ANIMATIONS on an object unless you use drag({allowTweens:true});

// basic animation - note as of ZIM Cat, time is in seconds
new Circle().center().animate({scale:2}, .5); // increase scale in half a second

// animate() is one of the only ZIM methods that has a parameter that is an object literal {}
// we have taken great pains to flatten parameters and offer ZIM DUO as an alternative.
// but with animate we always have nested object literals when using the DUO technique:
circle.animate({props:{scale:2}, time:.5});

// to tell the difference between the two object literals
// we call the overall configuration object the animate object
// and the inner object for the properties the props object
// it is often easier to understand by using multiple lines:
    wait:1, // wait one second before starting
    loopCall:()=>{zog("looping")} // also call, rewindCall, and more

// The reason for the props object is that we can animate any number of props at once
// here we animate the x and y to these positions in one second (the default time)
// note - for early versions of ZIM we could not do this
// as ZIM saw the single parameter object literal as the configuration object
// but ZIM can handle doing this now ;-)
circle.animate({x:100, y:200});

// for animate, the object being animated is called the target
// we can also call the animate() function on any object and pass a target as the first parameter
animate(circle, {color:red}, 2);

// this can be used to target an object without the animate method
// here we use the ZIM DUO configuration object to target a plain object literal:
// you can also animate CSS like this - see the docs under animate and then props parameter
const data = {count:20};
animate({target:data, props:{count:50}, time:2})
    zog(data.count); // count increases

// two or more animate objects can be added to an array to run in series
// there is more you an do with this such as mix in other objects
// set default values after the array, etc. but here are the basics:
    {props:{x:200, y:200}, time:2},
    {props:{x:500, alpha:0}, time:.5}

// you can chain on multiple tweens on the same object
// if one tween stops the other try setting override to false
circle.animate({x:500}, 2).animate({scale:2}, 1);

// an array or container can be run in sequence
// every .1s the next object in the array or container will animate
// note: setting the sequence time to 0
// will animate each object individually at the same time
animate({target:circlesArray, props:{x:200}, sequence:.1);
circlesContainer.animate({props:{x:200}, sequence:.1});

// animate has an id parameter that can be used to pause and stop animations of that id
circle.animate({props:{scale:2}, loop:true, rewind:true, id:"boing"});
pauseAnimate(); // will pause all animation
pauseAnimate(false); // will unpause all animation
circle.pauseAnimate(); // will pause all animations on circle
circle.stopAnimate(); // will stop all animations on circle
pauseAnimate(true, "boing"); // pause any animation with id "boing" - sprite and wiggle too

// you can animate objects from a property value to the current value of the property
// this is handy - imagine setting up a scene's final position
// then animating from alpha:0 or x:-1000 to the final position!
// another cool thing is setting ANIMATE = false
// will stop the animations from happening and your scene will be in final position
// which is great for passing by animations as you are building!
ANIMATE = false; // toggle this to true to see animations or for final product
new{from:true, props:{x:-100}});

A unique strength of ZIM animate is animating on paths - see ZIM NIO. Here are some features:

  • Animate with the path property along a Blob or a Squiggle
  • The path can be adjusted by the user while animating
  • percentages of the path including negative can be sent
  • The object can be dragged on the path (animation optional)
  • The object can orient to the path and flip or not
  • The object can orient to any point while animating
  • The object can zoom based on y to give 3D effect
  • The object can shift levels based on y
  • The object can change opacity based on y
  • The object can change any property base on any property
const path = new Squiggle().center()
    drag:true, // setting drag will automatically pause the animate
    startPaused:false // can cause the animation to go again

Animations can be done on Beads, LabelOnPath, LabelLetters, Shapes, Blobs, Squiggles there are all sorts of easing settings and more! Have fun exploring - the examples are good to look at!
Often we need to test if objects are hitting. This almost NEVER happens when the code first loads. Usually it happens in a function in one of three places:

// 1. Tests all the time for when objects are moving on their own

// 2. Use when user move object and the other objects are not moving
object.on("pressmove", e=>{});

// 3. Use when dropping an object in the trash for instance
object.on("pressup", e=>{});

Here is an example of the third:

const ball = new Circle(20).center().drag();
const can = new Rectangle(100, 200).pos(100, 100, RIGHT, BOTTOM);
ball.on("pressup", ()=>{
    // bigger shape hitting points around smaller circle
    if (can.hitTestCircle(ball)) {
        S.update(); // global variable S is the stage

// ~~~~~~~~~~~~~~~~~~~
// NEW! As of ZIM Cat there is a hitTestCircleRect() so use that for above:
ball.on("pressup", ()=>{
    if (ball.hitTestCircleRect(can)) {
        S.update(); // global variable S is the stage

WARNING: we could use ball.hitTestRect(can) but the ball is smaller and it could fit inside the bounds of the can. So the general rule when using hitTestRect() and hitTestCircle(), is put the method on the BIGGER object and test against the points on the Circle or Rectangle of the smaller object with the smaller object in the round brackets - hence, can.hitTestCircle(ball);

OPTIONS: there are other types of hitTests but for the most part, hitTestRect() and hitTestCircle() will be the most popular when hitting a rectangle or circle agains an unusual shape. If you have a circle and a rectangle use hitTestCircleRect(). If you have two rectangular shapes and then use hitTestBounds() or two circles and then use hitTestCircles(). These last two are very fast as they use equations. The fastest way to test if the mouse (or any object) is over a cell in a grid is with hitTestGrid() - see Docs. This also uses a mathematical calculation rather than comparing color/point based intersection which is used by a mouseover event. See the ZIM Bit or the ZIM Capture on hitTests.

There is also hitTestPath that tests the shape of the object against a Squiggle or a Blob.

HITTING TOO MANY TIMES! If your hitTest keeps telling you it is hitting and you only want to know once... for instance, to play a sound or add 1 to a score, etc. then you may end up playing the sound over and over very quickly or adding too much to your score. You will need to either:

// 1. Remove one of the objects so they are not hitting:
if (ball.hitTestRect(rect) {

// 2. Remove the Ticker or event that is calling the hitTest:
let ticker = Ticker.add(()=>{
    if (ball.hitTestRect(rect)) {
// OR
let mousemoveEvent = S.on("stagemousemove", e=>{
    // see Tip for RETINA as to why we do not use e.stageX and e.stageY
    ball.loc(F.mouseX, F.mouseY); // F is global variable frame
    if (ball.hitTestRect(rect)) {;;
        S.update(); // global variable S is the stage

// 3. Use a check variable (just some logic!):
let hitCheck = false;
ball.on("pressmove", ()=>{
    if (!hitCheck && ball.hitTestRect(rect)) {
        hitCheck = true;;
// you may need to set hitCheck to false some time later
// if you want to test for another hit!  ;-)

MULTIPLE OBJECTS: Often we want to test if something is hitting multiple objects. To do this, put the objects in a Container, loop through the container in the Ticker or event function and test each object:

const circles = new Container().addTo();
loop(20, ()=>{
    // ES6 tip - use let inside loop
    let circle = new Circle(20, green).loc(rand(stageW), rand(stageH), circles);
    circle.collected = false;
const collector = new Rectangle(50, 100).center().drag();
collector.on("pressmove", ()=>{
        if (!circle.collected && collector.hitTestCircle(circle)) {
            circle.color = black
            circle.collected = true;
            S.update(); // global variable S is the stage

REMOVING: when looping through a container or an array and removing an object, for instance, if the object that the collector hits is removed, then you MUST loop in reverse. This will make sure that the index numbers remain the same otherwise you will get intermittent errors. To loop backwards use true as the next parameter value in the loop:

collector.on("pressmove", ()=>{
        if (collector.hitTestCircle(circle)) {
            S.update(); // global variable S is the stage
    }, true); // the true makes loop loop in reverse
Any DisplayObject can be copied with clone(). This will make a new DisplayObject.

Some things to watch out for:

1. If you put objects into a ZIM Shape like Rectangle, Circle, Blob, etc. and clone the shape, the things inside will NOT be cloned. This is because the shape, even though it is a Container, is not expected to be used as a container. When cloned the shape will be remade with the constructor and the original parameters. To solve this, make a Container, add the shape to the container and anything formerly put into the shape, put into the container. Then clone the container.

const circle = new Circle(50,orange).center();
new Label("HI").center(circle);
const circle2 = circle.clone().pos(50,50); // the clone will NOT have the label

// instead, make a Container 

const circle = new Container().center();
new Circle(50,orange).addTo(circle);
new Label("HI").center(circle);
const circle2 = circle.clone().pos(50,50); // the clone will have the label 

2. Cloning a DisplayObject that uses ZIM VEE (Pick) values for dynamic parameters will clone using the ZIM VEE so may not clone exactly the same. In that case you can choose to clone exactly with the exact parameter - usually the first parameter of clone().

const circle = new Circle(50,[orange,red,green]).center();
// circle2 could be any one of the three colors 
const circle2 = circle.clone().pos(50,50); 
// circle3 will be the same color as the first circle
const circle3 = circle.clone(true).pos(50,50,RIGHT); 

3. asset() has now been replaced by new Pic(), new Aud(), new SVG() but if using asset() which still works, the asset() must be cloned to have more than one.

asset("pic.png").loc(300,300); // just moves the same asset to 300,300 
asset("pic.png").clone().loc(400,400); // now there is an asset at 300,300 and 400,400

ZIM is over 200K in size and growing but you can easily use Distill to create a minified file of only the ZIM code that you are using. In your scripts, before you call ZIM Frame, add the following:

DISTILL = true;

This starts a recording of function numbers. When your code is done (i.e. in a click event function) add the following:


At this point, a coded list of all the functions that have been used are displayed in the console (F12). Copy this list and go to the Distill page where you can paste them into the form and submit to receive the distilled minified code - and non-minified code for your reference. You can then paste this code in a remote JavaScript file and call it from your page instead of the full ZIM cdn link:

<script src="remote.js"></script>

Or load the code in between script tags. Here are some Examples and the Docs.
ZIM Retina is here which makes ZIM vector crisp and look amazing! One change with Retina, is that the Mouse Event object mouse position needs to be divided by the stage scale:

stage.on("stagemousedown", e=>{
    let x = e.stageX/stage.scaleX;
    let y = e.stageY/stage.scaleY;
    // etc.
// ~~~~~~~~~~~~~~~~~~~~~~~~~
// ** Note as of ZIM Cat and ZIM's CreateJS 1.3.2, this is no longer the case
// the CreateJS has been adjusted but you can still use the F.mouseX and F.mouseY below if desired

To avoid this, we have provided mouseX and mouseY properties on Frame that include the scale adjust. Use these as follows:

stage.on("stagemousedown", ()=>{
    let x = F.mouseX; // note mouseX not stageX and F is global variable frame
    let y = F.mouseY;
    // etc.
ZIM is built on CreateJS at and so all CreateJS documentation applies to ZIM. We recommend that you use the ZIM version of CreateJS as it has some helpful updates. See the top of the DOCS for the link.

ZIM Containers extend CreateJS Containers and many of the ZIM Display objects extend ZIM Containers. This means, the ZIM objects get all the CreateJS methods, properties and events like:

on(), setBounds(), x, y, rotation, alpha,
mousedown, mouseover, mouseout, pressmove, pressup, etc.

If we have a CreateJS display object such as a Container or Shape that comes from Adobe Animate, etc. then we can give this object all the ZIM display methods by using the following:


// this gives the CreateJS object
drag(), animate(), hitTestRect(), hitTestCircle(), etc.
center(), centerReg(), pos(), mov(), etc.

It should be noted too that ZIM objects have a width, height, widthOnly and heightOnly properties. These scale the object to give the desired width and height. They leave the bounds as originally set:

const rect = new Rectangle(100,100).center();
rect.width = 200; // scales the rect by 2 in both the x and y
zog(rect.width); // 200
zog(rect.getBounds().width); // 100
zog(rect.scaleX, rect.scaleY); // 2, 2

SETTING BOUNDS - when you are creating a Container or a Shape you have the choice of setting the width and height as parameters as you make the object. You can optionally set the boundsX and boundsY and the width and height. You can also let the container make its own bounds based on its contents by leaving the container parameters as null. And of course, you can get and set the bounds at anytime using getBounds() and setBounds(). Setting the bounds to null will have the container automatically calculate its bounds. For ZIM center() and centerReg() and various hitTest methods it is often helpful or necessary to have the bounds set.
Browsers have a console (F12) that can be used by developers to see what is happening in their code. The console is not seen by the end user - although, if they know how, they can view it. There are also debuggers but these are often not needed. We can
helpful messages to the console as we code.
is just short for JavaScript's
. There are colored zogs too! These help organize the console.

zogr(); zogb(); zogg(); zogy(); zogp(); zogo();

If you are just starting to code, it is a good idea to test often. Every time you make a function, the first thing you do should be to
inside the function to make sure the function is running. Here are a few examples of where we might use functions:

function test() {
    zog("test"); // will show test in the console when function runs
// this function above will not run until it is called:

object.on("click", ()=>{
    zog("clicked"); // runs when object is clicked

    time:2, // time in seconds as of ZIM Cat
    call:function() {
        zog("animation done"); // runs when animation finishes

    // runs at the frame rate - very fast!
    // just check then comment out or delete - can bog performance

interval(1, ()=>{ // time in seconds as of ZIM Cat
    zog("interval"); // runs every second

timeout(.5, ()=>{
    zog("timeout"); // runs once after half a second

loop(10, i=>{
    zog(i); // shows 0-9 as we loop

In all of these, we would want to make sure the function is running before we start coding inside the function. If we do not, we sometimes will think that our code inside is broken - when really, it is just that the function is not running.
Use the console (F12) to see any errors in your code - they are RED and will show a message and a line number. Sometimes the message does not make sense, or the line number seems strange. Here are some tips:
  • If the line number is at the end of the file, a bracket is probably missing somewhere in your code (not necessarily the end).
  • If the error is TypeError: ... null then you may be trying to set a property or run a function on an object that does not exist - check for typos or zog() the object to see if it exists.
  • If the error is SyntaxError: expected expression, got '.' then you probably have a semi-colon between your chaining.
  • If the error is TypeError: this.zimContainer_constructor is not a function then remember to use the new keyword when making objects.
  • If the error is TypeError: ... is not a consructor then make sure your variable name is not the same name as your class. For instance: const Shape = new Shape(); is bad!
  • If the error is TypeError: invalid assignment to const then you are assigning a different object to a constant
  • If the error is in ZIM or CreateJS then try commenting out your latest code and see if the error goes away. If so, then check the parameters of your latest code.
In general, if you can't figure out something then simplify. Comment out code until it works again. Or even try the problem code in a new file. Also remember to save your file and check to see you are testing the right file.
We are here and love to help. There is no question too small and no question too big. Here is an invite to the ZIM Slack Team and to the ZIM Discord server. It just takes a moment to sign up to Slack and it is all online. Many companies are using Slack for internal communication. Slack is being used as forums for software support, educational communications, etc. Here are the ZIM Slack channels - it helps to post in the relevant channels but you will find us all very friendly - so no worries:
  • Examples - view and show projects
  • General - posts that don't fit in other channels
  • Releases - ZIM announces each release here
  • Questions - ask how to do something
  • Random - chit-chat - maybe not about ZIM
  • Requests - what would you like to see in ZIM

Happy   C R E A T I N G   from Dr Abstract and Pragma - at ZIM!