Skip to content
Back to skills

Vehicle Model

ASecurity

Generate a hard-surface vehicle (car, spaceship, mech, boat, tank) as a static or VehicleBody3D mesh.

  • 77 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 16, 2026
ai-agentsrustgoshellnodeawsbackend

Works with

  • claude code
  • cursor
  • cli
  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 16, 2026

npx -y skills add SummerEngine/summer --skill vehicle-model --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Vehicle Model?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Vehicle Model
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/summerengine-vehicle-model-summer/badge)](https://www.skillsdirectory.com/skills/summerengine-vehicle-model-summer)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: vehicle-model
description: "Generate a hard-surface vehicle (car, spaceship, mech, boat, tank) as a static or VehicleBody3D mesh."
license: MIT
compatibility: [Cursor, Claude Code, Windsurf, Codex]
category: 3d-assets
user-invocable: true
allowed-tools: Read Grep summer_assets_search summer_assets_get summer_import_asset_by_id summer_assets_generate_3d summer_assets_generate_image summer_import_from_url summer_add_node summer_set_prop summer_inspect_node summer_inspect_resource summer_get_scene_tree summer_save_scene summer_jobs_wait summer_call
paths: ["assets/vehicles/**", "assets/models/**", "**/*.tscn", "**/*.gd"]
---

# Vehicle Model — Hard-Surface 3D Generation

Vehicles are the hardest 3D-gen category. Hard surfaces (flat panels, sharp edges, symmetrical bodies) expose every flaw the AI mesher has — smoothing-group artifacts on flat panels, asymmetric headlights, melted door seams. This skill exists to push the success rate up by giving the model **multi-angle reference**, picking the right backend, and using a **secondary detail pass** (decals) to recover crispness on the body panels.

Backing operation: `assets.generate_3d` (it answers with a job: `jobs.wait` until it finishes). Default model is `hunyuan` (best general quality). For pure hard-surface (clean spaceship, F1 car), try `trellis` first — it tends to preserve panel edges better.

## When to use

- "Make me a player car for a racing game."
- "Generate a sci-fi fighter spaceship."
- "I need a hover bike for the desert level."
- "Create a mech for the boss fight."
- "Background traffic — generate three civilian sedans."

## When NOT to use

- Character driving the vehicle → that's `character-model`. Generate them separately and parent the character to the vehicle's seat.
- Vehicle interior (cockpit, dashboard) as a first-person view → generate as a separate "interior" prop via `prop-model` with first-person framing.
- A scenery vehicle that never moves and is far from camera (parked truck in the distance) → `prop-model` is fine; vehicle-model's overhead isn't worth it.
- Procedural / customizable vehicles (modular ship parts) → use `environment-kit` to generate a vehicle-parts kit instead.

## Polycount targets

| Use case | Tris | Pass via |
|---|---|---|
| Player vehicle (close camera, lots of screen time) | 15k–30k | `targetPolycount: 25000` |
| Hero showpiece (cinematic, garage view) | 30k–60k | `targetPolycount: 50000` |
| Background traffic (mid-range, multiple onscreen) | 2k–5k | `targetPolycount: 4000` |
| Distant flyby / parked scenery | 1k–2k | `targetPolycount: 1500` |

Vehicles benefit more from polycount than props — flat panels need edge density to look right. Don't go below 2k for anything the camera will get close to.

## Multi-angle reference — the single biggest quality lever

Vehicles are highly view-dependent. A front-only reference produces a mesh with great front detail and a melted rear. There are two ways to give the mesher more than one angle, and they are not the same thing:

**(a) A real multi-image request — prefer this.** `assets.generate_3d` takes an `imageUrls` array of two to four views. These are passed through as separate views, not fused into one picture. Several views run on Meshy (`meshy` or `meshy-7.1`; any other model is switched to Meshy).

```
assets.generate_3d({
  kind: "image-to-3d",
  imageUrls: ["<front url>", "<3/4 rear-side url>", "<profile url>"],
  model: "meshy",
  targetPolycount: 25000
})
```

**(b) A composite reference image**, when you only have one slot to work with:

```
assets.generate_image({
  prompt: "A sleek red sports car, front view AND 3/4 rear-side view side by side, two angles in one image, white background, studio lighting, clean references for 3D modeling, isolated, no scenery.",
  aspectRatio: "16:9"
})

assets.generate_3d({
  kind: "image-to-3d",
  imageUrl: "<composite reference url>",
  model: "hunyuan",
  targetPolycount: 25000
})
```

If the user has reference images already (concept art, photos), pass them straight to `imageUrls` — do not composite them down into one image first; that throws away the multi-view path.

## Steps

### 1. Search before generating

```
assets.search({ query: "<vehicle type>", assetType: "3d_model", scope: "all" })
```

### 2. Pick model and polycount

For hard-edged vehicles (spaceships, F1, mechs), try `trellis` first — sharper panel edges. For organic-curved vehicles (muscle cars, motorcycles, classic boats), `hunyuan` handles the curves better.

### 3. Build the prompt

Pattern: `<vehicle type> + <silhouette / era / style> + <materials> + <surface state> + isolated suffix`.

| Goal | Prompt that works |
|---|---|
| Player race car | `A sleek modern Formula 1 race car, aerodynamic carbon-fiber bodywork, large rear wing, exposed wheels, racing livery in red and white. Front and 3/4 side views. Game asset, stylized, clean white background, isolated vehicle.` |
| Sci-fi fighter | `A sleek single-seat sci-fi space fighter, swept-forward wings, twin engine nacelles, glass cockpit canopy, painted matte gray with cyan trim. Front and 3/4 side views. Game asset, stylized hard-surface, white background, isolated vehicle.` |
| Hover bike | `A rusted desert hover bike, exposed engine block, single seat, handlebars, no wheels (hover thrusters underneath), weathered orange paint. Front and 3/4 side views. Game asset, stylized, white background, isolated vehicle.` |
| Mech | `A 4 meter tall bipedal combat mech, blocky armored torso, articulated arms with rifle and missile pod, thick legs with hydraulic pistons, painted olive drab with hazard stripes. Front and 3/4 side views. Game asset, hard-surface stylized, white background, isolated vehicle.` |
| Background sedan | `A generic 90s civilian sedan, four doors, beige paint, slightly worn. Front and 3/4 side views. Game asset, low-detail stylized, white background, isolated vehicle.` |

Nothing in the prompt text "triggers" multi-view. The phrase `front and 3/4 side views` only shapes what the *image* model draws; the 3D operation has no prompt-sniffing and sees whatever pixels you hand it. Multi-view comes from the `imageUrls` array, nothing else.

### 4. Confirm and call

> About to generate `red_race_car` via `hunyuan`, target ~25k tris, multi-angle ref. Uses credits, ~90s. OK?

The same call with `dryRun: true` first gives the credits for the confirmation (`estimate.credits`, and `enough` against their balance).

```
assets.generate_3d({
  prompt: "A sleek modern Formula 1 race car, ...",
  model: "hunyuan",
  targetPolycount: 25000
})
jobs.wait({ jobId: "<job.id>", timeoutSeconds: 50 })   // again until finished; result.assetId
assets.get({ assetId: "<assetId>" })
summer_import_asset_by_id(assetId="<assetId>", path="res://assets/vehicles/race_car.glb")
```

### 5. Inspect for hard-surface artifacts

```
summer_inspect_resource(path="res://assets/vehicles/race_car.glb")
```

Open the import preview. Look for:
- **Smoothing-group artifacts on flat panels** (visible as banding under light) → cover with step 6's detail decals, or re-import with `Generate Tangents = on` and a custom shader.
- **Asymmetric headlights / wheels** → regenerate with `symmetric, mirrored bilateral` added to the prompt.
- **Melted door seams / panel gaps** → regenerate from a cleaner multi-view reference, or paint the seams back with step 6's decals.

### 6. Optional: secondary detail pass

There is no texture-only 3D pass among the asset operations (`assets.generate_3d` takes `text-to-3d` or `image-to-3d`). For hero vehicles, recover panel-line crispness without re-meshing by drawing the detail as images and laying it on the mesh:

```
assets.generate_image({
  prompt: "Flat orthographic livery and panel-line decal for a red Formula 1 car side, crisp seams, sponsor stripes, transparent background",
  referenceImageUrl: "<original front-view reference>",
  aspectRatio: "16:9",
  removeBackground: true
})
```

Import it and apply it with `Decal` nodes or as a detail texture in a material override in the editor. Cheaper than re-meshing.

### 7. Wire into the scene

| Use case | Parent type | Notes |
|---|---|---|
| Player-driven (car, bike, hover) | `VehicleBody3D` (wheeled) or `RigidBody3D` (free physics) | Add `VehicleWheel3D` children for wheeled vehicles |
| Player-driven (spaceship, mech) | `RigidBody3D` or `CharacterBody3D` | Custom thrust / walk code (`character-movement` for walkers) |
| Background scenery (parked, flyby) | `MeshInstance3D` under a `Node3D` | No physics, no collision needed for distant traffic |
| Background traffic (moving but not interactive) | `Node3D` + `AnimationPlayer` driving the position | Cheap, no physics overhead |

**Player car wiring** (one `summer_run_script`; `scenePath` is the exact scene to change):

```
summer_run_script(scenePath="res://main.tscn", source="""
func run(ctx):
    var car = ctx.add_node("VehicleBody3D", "RaceCar", ctx.find("World"))
    ctx.instance_scene("res://assets/vehicles/race_car.glb", car, "Body")
    var box = BoxShape3D.new()
    box.size = Vector3(4.5, 1.1, 1.9)
    ctx.add_node("CollisionShape3D", "Collider", car, {"shape": box})
    # Add one VehicleWheel3D per wheel here, at the hub positions summer_inspect_asset measured on the model.
    ctx.save_scene()
""")
```

A `.glb` cannot be assigned to `MeshInstance3D.mesh` — an imported `.glb` is a scene, not a `Mesh` (`ResourceLoader.get_recognized_extensions_for_type("Mesh")` on the shipped engine returns `["tres", "mesh", "res"]`, no `glb`). Instantiate it (`ctx.instance_scene` in a script, `summer_instantiate_scene` for one model). Build and size the collision shape before you assign it.

**Background scenery wiring:**

```
summer_instantiate_scene(scenePath="res://main.tscn", parent="./World/Street", scene="res://assets/vehicles/sedan.glb", name="ParkedSedan")
summer_save_scene(scenePath="res://main.tscn")
```

## Anti-patterns

- **Single-angle reference for a hero vehicle.** Front-only → melted rear. Pass an `imageUrls` array (up to four views) for anything the player gets close to.
- **Expecting the prompt to request multi-view.** It cannot. `imageUrls` is the only multi-view mechanism.
- **Flat-shaded prompt for hard surfaces.** "Smooth shading", "rounded edges" → loses the panel-line crispness that defines vehicles. Prefer "hard-surface", "panel-lined", "crisp edges".
- **Skipping symmetry callouts.** Vehicles are bilaterally symmetric — without `symmetric, mirrored` you get one headlight bigger than the other 30% of the time.
- **Asking the mesh pass to invent decals / liveries.** It can't — the mesh has the silhouette but the decals get geometry-baked weirdly. Use step 6's decals for liveries.
- **Wrapping a background sedan in VehicleBody3D.** Wastes physics for a parked car. Use MeshInstance3D under Node3D.
- **Picking `meshy` (legacy).** Worse hard-surface fidelity than hunyuan or trellis.

## Edge cases

- **Tracked vehicle (tank).** AI mesh-gen handles the hull but the tracks come back as a fused ring. Generate the hull only, then add tracks as a separate `prop-model` (or use a tiled texture on a torus). For animation, scroll the track texture's UV.
- **Articulated vehicle (mech with shoulders, hips, knees).** The mesh is one piece — joints aren't separated. For animated mechs, treat as a humanoid: generate as `character-model` with the rig pass, then animate with `text-to-motion` (prompt "walks heavily").
- **Vehicle with rotor (helicopter, drone).** Generate without rotor, then add the rotor as a separate `prop-model` and parent it. Spin via code in `_process`.
- **Open-top vehicle (convertible, jeep).** Specify "open top, no roof" — defaults often add a roof.
- **The user wants the cockpit interior visible.** Generate exterior here, then a separate `prop-model` for the interior, and switch meshes when the camera enters first-person view.

## Without Summer Engine

In a session without Summer Engine tools (the assets profile; the `summer-assets` skill has the whole loop), do steps 1-6 and skip step 7 (scene wiring, `VehicleWheel3D`). Save the file where the person asked with `out` (the `summer-assets` skill says how), and tell them the path and format. The file is GLB and not at real-world size: give the person the target length (a car about 4.5 m) and tell them where the wheels are, so they can set up their engine's vehicle physics.

## Fallback (no MCP)

1. Generate the multi-angle reference at the Summer dashboard (or Midjourney / nano-banana web).
2. Upload to Hunyuan or Trellis web playground → image-to-3D → download `.glb`.
3. Drop into `res://assets/vehicles/`.
4. Wire as VehicleBody3D / MeshInstance3D in Summer Engine manually.

## Handoff

After the vehicle is wired:

> `race_car.glb` placed at `./World/RaceCar` as a VehicleBody3D. Next:
> - **Vehicle controls:** WASD steering / accel — write them with `engine_force`, `steering`, and `brake` on VehicleBody3D.
> - **Driver character:** generate via `character-model` and parent to the seat position.
> - **Engine sound + tire screech:** `sound-effect` for one-shots, `ambient-bed` for the engine loop.
> - **Particles:** exhaust smoke, dust trail, sparks on collision — `vfx-smoke` / `vfx-hit-spark` or built-in GPUParticles3D.

## See also

- `character-model` — for the driver/pilot.
- `prop-model` — for separable parts (rotors, decals as decals, modular kit pieces).
- `asset-strategy` — meta-router.
- `summer_docs_read` id `reference/mcp-tools-reference` — how to call `assets.generate_3d`; `summer_search` returns its exact input.

<!-- shell-commands: generated from the operation catalog by npm run generate:registry; do not edit by hand -->
## From a shell

No Summer MCP tools in this session? Run each one as a command; when `summer --version` is missing or below 4.0, use `npx -y summer-engine@4.3.0` in place of `summer`. Fields are flags in kebab-case (`--scene-path res://main.tscn`) or one `--input '<json>'`, and `summer ops describe <op>` prints the exact input. The `summer-cli` skill has the rest.

| In this skill | Command |
|---|---|
| `assets.generate_3d`, `summer_assets_generate_3d` | `summer assets generate-3d` |
| `summer_assets_generate_image` | `summer assets generate-image` |
| `summer_assets_get` | `summer assets get` |
| `summer_assets_search` | `summer assets search` |
| `summer_docs_read` | `summer docs read` |
| `summer_add_node` | `summer engine add-node` |
| `summer_get_scene_tree` | `summer engine get-scene-tree` |
| `summer_import_asset_by_id` | `summer engine import-asset-by-id` |
| `summer_import_from_url` | `summer engine import-from-url` |
| `summer_inspect_asset` | `summer engine inspect-asset` |
| `summer_inspect_node` | `summer engine inspect-node` |
| `summer_inspect_resource` | `summer engine inspect-resource` |
| `summer_instantiate_scene` | `summer engine instantiate-scene` |
| `summer_run_script` | `summer engine run-script` |
| `summer_save_scene` | `summer engine save-scene` |
| `summer_set_prop` | `summer engine set-prop` |
| `jobs.wait`, `summer_jobs_wait` | `summer jobs wait` |
| `summer_search` | `summer ops search "<what you want>"` |
<!-- /shell-commands -->

Files in this skill

  • SKILL.md14.9 KB
  • resource.yaml871 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.