Import an adventure
Start a whole game from one adventure zip: RollQuest checks the zip, shows you what it will build, and sets up every scene for you.
An adventure zip is a single file that holds an adventure ready for the table: its maps, token pictures, music and sounds, and a description of how they fit together, such as where each wall, door and light goes and which creatures wait, hidden, in each room. Importing it saves you building each scene by hand. You might get a zip from a creator who makes adventures for RollQuest, make one with your own tools, or write one by hand: the second half of this page, How an adventure zip is built, describes the format in full.
Plan: importing an adventure is on Pro. On Free and Starter you can see Import Adventure, but choosing a zip opens a window explaining the feature instead.
Import an adventure
- On your dashboard, click New Game. Or, in a game, open the menu (three lines, top left) and click Create Game. The Create New Game window opens.
- Click Import Adventure, the third button under the description.
- Click Choose an adventure .zip and pick the zip on your computer.
- Wait while it uploads (Uploading…, with a percentage) and then while RollQuest checks it (Checking your adventure…). A big adventure can take a minute or two.
- Read the report. It lists each scene with what it holds, then the playlists, tracks, sounds and journal notes. Anything you should know is listed under it; anything that stops the import is listed in red under This adventure can't be imported yet. See The check report, below.
- If the adventure has no game system of its own, Game System asks which rules your table plays. It starts on the first system the adventure says it works best with, and the line under it says so, such as Works best with 5e Compatible. You can pick any system, or None. Pick another if you like. An adventure made for one of RollQuest's own systems doesn't ask: it starts on that system. See Game system, below.
- Check the Game Name. If you left it empty, it fills in with the adventure's title. Change it if you like, up to 50 characters. A Description (Optional) you type replaces the adventure's own on the game's card; leave it empty to keep the adventure's.
- Click Create Game. The window shows Importing, the adventure's title and Storing, then the size, while the files are stored. Then you go straight into the new game, on the adventure's starting scene.
Nothing is added to your account until you click Create Game: the check only reads the zip. The first time you start a game this way, the short video Your campaign is ready plays, the same one a game from a content pack shows. See Start from a content pack.
The adventure's journal notes arrive in the game's campaign journal a moment after the game opens, one entry under Notes for each note.
Leave and come back
Closing the window doesn't stop an import. RollQuest keeps working on the server, and when you open Create New Game again and click Import Adventure, you pick up where you left off:
- Still checking: you see it working, then the report.
- Checked and ready: the report is waiting, so you can name the game and click Create Game whenever you like. It waits until you import it, remove it or upload another zip.
- Still importing: you see it working, then is imported. Click Create Game to make the game.
- Finished importing while the window was closed: the panel starts afresh, but the adventure is already yours, with a card of its own on your dashboard. Click Start a Game on that card, or Use Content Pack in this window and pick it, then click Create Game. See After the import, below.
Who can import
| Plan | What happens |
|---|---|
| Free | Import Adventure shows. Choose an adventure .zip carries a Pro badge, and clicking it opens Import an adventure, a short explanation with a video, Included with Pro, Not now and Upgrade to Pro. |
| Starter | The same as Free. |
| Pro | You can import. |
The Import Adventure panel, state by state
The panel sits under the three buttons while Import Adventure is picked.
| What you see | What it means | What you can do |
|---|---|---|
| Choose an adventure .zip, with Maps, tokens, walls, doors, lights, music and notes, set up for you. We check everything before anything is added. | Nothing chosen yet. | Click it to pick a zip. |
| Uploading…, a bar and a percentage | The zip is on its way to RollQuest. | Wait. |
| Checking your adventure… and Every map, token, track and note in, then the file's name | RollQuest is reading every file in the zip and checking how they fit together. | Cancel stops the check and takes you back to the start. |
| The report, with no red box | The adventure is ready to import. | Name the game and click Create Game. Choose another file checks a different zip instead; Remove clears it. |
| The report with This adventure can't be imported yet | Something in the zip has to be fixed first. Create Game stays greyed out. | Fix the zip and use Choose another file, or Remove. |
| Importing, the title, Storing and a size, This can take a minute. | You clicked Create Game and the files are being stored. | Wait. It can't be cancelled now. |
| The title and is imported., Press Create Game to start playing it. | The adventure is stored but the game isn't made yet. | Click Create Game. |
| A red line, such as The adventure could not be checked. Try uploading it again. | The check or the import failed. Nothing was added. | Choose another file to try again, or Remove. |
The other parts of the window work as they do for any game, with two differences while Import Adventure is picked: there's no Game Image (Optional), because the adventure brings its own cover, and Game System shows only once the report is in, and only for an adventure with no system of its own. Description (Optional) works as usual: what you type goes on the new game's card in place of the adventure's own description. See Create a game.
Messages you can see while choosing and uploading:
- Choose a .zip file. The file you picked doesn't end in .zip.
- An adventure is still being checked or imported. Let it finish first. You have one import at a time; wait for the other to finish.
- The zip is larger than 1024 MB. The zip is over the 1 GB limit.
- The upload failed. Check your connection and try again. The connection dropped during the upload.
- The adventure could not be uploaded. Try again. Something went wrong on RollQuest's side.
- Adventure import is a Pro feature. Your plan doesn't include it.
The check report
At the top: the adventure's title and how much storage its files will take, such as 32.7 MB. Then one line per scene:
- The scene's name (or Untitled scene), with Starts here on the scene the game opens on. Exactly one scene has it: the scene the zip's
activeScenenames, or else the one marked as its starting scene, or else the first. - What it holds, such as 82 walls · 6 doors · 9 lights · 14 tokens (11 hidden) · 6 markers, then any vistas and phases. Hidden tokens are on the map for you but not for your players. A scene with none of these says An empty scene.
Under the scenes, a line for the whole adventure, such as 2 playlists · 12 tracks · 0 sounds · 6 journal notes.
Things to know (warnings)
A yellow box headed with how many there are, such as 3 things to know, lists what the import will do differently from what the zip asks. They don't stop the import. The first five show; Show all lists the rest, and Show fewer folds them again. When the same kind of warning comes up more than 25 times, the 25 are followed by …and, the number, and more like this.
Under a warning about one part of the adventure, a smaller line says where it is, by name, then the field: such as Scene "The Old Mill" › enemy "Goblin" › avatarKey for a goblin's portrait. Blockers show the same line.
| You see | What it means | What to do |
|---|---|---|
| There is no Game System and its name here, so the game will have no system. | The zip names a game system RollQuest doesn't have built in. | Pick one in Game System, which shows under the report, or leave it on None. You can still change it later in Game Settings, until the game has its first character sheet. |
| A number and character sheet(s) are not imported yet; add them in the game. | The zip has character sheets. They're left out. | Make the characters in the game. |
| A number and card deck(s) are not imported yet. | The zip has card decks. They're left out. | Build the decks in the game if you need them. |
| A number and homebrew Game System(s) are not imported; the game will have no system. | The zip carries a homebrew game system. It's left out. | Pick a system in Game Settings. |
| Art credits in the zip are not carried into your game. | The zip names the artists or sellers of its art. The names don't come across. | Nothing. |
| A number and file(s) were missing when the zip was made. | Whoever made the zip listed files they couldn't include. | Anything that used them is left empty (see the next row). |
| A number and file(s) in the zip are not used by anything that is imported (only by character sheets, or by nothing), and are left out. | The zip has files that nothing imported points at. They aren't stored or counted against your storage. | Nothing. |
| A file name in quotes and is not in the zip, so it is left empty. | Something points at a file the zip doesn't have. That picture or sound is left blank. | Add the file to the zip, or ignore it. |
| A file name in quotes and is not in the zip, so this, then image, track, sound, vista or the like, is left out. | A library entry or a vista whose file the zip doesn't have. The whole entry is dropped; a scene that was showing that vista opens on its map. | Add the file to the zip, or ignore it. |
| A file name in quotes, has a space in it (or is not a stored file name (content-packs//...)), so its file is not imported and this is left empty. Rename it in pack.json and manifest.json. | The zip names a file in a form RollQuest can't store, such as with a space or as a relative path. The file isn't stored; the picture or sound is left blank, or the library entry or vista is left out (the message then says this, the kind, is left out). | Rename the file in both files, as the message says. See How pack.json points at a file, below. |
| A wall (or door, light, map marker, token) sits outside the map, its x and y, Positions are 0 to 1 of the background. | Something is placed off the edge of the map picture. | Check that position in the zip. |
| Playlist, its name, names a track that is not in the music library. | A playlist lists a track the adventure doesn't have. | The playlist plays without it. |
| Scene, its name, names a playlist that is not in the pack. | A scene's music, or its battle music, names a playlist the adventure doesn't have. | The scene has no playlist. |
| activeScene does not name one of the scenes; the game will start on the starting scene or the first one. | The zip's opening scene doesn't match any of its scenes. | Nothing, or fix the zip. |
Things that stop the import (blockers)
A red box headed This adventure can't be imported yet lists what has to be fixed in the zip first. Create Game stays greyed out until you choose a zip that passes. These messages are for whoever made the zip: if you didn't make it, send them the message.
| You see | What it means |
|---|---|
| This is not a readable zip, with a reason | The file isn't a zip, or it's damaged. |
| The zip has more than 20000 entries. | Too many files inside. |
| The zip contains, a name, which a content pack export never writes. | The zip has something the format doesn't allow, such as a folder entry, a .DS_Store file or a __MACOSX folder. See Making the zip, below. |
| The zip contains, a name, twice. | Two files inside have the same name. |
A name and is larger than 200 MB. (or 64 MB. for manifest.json and pack.json) |
One file inside is over its limit. |
| The zip unpacks to more than 2048 MB. | Everything inside adds up to more than 2 GB. |
The zip has no manifest.json., The zip has no pack.json. or The zip has no and a files/ name |
A file the format needs is missing. |
| A name and is not valid JSON, with a reason | manifest.json or pack.json can't be read. |
| manifest.json is not valid: and a list | manifest.json is missing a field or has one in the wrong form. Each line of the list names one. See manifest.json, below. |
| pack.json is not the pack the manifest names. | pack.json's _id isn't the manifest's pack.id. |
| pack.json is not a content pack (isContentPack must be true). | pack.json lacks "isContentPack": true. |
| The adventure has no scenes. | pack.json has no scenes. |
A files/ name, a file name and does not match its checksum or size in manifest.json. |
A file's bytes aren't what the manifest says: the zip is damaged, or the manifest is out of date. |
| A file name and cannot be stored as a key here. | A file's name can't be used, for example because it has .. in it. |
| Two different files would both be stored at and a name | Two different files have the same name. |
| pack.json could not be read as a game or pack.json has a value of an unexpected shape, with a reason | Something in pack.json isn't the shape it should be, such as text where a list should be. |
A message about one field, such as Path x (1.2) is more than maximum allowed value (1). |
A value in pack.json breaks a rule of the game format, such as a light off the map or a word that isn't one of the allowed values. The message names the field. |
| pack.json is, a size, once stored; the most a game can hold is 15 MB. Split it into smaller adventures. | pack.json itself is too big to store as one game. The pictures and sounds don't count towards this; very long notes or thousands of walls do. |
| The adventure needs, a size, and you have, a size, of storage left. | Its files won't fit in your remaining storage. Free some space or upgrade. |
When Create Game says no
Clicking Create Game checks a few things again, because time may have passed since the check. A message tells you if:
- you've reached your plan's game limit: You have reached your campaign limit of, the number, Upgrade your subscription, or delete a game, to import another adventure. (Before that, the Upgrade Required window may open, as it does for any new game.)
- your storage filled up since the check: The adventure needs, a size, and you have, a size, of storage left.
- something else changed since the check: Something changed since the check. Read the report below. The report shows what.
Nothing is added in any of these cases.
What comes across, and what doesn't
From the zip, the new game gets:
- every scene, with its map, grid, walls, doors (secret and locked ones included), lights, light level, phases (other versions of the map, such as before and after a flood), vistas (pictures shown to players instead of the map) and fog of war setting,
- tokens: creatures and NPCs (the characters you play) where the adventure puts them, hidden ones included, and player tokens with nobody assigned to them,
- elevation: how high a token, a light or a roof sits,
- map markers, the private notes pinned to the map,
- each scene's music, battle music and playlists, and the music and sound effects libraries,
- the image and asset libraries, pause screens, the cover picture, conditions, stat blocks, rollable tables and the calendar,
- the adventure's journal notes, in the campaign journal: notes for the Game Master (GM) are private, notes for players go in the players' journal. Up to 100 notes.
Left out, each with a warning in the report:
- character sheets,
- card decks,
- homebrew game systems,
- art credits.
The game system: a zip made for one of RollQuest's own systems, such as Ninefold or 5e Compatible, starts on that system. For anything else, Game System asks before you create the game, starting on the first system the adventure works best with; leave it on None for no system. You can still change it in Game Settings until the game has its first character sheet. See Game systems.
When the game is on a system, a creature token named after exactly one creature in that system's bestiary, such as "Goblin" or "Goblin 2", is linked to its stat block, so its numbers are filled in, unless the zip gave the token numbers of its own. A creature on a No System game keeps only what the zip gave it.
After the import
The adventure becomes a private content pack of your own: a saved copy that games are started from. Only you can see it.
- On your dashboard it has a card of its own, marked Imported adventure (hover: An adventure you imported. Start a game from it, or delete it while no game uses it.). That card is the adventure itself, kept so you can start it again: its button is Start a Game, not Continue Game, and it has no invite button. Play in the game you made, not in it.
- Start it again for a second group: click Start a Game on its card. The Create New Game window opens with Use Content Pack chosen, the adventure picked and the Game Name filled in, such as The Old Mill - Copy. Or click New Game, then Use Content Pack, and pick it: it shows with Draft and Yours. See Start from a content pack.
- Storage: its files count once towards your storage, however many games you start from it.
- Game limit: each game you start from it counts towards your plan's game limit. The adventure's own card doesn't.
- Each import is new: importing the same zip twice gives you two separate adventures.
Delete it
While no game uses the adventure, its card has a bin (hover: Delete imported adventure). That happens when an import finished while the window was closed, or after you've deleted every game you made from it.
- Click the bin on the adventure's card.
- Delete Adventure asks whether to delete the imported adventure, by name, and warns Its maps and files are removed and the storage they used is given back. This action cannot be undone. Click Confirm. The card goes, and a message says Game deleted successfully.
While a game you started from it still uses it, the bin is a padlock (hover: A game you started from this adventure still uses it. It goes when you delete that game.), and clicking it does nothing. Delete that game as usual: when you delete the last game made from the adventure, the adventure goes too, with its files, and the storage it took is given back. A picture from it that you saved to your Asset Drawer stays in your drawer. See Delete or leave a game.
An adventure you've made public or published as a content pack keeps its padlock, like any other content pack.
Limits
| What | Limit |
|---|---|
| The zip | 1 GB (1024 MB) to upload |
| Everything inside, unpacked | 2 GB (2048 MB) |
| Files inside the zip | 20,000 |
| One picture, sound or video inside | 200 MB |
manifest.json or pack.json |
64 MB each, and pack.json must come to no more than 15 MB once stored |
| Storage | The adventure's files must fit in what's left of your plan's storage (25 GB on Pro). The report shows how much they take. |
| Imports at a time | One. Uploading a new zip while one is checked and waiting replaces it. |
| Journal notes | The first 100 are written to the journal. |
An import that's still checking or importing after 45 minutes has stopped: the panel says This import stopped before it finished. Nothing was added; upload the adventure again. If RollQuest can't reach the server four times in a row while you wait, the panel stops following the import and says so; close the window and reopen it to check on it.
How an adventure zip is built
This part is for a creator, or a GM, who wants to make an adventure zip by hand or with their own tools. It's RollQuest's own format for content packs, so pack.json describes the adventure the same way RollQuest stores a game.
An adventure zip holds:
- manifest.json: what's in the zip, with a checksum for every file,
- pack.json: the adventure itself, as one game: its scenes, libraries and notes,
- files/: the pictures, sounds and videos, each under a numbered name.
the-old-mill.zip
├── manifest.json
├── pack.json
└── files/
├── 000001 the map (a WebP picture)
├── 000002 a goblin's token (a PNG picture)
├── 000003 a music track (an MP3)
└── 000004 the cover (a WebP picture)
Nothing else is allowed in the zip. Three more kinds of entry exist in the format, decks/<id>.json, sheets/<id>.json and systems/<id>.json, for card decks, character sheets and homebrew game systems; an import reads them and leaves them out, with a warning.
Making the zip
- Put
manifest.json,pack.jsonand thefiles/folder at the top level of the zip, not inside another folder. - Name each file
files/and six digits, such asfiles/000001, with no extension. The manifest says what each one is. - Leave out folder entries. Many zip tools add an entry for each folder (
files/), and the import refuses it: on the command line usezip -D, which leaves folder entries out. Don't zip with your computer's own "Compress" command if it adds hidden files such as__MACOSX/or.DS_Store. - Compressed (deflate) or stored entries both work. Encrypted zips don't.
manifest.json
Plain JSON: one object.
| Field | Type | Required | What it holds |
|---|---|---|---|
kind |
text | yes | Always "rollquest-content-pack". |
schemaVersion |
number | yes | Always 1. |
exportedAt |
text | yes | When the zip was made, as a date and time, such as "2026-10-17T09:00:00.000Z". |
sourceEnv |
text | no | A short name for whatever made the zip, such as "my-tool". Kept with the adventure for reference. |
pack.id |
text | yes | A 24-character id (0 to 9 and a to f, lowercase), the same as pack.json's _id. Make one up; RollQuest gives the adventure a new one when it imports it. |
pack.lineageId |
text | yes | Another 24-character id. Any will do. |
pack.version |
number | yes | A whole number, 1 or more. Use 1. |
pack.title |
text | no | The adventure's title. Used if pack.json has none. |
pack.price |
number | no | A whole number of cents, 0 or more. Ignored: an imported adventure is always free and private. |
systemPacks |
list | yes | The game system the adventure is for: [] for none, or one entry (see Game system, below). |
droppedSystemPackIds |
list | yes | []. |
decks |
list | yes | []. |
sheets |
list | yes | []. |
missing |
list | yes | [], or the names of files you meant to include but couldn't. Each one shows as a warning. |
files |
list | yes | One entry per file in files/ (see below). |
providers, droppedProviderIds and bundledSystems may be left out.
The files list
Each entry in files describes one file in the zip:
| Field | Type | What it holds |
|---|---|---|
entry |
text | Its name in the zip, such as "files/000001". Each one listed once, and each one must be in the zip. |
key |
text | The name the file is stored under, such as "content-packs/6710a0000000000000000001/maps/old-mill.webp". See How pack.json points at a file, below. |
refs |
list of text | Every way pack.json writes this file's name. For a zip you make, one: the same as key. Must not be empty. |
sha256 |
text | The SHA-256 checksum of the file's bytes: 64 characters, 0 to 9 and a to f, lowercase. |
size |
number | The file's size in bytes, exactly. |
contentType |
text | Its type, such as "image/webp", "image/png", "image/jpeg", "audio/mpeg" or "video/mp4". |
Every file is read in full during the check, and its checksum and size must match, or the import stops. On a Mac or Linux, shasum -a 256 files/000001 gives the checksum and wc -c < files/000001 the size; on Windows, certutil -hashfile files\000001 SHA256 and the file's properties.
A file that no refs entry matches anywhere in pack.json isn't stored, and the report says how many were left out.
How pack.json points at a file
Wherever pack.json needs a picture or a sound, such as a scene's map or a token's portrait, it gives the file's name as text. Write every such name like this:
content-packs/<pack.id>/<folder>/<file name>
for example content-packs/6710a0000000000000000001/tokens/goblin.png, where the 24 characters are your pack.id. The folder and file name after it are yours to choose. RollQuest stores the file under its own new id with the same folder and file name.
- The name must match a
refsentry in the manifest exactly, letter for letter. - No spaces anywhere in it: a name with a space isn't recognised as a file at all, so it isn't stored and the picture is left broken. Use
-or_instead. - No
.., no\, nothing likehttps://, and no/at the start. - The same file can be named in as many places as you like.
A name in that form with no file in the zip is left empty, with a warning (see the report, above). Names for RollQuest's own built-in art, starting system/, system-assets/, backgrounds/, map-asset-packs/ or stickers/, are kept as they are without a file.
Positions and sizes
Everything placed on a map is placed by where it sits on the map picture, from 0 to 1 across and down: x 0 is the left edge and 1 the right, y 0 the top and 1 the bottom. So { "x": 0.5, "y": 0.5 } is the middle of the map, whatever the picture's size.
- Walls, doors, map markers and tokens a little off the edge (up to 0.05) pass; further out, each gets a warning.
- Lights must be between 0 and 1 exactly, or the import stops.
- Sizes are in the map picture's own pixels:
gridSizeis one square's width and height, and a token'ssizeis its width. WithgridSize64, a token ofsize64 fills one square. - Light radii,
brightRadiusanddimRadius, are in the game system's unit: feet, at 5 feet a square, for No System and the D&D systems. The board reads them in squares of that size, whatever the map's own scale: on a town overview where one square stands for 25 ft, a lantern meant to reach 30 ft needs a radius of 6 (30 ÷ 25 × 5). elevation, on tokens, lights and assets, is height off the ground in feet: 30 is flying, -10 is down a pit, 0 is the ground.
Ids
Many things in pack.json have an id: the adventure (_id), each scene, each music track and playlist. An id is 24 characters, 0 to 9 and a to f. Write it as { "$oid": "6710a00000000000000000a1" }, which is how RollQuest writes them, or as plain text, "6710a00000000000000000a1"; both work. Where one thing points at another by id, such as a playlist's trackIds or a scene's musicPlaylistId, write the id as plain text.
Walls, doors, lights, tokens and markers have an id of their own instead: any text, unique within its scene, such as "wall-1" or "goblin-2". RollQuest gives them all new ids when it makes a game.
Dates can be text, such as "2026-10-17T09:00:00.000Z", or { "$date": "2026-10-17T09:00:00.000Z" }.
pack.json: the adventure
One object. The import keeps only the fields below and ignores everything else.
| Field | Type | Required | What it holds |
|---|---|---|---|
_id |
id | yes | The same as the manifest's pack.id. |
isContentPack |
true or false | yes | Always true. |
name |
text | no | The adventure's name. |
description |
text | no | The description the new game shows on its card, unless the GM types one in Description (Optional) when importing. |
contentPackMetadata |
object | no | How the adventure is listed: title (the name in the report and in Use Content Pack), description, category (such as "Dungeon", "Town", "Wilderness", "Campaign" or "Other"), tags (a list of words) and worksBestWith (up to 4 game system names, such as "Ninefold (2d10)"). For an adventure with no system of its own, Game System starts on the first of them when you import it, and Use Content Pack suggests them for a second game. Everything else in it is replaced. |
systemPackId |
id | no | The game system, or null. See Game system, below. |
scenes |
list | yes | At least one scene (see below). |
activeScene |
id | no | The _id of the scene the adventure opens on. It wins over isStartingScene. |
gameImageKey |
file name | no | The cover picture on the game's card. |
gameImageFraming |
object | no | Which part of the cover shows: x and y from 0 to 100 (50 is the middle) and scale from 1 to 3. |
imageLibrary |
list | no | The game's image library (see Libraries, below). |
assetLibrary |
list | no | The asset library: pictures to place on the map. |
musicLibrary |
list | no | The music library. |
musicPlaylists |
list | no | Playlists of tracks from the music library. |
soundLibrary |
list | no | The sound effects library. |
pauseScreens |
list | no | Pictures shown to players while the game is paused. Keep to 6, the most a game can have. |
journal |
list | no | Notes for the campaign journal. |
state |
object | no | Leave it out: it's rebuilt from the opening scene. Its players list is the one place for player tokens (see Tokens, below). |
statBlocks, rollableTables, conditionLibrary, conditionIconLibrary, journalCalendar, sightUnits, playerCardsBarEnabled, playerShortcutBarEnabled |
various | no | Carried into the game as they are, in the form RollQuest stores them in a game. Leave them out unless you know that form. |
A scene
Each entry in scenes:
| Field | Type | What it holds |
|---|---|---|
_id |
id | The scene's id. |
name |
text | The scene's name. |
isStartingScene |
true or false | true on the scene the game opens on, if activeScene doesn't name one. The import marks exactly one scene as the starting scene in the game it makes: activeScene's, else the one marked here, else the first. |
backgroundImage |
file name | The map: a picture, or an MP4 or WebM video for an animated map. |
backgroundImageWidth, backgroundImageHeight |
number | The map's size in pixels. |
thumbnail |
file name | The picture in the scene list. Usually the map. |
gridType |
text | "square" (the default), "hexFlat" or "hexPointy". |
gridSize |
object | { "width": 64, "height": 64 }: one square, in the map's pixels. A hex grid uses width. Default 100. |
gridOffset |
object | { "x": 0, "y": 0 }: where the grid starts, in pixels. |
showGrid, snapToGrid |
true or false | Whether the grid shows, and whether tokens snap to it. |
blockTokenMovement |
true or false | Block Wall Passage: walls stop tokens. |
fogOfWarEnabled |
true or false | Fog of war on. Default true. |
lightingEnvironment |
text | The light level: "brightLight" (the default), "dimLight" or "darkness", or a light level of the game's system. |
walls, doors, lights |
lists | See below. |
enemies, npcs |
lists | Creature and NPC tokens. See Tokens, below. |
mapMarkers |
list | GM-only notes on the map. |
phases, activePhaseId |
list, id | Other versions of the map, and the one it opens on. |
vistas |
list | Pictures shown to players instead of the map. Keep to 12, the most a scene can have. |
backgroundMusic, battleMusic |
object | One track: { "_id": …, "name": "…", "key": "<file name>", "loop": true }. Played if the scene has no playlist. |
musicPlaylistId, battleMusicPlaylistId |
text | The _id of a playlist in musicPlaylists, for the scene and for its battles. |
soundEffects |
list | { "_id": …, "name": "…", "key": "<file name>" } for each sound the scene uses. |
boardAssets |
list | Assets placed on the map: assetId (an asset library _id), position (0 to 1), size, rotation, elevation, layer ("map", "foreground" or "gm"). |
partyStart |
object | { "x": 0.7, "y": 0.6 }: where the characters' tokens are put, one square apart around it. |
clocks |
list | Progress clocks, { "name": "…", "segments": 4, "visibility": "everyone" } (or "gm"), for a system that has clocks. Segments 4, 6, 8 or 12. |
weather |
object | { "type": "rain", "intensity": 0.5 }: a weather preset, such as rain, snow, mist or ash, and how strong, from 0.05 to 1. |
Walls, doors and lights
A wall is a straight line from one point to another:
{ "id": "wall-1", "x1": 0.1, "y1": 0.2, "x2": 0.4, "y2": 0.2 }
A door is a line too, given as its two ends:
| Field | What it holds |
|---|---|
id |
Its id. |
points |
Its two ends: [{ "x": 0.45, "y": 0.5 }, { "x": 0.55, "y": 0.5 }]. |
isOpen, locked, isSecret |
Open, locked, or a secret door. All false by default. |
name |
Optional. |
A light:
| Field | What it holds |
|---|---|
id, name |
Its id and name. |
x, y |
Where it is, 0 to 1. Required. |
type |
"torch" (the default), "lantern", "candle", "magic" or "custom". |
brightRadius, dimRadius |
How far it's at full strength, and where it fades to nothing. Defaults 20 and 40. |
color |
A colour, such as "#FFA500". |
elevation |
Height in feet. A light above a roof's height doesn't light under the roof. |
cone |
Optional: { "angle": 90, "facing": 180 } makes it shine in a wedge, in degrees, facing measured clockwise from the top of the map. |
emissionOpacity |
How strongly its glow tints the map, from 0 to 1 (Emission Overlay Transparency in the Edit Light window). Leave it out for 0.05 (5%), the same as a light you place on the board. |
On a scene with phases, a wall, door or light can carry phaseIds: a list of the phase _ids it's on. Leave it out to put it on every phase. A lamp lit only at night, say, lists only the night phase: it fades in as the GM swaps to night and out again at daybreak.
Tokens
Each entry in enemies and npcs:
| Field | What it holds |
|---|---|
id, name |
Its id and name. A creature named after one in the game system's bestiary, such as "Goblin" or "Goblin 2", gets that stat block. |
position |
{ "x": 0.6, "y": 0.3 }: where its centre is. |
size |
Its width in the map's pixels. |
avatarKey |
File name of its portrait. |
visible |
false hides it from players (the GM still sees it). "isHidden": true does the same. |
elevation |
Height in feet. |
hp, maxHp, ac |
Optional numbers. A token with numbers of its own isn't linked to a stat block. |
prompt |
Optional notes about it. |
Player tokens go in state.players, with the same fields; they arrive with nobody assigned, ready for your players' characters.
Map markers
| Field | What it holds |
|---|---|
id |
Its id. |
x, y |
Where it is, 0 to 1. |
label |
Its title, up to 120 characters. |
notes |
What it says when opened, up to 20,000 characters. |
icon |
"diamond", "star", "skull", "key", "door", "chest", "eye", "book", "flame", "question", "exclamation" or "circle". |
color |
"#e0b341", "#d1495b", "#2a9d8f", "#4a7fd4", "#8f5cd1" or "#8a93a6". |
glyphText |
Up to 3 letters or numbers to show on the pin instead of the icon, such as "1" or "B3". |
phaseId |
On a scene with phases, the _id of the phase it's on; null on a scene without. Or give phaseIds, a list, with [] for every phase. |
A scene can hold up to 200 markers.
Phases and vistas
A phase is another version of the same map, such as a room before and after a flood. Once a scene has phases, list every version, the first included; activePhaseId names the one it opens on (the first, if left out).
| Phase field | What it holds |
|---|---|
_id |
Its id. |
label |
Its name. |
backgroundImage, backgroundImageWidth, backgroundImageHeight |
Its map, the same size as the scene's. |
transition |
{ "type": "fade", "durationMs": 600 }: fade, blur, shake or cut, up to 10,000 milliseconds. |
musicPlaylistId |
Optional: a playlist to switch to. |
lightingEnvironment |
Optional: a light level to switch to, such as "darkness". |
| Vista field | What it holds |
|---|---|
_id, label |
Its id and name. |
imageKey |
File name of the picture. Required: a vista whose picture isn't in the zip is left out, with a warning, and a scene that was showing it opens on its map. Put the picture in imageLibrary too. |
imageWidth, imageHeight |
Its size in pixels. |
transition |
{ "type": "fade", "durationMs": 800 }: fade or cut. |
Libraries
| List | Each entry | Notes |
|---|---|---|
imageLibrary |
name, key (file name), width, height, size (bytes), tags |
Put every map and vista picture here, so the GM can find them. |
assetLibrary |
_id, name, key, type, contentType, width, height, size, tags, defaultLayer ("map", "foreground" or "gm") |
Pictures to place on the map, such as tokens and props. |
musicLibrary |
_id, name, key, contentType (such as "audio/mpeg"), size, tags |
Each track's _id is what playlists list. |
musicPlaylists |
_id, name (required), trackIds (a list of track _ids), shuffle, repeat |
A scene or phase plays one by its _id. |
soundLibrary |
_id, name, key, contentType, size, tags |
|
pauseScreens |
_id, imageKey (required), imageSize, label |
|
journal |
key (required: any text, unique), title, body, type ("gm" or "player") |
One journal entry per note, in this order. "gm" notes are private; "player" notes go in the players' journal. |
An entry whose file is missing from the zip is dropped from its library.
Game system
To start the game on one of RollQuest's own systems, name it in the manifest and point systemPackId at it:
"systemPacks": [ { "id": "6710a00000000000000000f1", "slug": "ninefold-core", "name": "Ninefold" } ]
and in pack.json:
"systemPackId": { "$oid": "6710a00000000000000000f1" }
The id is any 24-character id you choose, the same in both places. The slug decides the system:
| Slug | System |
|---|---|
5e-core |
5e Compatible |
5-5e-core |
5.5e Compatible |
ashfall-core |
Ashfall |
brightline-core |
Brightline |
ninefold-core |
Ninefold |
tidewrack-core |
Tidewrack |
Any other slug imports as No System, with a warning. Leave systemPacks empty and systemPackId null for No System.
File types and sizes
Store pictures, sound and video in formats the app plays: pictures as PNG, JPG, WebP, GIF or SVG; animated maps as MP4 or WebM; music and sounds as MP3, OGG, WAV or WebM. A file whose contentType isn't a picture, sound, video or PDF is stored as a plain download, so give each file its true type. No file inside may be over 200 MB. See Limits and file types.
A worked example
A one-scene adventure, The Old Mill: a map, one hidden goblin, one wall, a door, a light, a marker, a music track in a playlist, a cover and a note for the GM. pack.id is 6710a0000000000000000001.
manifest.json (checksums and sizes shortened here: use the real ones):
{
"kind": "rollquest-content-pack",
"schemaVersion": 1,
"exportedAt": "2026-10-17T09:00:00.000Z",
"sourceEnv": "hand-made",
"pack": {
"id": "6710a0000000000000000001",
"lineageId": "6710a0000000000000000002",
"version": 1,
"title": "The Old Mill"
},
"systemPacks": [],
"droppedSystemPackIds": [],
"decks": [],
"sheets": [],
"missing": [],
"files": [
{
"entry": "files/000001",
"key": "content-packs/6710a0000000000000000001/maps/old-mill.webp",
"refs": ["content-packs/6710a0000000000000000001/maps/old-mill.webp"],
"sha256": "3f5a…",
"size": 812345,
"contentType": "image/webp"
},
{
"entry": "files/000002",
"key": "content-packs/6710a0000000000000000001/tokens/goblin.png",
"refs": ["content-packs/6710a0000000000000000001/tokens/goblin.png"],
"sha256": "9b01…",
"size": 48211,
"contentType": "image/png"
},
{
"entry": "files/000003",
"key": "content-packs/6710a0000000000000000001/music/mill-wheel.mp3",
"refs": ["content-packs/6710a0000000000000000001/music/mill-wheel.mp3"],
"sha256": "c47e…",
"size": 2880618,
"contentType": "audio/mpeg"
},
{
"entry": "files/000004",
"key": "content-packs/6710a0000000000000000001/art/cover.webp",
"refs": ["content-packs/6710a0000000000000000001/art/cover.webp"],
"sha256": "0d2c…",
"size": 201876,
"contentType": "image/webp"
}
]
}
pack.json:
{
"_id": { "$oid": "6710a0000000000000000001" },
"isContentPack": true,
"name": "The Old Mill",
"description": "Goblins have taken the old mill. One evening, one map.",
"contentPackMetadata": {
"title": "The Old Mill",
"category": "Dungeon",
"tags": ["goblins", "one-shot"],
"worksBestWith": ["5e Compatible"]
},
"systemPackId": null,
"gameImageKey": "content-packs/6710a0000000000000000001/art/cover.webp",
"activeScene": { "$oid": "6710a00000000000000000a1" },
"imageLibrary": [
{ "name": "The Old Mill", "key": "content-packs/6710a0000000000000000001/maps/old-mill.webp", "width": 2048, "height": 1536 }
],
"assetLibrary": [
{ "_id": { "$oid": "6710a00000000000000000d1" }, "name": "Goblin", "key": "content-packs/6710a0000000000000000001/tokens/goblin.png", "type": "token", "contentType": "image/png", "width": 256, "height": 256 }
],
"musicLibrary": [
{ "_id": { "$oid": "6710a00000000000000000b1" }, "name": "Mill Wheel", "key": "content-packs/6710a0000000000000000001/music/mill-wheel.mp3", "contentType": "audio/mpeg" }
],
"musicPlaylists": [
{ "_id": { "$oid": "6710a00000000000000000c1" }, "name": "The Old Mill", "trackIds": ["6710a00000000000000000b1"], "shuffle": false, "repeat": true }
],
"journal": [
{ "key": "note-1", "title": "Running the mill", "body": "The goblins hide in the wheel room until the party opens the door.", "type": "gm" }
],
"scenes": [
{
"_id": { "$oid": "6710a00000000000000000a1" },
"name": "The Old Mill",
"isStartingScene": true,
"backgroundImage": "content-packs/6710a0000000000000000001/maps/old-mill.webp",
"backgroundImageWidth": 2048,
"backgroundImageHeight": 1536,
"thumbnail": "content-packs/6710a0000000000000000001/maps/old-mill.webp",
"gridType": "square",
"gridSize": { "width": 64, "height": 64 },
"gridOffset": { "x": 0, "y": 0 },
"showGrid": true,
"snapToGrid": true,
"blockTokenMovement": true,
"fogOfWarEnabled": true,
"lightingEnvironment": "dimLight",
"walls": [
{ "id": "wall-1", "x1": 0.1, "y1": 0.5, "x2": 0.45, "y2": 0.5 }
],
"doors": [
{ "id": "door-1", "points": [{ "x": 0.45, "y": 0.5 }, { "x": 0.55, "y": 0.5 }], "isOpen": false, "locked": false, "isSecret": false }
],
"lights": [
{ "id": "light-1", "name": "Hearth", "type": "torch", "x": 0.3, "y": 0.7, "brightRadius": 20, "dimRadius": 40, "color": "#FFA500" }
],
"enemies": [
{ "id": "goblin-1", "name": "Goblin", "position": { "x": 0.6, "y": 0.3 }, "size": 64, "avatarKey": "content-packs/6710a0000000000000000001/tokens/goblin.png", "visible": false }
],
"npcs": [],
"mapMarkers": [
{ "id": "marker-1", "x": 0.6, "y": 0.25, "icon": "key", "color": "#e0b341", "glyphText": "1", "label": "1 The wheel room", "notes": "Four goblins wait here.", "phaseId": null }
],
"musicPlaylistId": "6710a00000000000000000c1",
"partyStart": { "x": 0.5, "y": 0.9 }
}
]
}
Before you upload
manifest.json,pack.jsonandfiles/at the top of the zip, and nothing else: no folder entries, no__MACOSX, no.DS_Store.pack.json's_idis the manifest'spack.id, andisContentPackistrue.- Every file name in
pack.jsonstartscontent-packs/<pack.id>/, has no spaces, and is arefsentry in the manifest. - Every
filesentry has the file's real SHA-256 (lowercase) and its exact size. activeScenenames the scene to open on, or one scene hasisStartingScene: true.- Lights are between 0 and 1.
- Every vista's picture is in the zip, or the vista is left out.
Then upload it. The report tells you anything else to fix, and nothing is added until it passes and you click Create Game.
Related
Create a game · Start from a content pack · Publish a content pack · Delete or leave a game · Limits and file types
