# Visuals and collisions

How a Transform defines a custom visual, and which geometry the motion planner actually collision-checks.
> Source: https://docs.viam.com/visualization/visuals-and-collisions/


A geometry is a simple shape, such as a box, sphere, or capsule, that represents an
object's physical extent. Viam uses one set of geometry types for two jobs: drawing a
custom visual in the 3D scene, and telling the motion planner about an obstacle.

To create a custom visual, you attach a geometry to a transform's `physical_object`
field and provide
that transform to a [world state store service](/reference/apis/services/world-state-store/).
This service holds the transforms you publish and streams them to the 3D scene. This
page covers what a transform contains, the difference between planner geometry and
visualization geometry, and how to build each geometry type.

## Anatomy of a transform

A `Transform` carries four things that together place and style a visual:

- **Reference frame and pose**: the visual's origin.
- **Geometry** (the `physical_object` field): the shape to draw (a box, sphere,
  capsule, mesh, or point cloud).
- **Metadata**: styling such as color and opacity.
- **UUID**: a stable identifier for this specific visual.

The reference frame and pose decide _where_, the geometry decides _what shape_,
and the metadata decides _how it looks_.

## The UUID gives a visual a stable identity

Each transform has a UUID. That identifier is what lets a module change one
visual without disturbing the rest of the scene: to update a visual, the module
re-sends a transform with the same UUID; to remove it, it references that UUID;
to add a new one, it uses a fresh UUID. Without stable identifiers the client
would have to re-render everything on every change. With them, the scene applies
incremental add, update, and remove operations to individual visuals.

## Metadata styles the visual

The metadata is a set of rendering attributes the scene reads when it draws the
geometry:

- `colors`: the fill color, or one color per point for point cloud geometry
- `opacities`: how transparent the shape is
- `show_axes_helper`: draws a coordinate triad at the visual's origin
- `invisible`: hides the visual by default

The scene reads only the keys it recognizes and ignores the rest. These are all
**visualization attributes**: they control how the visual looks.
The planner reads its solid geometry from the frame
system and the [`WorldState`](/motion-planning/obstacles/) you pass to `Move`, so
metadata changes what you see without changing what the planner plans around.

## The scene draws, the planner collision-checks

The geometry on a world state store transform renders in the 3D scene: publishing a
box draws a box. The motion planner collision-checks a separate geometry, which it
reads from two places:

- The **frame system**: each component's `frame.geometry`.
- The **`WorldState`** you pass to a `Move` call: obstacles and transforms
  supplied for that single planning request.

Despite the similar names, these are different things: the
[world state store service](/reference/apis/services/world-state-store/) holds transforms
for the scene to draw, and the [`WorldState`](/motion-planning/obstacles/) you pass to
`Move` carries obstacles for the planner to avoid. A world state store transform and a
`WorldState` obstacle travel two paths, each with its own job: one is drawn in the scene,
the other is planned around. The same shape can take both paths.

## Making a geometry both visible and collision-checked

If you want a geometry to appear in the scene _and_ be avoided by the planner,
you do both, separately:

- **For the scene**: publish it as a transform through the world state store
  service (see [Publish visuals from a module](/visualization/publish-visuals-from-a-module/)).
- **For planning**: add it to the frame system, or include it in the
  `WorldState` you pass to `Move`.

Today these are two separate outputs you produce from the same source data: one
transform for the scene, one geometry for the planner.

## Geometry types

The supported types are:

- **box**: dimensions in millimeters
- **sphere**: a radius
- **capsule**: a radius and length
- **mesh**: an arbitrary triangle mesh
- **point cloud**: a set of points

Choose the type that matches what you are representing: a box or capsule to
approximate a physical object, a mesh for a precise model, a point cloud for
sensor data. For guidance on matching a geometry type to a physical object, see the
[geometry types table](/motion-planning/obstacles/overview/#geometry-types).

You build a geometry as a `Geometry` proto, the same type a world state store
transform and a `WorldState` obstacle both carry. The Python SDK and the Go SDK
construct that proto directly, with no helper library. The box, sphere, and
capsule primitives also have a machine config (JSON) form. The transform you
attach the geometry to supplies its reference frame and pose.

For the constructor for each type, in JSON, Python, and Go, see
[Geometry constructors](/visualization/reference/geometry-constructors/).

## Assemble a transform

A geometry is only the shape. To render it as a visual, wrap it in a transform
that carries the other anatomy fields: a reference frame and pose, metadata, and a UUID.
The `draw` library assembles them for you, so you do not build the `Transform` proto by
hand:

```go
import (
    "github.com/golang/geo/r3"
    "github.com/viam-labs/motion-tools/draw"
    "go.viam.com/rdk/spatialmath"
)

// A red box at (400, 0, 200) in the world frame.
box, err := spatialmath.NewBox(
    spatialmath.NewZeroPose(), r3.Vector{X: 100, Y: 100, Z: 100}, "target-box",
)
if err != nil {
    return nil, err
}
drawn, err := draw.NewDrawnGeometry(
    box,
    draw.WithGeometryColor(draw.NewColor(draw.WithName("red"))), // metadata: color
)
if err != nil {
    return nil, err
}
transform, err := drawn.Draw(
    "target-box",             // the name of this visual's frame
    draw.WithID("target-box"), // UUID: a stable identity for later updates
    draw.WithParent("world"),  // reference frame the pose is expressed in
    draw.WithPose(spatialmath.NewPoseFromPoint(r3.Vector{X: 400, Y: 0, Z: 200})), // pose
)
```

Publish `transform` through a world state store service to draw it. For the full module
that serves transforms this way, see
[Publish visuals from a module](/visualization/publish-visuals-from-a-module/).

## What's next

- [Publish visuals from a module](/visualization/publish-visuals-from-a-module/):
  implement a world state store service that publishes transforms.
- [Define obstacles](/motion-planning/obstacles/): the geometry the planner
  collision-checks.
- [Frame system](/motion-planning/frame-system/): how the planner gets the
  geometry and frames it plans around.

