SETUP GUIDE

About 10 minutes, done once

Everything here is free. You copy a Google Sheet, connect it, and you're building lists.

Before You Start

What you'll need

Two free accounts, nothing else. You may already have most of these.

๐Ÿ“ง

Google Account

For Google Sheets and Apps Script. You almost certainly have one already.

โ˜๏ธ

Supabase (optional)

Free at supabase.com. Only needed if you want to save rosters across devices.

Not a developer? That's fine.
You don't need to write any code. Every step is copy-paste or point-and-click, with a screenshot for each one. If you can follow a recipe, you can follow this guide.
STEP 01

Copy the Google Sheet template

Required ยท ~2 min

This Sheet is your card database โ€” it's where every Character, Weapon, Armoury item, Special Order, and Keyword definition lives. The app reads it every time it loads. Making your own copy means you fully own and control it: you can add cards, fix typos, or update stats at any time, and the app picks up the changes immediately on the next refresh.

The template is a free download from the itch.io page. It took a fair amount of work to put together, so if you find it useful, a donation there is genuinely appreciated โ€” but it's entirely optional and nothing is held back if you don't.

  1. Download the template using the link below.
  2. Go to File โ†’ Make a copy, and save it to your own Google Drive.
  3. Rename it whatever you like โ€” the name doesn't matter to the app.
What you'll see when you open it
The Sheet has three tabs along the bottom: List (all your cards โ€” Characters, Weapons, Armoury items, Special Orders, and Rules all live here, distinguished by the Type column), Keywords (the definitions that appear on hover inside the app), and Translations (the English and French UI text โ€” touch this only if you want to add a new language or customise the wording). The template comes pre-filled with a few example rows so you can see exactly how a complete entry looks before you start adding your own.
โ†ณ

Understanding the Sheet

Reference

You don't need to fill out the whole Sheet before the app works โ€” the example rows are enough to test the connection in Step 3. But you'll need to understand the structure before you start adding real cards. This section explains how every part of it works.

The List tab: one row = one card

Each row in the List tab represents one card in the game. The Type column tells the app what kind of card it is โ€” Character, Armoury, Special Orders, Command Upgrades, Fireteam Upgrades, or Rules. Every other column is the data that shows up on that card in the app.

Columns explained:

  • Item Name โ€” the card's display name. This is what appears in the browse list and on the card itself. See the "Links in Item Name" section below for how to attach an image.
  • Faction โ€” which faction(s) can use this card. Use comma-separated values for items available to multiple factions (e.g. UNSC, Banished). The app uses this for competitive faction validation.
  • Detachment โ€” the detachment within a faction (e.g. ODST, Jiralhanae). Leave blank for cards with no detachment restriction.
  • Type โ€” see above. Must be one of the exact values the app recognises: Character, Armoury, Special Orders, Command Upgrades, Fireteam Upgrades, Rules.
  • Points โ€” the card's point cost. Numbers only, no units.
  • Keywords โ€” a comma-separated list of keyword names, exactly as they appear in the Keywords tab (e.g. Energy Shield (2), Tactician (1)). The app matches these against the Keywords tab to show hover definitions. Extra text in parentheses like (2) is fine โ€” the match is flexible.
  • RA / FI / SV / Speed / Armour / HP โ€” the six stat columns for Character rows. Leave these blank (or with a dash) for non-Character rows like Armoury items.
  • Weapon 1โ€“3 columns โ€” each weapon has a Type (Ranged,Close Combat, or Grenade), Name, Range, AP, and Keywords sub-column. For a character's built-in weapons, fill these in. For Armoury weapon rows, the app reads the weapon data from the same columns. See "Links in Weapon Names" below for attaching weapon images.
  • Description โ€” free text shown on the card and in the info panel. For Armoury items and Special Orders, this is the rules text. For Rules rows, this is the full rule text itself. Supports plain text; line breaks are fine.
  • Restrictions โ€” controls when an item can be added to a roster. Leave blank if there are no restrictions. See the Restrictions Guide tab in your Sheet for the full token reference.

Adding image links โ€” Item Name and Weapon Name cells

The app can display card art and weapon images by reading a link embedded directly in the cell โ€” not from a separate column. Here's how it works:

  1. Upload your card images to Google Drive (any folder is fine).
  2. Right-click the image in Drive โ†’ Get link โ†’ change sharing to "Anyone with the link" โ†’ copy the link.
  3. In your Sheet, click on the Item Name cell (or the Weapon Name cell) for that card.
  4. Press Ctrl+K (or Cmd+K on Mac) to open the Insert Link dialog.
  5. Paste the Google Drive link and click Apply. The cell text stays the same โ€” it just now has a link underneath it that the app can read.

The app checks whether a cell has a link attached to it. If it does, it uses that link as the image source. If it doesn't, it shows the default card placeholder. This means you can have a name like MA40 Assault Rifle display as text in the Sheet, but open as a card image inside the app.

Google Drive sharing: "Anyone with the link"
The image link needs to be set to "Anyone with the link can view" โ€” otherwise the app will get a permission error when it tries to load the image. The image is only displayed inside your own hosted copy of the app; this setting doesn't make the image searchable or publicly listed anywhere.

The Keywords tab

The Keywords tab has two columns: Keyword (the name, exactly as it'll be referenced in the List tab's Keywords column) and Definition (the rules text that appears on hover inside the app).

  • A keyword in the List tab matches an entry here if the keyword name contains the entry's name โ€” so Energy Shield (2) in a card's keywords will match the Energy Shield row in this tab.
  • If a keyword in a card's row has no matching entry here, the hover tooltip just won't appear for that keyword. Nothing breaks.
  • Keep definitions up to date with any official errata โ€” this is the single source of truth the app uses for keyword text, so if Mantic changes a keyword's rules, just edit the definition here and every card that uses it updates automatically.
  • There's no limit on definition length, but shorter is more readable in the hover tooltip.

The Translations tab

The Translations tab controls every piece of text in the app's UI โ€” button labels, error messages, modal titles, PDF export strings, everything. It ships with English and French columns already filled in. You don't need to touch this tab unless you want to:

  • Add a new language: create a new column to the right of French. The column header becomes the language name shown in Settings. Fill in every row in that column with your translated text. The app will automatically make this language available as a choice in the Settings โ†’ Language selector โ€” no code change required.
  • Customise existing text: just edit the English or French cell directly. For example, if you want to change "Add to Roster" to "Add to List" in your own copy, edit that cell and the app picks it up on the next refresh.

The Key column (first column, locked) is what the app uses internally to find each string. Don't edit the Key column. The English and French values are what actually appear in the UI.

Tip: use the Sheet for everything text-related
Because all UI text comes from your Sheet, you can translate the entire interface into any language without touching a line of code. The same goes for rule updates: if Mantic errata a keyword, edit the Keywords tab and you're done. No app update needed.

The Restrictions column โ€” quick reference

The Restrictions column controls when an item can be added to a roster, and for Special Orders, which competitive detachment context they appear in. Leave it blank if there are no restrictions. Multiple tokens are separated by | โ€” all conditions must be true.

Character & roster conditions โ€” who must be in the roster for this item to be available:

  • REQUIRES_CHAR_NAME_INCLUDES:value โ€” roster must include a character whose name contains this text (e.g. REQUIRES_CHAR_NAME_INCLUDES:master chief)
  • REQUIRES_CHAR_FACTION_INCLUDES:value โ€” roster must include a character of this faction
  • REQUIRES_CHAR_DETACHMENT_INCLUDES:value โ€” roster must include a character in this detachment
  • ALL_CHARS_DETACHMENT:value โ€” every character in the roster must be this detachment
  • ALL_CHARS_FACTION:value โ€” every character must be this faction

Special Orders โ€” competitive detachment visibility โ€” use these instead of the Detachment column for Special Orders. The Detachment column on Special Order rows must stay blank (writing anything there pollutes the browse filter dropdown):

  • ALL_UNITS_ONLY โ€” this Special Order only appears in comp when "All Units" is selected; hidden for specific detachments like ODST or Jiralhanae
  • DETACHMENT_ONLY:value โ€” this Special Order only appears in comp for this specific detachment (e.g. DETACHMENT_ONLY:ODST). Use multiple pipe-separated entries to allow more than one detachment: DETACHMENT_ONLY:ODST|DETACHMENT_ONLY:Jiralhanae

Weapon-slot rules:

  • REQUIRES_WEAPON:value โ€” character must already have this weapon on their base card (used for replacement weapons like combat knives)
  • BLOCKS_LEGEND โ€” item cannot be equipped by Legend-tier characters
  • EXEMPT_FROM_WEAPON_LIMIT โ€” item doesn't count against the weapon-per-character cap

The full reference with worked examples is in the Restrictions Guide tab of your Sheet.

STEP 02

Deploy the Apps Script

Required ยท ~5 min

Apps Script is a small free Google service that connects your Sheet to the app. Think of it as a messenger: the app asks it "give me the card data from this Sheet," it reads the Sheet and sends the data back. The connector script (Code.gs) is already included inside your copied Google Sheet โ€” you don't need to download or paste anything for that part.

  1. In your copied Sheet, go to Extensions โ†’ Apps Script. A new tab will open with a code editor. The script is already there โ€” don't delete or edit it.
  2. Click Deploy โ†’ New deployment.
  3. Next to "Select type," click the gear icon and choose Web app.
  4. Set Execute as to Me, and Who has access to Anyone.
  5. Click Deploy. Google will ask you to authorise the script โ€” click through the prompts and allow it.
  6. Copy the Web app URL shown on the final screen. It ends in /exec. Save this somewhere โ€” you'll paste it into the app in Step 5.
Optional: pre-configure script permissions with appsscript.json
Copying the appsscript.json manifest into your Apps Script project before deploying sets the correct OAuth scopes in advance, which makes the authorisation step smoother and avoids unexpected permission prompts. To use it: in the Apps Script editor, go to Project Settings โ†’ Show "appsscript.json" manifest file in editor, then replace the file's contents by pasting the text below. Click the button to copy it to your clipboard.

Paste this into the appsscript.json file in your Apps Script editor, replacing all existing content.

The "Anyone" setting โ€” and why it's safe
"Who has access: Anyone" sounds alarming, but it controls only who can call the script's web address โ€” not who can see or edit your Sheet. The URL itself is long and effectively unguessable, and the script only exposes the specific read-only actions written into it. There is no way to reach anything else in your Google account through it. This is the standard way Apps Script web apps work. See the FAQ for a longer explanation.
Setup_AppsScript_Modal
Most common mistake here
If "Who has access" isn't set to Anyone, the app will fail to connect later with a confusing error. Double-check this setting before clicking Deploy.
STEP 03

First-Run Wizard

Required ยท ~2 min

There's nothing to download or host โ€” the app is already online and ready to use. Open it, point it at your own Sheet, and you're done.

  1. Open the app using the link within itch download. On first visit it shows a short setup screen.
  2. Paste the Web app URL you saved at the end of Step 2 โ€” the one ending in /exec.
  3. Click Test Connection. You should see a green confirmation showing how many rows of card data it found in your Sheet.
  4. (Optional) Add your Supabase details if you want cloud roster saves โ€” see Step 4. You can skip this entirely and add it later.
  5. Click Save & Continue to enter the app.

Your connection details are remembered on your device, so you'll go straight into the app next time rather than seeing the setup screen again.

Nothing you enter here is sent to me
Your Apps Script URL and Supabase keys are stored only in your own browser, on your own device, so you don't have to retype them every visit. They are never transmitted to me, never stored on any server I run, and I have no way to see them or to reach your Sheet. More detail below.
If Test Connection fails
The most common cause is the "Who has access" setting from Step 2 not being set to Anyone. Go back to Extensions โ†’ Apps Script โ†’ Manage deployments, check the setting, and redeploy if needed. The new URL after redeployment will be different โ€” paste the new one in.
STEP 04

Connect Supabase for cloud saves

Optional ยท ~5 min

This step adds cloud roster saves โ€” the ability to save a roster in the app and load it again on any device (your phone, your partner's tablet, a different computer). If you skip it, you can still save and share rosters as JSON files, which works with zero setup and never expires.

  1. Create a free account at supabase.com.
  2. Click New project. Give it a name, set a database password (store it somewhere โ€” you won't need it often, but Supabase requires it), and choose the region closest to you.
  3. Wait for the project to finish initialising (usually 1โ€“2 minutes).
  4. Go to the SQL Editor tab in your project dashboard.
  5. Copy the supabase-setup.sql script using the button below and paste it into the SQL Editor. Click Run. This creates the single table the app needs to save rosters.

Paste this into the Supabase SQL Editor and click Run.

  1. Go to Project Settings โ†’ Data API to find your Project URL. Copy only the base URL โ€” it ends in .supabase.co. Delete anything that comes after that (such as /rest/v1/) before pasting it into the app.
  2. Go to Project Settings โ†’ API Keys to find your anon public key. Copy that key (not the service_role key).
  3. Back in the app, open Settings โ†’ Edit Connections, paste both values into the Supabase fields, and click Test Connection.
Setup_Supabase_SQL
Setup_Supabase_Keys1
Setup_Supabase_Keys2
Skipping this for now is completely fine
You can always add Supabase later from Settings โ†’ Edit Connections without redoing any other step. Local JSON save/load always works regardless โ€” it doesn't require Supabase.
STEP 05

Run a Health Check

Recommended ยท ~1 min

Before building your first list, go to Settings โ†’ Sheet Health Check โ†’ Run Health Check. This scans your card data for the most common setup problems: missing required fields, duplicate card names, keywords referenced in cards that don't exist in the Keywords tab, and broken image links.

A clean result (zero errors) means your Sheet is correctly structured and the app will behave as expected. If there are warnings, the Health Check tells you exactly which row and column to look at.

You're done
From here, head to the Features page for a tour of everything the app can do โ€” or just start building your first roster. Any time you add new cards to the Sheet, run the Health Check again to catch any typos before they cause a problem mid-game.
๐Ÿ”’

Your data, and what I can see

Worth reading

Short version: I can't see any of it. Here's exactly how it works, so you can judge that for yourself rather than taking my word for it.

  • Your Sheet stays yours. It lives in your Google Drive, under your account. Your Apps Script deployment runs under your Google account too. I have no access to either.
  • Your connection details never leave your device. The Apps Script URL and Supabase keys you enter are saved in your own browser's local storage so you don't have to retype them each visit. They are not sent to me, not stored on any server I run, and not logged anywhere.
  • Card data goes straight from your Sheet to your browser. When the app loads your cards, that request goes from your device directly to your own Apps Script. It does not pass through me.
  • Rosters are yours. Saved locally, or to your own Supabase project if you set one up. I have no visibility into either.
  • No account, no login, no tracking. There's nothing to sign up for, so there's nothing for me to hold.

I host the app itself and nothing more. Think of it as a page that knows how to read your spreadsheet โ€” the page is mine, everything it reads and writes is yours.

The honest trade-off
Because I host the app, you do depend on that staying online. If this page ever went away, your Sheet, your Apps Script, your Supabase project and every roster in them would still be completely intact and untouched โ€” but you'd need another front end to use them with.
Why it's free
This started as something I built so I could actually play with a couple of friends without all of us paying a subscription. It grew well past that, and it seemed a shame not to share it. It's free because the alternative โ€” charging for it โ€” would make it a worse thing for the community and a more complicated thing for me. If it saves you time and you'd like to say thanks, there's a donation option on the itch.io page.
BONUS

Install on your phone or tablet

Optional ยท ~1 min

The app can be installed on both iPhone/iPad and Android devices so it opens like a native app โ€” full screen, no browser bar, with its own icon on your home screen.

iPhone & iPad (Safari only)

This only works in Safari. Chrome and Firefox on iOS cannot install web apps to the home screen.

  1. Open the app in Safari on your iPhone or iPad.
  2. Wait for the page to fully load โ€” you should see the first-run setup screen or the Browse panel if already connected.
  3. Tap the Share button at the bottom of the screen (the box with an arrow pointing up).
  4. Scroll down in the share sheet and tap Add to Home Screen.
  5. Give it a name (or keep the default) and tap Add in the top right.
  6. The app now appears on your home screen with its own icon and opens full-screen.
Setup_iOS_ShareSheet1
Setup_iOS_ShareSheet2
iOS_Background
iOS home screen icon
The apple-touch-icon.png file in your GitHub repository is what gives the home screen icon its correct appearance on iOS โ€” without it, iOS falls back to a generic screenshot thumbnail.

Android (Chrome)

On Android, installation works through Chrome and is even more straightforward โ€” Chrome often prompts you automatically.

  1. Open the app in Chrome on your Android device.
  2. Wait for the page to fully load.
  3. Tap the three-dot menu in the top right corner.
  4. Tap Add to Home screen (or Install app if Chrome shows that option instead โ€” both do the same thing).
  5. Give it a name and tap Add. The app icon will appear on your home screen.
  6. Opening it from the home screen launches it full-screen without the browser bar.
Setup_Android_Install
Setup_Android_HomeScreen
Offline use after install
On both iOS and Android, once the app has loaded once with signal it'll keep working for the rest of that session even if you lose connection โ€” handy at a venue with patchy wifi.