Assembly Asset Authoring Workflow¶
This is the current lightweight workflow for turning an assembly-v1 .rbxm
asset plus vehicle-developer product input into vehicle-definition and
dealership-package data. It is not fully automated yet, but the inspection
output is meant to make the hand-authored files more mechanical.
The intended direction is standardized vehicle-developer input: trims/packages,
VehicleIds, prices, images, display names, paints, rims, base assembly,
accessories, and tuning should be provided in an easy repeatable shape. A
generator can then produce source files from that input. If the standardized
input omits a product value, the generated draft may use a placeholder such as
0, "", or a temporary id, but those placeholders should be visible review
items rather than hidden assumptions.
Development direction¶
The long-term direction is for more of the vehicle-definition surface to become generated source code produced by vehicle-developer tooling:
VehicleDef/Vehicles/<vehicle>/init.luauassembly_definitions.luauaccessory_definitions.luautuning_definitions.luauDealershipPackageGroups/<vehicle_key>.luau
That is the reason the repository's docs/vehicles/case-studies/ folder keeps historical
agent-assisted migrations and asset-specific notes. Each migration records which source inputs existed, which details had to
be inferred from the RBXM, which product fields were missing, and which
placeholder values remained. Those notes are not meant to be permanent manual
rituals; they are training data for the workflow we want to standardize.
Because these files are moving toward generated output, prefer denormalized vehicle-def code. Repeated trims, package entries, assembly definitions, accessory definitions, and customization item lists should usually be written inline rather than hidden behind shared helper tables or clever local factory functions. A little local structure is fine when it matches an existing authored pattern, but the default should be boring, explicit data. Explicit repeated data is easier for generators to emit, easier for vehicle developers to review, and easier for agents to compare against the authored asset and product input.
In other words: optimize these files for mechanical generation and review, not for hand-written abstraction elegance.
Inspect the asset¶
Use the RBXM helpers before writing definitions:
mise exec -- lune run .lune/demos/rbxm/inspectModel.luau "src/ServerStorage/LocalVehicles/4444.rbxm"
mise exec -- lune run .lune/demos/rbxm/inspectScriptSources.luau "src/ServerStorage/LocalVehicles/4444.rbxm" --full
mise exec -- lune run .lune/demos/rbxm/inspectAssemblyVehicleAsset.luau "src/ServerStorage/LocalVehicles/4444.rbxm"
mise exec -- lune run .lune/verifyVehicleAssemblyAsset.luau "src/ServerStorage/LocalVehicles/4444.rbxm"
inspectAssemblyVehicleAsset.luau summarizes the asset paths that usually seed:
assembly_definitions.luauentries fromassembly/<slot>/<model>accessory_definitions.luauentries fromaccessory/<model>tuning_definitions.luauentries from nested models undertuning/
Generated definition ids commonly start equal to these paths, but ids and paths
are different concepts. The id is stable package/saved-data identity; path
is the movable address under the RBXM asset.
It also lists DriveSeat paths and tags. Assembly runtime code expects the
assembled output to have exactly one VehicleAssembly__DriveSeat tag and at
least one VehicleAssembly__Wheel tag.
verifyVehicleAssemblyAsset.luau is the publish gate for asset shape. It also
validates the assembly-v1 folding-mirror contract documented in
vehicle-assets.md: explicit moving-model and pivot tags; per-model
degree/speed configuration; no authored anchors; and no legacy mirror runtime
artifacts.
Required LocalVehicles RBXM hierarchy¶
An assembly-v1 file under ServerStorage/LocalVehicles must use this exact
outer shape:
The serialized RBXM root is the Model container, not the vehicle asset
Folder itself. VehicleModelManager clones the LocalVehicles entry and
passes its first child to the assembly builder. Serializing the asset Folder as
the root makes the manager pass that Folder's first child—often assembly—as
the asset, which then fails because it has no nested assembly folder. Keep
exactly one vehicle asset Folder inside the Model container, and name the outer
Model after the local pseudo-asset id or published asset id.
To run the asset-shape, asset/VehicleDef contract, and package-group/VehicleDef
contract validators across every assembly vehicle whose asset is currently
maintained in LocalVehicles, use:
The reviewed vehicle list is intentionally hard-coded in
.lune/vehicleValidation/assemblyVehicles.luau until the repository contains
the complete assembly-vehicle asset set. The command prints individual failure
diagnostics followed by check and vehicle totals.
The package contract follows each base_accessories installation recursively.
At the first level, its key must name a socket on the package's selected
assembly part. At every nested level, the key must name a socket exposed by the
selected parent accessory, and the installed part must be one of that socket's
declared options. For example, a roof-rack:plastic accessory mounted to a
frame's roof-rack socket hosts roof-rack:crossbars through its own
crossbars socket—not another roof-rack socket.
Generate from a multi-vehicle authoring bundle¶
An authoring bundle may contain shared product metadata plus several vehicle
containers instead of one publishable asset root. Treat that file as generator
input, not as a LocalVehicles asset: the publish validator requires each
output RBXM to deserialize to exactly one outer Model containing exactly one
vehicle asset Folder.
The checked-in Delton bundle preparer is a concrete, repeatable example:
mise exec -- lune run .lune/prepareNewDeltonAssemblyVehicles.luau `
"C:\Users\conta\Desktop\new_delton_vehicles.rbxm" `
".tmp/new_delton_vehicles"
It writes drafts rather than editing runtime source in place:
assets/<asset-id>.rbxmfor each split and normalized vehicle asset;vehicles/<vehicle-key>/with the initializer and three definition modules;package_groups/<vehicle-key>.luau;- factory-paint and factory-rim entry snippets;
summary.mdrecording the applied product decisions and output counts.
The script also demonstrates how to keep repeatable asset corrections at the generation boundary: move misplaced assembly sockets, add inferable mount attachments, normalize stable path names, remove legacy executable runtime state, add assembly tags, and convert old power-folding mirror scripts into the tag-and-attribute contract. Every correction is derived from authored geometry, legacy configuration, or an explicit product decision; the generator should fail when it cannot make that derivation safely.
The repository's
docs/vehicles/case-studies/delton-holsman-family-assembly-generation.md
records the input precedence rules, collision resolution, inferred Landslide
Fleet package, and validation results from this bundle.
Author the vehicle¶
For a new assembly-v1 vehicle:
- Set
AssemblySystem = "assembly-v1"and pointAssetIdat the local or published assembly asset. - Set
RootAssemblySlotto the root physical slot. Define each reachable child slot in the selected part'sassembly_sockets. - Put sibling definition modules next to the vehicle
init.luau:assembly_definitions.luau,accessory_definitions.luau, and, if needed,tuning_definitions.luau. - Author a matching
DealershipPackageGroups/<vehicle_key>.luauwhen packages need to expose choices that are not one-package-per-trim. - Make each package's
vehicle_idexplicit. It is the purchased trim identity, not something package purchase derives from the final assembly.
Package-group display names¶
Set a package group's display_name to "" when the vehicle has only one
group. The vehicle and package names already provide the useful labels, so a
group-level label would only repeat them. Give groups display names only when a
vehicle exposes multiple groups and the UI must distinguish their purposes,
such as Sierra HT's Stock, Tow, Delivery, and Stakebed groups. This convention
applies to generated package groups as well as hand-authored ones.
For the 2026 Sternauster-Mullerline Standhaft, the initial tree is frame -> body.
The asset also has a drivetrain-badge assembly socket, but there is no base
"no badge" part yet, so the first package setup keeps V12 as a tuning overlay
only.