Image to Three.js Model
img2threejs/img2threejs
Rebuilds the object in a reference image as a procedural, animation-ready Three.js model written entirely in code, using staged sculpting with quality checks.
Inspect, generate, transform, and visualize UV channels on StaticMesh assets (UVMappingService).
$ npx skills add kevinpbuckley/VibeUE --skill uv-mapping -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install kevinpbuckley/VibeUE uv-mapping --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/kevinpbuckley/VibeUE.git skills-src && mkdir -p .claude/skills && cp -r skills-src/Content/Skills/uv-mapping .claude/skills/uv-mapping && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "uv-mapping" agent skill from https://github.com/kevinpbuckley/VibeUE/tree/master/Content/Skills/uv-mapping into .claude/skills/uv-mapping/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "uv-mapping", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/kevinpbuckley/VibeUE/tree/master/Content/Skills/uv-mappingType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add kevinpbuckley/VibeUE --skill uv-mapping -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install kevinpbuckley/VibeUE uv-mapping --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/kevinpbuckley/VibeUE.git skills-src && mkdir -p .agents/skills && cp -r skills-src/Content/Skills/uv-mapping .agents/skills/uv-mapping && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "uv-mapping" agent skill from https://github.com/kevinpbuckley/VibeUE/tree/master/Content/Skills/uv-mapping into .agents/skills/uv-mapping/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "uv-mapping", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add kevinpbuckley/VibeUE --skill uv-mapping -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install kevinpbuckley/VibeUE uv-mapping --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/kevinpbuckley/VibeUE.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/Content/Skills/uv-mapping .cursor/skills/uv-mapping && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "uv-mapping" agent skill from https://github.com/kevinpbuckley/VibeUE/tree/master/Content/Skills/uv-mapping into .cursor/skills/uv-mapping/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "uv-mapping", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/kevinpbuckley/VibeUE.git --path Content/Skills/uv-mapping--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add kevinpbuckley/VibeUE --skill uv-mapping -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install kevinpbuckley/VibeUE uv-mapping --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/kevinpbuckley/VibeUE.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/Content/Skills/uv-mapping .gemini/skills/uv-mapping && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "uv-mapping" agent skill from https://github.com/kevinpbuckley/VibeUE/tree/master/Content/Skills/uv-mapping into .gemini/skills/uv-mapping/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "uv-mapping", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install kevinpbuckley/VibeUE uv-mappingInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add kevinpbuckley/VibeUE --skill uv-mapping -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/kevinpbuckley/VibeUE.git skills-src && mkdir -p .github/skills && cp -r skills-src/Content/Skills/uv-mapping .github/skills/uv-mapping && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "uv-mapping" agent skill from https://github.com/kevinpbuckley/VibeUE/tree/master/Content/Skills/uv-mapping into .github/skills/uv-mapping/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "uv-mapping", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add kevinpbuckley/VibeUE --skill uv-mapping -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install kevinpbuckley/VibeUE uv-mapping --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/kevinpbuckley/VibeUE.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/Content/Skills/uv-mapping .opencode/skills/uv-mapping && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "uv-mapping" agent skill from https://github.com/kevinpbuckley/VibeUE/tree/master/Content/Skills/uv-mapping into .opencode/skills/uv-mapping/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "uv-mapping", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
uv-mappingInspect, generate, transform, and visualize UV channels on StaticMesh assets (UVMappingService).
Uv Mapping is an agent skill from kevinpbuckley/VibeUE. Inspect, generate, transform, and visualize UV channels on StaticMesh assets (UVMappingService). Use when the user asks to check/add/remove UV channels, auto-unwrap UVs, transform (tile/offset/rotate) UVs, check UV health/islands, or export a UV layout image.
Its SKILL.md is about 4.8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files, including scripts.
It sits in Game Development. The repository describes itself as: Unreal Engine Vibe Coding tool. The licence is MIT.
2 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit dc051be. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships 1 file in scripts/, which the agent can run.
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Uv Mapping loads about 4.8k tokens when it runs. Until then it costs about 68 tokens; SKILL.md has 1,678 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from kevinpbuckley/VibeUE at commit dc051be, republished under its MIT licence (© kevinpbuckley). 1,678 words, ~4,792 tokens.
.claude/skills/uv-mapping/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.🧠 Brains complement: IF an
unreal-engine-skills-managertool (external MCP) exists in this session, call it with{action: "load", skill: "meshes-static-and-skeletal"}for UE domain knowledge on this topic — correct APIs, architecture, best practices — and treat it as the rubric for any review / "best practices" question. If no such tool is available (e.g. running under Claude Code or Codex without that MCP), skip this line entirely and proceed with this skill alone — do NOT attempt the call.
For seams on imported organic assets, first distinguish UV boundaries from split
corner normals, image-border wrapping and invalid material-section indices. See
the materials skill's references/generated-organic-surfaces.md and the
asset-management skill's references/mesh-reimport-materials.md. Do not unwrap
an approved mesh merely because its shading has a sharp band.
UVMappingService provides automation-grade UV channel manipulation for StaticMesh assets in UE 5.7+. The service is built around mesh-description editing and post-build commits — every mutation marks the package dirty and rebuilds render data, but does not save. Follow with unreal.EditorAssetLibrary.save_asset(mesh_path) once you finish a batch.
UV transforms are the wrong tool for fixing a tiling material that looks bad on a basic shape (cube, sphere, cylinder, cone). Symptoms that say "this is not a UV problem":
These are material-orientation problems, not UV-layout problems. A single 2D UV transform can't satisfy multiple face orientations on a 3D shape — whichever projection you pick, at least one face will be wrong. Reach for one of these instead:
Tiling overridden. If the parent material exposes a Tiling scalar (Megascans M_MS_Srf does), create a child MI with the right multiplier and assign it to the specific actor. The mesh keeps its stock UVs./Engine/Functions/Engine_MaterialFunctions02/Texturing/WorldAlignedTexture and WorldAlignedNormal for this.UVMappingService is the right tool for:
If the user asks to "fix UVs" on a basic shape with a tiling material, ask whether they want material-side or mesh-side first — defaulting to mesh-side will burn iterations.
Detailed inspection and all mutating operations target UStaticMesh. SkeletalMesh meshes are accepted by list_uv_channels and mesh_has_uv_channel for read-only channel counts but all other methods will fail on skeletal meshes — the editing path goes through FSkeletalMeshLODModel and is not yet implemented. If you're prompted to UV-map a skeletal mesh, stop and tell the user.
UVMappingService calls MarkPackageDirty() and PostEditChange() on every successful mutation but does not save. After a batch of edits:
unreal.UVMappingService.set_lightmap_settings("/Game/Meshes/SM_Wall", 1, 0, 128, True)
unreal.UVMappingService.generate_lightmap_uvs("/Game/Meshes/SM_Wall", 0, 1, 1.0)
# Save once at the end:
unreal.EditorAssetLibrary.save_asset("/Game/Meshes/SM_Wall")Always run get_uv_health first. It is a single call that tells you channel count, lightmap config, overlap status, and texel density per channel. This prevents wasted work like generating lightmap UVs into an index that already has good UVs.
By UE convention:
LightMapCoordinateIndex on the static mesh must point at the lightmap channel.generate_lightmap_uvs automatically sets LightMapCoordinateIndex = DestUVIndex for you. remove_uv_channel adjusts it if you remove a channel above or at the lightmap.
remove_uv_channel rejects channel 0 — every static mesh must have at least one UV channel. To replace channel 0's contents, use auto_unwrap_uvs or copy_uv_channel.
Static meshes support at most 8 UV channels. add_uv_channel returns failure beyond this limit; set_uv_channel_count rejects counts > 8.
OverlapPercent uses an O(N²) AABB-overlap heuristic on triangle UV bounding boxes, capped at 5,000 triangles. Above the cap, the field returns -1.0 to signal "skipped." It produces conservative false positives (touching but non-overlapping AABBs) — use it as a smoke test, not a precise measurement.
pack_uvs rescales the entire channel's UV bounds into [padding, 1-padding]^2. It does not detect connected islands and shelf-pack them. For real island packing, run auto_unwrap_uvs with Box projection first — that produces island-shaped charts the engine packs internally.
For meshes where one face/region needs a different UV transform than the rest (e.g. a thin disc whose side strip distorts a wall texture while the cap looks fine), use the per-region transforms. They apply an affine transform to a subset of vertex instances, leaving everything else untouched.
transform_u_vs_by_normal(mesh, lod, channel, axis_x, axis_y, axis_z, min_dot, max_dot, scale_u, scale_v, rotation_degrees, offset_u, offset_v)
Applies the affine transform only to vertex instances whose normal, dotted with the given axis, falls in [min_dot, max_dot]. Common windows for axis = world +Z (0,0,1):
| Window | Selects |
|---|---|
min_dot=0.5, max_dot=1.0 | Top (upward-facing) |
min_dot=-1.0, max_dot=-0.5 | Bottom (downward-facing) |
min_dot=-0.5, max_dot=0.5 | Sides (horizontal-pointing) |
min_dot=0.7, max_dot=1.0 | Strict "up" only |
count_vertices_by_normal(mesh, lod, axis_x, axis_y, axis_z, min_dot, max_dot) previews the selection without modifying anything — call it first to verify your filter is selecting the right region.
Worked example — fix a thin disc's side strip aspect ratio while leaving the cap correct:
# Disc: scale (2.5, 2.5, 0.4), so world dimensions 250cm wide × 40cm tall.
# Side strip is 785cm (circumference) × 40cm (height) — 20:1 aspect.
# Cap is 250×250cm — 1:1 aspect.
# With a uniform brick material at Tiling=4, the cap renders correct bricks
# but the side renders as horizontal pinstripes.
# Step 1: confirm the filter selects only the side
side = unreal.UVMappingService.count_vertices_by_normal(
"/Game/Meshes/SM_Disc", 0, 0,0,1, -0.5, 0.5)
print(f"side vertex instances: {side}") # ~960 for engine cylinder
# Step 2: scale U on the side only by 20x to bring tile aspect back to ~1:1
unreal.UVMappingService.transform_u_vs_by_normal(
"/Game/Meshes/SM_Disc", 0, 0,
0,0,1, # axis = world Z
-0.5, 0.5, # side selector
scale_u=20.0, scale_v=1.0, # only U
)
unreal.EditorAssetLibrary.save_asset("/Game/Meshes/SM_Disc")💡 Which axis to scale: figure out the world-space aspect of the misbehaving region, then scale UVs to compensate. If a region is 20× wider than tall in world, scale U by 20× to make the brick texture tile 20× more in U than V — bricks now appear correctly proportioned.
Use identify_uv_islands + transform_uv_island when normal-direction or polygon-group filters can't cleanly separate the regions you want to operate on (e.g. an irregular mesh, or a UV layout where similar-normal faces are still distinct islands).
identify_uv_islands(mesh, lod, channel) returns an array of FUVIslandInfo, one per connected UV island. Two vertex instances are in the same island iff they're reachable through triangles with no UV seam between them.
islands = unreal.UVMappingService.identify_uv_islands("/Game/Meshes/SM_Disc", 0, 0)
for i in islands:
n, c = i.average_normal, i.world_center
print(f"Island {i.island_id}: tris={i.triangle_count} VIs={i.vertex_instance_count} "
f"bounds=({i.min_u:.2f},{i.min_v:.2f})..({i.max_u:.2f},{i.max_v:.2f}) "
f"normal=({n.x:.2f},{n.y:.2f},{n.z:.2f}) center=({c.x:.0f},{c.y:.0f},{c.z:.0f})")Each island carries its own bounds, area, average world-space center and average normal — use those fields to identify which island is which. For a simple cylinder you'll get 3 islands: top cap (normal ≈ +Z), bottom cap (normal ≈ -Z), and the side strip (largest triangle count).
Once you've identified the island, transform just it:
# Example: scale only the side strip's UV U by 4x — caps and other islands untouched
side = max(islands, key=lambda i: i.triangle_count)
unreal.UVMappingService.transform_uv_island(
"/Game/Meshes/SM_Disc", 0, 0, side.island_id,
scale_u=4.0, scale_v=1.0)Island ids are stable as long as the mesh's UV topology hasn't changed since identify_uv_islands was called. If you re-run an auto_unwrap / pack / structural change, call identify_uv_islands again for fresh ids before transforming.
transform_u_vs_by_polygon_group(mesh, lod, channel, polygon_group_name, scale_u, scale_v, rotation_degrees, offset_u, offset_v)
Applies the transform only to triangles in the named polygon group (typically a material slot). Use when the mesh has clean per-section slots — e.g. a wall with separate body and trim material slots, where you want different tiling per slot but the same base material.
list_polygon_groups(mesh, lod) returns the slot names available on a LOD. The engine basic shapes have just one slot (DefaultMaterial), so this filter is most useful on imported meshes with authored slots.
groups = unreal.UVMappingService.list_polygon_groups("/Game/Meshes/SM_Wall", 0)
# ['Body', 'Trim']
unreal.UVMappingService.transform_u_vs_by_polygon_group(
"/Game/Meshes/SM_Wall", 0, 0, "Trim",
scale_u=2.0, scale_v=2.0, # 2x denser bricks on trim only
)| WRONG | CORRECT |
|---|---|
result.success returning False but no error string | Check result.message — every failure includes a reason |
Generating lightmap UVs without setting MinChartSpacingPercent | Pass at least 1.0 for typical meshes; smaller values pack tighter but risk bleeding |
Calling transform_uvs on the lightmap channel | Avoid — transforms break the channel's [0,1] packing. Use it on material UV channels only |
| Forgetting to save after edits | Add unreal.EditorAssetLibrary.save_asset(...) after the batch |
| Editing UVs on a skeletal mesh | Not supported — only StaticMesh works |
Setting LightMapCoordinateIndex past the channel count | Use set_uv_channel_count first, or add_uv_channel |
| Property | Type | Description |
|---|---|---|
success | bool | True iff the operation completed |
mesh_path | str | Echoes the input path |
message | str | Failure reason or success summary |
list_uv_channels, get_uv_channel_info)| Property | Type | Description |
|---|---|---|
lod_index | int | LOD this channel belongs to |
channel_index | int | UV channel (0..7) |
vertex_instance_count | int | Number of vertex instances |
triangle_count | int | Number of triangles |
min_u, min_v, max_u, max_v | float | UV bounding box |
overlap_percent | float | % of triangles with overlapping UV AABB. -1 if mesh too large (>5000 tris) |
in_unit_square_percent | float | % of vertex UVs inside [0,1]^2 |
texel_density1k | float | Avg texels/UE-unit at 1024px reference |
get_uv_health)| Property | Type | Description |
|---|---|---|
mesh_path | str | |
lod_count | int | |
lightmap_coordinate_index | int | The channel lightmaps sample at runtime |
light_map_resolution | int | Per-mesh lightmap texel size |
b_generate_lightmap_uvs | bool | LOD 0 BuildSettings flag |
channels | list[FUVChannelInfo] | Per-LOD per-channel stats |
b_lightmap_has_overlaps | bool | True if the lightmap channel has any AABB overlap |
warnings | list[str] | Human-readable warnings |
get_lightmap_settings)| Property | Type | Description |
|---|---|---|
b_generate_lightmap_uvs | bool | LOD 0 BuildSettings flag |
source_lightmap_index | int | UV channel the generator reads seams from |
destination_lightmap_index | int | UV channel the generator writes into |
lightmap_coordinate_index | int | Runtime sample channel |
light_map_resolution | int | Mesh-level lightmap resolution |
min_lightmap_resolution | int | Min allowed lightmap resolution |
import unreal
mesh = "/Game/Meshes/SM_Wall"
# 1. Health check
ok, health = unreal.UVMappingService.get_uv_health(mesh)
print(f"Channels found: {len(health.channels)}, lightmap idx: {health.lightmap_coordinate_index}")
# 2. Generate the lightmap channel (creates channel 1 if needed, sets LightMapCoordinateIndex=1)
result = unreal.UVMappingService.generate_lightmap_uvs(
mesh,
source_uv_index=0,
dest_uv_index=1,
min_chart_spacing_percent=1.0,
)
print(f"GENERATED: {result.message}")
# 3. Configure lightmap resolution (256 for hero props, 64 for background)
unreal.UVMappingService.set_lightmap_settings(mesh, 1, 0, 128, True)
# 4. Save
unreal.EditorAssetLibrary.save_asset(mesh)
# 5. Verify
ok, health = unreal.UVMappingService.get_uv_health(mesh)
assert not health.b_lightmap_has_overlaps, "Lightmap still has overlaps after generation"import unreal
mesh = "/Game/Meshes/SM_Wall"
# Add channel 2 if not present
if not unreal.UVMappingService.mesh_has_uv_channel(mesh, 0, 2):
r = unreal.UVMappingService.add_uv_channel(mesh, 0)
print(f"ADDED: {r.message}")
# Copy material UVs (channel 0) into channel 2 as a starting point
r = unreal.UVMappingService.copy_uv_channel(mesh, 0, 0, 2)
print(f"COPIED: {r.message}")
# Tile by 4 (scale UVs)
r = unreal.UVMappingService.transform_uvs(mesh, 0, 2, scale_u=4.0, scale_v=4.0)
print(f"TILED: {r.message}")
unreal.EditorAssetLibrary.save_asset(mesh)import unreal
mesh = "/Game/Meshes/SM_RuinPiece"
# Box projection produces clean per-face charts on chunky props
r = unreal.UVMappingService.auto_unwrap_uvs(
mesh, lod_index=0, channel_index=0,
projection_type="Box",
hard_angle_threshold=66.0,
)
print(f"UNWRAPPED: {r.message}")
# Pack the result tightly
r = unreal.UVMappingService.pack_uvs(mesh, 0, 0, padding_percent=1.0)
print(f"PACKED: {r.message}")
# Regenerate the lightmap channel from the new charts
unreal.UVMappingService.generate_lightmap_uvs(mesh, 0, 1, 1.0)
unreal.EditorAssetLibrary.save_asset(mesh)import unreal, os
mesh = "/Game/Meshes/SM_Wall"
out = os.path.join(os.environ["TEMP"], "uv_layout.png")
r = unreal.UVMappingService.export_uv_layout_image(
mesh, lod_index=0, channel_index=1, output_path=out, image_size=1024)
print(f"EXPORTED: {r.message}")
# Then read the PNG back to inspect it visually (Read the file path directly,
# or surface it through the engine's screenshot/image toolset).import unreal
results = unreal.EditorAssetLibrary.list_assets("/Game/Meshes/Architecture")
for asset in results["assets"]:
if asset["asset_class"] != "StaticMesh":
continue
path = asset["asset_path"]
ok, health = unreal.UVMappingService.get_uv_health(path)
if health.b_lightmap_has_overlaps or not health.b_generate_lightmap_uvs:
unreal.UVMappingService.generate_lightmap_uvs(path, 0, 1, 1.0)
unreal.UVMappingService.set_lightmap_settings(path, 1, 0, 128, True)
unreal.EditorAssetLibrary.save_asset(path)
print(f"FIXED: {path}")
else:
print(f"OK: {path}")auto_unwrap_uvs)String, case-insensitive:
"Planar" — projects along world +Z. Best for flat panels."Box" — six-axis projection with seams along sharp edges. Best general-purpose unwrap."Cylindrical" — wraps around world Z axis. Best for tubes / columns.generate_lightmap_uvs)Float, percent of UV space (0.5..2.0 typical):
0.5 — tight packing, risk of bleeding at low lightmap resolution1.0 — default, safe for 64–128 lightmap resolution2.0 — generous, good for 32 resolution background propsset_lightmap_settings)Power of two preferred:
32–64 — background / non-hero128 — typical world geometry256–512 — hero props, large architectureFor lightmap-related changes, always re-run get_uv_health after the save to verify:
ok, health = unreal.UVMappingService.get_uv_health(mesh)
assert ok
assert not health.b_lightmap_has_overlaps
assert health.lightmap_coordinate_index == 1For unwrap operations, export the layout PNG and visually inspect it (read the PNG back, or surface it through the engine's screenshot/image toolset) — the cheapest way to confirm the unwrap looks reasonable.
execute_python_code)scripts/inspect_uvs.txt — inspect UV channels/health and export a UV layout image.© kevinpbuckley, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file (scripts) in Content/Skills/uv-mapping of kevinpbuckley/VibeUE.
Open the folder on GitHubat commit dc051be
Uv Mapping next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Uv Mapping this skillkevinpbuckley/VibeUE | 730 | — | ~4.8k | Automated safety check: Pass | MIT | |
| Image to Three.js Modelimg2threejs/img2threejs | 18k | 1 repos | ~8.2k | Automated safety check: Pass | Apache-2.0 | |
| Web CloneJane-xiaoer/claude-skill-web-clone | 1k | 1 repos | ~2.7k | Automated safety check: Pass | MIT | |
| Threejs Game Directormajidmanzarpour/threejs-game-skills | 2.5k | — | ~2.2k | Automated safety check: Pass | MIT | |
| Game Asset Generatorhtdt/godogen | 7.1k | — | ~2.8k | Automated safety check: Pass | MIT | |
| Threejs Gameplay Systemsvalkor-ai/loom | 1.2k | 1 repos | ~1.4k | Automated safety check: Pass | Apache-2.0 |
img2threejs/img2threejs
Rebuilds the object in a reference image as a procedural, animation-ready Three.js model written entirely in code, using staged sculpting with quality checks.
Jane-xiaoer/claude-skill-web-clone
网站复刻 / 克隆方法论。USE WHEN 用户说 复刻网站、克隆网站、clone website、抄个站、仿站、 照着这个站做一个、reproduce site、还原某个网页效果、把这个站搬下来改成我的、 复刻某个交互/WebGL/Canvas/Three.js 效果。提供「先拿真源码 → 判路径 → 逆向拆解 → 搭工程 → 替换内容」的可移植决策树,覆盖静态站 /…
majidmanzarpour/threejs-game-skills
Entrypoint for building, upgrading, and finishing Three.js browser games.
htdt/godogen
Generates game art from text prompts: PNG images, GLB 3D models, rigged characters, animations and sprites, with background removal.
valkor-ai/loom
Build and iterate playable Three.js game systems: starter scaffold, architecture, design briefs, core loops, level and encounter design, entities, input, camera, collision and physics, scoring…
CyberAgentGameEntertainment/NovaShader
Execute C with Unity APIs when existing uloop tools cannot inspect or edit enough.
kevinpbuckley/VibeUE
Previews, validates and bakes bone-rotation edits on Unreal Engine AnimSequences, enforcing a coordinate space and a constraint-checked preview-validate-bake loop.
kevinpbuckley/VibeUE
Creates and edits Unreal Engine Animation Montages through AnimMontageService: sections, slots, segments, branching points, notifies and blend settings.
kevinpbuckley/VibeUE
Creates and edits AnimSequence keyframes and bone tracks in Unreal Engine through AnimSequenceService, following an inspect, preview, validate and bake workflow with correct bone-space handling.
kevinpbuckley/VibeUE
Imports files into Unreal Engine, exports textures, reads the Content Browser selection and checks open assets via VibeUE, plus mesh reimport material fixes.
kevinpbuckley/VibeUE
Changes Unreal Engine console variables, scalability levels and raw INI values through VibeUE's Python API, now that registered settings moved to the engine's own toolset.
kevinpbuckley/VibeUE
Creates and wires Unreal Engine Enhanced Input assets through VibeUE's InputService: Input Actions, Mapping Contexts, key bindings, triggers and modifiers.
Categories
Inspect, generate, transform, and visualize UV channels on StaticMesh assets (UVMappingService). Uv Mapping is an agent skill from kevinpbuckley/VibeUE. Inspect, generate, transform, and visualize UV channels on StaticMesh assets (UVMappingService).
Uv Mapping fits situations like: the user asks to check/add/remove UV channels; auto-unwrap UVs; transform (tile/offset/rotate) UVs; check UV health/islands.
Run `npx skills add kevinpbuckley/VibeUE --skill uv-mapping -a claude-code`. Or copy the skill folder (Content/Skills/uv-mapping in kevinpbuckley/VibeUE) into .claude/skills/uv-mapping in your project. Claude Code loads it when a task matches its description.
Run `npx skills add kevinpbuckley/VibeUE --skill uv-mapping -a codex`. Or copy the skill folder (Content/Skills/uv-mapping in kevinpbuckley/VibeUE) into .agents/skills/uv-mapping in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add kevinpbuckley/VibeUE --skill uv-mapping -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/uv-mapping, .gemini/skills/uv-mapping, .github/skills/uv-mapping and .opencode/skills/uv-mapping in your project.
SKILL.md names no scripts, command-line tools or credentials: Uv Mapping is instructions for the agent only. Our summary lists: Python 3.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Uv Mapping is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.8k tokens (SKILL.md is roughly 19k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Uv Mapping: Image to Three.js Model (img2threejs/img2threejs, 18k stars), Web Clone (Jane-xiaoer/claude-skill-web-clone, 1k stars), Threejs Game Director (majidmanzarpour/threejs-game-skills, 2.5k stars) and Game Asset Generator (htdt/godogen, 7.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
kevinpbuckley (a GitHub user) maintains it in kevinpbuckley/VibeUE, which has 730 GitHub stars. The repository holds 39 skills in this directory. The repository was last updated on October 7, 2026.
Source: kevinpbuckley/VibeUE on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.