SheetForge — Google Sheets & Excel to ScriptableObject


SheetForge — Google Sheets & Excel to ScriptableObject


by Snowdrop


Price History +

■ TRY IT IN YOUR BROWSER BEFORE YOU BUY



Open web.sheetforge.workers.dev and paste in a sheet of your own. It runs this package's own C# core compiled to WebAssembly — same parser, same validator, same error messages. Nothing to install, and what you see there is what the editor will say about your data.



■ YOUR SHEET AND YOUR SCRIPTABLEOBJECTS STOPPED MATCHING MONTHS AGO



Somewhere in your project sits a spreadsheet nobody fully trusts, and a folder of ScriptableObjects that quietly drifted away from it. SheetForge ends that split: the sheet is the single source of truth, and the tool enforces it — the baked ScriptableObject is a read cache with no writable path back, so it cannot drift. Every change passes validation before it becomes real.



■ SEE IT RUNNING BEFORE YOU WRITE A LINE



Two demo projects ship in the package: double-click, Import once, press Play — a spreadsheet running as a game. The plugin demo assembles its fireball damage from three tabs: Damage(10) + DamageOverTime(3x3) = 19. A Getting Started window walks the first run.



■ THE TYPE LIVES IN THE SHEET, NOT IN A C# ATTRIBUTE



A @type row sits right above your data: int, float, Color, AnimationCurve, Gradient, Enum<Rarity>, RecordId@Items, LocRef@Strings, AssetRef@Icons<Sprite>, List<T>. No schema file, no attributes, no mapping dialog. A designer adds a column and declares what it holds; the next import regenerates the C# class, rides out the compile and finishes baking on its own. Enums live in the sheet too, created, renamed and deleted from either host.



■ EVERY ERROR IT CAN SEE, IN ONE PASS, WITH THE FIX



Most importers say something is wrong and leave you bisecting the sheet for the bad cell. SheetForge reports every problem together: tab, row, column letter and name, the offending value, the violated rule, and — for a typo in a reference, an enum value or an asset key — the nearest match. 108 error codes, each with a written why and how-to-fix, and every flagged cell carries a jump link straight to it.



Nothing is generated while a single error stands — no half-baked data ever reaches play mode. But the sheet still opens for editing — most tools get this backwards and make the failing sheet vanish from the one window where you could fix it. Here it lands, wears an error badge and lets you work; only the exits wait for a clean run.



■ THE CELL IS A UNITY FIELD, NOT A TEXT BOX



Color, AnimationCurve and Gradient are built-in types, and in the Data Studio the cell *is* Unity's colour, curve or gradient field — the whole cell, no raw text. Each keeps a short form you can type (#FF8800, 0:0,1:1) and a canonical form every tool writes, so the round trip is lossless; the browser ships full editors for all three.



An AssetRef cell behaves like Unity's object field too: drag a sprite from the Project window onto it and the address lands in the cell — several onto a List<> column append in order. The picker lists that group's addresses, narrowed to the column's type; cells show their asset's thumbnail, and an AudioClip cell plays with a seekable waveform. Something not addressable yet is staged for registration — address, group entry, even the group itself are created when you reflect, and one Ctrl+Z takes back value and registration together. Sub-assets are first-class (parent[sub]), and AssetRef@Icons<Sprite> restricts a column to one asset type, so a prefab on an icon column is refused at the door, not at runtime.



■ YOUR GAME'S TEXT LIVES IN A SHEET TOO



One @loc marker row turns a sheet into a localization table: rows are keys, columns are locales, the first is the source language. Data sheets point at entries with LocRef@Strings — validated, picked and rename-propagated like any reference — and the cell shows the source text inline. Typing into an empty LocRef cell mints the entry — key, text and reference in one undo step.



With com.unity.localization installed, every import fills real StringTables. A key rename preserves the entry's internal id, so LocalizedString references in scenes survive; a table edited elsewhere makes the next sync stop and ask instead of overwriting, and a key that left the sheet is kept as a listed orphan. A reverse importer turns an existing collection into a sheet, a translation workbook round-trips locales through xlsx, and generated key constants give game code compile-time safety. The package is optional: everything but the sync itself works without it.



■ EDIT IN UNITY. THE SHEET STILL WINS.



The Data Studio is a grid in the editor that writes to your spreadsheet — never to the ScriptableObject. It behaves like the spreadsheet you came from — drag column widths, hide, filter, sort, select many rows or columns and drag them to a new place, all mirrored in the web app. Edit cells, rows, columns and column types, then push: all validated in memory first, written to the source and re-imported through the same gate. Undo is Unity's native Ctrl+Z across all of it, structure included, and the table renders only the rows you can see, so a 50,000-row sheet opens like a small one.



Open a row and a canvas unfolds beneath the table — materials on the left, consumers on the right; drag a wire between ports to link records, or drop one on empty space to create the missing record in the same undo step. Renaming is safe everywhere: a record-ID rename rewrites every referring cell across every tab after showing you the count, and a tab rename updates every @type that points at it, cycles included. A project holds several workbooks side by side — separate baked assets, code and addresses each — with one Import All that walks them all.



■ TWO DESIGNERS, ONE SHEET, NO LOST WORK



Push runs a live diff right before sending. A cell a teammate changed since your import is skipped and counted, never overwritten. A row you deleted is deleted in the live sheet — matched by key, every deletion listed for approval first, and a row that moved since your import is skipped rather than deleting the wrong line. The studio also watches your source: a badge appears when the sheet genuinely changed; clicking it offers the import.



Export goes the other way: TSV, CSV, JSON, or one xlsx workbook holding every tab, reference columns as live dropdown rules. Baked ScriptableObjects are a cache your team does not commit — you merge spreadsheets, not binary .assets — and a build hook stops a build whose cache is stale.



■ YOUR DESIGNERS NEVER HAVE TO OPEN UNITY



The companion web app is not a viewer or a cut-down version: it compiles this package's own C# core sources, so the browser cannot disagree with the editor about a cell. With no Unity and no install, a designer gets the same table, structure editing, canvas, search and Problems panel, the visual editors, .xlsx workbook import — and Google Sheets read and write.



Signing in with Google asks only for the files you open — per-file access through Google's own picker, no account-wide scope, no "unverified app" warning, nothing written to your Drive. A service-account key works too, signed inside your browser; it never reaches our server. Code generation and baking stay in Unity — a browser cannot write .cs files or ScriptableObjects — so the two surfaces meet at the sheet.



■ EXTEND IT FROM YOUR OWN ASSEMBLY



Most projects never need this — the built-ins cover the ordinary shapes. When your data has one they cannot say, you extend SheetForge from your own assembly: sixteen contracts — custom cell types, wrapper shapes, cross-tab validators, structural markers, sheet templates, import sources, declarative studio UI and more — each joining with zero edits inside the core. The assembly boundary makes contact a compile error — an update cannot collide with your customizations. The plugin demo proves it: a complete skills domain added without one line changed inside SheetForge.



■ MEASURED, NOT ASSERTED



50,000 rows x 20 columns import in about 628 ms in the live editor, 144 ms headless (i9-13900K). 4,000 broken references at once: about 45 ms to report them all with suggestions — linear, not quadratic.



0 bytes of import machinery in your player build: everything editor-side lives in an editor-only assembly, excluded at any scripting backend and stripping level, IL2CPP included; the runtime path uses no reflection and no link.xml. Locale-independent by contract: 1.5 means the same thing on a German and an American machine. No third-party code — even the XLSX reader and writer are implemented in-package.



3,124 headless .NET tests run against this build, alongside a Unity EditMode suite, 742 web unit tests and 171 end-to-end browser tests. Menus, dialogs and every error explanation ship in ten languages, chosen per user — Korean, Japanese, Chinese, Spanish, French, German, Portuguese and Russian among them.



■ WHAT THIS TOOL REFUSES TO DO



For a handful of records this is overkill — a plain ScriptableObject is simpler. It earns its keep around a few hundred rows, or when a designer first edits data without you.


Requires the Addressables package (free, from Package Manager). The asset compiles without it and guides the install, but the pipeline stays locked until it is there; no Resources fallback.


xlsx sources are read-mostly: write-back into a workbook is refused outright — edit it in Excel and re-import.


Renaming a column or tab changes generated code — game code referencing it needs a manual update, which the write-back cannot undo.


A tab with no key column still imports, but takes no new records and its edits anchor to row position; add a RecordId column and the safety net is back.


It never touches ScriptableObjects you already have, so you adopt one table at a time. Drop the asset later and your data is still a plain sheet, the generated classes ordinary C# files.



■ DOCS AND SUPPORT



Read the limitations before you buy, not after — the documentation site itemizes them: docs.sheetforge.workers.dev


Companion web app: web.sheetforge.workers.dev