Skip to content

Importing and exporting

Everything here happens in OpsLink — a browser on any device on your network. There are three ways in, and they do different jobs:

where it iswhat it is for
Send a tableLibrary → ImportOne table at a time, from the device you are holding. A .vpx, a .zip or a .vpxz package
Add a fileLibrary → the table → FilesEverything else that belongs to a table you already have: its ROM, backglass, PuP pack, alt sound, artwork. You choose the slot, so nothing is guessed
Bulk importLibrary → ImportA whole directory of tables and backglasses you already own, done in one pass, best effort and fully reported
Take this table with youLibrary → the tableThe way out: packages a table back into one .vpxz file you can move somewhere else

The first two are the normal path. Send the table, then open it and fill in the rest — that separation is what stops vPinOps guessing at your files, because the moment you pick a slot yourself there is nothing left to guess. Bulk import is the migration tool: reach for it when you already have a library laid out by something else.

This is the normal way, and it is one table at a time. From OpsLink: Library → Import → Send a table from this device.

Three things go in:

.vpxthe table on its own
.vpx inside a .zipthe usual download shape — vPinOps opens this one
.vpxza packaged table: the whole folder, zipped. Comes across exactly as packed

Sending is not importing, and that catches people, so here is the whole loop:

  1. Send it. Library → Import → Send a table from this device → Choose a file… The file is copied to the machine and put in a holding folder called the inbox. Nothing has been imported and nothing in your library has changed yet.
  2. Send more, if you want. Sending is one file at a time, but they stack up. Queue up five tables and deal with them in one go — you do not have to finish one before starting the next.
  3. Then tell it to look. Back on the Import page there is now a section headed Waiting in your inbox with a button: Look at these N file(s). Press it. That is the step people miss, because a send that worked looks finished.
  4. Check the preview. Everything in the inbox is read at once, so you see all five together — the name it worked out for each, the alternatives it considered, and a box to type your own.
  5. Press Import. Nothing is written to your library until you do.

2 · Then fill it in — the table’s Files

Section titled “2 · Then fill it in — the table’s Files”

Open Library, tap the table, and scroll to Files → Add a file. Choose the slot, upload, done. It goes where you said, because you said so — no matching, no guessing, no name rules.

These pages call it the drawer, which is just a shorter name for that Files section.

slotwhat goes in it
The table folder.directb2s backglass, .ini, .vbs — the table’s own files
medias/art and video, including the kinds vPinOps does not display itself
music/the table’s music
pinmame/roms/this table’s own ROM, if you want it to travel with the table
pinmame/nvram/its saved scores
altsound/ · serum/ · vni/ · pupvideos/alternate sound and colour-DMD packages
scripts/scripts the table needs

A packaged table (.vpxz) — everything comes across

Section titled “A packaged table (.vpxz) — everything comes across”

A .vpxz is your whole table folder, zipped: table, medias/, music/, the table’s own asset folders, companions, and its pinmame/ folder if the packager had one.

All of it is imported exactly as packaged. Nothing is renamed, nothing is moved, nothing is left behind — including the ROM, if the package brought one. It stays where the package put it.

Why it is not tidied up: that package already works on a desktop, a cab and a phone. The community built it that way and Visual Pinball runs it that way. Rearranging a thing that works on four platforms is how you break it on the fifth. If you later want your ROMs consolidated into one shared folder, that is your decision and its own action — never something an import does to you.

If you already have a directory of tables and backglasses, point vPinOps at it and it will do its best on all of them at once. This is a different job from sending one table, and it makes a different promise: best effort, fully reported.

It builds the structure, matches what it can, suggests names you can override, and names every file it could not place, with the reason. The measure is not a percentage — it is that nothing vanishes. Measured on a real 235-table library: every one of its 406 files was either placed or explained.

whatfile typeswhere it ends up
The table.vpxthe table folder, keeping its own filename
A packaged table.vpxz, *.vpx.zipunpacked into the folder
Backglass.directb2sbeside the table, renamed onto a name the table will find
Companions.ini · .vbs · .info · .scvbeside the table
Mediaimages .png .apng .jpg .jpeg .webp .bmp .gif · video .mp4 .m4v .webm .mov .mkv .avi .f4v .wmvmedias/(Kind) <table>.<ext>

Media is only placed when the filename says which surface it is for

Section titled “Media is only placed when the filename says which surface it is for”

These words are recognised anywhere in the name — and nothing else:

word in the filenamesurface
wheel, logoWheel
playfield, table, pfPlayfield
backglass, bgBackglass
dmdDMD
fulldmdFullDMD
realdmdRealDMD
topperTopper

MyTable wheel.png is placed. MyTable art.png is not — it is reported rather than guessed at, because a wrong guess puts somebody’s playfield on their topper. Put that one in the drawer instead.

What bulk import leaves for you — and it tells you about every one

Section titled “What bulk import leaves for you — and it tells you about every one”

Almost everything here has a home in the drawer. Bulk import guesses from filenames, so it only places what a name can prove; the drawer needs no guessing because you pick the slot. Nothing is ever silently skipped — every file below is listed with its reason.

what bulk import leaveswhere it goes instead
A plain .zip / .7z / .rar that does not name a tableBulk import will not guess what is inside one. Extract it and drop the contents in — or, if it is a pack, send the zip to the matching drawer bay, which does unpack it
A ROM (mm_109c.zip)The pinmame/roms bay, or your shared PinMAME folder — leave it zipped either way
Audio (.mp3, .ogg, .wav, …)The music bay, or altsound for an altsound pack
Media with no surfacecab.png, flyer.pngThe filename has to say which screen it is for, and these do not. A wrong guess puts a cabinet photo on your playfield. Pick the slot yourself in the medias bays
A table’s own asset folderSomeTableDMD/, pupvideos/, altsound/The pupvideos, altsound, serum, vni and scripts bays. ⚠ The folder keeps its own name, because the table’s script refers to it by name — vPinOps will tell you if that name does not look like the ROM, and will not rename it for you
A .pov fileNowhere — it is refused outright. VPX no longer creates them, and on this build a .pov without a per-table .ini crashes the table on load. The file is refused; the table is not. Set your view in VPX’s F12 menu instead

Laying the folder out to get the best result

Section titled “Laying the folder out to get the best result”
  • Extract your downloads first for bulk import. A .vpx it can see beats a .zip it will not open.
  • One folder is enough. Subfolders are read, so a folder-per-download is fine and so is a flat pile.
  • A subfolder containing exactly one table owns everything in it, whatever those files are called. That is the most reliable arrangement, because names stop mattering.
  • In a flat pile, matching is by name, helped by a catalogue of 2,554 machines.
  • Put your ROMs in your shared PinMAME roms/ folderROMs and nvram.
  • downloads tables, ROMs or backglasses — you bring those
  • creates a table folder on top of one that already exists. Bulk import refuses rather than merging two tables into one folder. ⚠ This is about creating a table, not about adding to it — the drawer writes into an existing table’s folder all day, which is what it is for
  • guesses which screen an unnamed image belongs on
  • renames or overwrites media you put there yourself

Every table’s own page has a Take this table with you row. It packages that table’s folder into a single .vpxz — the same format import reads, so anything you export here can be imported anywhere that reads packages, including back into this cab.

What travels: the table, its media, your saved scores, and its ROM if the ROM is inside the table’s own folder. Most tables come out at a few hundred MB.

Two scopes, in the dropdown beside the button:

EverythingThe whole folder. This is the default
Smaller — no artworkLeaves out the frontend art vPinOps shows between games, and Visual Pinball’s texture cache — roughly a fifth off most tables. The .directb2s backglass still travels. Whatever imports it will have no wheel art until you fetch media
  • A whole PinUP Popper library through bulk import. A flat directory of tables, backglasses and ROMs. It should work and has not been run against a real one. ⚠ There is now a community tool that turns a Popper library into .vpxz packages — if you have one, that route is the one we can actually stand behind, because a package imports exactly.
  • That every placed backglass loads. B2S’s resolution chain is read from source but not yet driven end to end on a test rig.
  • Loading an exported .vpxz on a phone. Export itself is driven — a real table out, and back in through our own importer. Visual Pinball Standalone does ship iOS and Android builds, so the target is real, but we have not put one of our packages on a phone and played it, so we do not claim it.