Discover Learn Reference Get OpenPLX Search Contact

Vehicles Bundle Architecture

This is an introduction to the design idea behind the Vehicles bundle in a generic way. The important point is that the bundle is not a library of fixed machines. It is a set of reusable vehicle-domain building blocks that let you turn low-level physics assets into configurable machine models.

%%{init: {"flowchart": {"curve": "basis", "nodeSpacing": 38, "rankSpacing": 56, "htmlLabels": true}}}%%
flowchart TB

    title["openplx Vehicles Bundle Overview<br/>From low-level physics assets to configurable vehicle models"]

    subgraph assets_layer["Layer 1: Low-Level Assets"]
        direction TB
        physics3d["Physics3D<br/>Bodies, geometries,<br/>constraints"]
        assets["Assets<br/>Exported rigid bodies,<br/>meshes, transforms,<br/>mate connectors"]
        asset_traits["Asset Traits<br/>FrameBody, AxleBody,<br/>WheelBody"]
    end

    subgraph machine_layer["Layer 2: Machine-Level Components"]
        direction TB
        primitive["Primitive Components<br/>Wrap bodies as reusable<br/>machine parts"]
        interfaces["Vehicle Interfaces<br/>Expected connectors<br/>and outputs"]
        upgraded_parts["Upgraded Parts<br/>Front frame, rear frame,<br/>axle, cargo bed,<br/>track wheel, link"]
    end

    subgraph domain_layer["Layer 3: Vehicle-Domain Building Blocks"]
        direction LR
        chassis["Vehicles.Chassis.*<br/>Rigid, articulated,<br/>dual-pivot, intermediate-link"]
        running_gear["Vehicles.Wheels.*<br/>Vehicles.TrackSystem.*<br/>Rims, tires, sprockets,<br/>idlers, rollers, links"]
        supporting_systems["Suspensions,<br/>DriveTrain,<br/>Connections,<br/>Attachments"]
        steering["Vehicles.Steering.*<br/>DualCylinder,<br/>DualDistance,<br/>Ackermann variants"]
    end

    subgraph family_layer["Layer 4: Machine Archetype Composition"]
        direction TB
        families["Archetype Modules<br/>Vehicles.DumpTruck.*<br/>Vehicles.Bulldozer.*<br/>Other machine bundles"]
        assembly["Reusable Vehicle Assembly<br/>Choose topology and connect<br/>subsystems without hard-coding<br/>one fixed machine"]
    end

    subgraph variants_layer["Layer 5: Traits and Variants"]
        direction LR
        traits["Traits<br/>Suspension, hydraulic tuning,<br/>connector conventions,<br/>motors, optional equipment"]
        variants["Variant Choices<br/>Wheeled or tracked<br/>Simple or detailed steering<br/>Optional bed, blade, ripper"]
    end

    result["Final openplx Vehicle Model<br/>A configurable machine assembled from reusable layers"]
    scene["Scene Setup<br/>Terrain, controls, ranges,<br/>springs, contact properties"]

    title --> physics3d

    physics3d --> assets --> asset_traits
    asset_traits --> primitive
    primitive --> upgraded_parts
    interfaces --> upgraded_parts
    asset_traits -.-> interfaces

    upgraded_parts --> chassis
    upgraded_parts --> running_gear
    upgraded_parts --> supporting_systems
    upgraded_parts --> steering

    chassis --> families
    running_gear --> families
    supporting_systems --> families
    steering --> families

    families --> assembly --> result --> scene
    traits --> assembly
    variants --> assembly

    classDef titleClass fill:#243746,stroke:#243746,color:#ffffff,stroke-width:2px;
    classDef assetsClass fill:#fff8dc,stroke:#d7c7a3,color:#222222,stroke-width:1.5px;
    classDef machineClass fill:#edf7fc,stroke:#9eb7c8,color:#222222,stroke-width:1.5px;
    classDef domainClass fill:#f4fae8,stroke:#9fb88b,color:#222222,stroke-width:1.5px;
    classDef familyClass fill:#f9ebe5,stroke:#c79076,color:#222222,stroke-width:1.5px;
    classDef variantClass fill:#f4ecfa,stroke:#a58ab5,color:#222222,stroke-width:1.5px;
    classDef resultClass fill:#d5efe1,stroke:#4f7b68,color:#222222,stroke-width:2px;
    classDef sceneClass fill:#fff6ea,stroke:#b98b42,color:#222222,stroke-width:1.5px;

    style assets_layer fill:#fffef8,stroke:#d7c7a3,stroke-width:1.5px,color:#222222;
    style machine_layer fill:#f8fcfe,stroke:#9eb7c8,stroke-width:1.5px,color:#222222;
    style domain_layer fill:#fbfdf7,stroke:#9fb88b,stroke-width:1.5px,color:#222222;
    style family_layer fill:#fdf8f5,stroke:#c79076,stroke-width:1.5px,color:#222222;
    style variants_layer fill:#faf8fd,stroke:#a58ab5,stroke-width:1.5px,color:#222222;

    class title titleClass;
    class physics3d,assets,asset_traits assetsClass;
    class primitive,interfaces,upgraded_parts machineClass;
    class chassis,running_gear,supporting_systems,steering domainClass;
    class families,assembly familyClass;
    class traits,variants variantClass;
    class result resultClass;
    class scene sceneClass;

Core idea

The workflow is layered:

  1. Assets define low-level physical parts.
  2. MachineModeling components give those parts structure and meaning.
  3. Vehicles components add domain-specific behavior such as chassis layouts, wheel systems, tracks, steering, suspensions, and attachments.
  4. Traits specialize the model for a machine family or a concrete variant.

This separation makes it possible to reuse the same physical parts in several vehicle configurations without duplicating the full assembly.

Layer 1: Assets are raw physics building blocks

The lowest layer usually comes from exported geometry and connector data. At this level, a part is mostly a rigid body plus the information needed to attach it to other parts:

In practice, an asset trait often looks like this:

trait FrameBody:
    axle_c is Physics3D.Interactions.MateConnector:
        position: {...}
        main_axis: {...}
        normal: {...}

    visual is Visuals.Geometries.ExternalTriMeshGeometry:
        path: @"frame.obj"

    geometry is Physics3D.Geometries.ExternalTriMeshGeometry:
        path: visual.path

At this stage the part does not yet "know" that it belongs to a dump truck, bulldozer, wheel loader, or any other machine class. It is only a physical part with geometry and attachment points.

Layer 2: Primitive components are upgraded into vehicle parts

The next step is to wrap exported bodies in higher-level component definitions. This is where low-level assets are promoted into domain-aware machine parts.

For example, a rigid body can become a front frame, rear frame, axle, wheel carrier, track wheel, cargo bed, or equalizer bar by combining:

Typical pattern:

FrontFrame is MachineModeling.Components.Primitive.Base
    with Vehicles.Chassis.Articulated.Interfaces.DualJoint
    with Vehicles.DumpTruck.Interfaces.Chassis.AFrame:

    body becomes Physics3D.Bodies.RigidBody with FrameBody

    upper_joint_connector: body.upper_joint_c
    lower_joint_connector: body.lower_joint_c
    center_a_frame_connector: body.axle_c

This is the key "upgrade" step:

After this step the model is no longer just a mesh with connectors. It has become a reusable vehicle subsystem component.

Layer 3: Vehicles bundle modules encode vehicle-domain structure

The Vehicles bundle adds machine-specific abstractions on top of the primitive parts. These abstractions describe how a vehicle is organized rather than how each triangle mesh was authored.

Examples of domain modules in the bundle:

These modules define reusable patterns such as:

Layer 4: Traits define reusable variation

Traits are what keep the system composable. They allow variation to be expressed orthogonally instead of forcing every variant into a separate monolithic class.

Common uses for traits in the vehicle stack:

This makes it possible to mix and match behavior:

MyVehicle is Vehicles.DumpTruck.ArticulatedWithLink:
    with Suspension
    with Hydraulic
    with IndividualWheelMotors

The machine variant is then defined by composition rather than by copying an entire machine model and editing it in place.

Why this is useful

This architecture solves a common modeling problem: the same machine family often needs several variants with different fidelity, hardware layouts, or optional equipment.

With the bundle approach, you can change one concern at a time:

That is much more maintainable than building every machine as an isolated, fully-specialized model.

A generic assembly flow

A typical workflow for building a custom vehicle from the bundle is:

  1. Export or author the physical parts in Assets.
  2. Define body traits with geometry, visuals, and mate connectors.
  3. Wrap those bodies in primitive components and attach the relevant Vehicles.*.Interfaces.*.
  4. Choose a vehicle topology from the bundle, such as rigid, articulated, wheeled, or tracked.
  5. Add connection modules for axles, suspensions, cargo beds, blades, or tools.
  6. Apply reusable traits for tuning, hydraulics, drivetrain behavior, and options.
  7. Place the assembled vehicle in a scene and add ranges, springs, contact properties, terrain, and controls.

This means a packaged machine model is usually split into at least three concerns:

How to think about a machine package

A machine package should be read as a composition of layers, not as one flat file. Even when a final model looks specific, the structure is usually generic:

That is why a concrete machine can still be a good example of the general design, without the design being tied to that one machine.

Practical rule of thumb

When adding a new machine, ask these questions in order:

  1. Which parts are just physical assets?
  2. Which parts are reusable vehicle-domain components?
  3. Which decisions belong to the chosen machine family?
  4. Which differences should be expressed as traits instead of new classes?

If those responsibilities stay separate, the result is usually easy to extend, retune, and recombine into new vehicle variants.

OpenPLX is a work in progress. This draft version will evolve with user feedback and experience. We welcome your input and collaboration.
X