Editing menus with an addon ​
Where things sit on a menu screen is stored in the screen's scene, an .idf in the game's UI archives. To move elements or add a slot, edit the scene in Swofty UI, export it, and ship the exported .idf in an addon with one replace-resource ERP operation per archive that holds the scene.
1. Open the scene ​
Start Swofty UI and press Ctrl+K. Search for the screen by file name or folder, such as rnd_overview or career laptop, and press Enter. The title bar shows the scene's path, and the archive picker beside it lists every archive that holds it.
Swofty UI reads the archives in the game folder as they are. After swofty apply, those include your own edits; run swofty restore first to start from stock.
2. Edit it ​
Select an element on the canvas or in the hierarchy, then:
- drag it, or nudge it with the arrow keys, to move it;
- type a new position, scale, rotation or param value in the inspector;
- press Ctrl+D to clone it as a new sibling, with a new name and the ids it needs;
- rename it in the inspector, or press Del to delete it;
- for an
eXRef, type another scene's path in the inspector's XRef section and press Retarget to make it draw that scene.
Every edit goes in the Edits list, and Ctrl+Z undoes it. Before moving an element, look for an Anims section in the inspector: an animated element's position is replaced when its animation plays, so move its unanimated children instead.
3. Export ​
Press Ctrl+S. Swofty UI writes the scene, checks it, and saves three files to its export folder:
| File | Contents |
|---|---|
rnd_overview. | The edited scene |
rnd_overview. | An ERP operations file: one replace-resource per archive that holds the scene |
rnd_overview. | The edit list, the source scene and archive, and the SHA-1 of the source and the export |
4. Add it to your addon ​
Put the .idf in your addon's ui/ folder and the operations file in erp/:
my-addon/
├── swofty.json
├── erp/
│ └── scenes.json (rnd_overview.erp.json)
└── ui/
└── rnd_overview.idf{
"schema_version": 1,
"ops": [
{
"op": "replace-resource",
"erp": "2025_asset_groups/ui_package/flow_career_hub.erp",
"resource": "eaid://ui_package/art/screens/career/rnd_overview.idf",
"source": "ui/rnd_overview.idf"
},
{
"op": "replace-resource",
"erp": "2025_asset_groups/ui_package/flow_team_hq.erp",
"resource": "eaid://ui_package/art/screens/career/rnd_overview.idf",
"source": "ui/rnd_overview.idf"
}
]
}List the operations file under operations.erp in the manifest:
{
"schema_version": 1,
"id": "author.rnd-layout",
"name": "R&D layout",
"version": "1.0.0",
"author": "Your Name",
"compat": { "game": "f1_25" },
"kind": ["erp"],
"operations": { "erp": ["erp/scenes.json"] }
}Each replace-resource replaces the scene's single fragment in one archive. Keep every archive Swofty UI listed: the game reads a scene from whichever archive loads it first.
5. Build and play ​
swofty addons install ./my-addon
swofty addons enable author.rnd-layout
swofty buildThen press Play in the launcher. The build:
Checks that each
sourceis a scene saved from the same.idf, by its componentId, and fails otherwise:textthe source is scene 0x…, this resource is scene 0xbe419b0b8324e33c; it was saved from another .idfWrites the new fragment, recompresses it, and updates the archive's sizes, offsets and hashes. Every other resource is copied byte for byte.
Delivers the archive. The in-game loader's overlay only carries a replacement with the stock fragment size; an edited scene usually changes size, so the build writes those archives into the game files through the journal and prints:
texterp: 2025_asset_groups/ui_package/flow_career_hub.erp built into the game files; 1 resource(s) change their stock layout, which the in-game loader cannot load, such as eaid://ui_package/art/screens/career/rnd_overview.idf: fragment 0 is 30108 bytes, the stock one 29596; …Warns when another stock archive in the same folder also holds the resized scene and your addon doesn't replace it there.
The launcher restores the rewritten archives when the game exits. swofty restore puts them back by hand, such as after swofty apply or a crash. See ERP operations for the operation itself.
Limits ​
- Live data needs
.uiwiring or native code. A scene holds rectangles, not content. Text, numbers, lists and colours come from the.uinode attached to an element and the view model behind it. A new element stays empty until a node attaches to its name, either in the screen's.uior built by an engine plugin. Data the screen's view model doesn't publish needs native code. - Animations and stackers override stored positions. An animated element takes its transform from its clip while the clip plays. An
eStackerlays out its children at runtime, so a child's stored position is replaced; a child added to a stacker is placed with the rest. - New art needs new textures or meshes. A scene can reuse art: a clone keeps its geoms, and an
eXRefcan point at another scene. A new image is a new texture resource (Textures and models), and a new shape, such as a narrower pie wedge, is a new mesh. - A reference loads the scene its
xrefid names. The game finds aneXRef's scene by itsxrefid, the md5-64 of the scene's path, not by itsfileRefpath. A scene written by another tool with a newfileRefand the oldxrefstill shows the old scene in game. Swofty UI draws the scene the id names, marks the mismatch and refuses to export it; see References. - A scene replaces the whole stock scene. When a game update changes a scene your addon ships, export it again from the new stock scene. The
.edits.jsonholds your edits for replaying them.
Next ​
- Techniques: tracing what draws an element, counts fixed in native code and patching them safely.
- Debugging live: attaching gdb to the running game.
- ERP operations: every field of
replace-resource. - Packaging and publishing: sharing the addon.