Porymap is extensible via scripting capabilities. This allows the user to write custom JavaScript (technically, ECMAScript) files to support enhanced workflows, without having to fork Porymap itself. While the possibilities are endless, some useful examples of scripting might be:
At the top there are three basic buttons for managing your scripts:
- |button-create| Opens a prompt to create a new script file, which will be populated with a basic template.
- |button-load| Lets you add an existing script file to Porymap that you've already created or downloaded from elsewhere.
- |button-refresh| Any edits made to your scripts while Porymap is already open will not be reflected until you select this button.
Below these buttons is a list of all the custom scripts you have loaded for your project. Each entry will have a text box showing the path of the script file. This path can be freely updated, or you can choose a new path with the |button-folder| button next to it. The |button-edit| button will open the script file in your default text editor, and the |button-remove| button will remove it from the list. The check box to the left of the filepath indicates whether your script should be running. If you'd like to temporarily disable a script you can uncheck this box.
Let's write a custom script that will randomize grass patterns when the user is editing the map. This is useful, since it's cumbersome to manually add randomness to grass patches. With the custom script, it will happen automatically. Whenever the user paints a grass tile onto the map, the script will overwrite the tile with a random grass tile instead.
First, open the ``Options -> Custom Scripts...`` window and select the |button-create| button. This will open a file save prompt; let's name our new script file ``my_script.js`` and save it. We've successfully added a new script! We can now see it listed in the editor.
At the moment our script doesn't do anything. Let's select the |button-edit| button to open it and write the actual code that will power the grass-randomizer. Once the script file is open you will notice that there are several empty functions already inside. These are special "callback" functions that will be called automatically for certain events that occur while Porymap is running. We're interested in the ``onBlockChanged()`` callback, since we want our script to take action whenever a user paints a block on the map.
We can leave the rest of the callback functions in here alone, or we can delete them because we're not using them. Every callback function does not need to be defined in your script. **Note**: For Porymap to be able to execute these callback functions they need to have the ``export`` keyword. The rest of the functions in your script do not need this keyword.
In addition to the callbacks, Porymap also supports a scripting API so that the script can interact with Porymap in interesting ways. For example, a script can change a block or add overlay text on the map. Since we want to paint random grass tiles, we'll be using the ``map.setMetatileId()`` function. Let's fill in the rest of the grass-randomizing code.
**For pokeemerald/pokeruby users**: We only have 1 regular grass metatile, but if you want to try this script you could replace ``const grassTiles = [0x8, 0x9, 0x10, 0x11];`` in the code below with ``const grassTiles = [0x1, 0x4, 0xD];`` to randomize using tall grass and flowers instead!
Let's apply our changes by selecting the |button-refresh| button. Because we've added a new script we'll be met with this confirmation prompt. Accept this prompt by selecting ``YES``.
The grass-randomizer script above happens implicitly when the user paints on the map. However, other times we probably want to call the custom script on demand. One of the API functions Porymap provides is the ability to trigger scripting functions from the ``Tools`` menu, or a keyboard shortcut. To do this, we will usually want to register the action when the project loads. Here is an example script where some custom actions are registered.
Then, to trigger the ``applyNightTint()`` function, we could either click ``Tools -> View Night Tint`` or use the ``T`` keyboard shortcut. **Note**: Like callbacks, functions registered using ``utility.registerAction()`` also need the ``export`` keyword for Porymap to call them.
Called when the selected tab in the main tab bar is changed. Tabs are indexed from left to right, starting at 0 (``0``: Map, ``1``: Events, ``2``: Header, ``3``: Connections, ``4``: Wild Pokemon).
Called when the selected tab in the map view tab bar is changed. Tabs are indexed from left to right, starting at 0 (``0``: Metatiles, ``1``: Collision, ``2``: Prefabs).
:param collision:the collision of the block (``0`` = passable, ``1-3`` = impassable)
:type collision:number
:param elevation:the elevation of the block
:type elevation:number
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
..js:function:: map.setBlock(x, y, rawValue, forceRedraw = true, commitChanges = true)
Sets a block in the currently-opened map. This is an overloaded function that takes the raw value of a block instead of each of the block's properties individually.
:param rawValue:the 16 bit value of the block. Bits ``0-9`` will be the metatile id, bits ``10-11`` will be the collision, and bits ``12-15`` will be the elevation.
:type rawValue:number
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
:param xDelta:number of blocks to shift horizontally
:type xDelta:number
:param yDelta:number of blocks to shift vertically
:type yDelta:number
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:type forceRedraw:boolean
:param commitChanges:Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``.
Sets the dimensions of the border of the currently-opened map. If the config setting ``use_custom_border_size`` is set to ``0`` then this does nothing.
Redraws the entire map area. Useful when delaying map redraws using ``forceRedraw = false`` in certain map editing functions.
..js:function:: map.commit()
Commits any uncommitted changes to the map's edit/undo history. Useful when delaying commits using ``commitChanges = false`` in certain map editing functions.
Sets the name of the background song for the currently-opened map. The song name must be one of the names in the "Song" dropdown menu on the Header tab.
Sets the name of the region map location for the currently-opened map. The location name must be one of the names in the "Location" dropdown menu on the Header tab.
Sets the name of the battle scene for the currently-opened map. The battle scene name must be one of the names in the "Battle scene" dropdown menu on the Header tab.
The following functions are related to tilesets and how they are rendered. The functions with "preview" in their name operate on a "fake" version of the palette colors. This means that changing these "preview" colors won't affect the actual tileset colors in the project. A good use of the "preview" palettes would be Day/Night tints, for example.
Sets a palette in the primary tileset of the currently-opened map. This will NOT affect the true underlying colors--it only displays these colors in the map-editing area of Porymap.
:param colors:array of colors. Each color is a 3-element RGB array
:type colors:array
:param forceRedraw:Redraw the elements with the updated palette. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
Sets all of the palettes in the primary tileset of the currently-opened map. This will NOT affect the true underlying colors--it only displays these colors in the map-editing area of Porymap.
:param palettes:array of arrays of colors. Each color is a 3-element RGB array
:type palettes:array
:param forceRedraw:Redraw the elements with the updated palettes. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
Sets a palette in the secondary tileset of the currently-opened map. This will NOT affect the true underlying colors--it only displays these colors in the map-editing area of Porymap.
:param colors:array of colors. Each color is a 3-element RGB array
:type colors:array
:param forceRedraw:Redraw the elements with the updated palette. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
Sets all of the palettes in the secondary tileset of the currently-opened map. This will NOT affect the true underlying colors--it only displays these colors in the map-editing area of Porymap.
:param palettes:array of arrays of colors. Each color is a 3-element RGB array
:type palettes:array
:param forceRedraw:Redraw the elements with the updated palettes. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
:param colors:array of colors. Each color is a 3-element RGB array
:type colors:array
:param forceRedraw:Redraw the elements with the updated palette. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
:param palettes:array of arrays of colors. Each color is a 3-element RGB array
:type palettes:array
:param forceRedraw:Redraw the elements with the updated palettes. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
:param colors:array of colors. Each color is a 3-element RGB array
:type colors:array
:param forceRedraw:Redraw the elements with the updated palette. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
Sets all of the palettes in the secondary tileset of the currently-opened map. This will permanently affect the palettes and save the palettes to disk.
:param palettes:array of arrays of colors. Each color is a 3-element RGB array
:type palettes:array
:param forceRedraw:Redraw the elements with the updated palettes. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
Sets the raw attributes value for the specified metatile.
**Warning:** This function writes directly to the tileset. There is no undo for this. Porymap will not limit the value of existing attributes to their usual range.
:param xflip:whether the new tile is flipped horizontally
:type xflip:boolean
:param yflip:whether the new tile is flipped vertically
:type yflip:boolean
:param palette:new tile's palette number
:type palette:number
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
Sets the tile at the specified index of the metatile. This is an overloaded function that takes a single tile as a JavaScript object instead of each of the tile's properties individually.
:param tile:the new tile. ``tile`` is an object with the properties ``{tileId, xflip, yflip, palette}``
:type tile:object
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
:param xflip:whether the new tiles are flipped horizontally
:type xflip:boolean
:param yflip:whether the new tiles are flipped vertically
:type yflip:boolean
:param palette:new tiles' palette number
:type palette:number
:param tileStart:index of the first tile to set. Defaults to ``0`` (the first tile)
:type tileStart:number
:param tileEnd:index of the last tile to set. Defaults to ``-1`` (the last tile)
:type tileEnd:number
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
Sets the tiles in the specified range of the metatile. This is an overloaded function that takes an array of tiles as JavaScript objects instead of each of the tile properties individually.
:param tiles:array of tiles to set. Each tile is an object of the form ``{tileId, xflip, yflip, palette}``. If the array does not have sufficient objects to set all the tiles in the specified range then the remaining tiles will be set with all default values.
:type tiles:array
:param tileStart:index of the first tile to set. Defaults to ``0`` (the first tile)
:type tileStart:number
:param tileEnd:index of the last tile to set. Defaults to ``-1`` (the last tile)
:type tileEnd:number
:param forceRedraw:Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``.
Gets the pixel data for the specified tile. The pixel data is an array of indexes indicating which palette color each pixel uses. Tiles are 8x8, so the pixel array will be 64 elements long.
The following functions are related to an overlay that is drawn on top of the map area. Text, images, and shapes can be drawn using these functions. Items can be drawn and manipulated on separate layers by specifiying a layer id. Items on higher layer ids will be drawn above those on lower layers. The visibility, opacity, position, rotation, and scale of each layer can be changed; by default all layers are visible, have an opacity of ``100``, are at position ``0,0``, an angle of ``0``, and a horizontal and vertical scale of ``1.0``.
This is an overloaded function. Sets the opacity of all active overlay layers. Layers that have not been used yet will not have their opacity changed. Opacity ranges from ``0`` (invisible) to ``100`` (completely opaque).
This is an overloaded function. Sets the horizontal scale of all active overlay layers. Layers that have not been used yet will not have their scale changed. ``1.0`` is normal size.
This is an overloaded function. Sets the vertical scale of all active overlay layers. Layers that have not been used yet will not have their scale changed. ``1.0`` is normal size.
This is an overloaded function. Sets the horizontal and vertical scale of all active overlay layers. Layers that have not been used yet will not have their scale changed. ``1.0`` is normal size.
This is an overloaded function. Sets the angle that all active overlay layers are rotated to. Layers that have not been used yet will not have their angle changed.
This is an overloaded function. Rotates the all active overlay layers. Layers that have not been used yet will not be rotated. A positive number of degrees is clockwise rotation, a negative number of degrees is counterclockwise rotation.
This is an overloaded function. Sets the x position of all active overlay layers. Layers that have not been used yet will not have their position changed.
This is an overloaded function. Sets the y position of all active overlay layers. Layers that have not been used yet will not have their position changed.
..js:function:: overlay.setClippingRect(x, y, width, height, layer)
Sets the rectangular clipping region for the specifieid overlay layer. A clipping region will cause the overlay's rendering to be contained inside it. In other words, any content from the overlay layer will not be visible outside of the specified rectangle.
This is an overloaded function. Sets the rectangular clipping region for all overlay layers. A clipping region will cause the overlay's rendering to be contained inside it. In other words, any content from the overlay layer will not be visible outside of the specified rectangle.
This is an overloaded function. Sets the position of all active overlay layers. Layers that have not been used yet will not have their position changed.
Adds a text item to the specified overlay layer. Text can be additionally formatted with a `limited set of HTML tags <https://doc.qt.io/qt-5/richtext-html-subset.html#supported-tags>`_. Note that only text can be displayed, so text decoration like underlines or table borders will not appear.
Draws a straight path on the specified layer by connecting the coordinate pairs in ``coords``. The area enclosed by the path can be colored in, and will follow the `"odd-even" fill rule <https://doc.qt.io/qt-5/qt.html#FillRule-enum>`_.
:param coords:array of pixel coordinates to connect to create the path. Each element of the array should be an array containing an x and y pixel coordinate
:type coords:array
:param borderColor:the color of the path. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to black.
:type borderColor:string
:param fillColor:the color of the area enclosed by the path. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to transparent.
This is an overloaded function. Draws a straight path on the specified layer by connecting the coordinates at (``xCoords``, ``yCoords``). The area enclosed by the path can be colored in, and will follow the `"odd-even" fill rule <https://doc.qt.io/qt-5/qt.html#FillRule-enum>`_.
:param x:the x pixel coordinate of the image's top-left corner (relative to the layer's position)
:type x:number
:param y:the y pixel coordinate of the image's top-left corner (relative to the layer's position)
:type y:number
:param filepath:the image's filepath
:type filepath:string
:param layer:the layer id. Defaults to ``0``
:type layer:number
:param useCache:whether the image should be saved/loaded using the cache. Defaults to ``true``. Reading images from a file is slow. Setting ``useCache`` to ``true`` will save the image to memory so that the next time the filepath is encountered the image can be loaded from memory rather than the file.
Creates an image item on the specified overlay layer. This differs from ``overlay.addImage`` by allowing the new image to be a transformation of the image file.
:param x:the x pixel coordinate of the image's top-left corner (relative to the layer's position)
:type x:number
:param y:the y pixel coordinate of the image's top-left corner (relative to the layer's position)
:type y:number
:param filepath:the image's filepath
:type filepath:string
:param width:the width in pixels of the area to read in the image. If ``-1``, use the full width of the original image. Defaults to ``-1``
:type width:number
:param height:the height in pixels of the area to read in the image. If ``-1``, use the full height of the original image. Defaults to ``-1``
:type height:number
:param xOffset:the x pixel coordinate on the original image where data should be read from. Defaults to ``0``
:type xOffset:number
:param yOffset:the y pixel coordinate on the original image where data should be read from. Defaults to ``0``
:type yOffset:number
:param hScale:the horizontal scale for the image. Negative values will be a horizontal flip of the original image. Defaults to ``1``
:type hScale:number
:param vScale:the vertical scale for the image. Negative values will be a vertical flip of the original image. Defaults to ``1``
:type vScale:number
:param paletteId:the id of which currently loaded tileset palette to use for the image. If ``-1``, use the original image's palette. Defaults to ``-1``
:type paletteId:number
:param setTransparency:whether the color at index 0 should be overwritten with transparent pixels. Defaults to ``false``
:type setTransparency:boolean
:param layer:the layer id. Defaults to ``0``
:type layer:number
:param useCache:whether the image should be saved/loaded using the cache. Defaults to ``true``. Reading images from a file is slow. Setting ``useCache`` to ``true`` will save the image to memory so that the next time the filepath is encountered the image can be loaded from memory rather than the file.
..js:function:: overlay.addTileImage(x, y, tile, setTransparency = false, layer = 0)
Creates an image of a tile on the specified overlay layer. This is an overloaded function that takes a single tile as a JavaScript object instead of each of the tile's properties individually.
Gets the index of the currently selected main tab. Tabs are indexed from left to right, starting at 0 (``0``: Map, ``1``: Events, ``2``: Header, ``3``: Connections, ``4``: Wild Pokemon).
Sets the currently selected main tab. Tabs are indexed from left to right, starting at 0 (``0``: Map, ``1``: Events, ``2``: Header, ``3``: Connections, ``4``: Wild Pokemon).
Gets the index of the currently selected map view tab. Tabs are indexed from left to right, starting at 0 (``0``: Metatiles, ``1``: Collision, ``2``: Prefabs).
Registers a JavaScript function to an action that can be manually triggered in Porymap's ``Tools`` menu. Optionally, a keyboard shortcut (e.g. ``"Ctrl+P"``) can also be specified, assuming it doesn't collide with any existing shortcuts used by Porymap. The function specified by ``functionName`` must have the ``export`` keyword.
Registers a JavaScript function to an action that can be manually triggered in Porymap's ``Tools`` menu. Optionally, a keyboard shortcut (e.g. ``"Ctrl+P"``) can also be specified, assuming it doesn't collide with any existing shortcuts used by Porymap. A check mark will be toggled next to the action name each time its activated. Whether the check mark is initially present can be set with ``checked``. The function specified by ``functionName`` must have the ``export`` keyword.
This behaves essentially the same as JavaScript's ``setTimeout()`` that is used in web browsers or NodeJS. The ``func`` argument is a JavaScript function (NOT the name of a function) which will be executed after a delay. This is useful for creating animations or refreshing the overlay at constant intervals.
:param label:the text adjacent to the input entry area
:type label:string
:param default:the text in the input entry area when the window is opened. Defaults to ``""``
:type default:string
:returns:``input`` will be the input text and ``ok`` will be ``true`` if ``OK`` was selected. ``input`` will be ``""`` and ``ok`` will be ``false`` if ``Cancel`` was selected or if the window was closed without selection.
:param label:the text adjacent to the input entry area
:type label:string
:param default:the number in the input entry area when the window is opened. Defaults to ``0``
:type default:number
:param min:the minimum allowable input value. Defaults to ``-2147483648``
:type min:number
:param max:the maximum allowable input value. Defaults to ``2147483647``
:type max:number
:param decimals:the number of decimals used for the input number. Defaults to ``0``
:type decimals:number
:param step:the increment by which the input number will change when the spinner is used. Defaults to ``1``
:type step:number
:returns:``input`` will be the input number and ``ok`` will be ``true`` if ``OK`` was selected. ``input`` will be ``default`` and ``ok`` will be ``false`` if ``Cancel`` was selected or if the window was closed without selection.
:param label:the text adjacent to the input entry area
:type label:string
:param items:an array of text items that will populate the dropdown
:type items:array
:param default:the index of the item to select by default. Defaults to ``0``
:type default:number
:param editable:whether the user is allowed to enter their own text instead. Defaults to ``false``
:type editable:boolean
:returns:``input`` will be the input text and ``ok`` will be ``true`` if ``OK`` was selected. ``input`` will be the text of the item at ``default`` and ``ok`` will be ``false`` if ``Cancel`` was selected or if the window was closed without selection.
Some constant values are provided for convenience. These are read-only properties guaranteed not to change unless a new project is opened or the current one is reloaded.
All constants are accessible via the global ``constants`` object.
..js:attribute:: constants.max_primary_tiles
The maximum number of tiles in a primary tileset.
..js:attribute:: constants.max_secondary_tiles
The maximum number of tiles in a secondary tileset.
..js:attribute:: constants.max_primary_metatiles
The maximum number of metatiles in a primary tileset.
The number of tile layers used in each metatile. This will either be ``2`` or ``3``, depending on the config setting ``enable_triple_layer_metatiles``.
..js:attribute:: constants.tiles_per_metatile
The number of tiles in each metatile. This will either be ``8`` or ``12``, depending on the config setting ``enable_triple_layer_metatiles``.