CommandariumPLUS
Commandarium
Get Commandarium Plus
More room for your decks and binders, and a little help keeping the forge lit.
My decks
Discover what your collection can do
Have a deck built from the cards you already own — with synergy analysis, a rules check and a shopping list.
Import collection
CSV exports from ManaBox, Moxfield, Archidekt, Deckbox or Delver Lens.
CSV file
Drop your CSV hereChoose your CSV
Or choose an export from your computer.Select an export from your files.
One row per card. Quantities are optional.
Supported columns & printing details
- Name (or Card Name) is the only column needed.
- Also read: Quantity, Set code, Collector number, Scryfall ID, Foil, Language, Condition, Binder or Folder, Date added, and Misprint, Altered, Signed, Proxy.
- A Scryfall ID, or a set code with a collector number, picks the exact printing. Without them a representative printing is used, which can throw prices off for alternate art.
- German column headers are recognised too.
No file at hand?
Add a few cards with the scanner.
Collection and decks are stored in this browser.
Collection
Your collection, organised into binders. Open one, or browse everything at once.
Choose your commander
Legendary creatures from your own collection, or the most-played commanders that fit your colors.
Decks
Every deck you've built. Open one to edit it card by card, or start a new one from a commander.
Scan cards
Hold a card in front of the camera and keep it still. It is recognised on your device by its artwork and frame, and lands in the stack below — you check the stack before it enters your collection.
Match
Search
Search every card ever printed. Filters combine into a single Scryfall query — cards you already own are marked automatically.
Settings
https://abcdefgh.supabase.co.sb_secret_… key here — it bypasses row level security.
create table if not exists public.command_forge (
user_id uuid primary key references auth.users(id) on delete cascade,
payload jsonb not null default '{}'::jsonb,
updated_at timestamptz not null default now()
);
alter table public.command_forge enable row level security;
create policy "read own row" on public.command_forge
for select using (auth.uid() = user_id);
create policy "insert own row" on public.command_forge
for insert with check (auth.uid() = user_id);
create policy "update own row" on public.command_forge
for update using (auth.uid() = user_id) with check (auth.uid() = user_id);
const UPSTREAM = {
moxfield: "https://api.moxfield.com/",
archidekt: "https://archidekt.com/",
edhrec: "https://json.edhrec.com/"
};
export default {
async fetch(request) {
if (request.method === "OPTIONS") return new Response(null, { headers: cors() });
const url = new URL(request.url);
const path = url.pathname.replace(/^\/+/, "");
if (!path) return new Response("ok");
// "/moxfield/v2/decks/all/xyz" -> that site; anything else stays EDHREC,
// so an existing EDHREC-only setup keeps working unchanged.
const slash = path.indexOf("/");
const head = slash < 0 ? path : path.slice(0, slash);
const base = UPSTREAM[head] || UPSTREAM.edhrec;
const rest = UPSTREAM[head] ? path.slice(head.length + 1) : path;
const upstream = await fetch(base + rest + url.search, {
headers: { Accept: "application/json", "User-Agent": "Commandarium/1.0" },
cf: { cacheTtl: 3600, cacheEverything: true }
});
return new Response(upstream.body, {
status: upstream.status,
headers: { ...cors(), "Content-Type": "application/json" }
});
}
};
function cors() {
return {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,OPTIONS",
"Cache-Control": "public, max-age=3600"
};
}