ueboxai/uebox/ue-content-import-organize
Claude Code and agent skill by ueboxai/uebox
- community
Checking that the SKILL.md file is still in the repository.
Bring external files into the project, find and inspect existing assets, batch-rename or relocate them, enforce a naming convention, trace dependencies and referencers, clean up redirectors, migrate assets with their dependencies to another project, and read or edit DataTable rows (数据表、配置表). Use when the user wants files imported, the content folder tidied or restructured, names normalised, "what uses this" answered, assets moved to another project, or values in a DataTable changed (改表里的数值、加一行、…
Install
npx vskill@latest install ueboxai/uebox/ue-content-import-organizeSKILL.md
Content import and organisation
Verified against UE 5.5.4 with UnrealAgentLink by running the whole job end to end: import three textures → find them → inspect → rename to a convention → audit → clean up.
Before you start: get real paths, never guessed ones
ue_content_import needs absolute file paths, and a wrong one fails the whole call. Three ways to get them, in order of preference:
- On disk —
list_local_dirfor one folder,find_local_fileswith a glob
(**/*.fbx) when the files could be at any depth. "把 D:/Downloads/kit 里的都导进来" starts here: list it, show the user what you found, then import.
- In the box's asset library —
search_assetsfirst, takereal_pathfrom each result. - Neither — ask the user for the paths. Do not guess filenames from a folder's name.
Import does more than you asked
Importing image files also auto-generates PBR material instances from them. Three textures came back as five assets: the three textures plus MI_wood_Mat and MI_rock_Mat, each flagged auto_generated: true.
Always compare imported_count against requested_count and tell the user what extra assets appeared. They will otherwise find material instances in their project that they never asked for and have no idea where they came from.
Naming matters at import time: the texture type is guessed from the filename alone. A file named *_normal.png becomes a normal map (TC_Normalmap / BC5 / sRGB off); a name it cannot classify keeps whatever the engine chose — usually sRGB on. The receipt's texture_setup lists, per texture, the type it was read as and the srgb / compression it ended up with. Say so before importing badly named files, and check that list afterwards — see _After importing: acceptance checks_.
Check saved_count too. It should equal the number of assets imported; a save_warning means some assets exist only in the current editor session and will be lost when the user closes UE.
Name them on the way in, not afterwards. asset_names takes a per-file map — { "hero.fbx": "SK_Hero", "wood_color.png": "T_Wood_D" } — and the rename happens while the asset is brand new and nothing references it yet, so it leaves no redirectors. Renaming later with ue_content_move rewrites every referencer but leaves a redirector behind at each old path — cleaning those up is a separate ue_fixup_redirectors step. A name already taken is skipped, not forced: the asset keeps its original name and the reply carries rename_failed plus a line in the message — read it, do not assume the name you asked for is the name you got. Only rename when the user asked for a convention; they may be looking for the file under its original name.
Scale is a parameter, not a fact of life. Meshes come in at the format's default: OBJ ×100 (the format carries no unit, so the plugin assumes metres), glTF/GLB and FBX ×1 (the engine already converts metres to centimetres for glTF, and FBX carries its own units). When a model lands a hundred times too small or too large, re-import it with scale set — do not tell the user to go fix Build Scale in the editor themselves.
After importing: acceptance checks
imported_count proves the files went in, not that they are usable. Before reporting success, read back what the engine actually made. Read import_messages (the importer's own warnings and errors) before calling an import clean; if the reply has no such field (older plugin), check ue_message_log (action: "list", then the import-related category) when anything looks off.
Meshes — one `mesh_describe` per mesh, then compare against what the asset is:
| Check | Read | Wrong looks like | Fix | |
|---|---|---|---|---|
| Real-world size | bounds.size (cm) | a chair 0.9 cm or 9000 cm tall | re-import with scale | |
| Up axis | which bounds axis is longest | a door lying flat (Z smallest) | fix in the DCC, re-export | |
| Pivot | origin line (centred / on base / at corner) | floor prop pivoting from its middle | DCC (blender-ue-pipeline) — do not compensate on every actor | |
| Collision | ⚠️ no collision / primitive count | player walks through it | mesh_optimize collision (box for crates, convex for concave shapes) | |
| Lightmap UV | ⚠️ invalid lightmap index | dark blotches after a lighting build | only matters with baked lighting; Lumen-only projects can skip | |
| Nanite / LODs | nanite, per-LOD source and triangles | dense non-Nanite mesh with one LOD | see below | |
| Materials | every slot has a material | Legacy Phong parent, empty slots | see _Third-party packs_ |
index_valid only says the lightmap channel exists; overlapping lightmap UVs show up as lighting-build warnings, not here. Nanite: opaque, dense static meshes on a desktop/console project should have it on (ue_content_set_properties, "NaniteSettings.bEnabled": true) — then judge cost by Nanite, not by the raw triangle count. Translucent materials and mobile targets keep classic LODs; add auto LODs (mesh_optimize lods) before anyone decimates LOD0. Skeletal meshes: confirm skeleton is the one the user's animations use and that a physics asset exists.
Textures — `ue_content_describe` per texture, compare srgb and compression:
| Texture | srgb | compression | |
|---|---|---|---|
| Base colour, emissive | true | TC_Default | |
| Normal | false | TC_Normalmap | |
| Single-channel roughness / metallic / AO / height | false | TC_Masks (HDR sources keep TC_HDR*) | |
| Packed ORM / ARM / RMA / MRA / mask | false | TC_Masks |
texture_setup already shows these per texture; ue_content_describe is for textures imported earlier or by hand. What the filename guess handles, and where it stops:
- Packed masks are recognised only when the type word ends the name (
T_Rock_ORM, not
T_Arm_BaseColor). The receipt gives channels for ORM/ARM (R = AO, G = roughness, B = metallic), RMA and MRA; plain _Mask has no known order — ask. Packed masks are not wired into the auto-generated instance (its master has no per-channel inputs); wiring one is a material job.
- `bump` is read as height, not as a normal map.
- Green flip happens only when the name says
gl/openglas a word (flip_reasonsays
which). OpenGL normal maps without that marker (Blender, many free or AI sources) are not flipped and render with bumps pushed in: ask where the maps came from, or have the user look at a lit surface, before flipping by hand.
Fix anything else with ue_content_set_properties; its receipt reads every value back (flip included), and it saves by default:
An OpenGL normal map instead: { "bFlipGreenChannel": true }.
Then check the material: material_describe the auto-generated instance; each texture_setup entry names the material parameter its texture went into. A texture that landed in the wrong parameter (an older plugin put bump images in Normal) goes back to a flat normal with material_set_param and /Engine/EngineMaterials/DefaultNormal (it cannot clear a texture parameter).
Same-named textures inside meshes silently overwrite each other
FBX and GLB carry their textures inside the file, and the names are whatever the author chose — AI-generated models are almost always Color, Normal, Roughness, Metallic. Import two such models into one folder and the engine behaves asymmetrically: the meshes get deduplicated (model → model_1), the textures do not. The second file's textures are skipped without an error because the target names already exist, so every model's material points at the _first_ model's textures. Different UV layouts then sample the wrong texture and the surfaces render as scrambled fragments. imported_count still reports success.
isolate defaults to auto, which puts each mesh file in its own subfolder whenever there is risk — two or more mesh files in one call, or a destination folder that already has assets in it. So the normal case is handled and you do not pass the parameter. Two things you still owe the user:
- Read
isolatedin the response. The assets are in<destination_path>/<filename>/, not
directly in destination_path — say so, and use those paths for anything downstream.
- Treat
reuse_warningas a failure even thoughokis true. It means textures were reused
rather than created; re-import with isolate: "always" or a fresh destination_path.
Pass isolate: "never" only when the user explicitly wants everything flat in one folder and accepts that same-named textures will collide.
Third-party packs: the materials usually arrive broken
An FBX pack imports "successfully" and the meshes render as red/blue/green candy. That is not a failed import — it is the normal outcome. The FBX material definitions are Phong, which the engine cannot represent, so it parents every material instance to FBXLegacyPhongSurfaceMaterial (a placeholder) and leaves the PBR textures imported but unreferenced. Nothing in the import response says this.
Run this after importing any pack you did not author, before telling the user it worked:
broken_materials non-empty means the pack needs real materials built by hand — material_create plus material_apply_graph wiring BaseColor / Metallic / Roughness / Normal / AO, then material_apply onto the slots. Say that to the user before they discover it in the viewport; it is a job of its own, not a detail of the import.
Material slot names are not a mapping. Maya exports them as blinn2, blinn3 … which carry no meaning at all. Do not guess which texture set belongs to which slot — assign one, look at it, then move on. A guessed mapping looks plausible in the content browser and wrong in the game.
Geometry you generated yourself
Writing an OBJ with a script and importing it is a legitimate way to make simple shapes. Get the face syntax right or the import can take the whole editor down with it.
In f a/b/c, the three slots are vertex / texture coordinate / normal. The middle slot is the UV index — it is not the normal. When the file has normals but no UVs, the middle slot must be left empty with a double slash:
The second form crashed UE 5.5 outright on 2026-09-02 — the Interchange OBJ translator indexes an empty UV array and the assertion is fatal, so everything unsaved in the editor is lost. The plugin now checks OBJ files before handing them over and returns rejected with the offending line instead of importing, but do not rely on that to catch it: write the file correctly.
Rules that keep a generated OBJ importable:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 96 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingresources/skills/ue-content-import-organize/SKILL.md
Popularity
- Repository stars
- 208
- Repository forks
- 19
- 7-day trend score
- 0
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/ueboxai/uebox/ue-content-import-organize)