2026-08-13 13:44:07 -04:00
2026-08-12 19:58:42 -04:00
2026-07-29 14:20:30 -04:00
V.1
2026-08-07 17:11:04 -04:00
2026-07-29 14:20:30 -04:00
2026-07-29 14:20:30 -04:00
2026-07-29 14:20:30 -04:00
2026-07-29 14:20:30 -04:00
2026-07-29 14:20:30 -04:00
2026-07-29 14:20:30 -04:00
2026-07-29 14:20:30 -04:00
2026-07-29 14:20:30 -04:00
2026-07-29 14:20:30 -04:00
2026-07-29 14:20:30 -04:00
2026-08-13 13:44:07 -04:00

UE4SS Object Explorer

u34ss-explorer.gimme.pet

A browser-based explorer for UE4SS DumpObjects output - the very large text files an Unreal Engine game emits when you ask it to enumerate every live UObject.

Drop the dump in and it becomes a searchable, filterable, linkable index of the game's object graph. Nothing is uploaded; the file is parsed and stored in your own browser. Built for Palworld modding, but the format is UE4SS's, not the game's, so it works for most UE4SS-supported titles.

Why it exists

A UE4SS object dump is a text file with one line per object and no index:

[00000226E92B0000] Package /Script/CoreUObject [n: 13891] [c: 00000226DCC55980] [or: 0000000000000000]

At ~292,000 objects and 59 MB, the usual tools give up. Ctrl+F in an editor answers one question at a time, and grep can't tell you what owns the thing you found. This turns the file into a structure you can navigate.

Features

  • Package tree — the /Script/… and /Game/… hierarchy, built from the dump's own path separators (/, ., :), with object counts per node. Sort branches by weight or alphabetically.
  • Virtualized table — all 292k rows in one scroller, rendering only the ~60 on screen. Columns are click-to-sort (asc → desc → dump order) and drag-to-resize, with widths remembered between visits.
  • Faceted filtering — full-path and leaf-name substring search, path scoping, and type chips whose counts stay live against everything except the type filter itself.
  • Inspector — address, field offset, full path, and a resolved link to the object's Outer, so you can walk ownership upward.
  • Shareable views — every dump gets a content hash; that hash plus the active filters live in the URL. Send someone a link and they land on your exact view, provided they hold the same dump.
  • Filter history — each change is recorded as a frame with back/forward navigation. Branching from an earlier frame truncates the ones after it, like a browser but scoped to the query.
  • Hosted dumps — dumps the site ships with are listed but never auto-downloaded; one click fetches, caches and opens.
  • Type-coded rows — UE's type zoo collapses into six families by colour. The address gutter ghosts the leading hex digits every object shares and lights only the ones that differ.

Breakdown

Nuxt 4 / Vue 3 / TypeScript, statically generated, no backend. The interesting parts are all about not letting 59 MB touch the main thread.

Columnar parse. A byte-level tokenizer reads the dump into parallel typed arrays — Float64Array of addresses, Uint8Array path blob with offset indices, interned type ids — rather than an array of objects. No per-row allocation, no GC pressure, and the result is a set of buffers that postMessage and IndexedDB both move without serialising. Parses 59 MB in ~700 ms.

The line format is harder than it looks: object paths contain spaces, so trailing [k: v] groups have to be peeled from the right; enum constants carry no path at all; and UE4SS occasionally truncates a record mid-write. Each shape is handled and counted rather than silently dropped.

Worker-owned state. The parsed columns never leave the Web Worker; the UI asks for a window of rows and gets ~60 plain objects back. Queries are a single linear pass over every row, comparing case-folded bytes in the path blob directly. At this scale that is cheaper to run than an inverted index would be to maintain.

Sorting under virtualization. Because windowing is over a Uint32Array of matching row indices, order is decided before any chunk is handed out. A re-sort is one comparator pass in the worker, not a merge across already-delivered pages.

Content addressing. Dumps are identified by a 64-bit FNV-1a over every byte — four interleaved lanes to break the multiply dependency chain, ~50 ms for 59 MB. Content-only is the point: two people holding the same file must derive the same id, so the hash can't include the filename or the parse time.

Build-time prebake. npm run prebake parses a dump into a flat .pdx bundle of length-prefixed column buffers. Homogeneous columns gzip far better than JSON — 40 MB down to 4.3 MB on the wire — and the browser does one fetch and a few typed-array views instead of parsing anything.

Running it

npm install
npm run dev                                   # localhost:3000
npm run build                                 # static site in .output/public

npm run prebake -- dump.txt public/dump.pdx   # optional: ship a parsed dump

Docker, serving the static output through nginx:

docker compose up              # localhost:8080
docker compose --profile dev up

To offer a dump from the site, drop the file in public/ and add an entry to public/dumps.json.

Measurements above are from the the only included Palworld dump: 58.9 MB, 292,342 objects.

Description
ue4ss object explorer
Readme 9.2 MiB
Languages
TypeScript 48.1%
Vue 46.9%
JavaScript 2.3%
CSS 2.1%
Dockerfile 0.6%