Skip to content

draw

import "github.com/viam-labs/motion-tools/draw"

Package draw provides a Go API for building 3D scenes for the motion-tools visualizer.

This package contains the in-memory scene builder for assembling snapshots of geometric primitives, 3D models, frame systems, and robot states. Snapshots can be serialized to JSON or Protobuf and rendered in the visualizer either by drag-and-drop or by passing the file as a component prop. For drawing directly to a running visualizer instance over Connect-RPC, see the client/api package.

The package provides high-level methods on Snapshot organized into three categories:

  • Drawings: Visual primitives like arrows, lines, points, NURBS curves, and 3D models
  • Transforms: Spatial objects like geometries, frames, and frame systems
  • Serialization: Export a snapshot as JSON, binary protobuf, or gzip-compressed binary

Each Draw* method accepts a name and options, and registers the object on the snapshot. Calling a Draw* method with an existing name updates that object in place.

package main

import (
    "os"

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

func main() {
    // Create a snapshot with a custom camera and grid settings.
    camera := draw.NewSceneCamera(
        r3.Vector{X: 2000, Y: 2000, Z: 2000},
        r3.Vector{X: 0, Y: 0, Z: 0},
        draw.WithAnimated(true),
    )
    snapshot := draw.NewSnapshot(
        draw.WithSceneCamera(camera),
        draw.WithGrid(true),
        draw.WithGridCellSize(250),
    )

    // Draw a box at the origin.
    box, _ := spatialmath.NewBox(
        spatialmath.NewZeroPose(),
        r3.Vector{X: 100, Y: 100, Z: 100},
        "my-box",
    )
    snapshot.DrawGeometry(box, spatialmath.NewZeroPose(), "world", draw.NewColor(draw.WithName("red")))

    // Export the scene as JSON for the visualizer.
    jsonData, _ := snapshot.MarshalJSON()
    os.WriteFile("scene.json", jsonData, 0644)
}

Default colors for various drawing primitives, as specified in drawing.proto.

var (
    // DefaultArrowColor is the default color for arrows (green).
    DefaultArrowColor = NewColor(WithName("green"))

    // DefaultLineColor is the default color for lines (blue).
    DefaultLineColor = NewColor(WithName("blue"))

    // DefaultLineDotColor is the default color for dots at line vertices (dark blue).
    DefaultLineDotColor = NewColor(WithName("darkblue"))

    // DefaultPointColor is the default color for point clouds (gray).
    DefaultPointColor = NewColor(WithName("gray"))
)

var (
    // DefaultLineWidth is the default line width in millimeters.
    DefaultLineWidth float32 = 5.0
    // DefaultLineDotSize is the default dot size for Line vertices in millimeters.
    DefaultLineDotSize float32 = 10.0
)

var (
    // DefaultModelScale is the default model scale (1.0, 1.0, 1.0 - no scaling).
    DefaultModelScale = r3.Vector{X: 1.0, Y: 1.0, Z: 1.0}

    // DefaultModelAnimationName is the default animation name (empty string means no animation).
    DefaultModelAnimationName = ""
)

var (
    // DefaultNurbsDegree is the default polynomial degree for NURBS curves (cubic).
    DefaultNurbsDegree int32 = 3

    // DefaultNurbsWeight is the default weight value for NURBS control points.
    DefaultNurbsWeight = 1.0

    // DefaultNurbsColor is the default color for NURBS curves (cyan).
    DefaultNurbsColor = NewColor(WithName("cyan"))
)

var (
    // DefaultSceneCamera is the default camera configuration with a perspective view from position
    // [3000, 3000, 3000]mm looking at the origin. Provides an isometric-style view of the scene.
    DefaultSceneCamera = SceneCamera{
        Position:          r3.Vector{X: 3000, Y: 3000, Z: 3000},
        LookAt:            r3.Vector{X: 0, Y: 0, Z: 0},
        Animated:          false,
        PerspectiveCamera: &drawv1.PerspectiveCamera{},
    }

    // DefaultGridEnabled specifies whether the grid is visible by default.
    DefaultGridEnabled = true
    // DefaultGridCellSize is the default grid cell size in millimeters (500mm).
    DefaultGridCellSize float32 = 500.0
    // DefaultGridSectionSize is the default grid section size in millimeters (10000mm).
    DefaultGridSectionSize float32 = 10000.0
    // DefaultGridFadeDistance is the default distance at which the grid fades out (25000mm).
    DefaultGridFadeDistance float32 = 25000.0
)

DefaultFrameColor is the color used to render frames whose name is not present in a DrawnFrames.Colors map (red).

var DefaultFrameColor = NewColor(WithName("red"))

DefaultOpacity is the default alpha value (fully opaque).

var DefaultOpacity = uint8(255)

var (
    // DefaultPointSize is the default point size in millimeters.
    DefaultPointSize float32 = 10.0
)

func MetadataToStruct(metadata Metadata) *structpb.Struct

MetadataToStruct converts drawing Metadata to a Protocol Buffer structpb.Struct suitable for embedding in transforms.

func NewTransform(config *DrawConfig, geometry spatialmath.Geometry, metadataOpts ...DrawMetadataOption) *commonv1.Transform

NewTransform creates a Viam Transform representing an object in 3D space.

func RelationshipsFromStruct(s *structpb.Struct) []*drawv1.Relationship

RelationshipsFromStruct extracts the “relationships” list from a structpb.Struct that is used as a Transform’s metadata.

func SetRelationshipsOnStruct(s *structpb.Struct, rels []*drawv1.Relationship)

SetRelationshipsOnStruct writes the “relationships” field into a structpb.Struct used as a Transform’s metadata.

Arrows represents a set of directional arrows positioned at specific poses in 3D space. Each arrow visualizes orientation and position, useful for showing coordinate frames or directions.

type Arrows struct {
    // Poses defines the position and orientation of each arrow to render.
    Poses []spatialmath.Pose

    // Colors specifies the color for each arrow. Can be a single color (applied to all arrows)
    // or one color per pose.
    Colors []Color
}

func NewArrows(poses []spatialmath.Pose, options ...DrawArrowsOption) (*Arrows, error)

NewArrows returns an Arrows positioned at the given poses. Without any color option, every arrow is rendered with DefaultArrowColor. Returns an error if the configured color count is neither 1 (single shared color) nor len(poses) (one color per arrow).

func (arrows Arrows) Draw(name string, options ...DrawableOption) *Drawing

Draw wraps the Arrows in a Drawing identified by name. The DrawableOptions control placement (parent frame, pose, center), identity (UUID), and visibility — see DrawableOption for the full set.

type BufferPackedEntry interface {
    // contains filtered or unexported methods
}

BufferPacker provides efficient direct buffer writing for numeric data. The type parameter T must be either float32 or uint8.

type BufferPacker[T BufferPackedEntry] struct {
    // contains filtered or unexported fields
}

func NewBufferPacker[T BufferPackedEntry](elementCount, fieldsPerElement int) *BufferPacker[T]

NewBufferPacker creates a new buffer packer with pre-allocated capacity for elementCount items, each with fieldsPerElement fields.

func (packer *BufferPacker[T]) Read() []byte

Read returns the packed buffer as little-endian bytes. For uint8 buffers, returns the buffer directly. For float32 buffers, converts each value to its little-endian byte representation.

func (packer *BufferPacker[T]) Write(values ...T)

Write appends values directly to the buffer at the current offset and advances the offset.

Chunk holds a single chunk of data as a ready-to-send proto.

type Chunk struct {
    // Proto is the drawv1.Drawing payload for this chunk; the first chunk carries
    // the full entity shape, while later chunks carry only the additional data
    // to append.
    Proto *drawv1.Drawing
    // Start is the index of the first element in this chunk relative to the full
    // entity (0 for the first chunk, ChunkSize for the second, and so on).
    Start uint32
    // IsFirst is true only for the first chunk in the stream and signals to
    // senders that the entity should be created (AddEntity) rather than appended
    // to (UpdateEntity).
    IsFirst bool
}

ChunkProgress reports the progress of a chunked entity upload after each chunk has been sent.

type ChunkProgress struct {
    // Index is the zero-based position of the chunk that was just sent.
    Index int
    // Sent is the cumulative number of entity elements (points, vertices, etc.)
    // sent across all chunks so far.
    Sent uint32
    // Total is the total number of elements expected across the entire entity,
    // taken from the Chunks metadata supplied to NewChunkSender.
    Total uint32
    // Done is true once Sent has reached Total.
    Done bool
}

ChunkSender drives the upload of a chunked entity to a draw service. Iteration is caller-paced: each call to Next sends exactly one chunk and returns control to the caller, allowing the caller to throttle, retry, or interleave other work between chunks.

type ChunkSender struct {
    // contains filtered or unexported fields
}

func NewChunkSender(chunker DrawableChunker, client drawv1connect.DrawServiceClient, metadata *drawv1.Chunks, onProgress func(ChunkProgress)) *ChunkSender

NewChunkSender returns a ChunkSender that ferries the given chunker’s output to the supplied draw service client. metadata supplies the chunk-size, total element count, and stride attached to the first chunk. onProgress is invoked after each successful chunk send; pass nil to skip progress reporting.

func (s *ChunkSender) Done() bool

Done reports whether the sender has exhausted its chunk channel; once true, subsequent calls to Next return io.EOF without making any RPCs.

func (s *ChunkSender) Next() error

Next sends the next chunk to the draw service. The first call issues an AddEntity RPC to create the entity (and records the server-assigned UUID for retrieval via UUID); subsequent calls issue UpdateEntity RPCs against that UUID. After each successful send, the configured progress callback (if any) is invoked. Returns io.EOF when every chunk has been sent, or a wrapped RPC error if a send fails.

func (s *ChunkSender) UUID() []byte

UUID returns the entity UUID assigned by the server after the first chunk has been sent. Returns nil if Next has not been called yet, or if the first send failed.

Color represents an RGBA color with 8-bit channels (0-255 range).

type Color struct {
    // R is the red channel value (0-255).
    R   uint8 `json:"r"`
    // G is the green channel value (0-255).
    G   uint8 `json:"g"`
    // B is the blue channel value (0-255).
    B   uint8 `json:"b"`
    // A is the alpha (transparency) channel value (0-255, where 0 is fully transparent and 255 is fully opaque).
    A   uint8 `json:"a"`
}

func ColorFromColorRGBA(rgba color.RGBA) Color

ColorFromColorRGBA returns a Color converted from a standard library color.RGBA. It is shorthand for NewColor(WithColorRGBA(rgba)).

func ColorFromHSV(h, s, v float32) Color

ColorFromHSV returns a Color converted from HSV values with full opacity. All parameters must be in the range 0.0-1.0, where h is hue, s is saturation, and v is value/brightness. It is shorthand for NewColor(WithHSV(h, s, v)).

func ColorFromHex(hex string) Color

ColorFromHex returns a Color parsed from a 6-digit RGB hex string, with or without a leading ”#” (e.g., “#FF0000” or “FF0000”). Invalid input falls back to black with full opacity. It is shorthand for NewColor(WithHex(hex)).

func ColorFromName(name string) Color

ColorFromName returns a Color matching the given SVG/CSS color name (e.g., “red”, “magenta”). Unrecognized names produce a zero-valued (transparent black) Color. See https://www.w3.org/TR/SVG11/types.html#ColorKeywords for the complete list. It is shorthand for NewColor(WithName(name)).

func ColorFromRGB(r, g, b uint8) Color

ColorFromRGB returns a Color with the given RGB channels and full opacity. It is shorthand for NewColor(WithRGB(r, g, b)).

func ColorFromRGBA(r, g, b, a uint8) Color

ColorFromRGBA returns a Color with the given RGBA channels. It is shorthand for NewColor(WithRGBA(r, g, b, a)).

func NewColor(options ...colorOption) Color

NewColor creates a new Color with the given options. If no options are provided, returns black with full opacity (0, 0, 0, 255).

func (color Color) SetAlpha(alpha uint8) Color

SetAlpha returns a new Color with the specified alpha value, preserving the RGB values.

func (color Color) SetRGB(r, g, b uint8) Color

SetRGB returns a new Color with the specified RGB values, preserving the original alpha value.

func (color Color) SetRGBA(r, g, b, a uint8) Color

SetRGBA returns a new Color with all RGBA values set.

func (color Color) ToHex() string

ToHex returns the color’s RGB channels as an uppercase hex string in the form “#RRGGBB”. The alpha channel is not included.

ColorChooser cycles through a list of colors, useful for automatically assigning distinct colors to multiple objects. Each call to Next advances an internal counter and wraps around to the start of the palette once the end is reached.

ColorChooser is not safe for concurrent use; callers that share an instance across goroutines must provide their own synchronization.

type ColorChooser struct {
    // contains filtered or unexported fields
}

var (
    // ChromaticColorChooser is a package-level ColorChooser that cycles through all SVG
    // named colors with a perceptible hue. Like all ColorChoosers, it is not safe for
    // concurrent use; create your own instance with NewColorChooser if you need isolated
    // state or a different palette.
    ChromaticColorChooser ColorChooser

    // AchromaticColorChooser is a package-level ColorChooser that cycles through SVG
    // named colors that are achromatic or near-achromatic (whites, grays, and similar
    // low-chroma hues). Like all ColorChoosers, it is not safe for concurrent use.
    AchromaticColorChooser ColorChooser
)

func NewColorChooser(colors []Color) ColorChooser

NewColorChooser returns a ColorChooser that cycles through the given palette in order. If colors is empty, the chooser falls back to a palette built from all SVG named colors.

func (chooser *ColorChooser) Get(count int) []Color

Get returns a slice of the next count colors from the palette, advancing the internal counter by count. A subsequent call to Next or Get continues from where this call left off rather than restarting at the beginning of the palette.

func (chooser *ColorChooser) Next() Color

Next returns the next color in the palette and advances the internal counter, wrapping back to the first color after the end of the palette.

DrawArrowsOption configures color settings for an Arrows constructed via NewArrows. When multiple color options are supplied, the last one wins.

type DrawArrowsOption func(*drawArrowsConfig)

func WithArrowColorPalette(palette []Color, numPoses int) DrawArrowsOption

WithArrowColorPalette generates numPoses per-arrow colors by cycling through the given palette. Pass numPoses equal to the number of poses passed to NewArrows.

func WithPerArrowColors(colors ...Color) DrawArrowsOption

WithPerArrowColors assigns one color per arrow. The number of colors must equal the number of poses passed to NewArrows.

func WithSingleArrowColor(color Color) DrawArrowsOption

WithSingleArrowColor uses a single color for every arrow.

DrawConfig holds the resolved configuration produced by NewDrawConfig and consumed by drawing primitives such as NewDrawing and NewTransform. Most callers obtain a DrawConfig via NewDrawConfig rather than constructing one directly.

type DrawConfig struct {
    // UUID is a stable, byte-encoded identifier for the resulting Drawing or Transform.
    UUID []byte
    // Name is the reference-frame name used to identify the Drawing or Transform; it
    // is also used as the geometry/shape label in serialized output.
    Name string
    // Parent is the name of the reference frame this entity is attached to.
    Parent string
    // Pose is the pose of the Drawing or Transform expressed in the parent frame.
    Pose spatialmath.Pose
    // Center is the local center of the Shape within the Drawing's own frame.
    Center spatialmath.Pose
    // ShowAxesHelper requests that the visualizer render an RGB XYZ axes helper at
    // the entity's origin.
    ShowAxesHelper bool
    // Invisible hides the entity from rendering by default; the user can still toggle
    // it on in the visualizer.
    Invisible bool
}

func NewDrawConfig(name string, options ...DrawableOption) *DrawConfig

NewDrawConfig resolves the given options into a DrawConfig.

Defaults applied when options omit a field:

  • Parent: referenceframe.World
  • Pose: identity pose
  • Center: identity pose
  • ShowAxesHelper: true
  • Invisible: false

If neither WithUUID nor WithID is supplied, UUID is derived deterministically from the “name:parent” pair using UUID v5 so that the same name and parent always produce the same UUID.

func (c *DrawConfig) BuildMetadata(opts ...DrawMetadataOption) Metadata

BuildMetadata returns Metadata seeded with the universal fields carried by the DrawConfig (axes helper visibility, invisibility) and overlaid with the given type-specific options. Type-specific options that touch the same fields take precedence over the universal defaults.

DrawFrameSystemOption configures color overrides for a DrawnFrameSystem.

type DrawFrameSystemOption func(*drawnFrameSystemConfig)

func WithFrameSystemColor(frameName string, color Color) DrawFrameSystemOption

WithFrameSystemColor sets or overrides the color for a single frame, leaving other frames’ entries untouched.

func WithFrameSystemColors(colors map[string]Color) DrawFrameSystemOption

WithFrameSystemColors replaces the entire frame-to-color map. Any earlier per-frame entries set via WithFrameSystemColor are discarded; combine the two by listing WithFrameSystemColors first, then WithFrameSystemColor.

DrawFramesOption configures a DrawnFrames produced by NewDrawnFrames. When multiple options touch the same field, the last option in the argument list wins.

type DrawFramesOption func(*drawnFramesConfig)

func WithFramesColors(colors map[string]Color) DrawFramesOption

WithFramesColors sets per-frame render colors keyed by frame name. Frames not present in the map fall back to DefaultFrameColor.

DrawGeometriesInFrameOption configures color and downscaling settings for a DrawnGeometriesInFrame produced by NewDrawnGeometriesInFrame. When multiple options touch the same field, the last option in the argument list wins.

type DrawGeometriesInFrameOption func(*drawnGeometriesInFrameConfig)

func WithGeometriesColorPalette(palette []Color, numGeometries int) DrawGeometriesInFrameOption

WithGeometriesColorPalette generates numGeometries per-geometry colors by cycling through the given palette. Pass numGeometries equal to the number of geometries in the GeometriesInFrame.

func WithGeometriesDownscalingThreshold(threshold float64) DrawGeometriesInFrameOption

WithGeometriesDownscalingThreshold reduces the number of rendered points in any point-cloud geometries in the collection by keeping only points whose mutual distance exceeds threshold (millimeters). A threshold of 0 (the default) disables downscaling. Has no effect on non-point-cloud geometries.

func WithPerGeometriesColors(colors ...Color) DrawGeometriesInFrameOption

WithPerGeometriesColors assigns one color per geometry. The number of colors must equal the number of geometries in the GeometriesInFrame passed to NewDrawnGeometriesInFrame.

func WithSingleGeometriesColor(color Color) DrawGeometriesInFrameOption

WithSingleGeometriesColor renders every geometry in the collection with the given shared color.

DrawGeometryOption configures a DrawnGeometry produced by NewDrawnGeometry. When multiple options touch the same field, the last option in the argument list wins.

type DrawGeometryOption func(*DrawnGeometryConfig)

func WithGeometryColor(color Color) DrawGeometryOption

WithGeometryColor renders the geometry with a single shared color.

func WithGeometryColors(colors ...Color) DrawGeometryOption

WithGeometryColors assigns multiple colors to the geometry. Most simple geometries only honor the first color; point clouds may use one color per vertex when the length matches the point count.

func WithGeometryDownscaling(threshold float64) DrawGeometryOption

WithGeometryDownscaling reduces the number of rendered points by keeping only points whose mutual distance exceeds threshold (millimeters). A threshold of 0 (the default) disables downscaling. The option is only honored when the geometry is a point cloud; it is ignored for other geometry types.

Note: the underlying algorithm is O(n^2) in the input point count, so large Note: the underlying algorithm is O(n^2) in the input point count, so small thresholds (which retain more points) on dense clouds can be slow.

DrawLineOption configures geometry, sizing, and color settings for a Line constructed via NewLine. When multiple options touch the same field, the last option in the argument list wins.

type DrawLineOption func(*drawLineConfig)

func WithDotColorPalette(palette []Color, numPositions int) DrawLineOption

WithDotColorPalette creates a line option that sets colors for vertex dots by cycling through a palette. The palette is repeated to fill numPositions colors.

func WithDotSize(size float32) DrawLineOption

WithDotSize creates a line option that sets the size of vertex dots in millimeters.

func WithLineColorPalette(palette []Color, numPositions int) DrawLineOption

WithLineColorPalette creates a line option that sets colors for line segments by cycling through a palette. The palette is repeated to fill numPositions colors.

func WithLineWidth(width float32) DrawLineOption

WithLineWidth creates a line option that sets the line segment width in millimeters.

func WithPerDotColors(colors ...Color) DrawLineOption

WithPerDotColors creates a line option that sets one color per vertex dot.

func WithPerLineColors(colors ...Color) DrawLineOption

WithPerLineColors creates a line option that sets one color per vertex for line segments.

func WithSingleDotColor(color Color) DrawLineOption

WithSingleDotColor creates a line option that sets a single color for all vertex dots.

func WithSingleLineColor(color Color) DrawLineOption

WithSingleLineColor creates a line option that sets a single color for all line segments.

DrawMetadataOption configures a Metadata. Options accumulate; later options that set the same field overwrite earlier ones. Used by NewMetadata, NewDrawing, and NewTransform (via DrawConfig.BuildMetadata).

type DrawMetadataOption func(*drawMetadataConfig)

func MetadataOptionsFromProto(md *drawv1.Metadata) []DrawMetadataOption

MetadataOptionsFromProto converts a *drawv1.Metadata proto into a slice of DrawMetadataOption. Nil input returns nil options. Fields that are unset in the proto are skipped.

func WithMetadataAxesHelper(show bool) DrawMetadataOption

WithMetadataAxesHelper toggles the RGB XYZ axes helper at the entity’s origin.

func WithMetadataColors(colors ...Color) DrawMetadataOption

WithMetadataColors sets the Colors field on the resulting Metadata. Pass either a single color (applied to all components) or one color per component; the component-count interpretation is geometry-specific.

func WithMetadataInvisible(invisible bool) DrawMetadataOption

WithMetadataInvisible hides the entity from rendering by default when set to true; the user can still toggle visibility on in the visualizer.

func WithMetadataRelationships(relationships []*drawv1.Relationship) DrawMetadataOption

WithMetadataRelationships attaches links to other entities (such as parent/child references) used by the visualizer’s relationship inspector.

DrawModelAssetOption configures optional fields on a ModelAsset constructed via NewURLModelAsset or NewBinaryModelAsset.

type DrawModelAssetOption func(*drawModelAssetConfig)

func WithModelAssetSizeBytes(sizeBytes uint64) DrawModelAssetOption

WithModelAssetSizeBytes records the expected payload size of the asset. The visualizer uses this value for progress reporting while the asset loads; it does not validate the payload against the size.

DrawModelOption configures asset, scale, and animation settings for a Model constructed via NewModel. When multiple options touch the same field, the last option in the argument list wins.

type DrawModelOption func(*drawModelConfig)

func WithModelAnimationName(animationName string) DrawModelOption

WithModelAnimationName selects an animation embedded in the model assets to play on render. The empty string (the default) disables animation playback.

func WithModelAssets(assets ...*ModelAsset) DrawModelOption

WithModelAssets sets the list of assets to attach to the model. Repeated calls replace (not append to) the previous list. NewModel requires at least one asset.

func WithModelScale(scale r3.Vector) DrawModelOption

WithModelScale sets the model’s per-axis scaling factor. Defaults to DefaultModelScale (1.0 on each axis). NewModel rejects scales with any zero axis.

DrawNurbsOption configures degree, weights, line width, and color settings for a Nurbs constructed via NewNurbs. When multiple options touch the same field, the last option in the argument list wins.

type DrawNurbsOption func(*drawNurbsConfig)

func WithNurbsColors(defaultColor Color, perPointColors ...Color) DrawNurbsOption

WithNurbsColors sets the curve’s color. defaultColor is required and serves as the curve color when used alone; the variadic perPointColors are appended and stored for forward compatibility with per-control-point coloring. Currently only the first color is rendered; pass len(controlPoints) values total if you want to satisfy the per-control-point validation in NewNurbs. Defaults to DefaultNurbsColor (cyan).

func WithNurbsDegree(degree int32) DrawNurbsOption

WithNurbsDegree sets the polynomial degree of the curve. Higher degrees produce smoother curves but require more control points and a longer knot vector (len(controlPoints) + degree + 1). Defaults to DefaultNurbsDegree (3, cubic).

func WithNurbsLineWidth(width float32) DrawNurbsOption

WithNurbsLineWidth sets the rendered thickness of the curve in millimeters. Defaults to DefaultLineWidth (5mm).

func WithNurbsWeights(weights []float64) DrawNurbsOption

WithNurbsWeights sets one weight per control point. Higher weights pull the curve closer to that control point. The number of weights must equal the number of control points passed to NewNurbs. Defaults to 1.0 for every control point (uniform weighting).

DrawPointCloudOption configures a DrawnPointCloud produced by NewDrawnPointCloud. When multiple options touch the same field, the last option in the argument list wins.

type DrawPointCloudOption func(*DrawnPointCloudConfig)

func WithPerPointCloudColors(colors ...Color) DrawPointCloudOption

WithPerPointCloudColors assigns one color per point. The number of colors must equal the number of points in the cloud passed to NewDrawnPointCloud.

func WithPointCloudColorPalette(palette []Color, numPoints int) DrawPointCloudOption

WithPointCloudColorPalette generates numPoints per-point colors by cycling through the given palette. Pass numPoints equal to the number of points in the cloud.

func WithPointCloudDownscaling(threshold float64) DrawPointCloudOption

WithPointCloudDownscaling reduces the number of rendered points by keeping only points whose mutual distance exceeds threshold (millimeters). A threshold of 0 (the default) disables downscaling.

Note: the underlying algorithm is O(n^2) in the input point count, so applying downscaling to large clouds can be slow.

func WithSinglePointCloudColor(color Color) DrawPointCloudOption

WithSinglePointCloudColor renders every point in the cloud with the given color.

DrawPointsOption configures sizing and color settings for a Points constructed via NewPoints. When multiple options touch the same field, the last option in the argument list wins.

type DrawPointsOption func(*drawPointsConfig)

func WithPerPointColors(colors ...Color) DrawPointsOption

WithPerPointColors assigns one color per point. The number of colors must equal the number of positions passed to NewPoints.

func WithPointColorPalette(palette []Color, numPoints int) DrawPointsOption

WithPointColorPalette generates numPoints per-point colors by cycling through the given palette. Pass numPoints equal to the number of positions passed to NewPoints.

func WithPointsSize(size float32) DrawPointsOption

WithPointsSize sets the rendered diameter of every point in millimeters.

func WithSinglePointColor(color Color) DrawPointsOption

WithSinglePointColor uses a single color for every point.

DrawService is the in-memory backing store and Connect-RPC handler for the draw service. It keeps every transform and drawing keyed by UUID, persists scene metadata, and fans out add/update/remove events to streaming subscribers.

Chunked drawings (point clouds and similar large entities) are accumulated to disk under a configurable temp directory and served on demand via GetEntityChunk; the rest of the state lives entirely in memory.

All public methods are safe for concurrent use.

type DrawService struct {
    // contains filtered or unexported fields
}

func NewDrawService(tempDir string) *DrawService

NewDrawService returns a DrawService whose chunked-entity payloads are buffered in tempDir. If tempDir is empty, os.TempDir is used. The directory is created if it does not exist and any stale chunk files left over from a previous run are removed at startup. NewDrawService never fails: directory or cleanup errors are logged and the service is returned anyway.

func (svc *DrawService) AddEntity(_ context.Context, req *connect.Request[drawv1.AddEntityRequest]) (*connect.Response[drawv1.AddEntityResponse], error)

AddEntity stores a transform or drawing and returns the assigned UUID. If the incoming entity carries a valid Uuid, that ID is used (replacing any existing entity with the same ID — i.e. upsert); otherwise a fresh UUID is generated.

Drawings whose metadata.chunks field is set are registered as chunked entities: the first call captures the template and the initial chunk, and subsequent chunks must be delivered via UpdateEntity.

Returns InvalidArgument if the entity, transform, or drawing field is missing, and Internal if a chunked entity cannot be initialized on disk.

func (svc *DrawService) CreateRelationship(_ context.Context, req *connect.Request[drawv1.CreateRelationshipRequest]) (*connect.Response[drawv1.CreateRelationshipResponse], error)

CreateRelationship creates or replaces a relationship from the source entity to the target named in the relationship. Relationships are stored in the source entity’s metadata; an existing relationship with the same target_uuid is replaced in place rather than duplicated. The change is published to entity subscribers as an UPDATED event on the source.

Returns InvalidArgument for missing source_uuid, relationship, or target_uuid, when source and target UUIDs are equal, or when a UUID byte slice cannot be parsed; NotFound when either entity does not exist.

func (svc *DrawService) DeleteRelationship(_ context.Context, req *connect.Request[drawv1.DeleteRelationshipRequest]) (*connect.Response[drawv1.DeleteRelationshipResponse], error)

DeleteRelationship removes the relationship from the source entity to target_uuid and publishes an UPDATED event on the source.

Returns InvalidArgument for missing source_uuid or target_uuid, NotFound when the source entity does not exist or no matching relationship is found.

func (svc *DrawService) GetEntityChunk(ctx context.Context, req *connect.Request[drawv1.GetEntityChunkRequest]) (*connect.Response[drawv1.GetEntityChunkResponse], error)

GetEntityChunk returns a single chunk of accumulated data from a chunked entity, starting at the requested element index. The call blocks until enough data has been accumulated to satisfy the request or the entity is marked complete; passing a context with a deadline is the recommended way to bound the wait. The Done flag in the response is set when the returned chunk finishes the entity.

Returns InvalidArgument for a missing or unparseable UUID, NotFound when no chunked entity has the given UUID, Canceled if the context is cancelled before the chunk becomes available, and Internal if the chunk cannot be rebuilt from the on-disk buffer.

func (svc *DrawService) RemoveAll(_ context.Context, _ *connect.Request[drawv1.RemoveAllRequest]) (*connect.Response[drawv1.RemoveAllResponse], error)

RemoveAll removes every transform and drawing entity, releases any associated chunked-entity buffers, and publishes a REMOVED event for each. Returns the number of transforms and drawings removed. Note: unlike RemoveAllTransforms and RemoveAllDrawings, this method does not run the relationship cascade because every entity is being removed.

func (svc *DrawService) RemoveAllDrawings(_ context.Context, _ *connect.Request[drawv1.RemoveAllDrawingsRequest]) (*connect.Response[drawv1.RemoveAllDrawingsResponse], error)

RemoveAllDrawings removes every drawing entity, releases any associated chunked-entity buffers, publishes a REMOVED event for each, and cascades any relationships pointing at the removed drawings. Transforms are left untouched. Returns the number of drawings removed.

func (svc *DrawService) RemoveAllTransforms(_ context.Context, _ *connect.Request[drawv1.RemoveAllTransformsRequest]) (*connect.Response[drawv1.RemoveAllTransformsResponse], error)

RemoveAllTransforms removes every transform entity, publishes a REMOVED event for each, and cascades any relationships pointing at the removed transforms. Drawings are left untouched. Returns the number of transforms removed.

func (svc *DrawService) RemoveEntity(_ context.Context, req *connect.Request[drawv1.RemoveEntityRequest]) (*connect.Response[drawv1.RemoveEntityResponse], error)

RemoveEntity removes the entity with the given UUID and publishes a REMOVED event. If the entity is a chunked drawing, its on-disk buffers are released. Any relationship pointing at the removed entity is dropped from other entities’ metadata, and each affected source emits its own UPDATED event.

Returns InvalidArgument for a missing or unparseable UUID, NotFound when no entity has the given UUID.

func (svc *DrawService) SetScene(_ context.Context, req *connect.Request[drawv1.SetSceneRequest]) (*connect.Response[drawv1.SetSceneResponse], error)

SetScene replaces the current scene metadata and publishes the new metadata to every scene subscriber.

Returns InvalidArgument if scene_metadata is nil.

func (svc *DrawService) StreamEntityChanges(ctx context.Context, _ *connect.Request[drawv1.StreamEntityChangesRequest], stream *connect.ServerStream[drawv1.StreamEntityChangesResponse]) error

StreamEntityChanges streams ADDED, UPDATED, and REMOVED events for every transform and drawing in the scene. On connect, the current world state is replayed as a series of ADDED events so new subscribers see existing entities before live updates begin. The stream ends when the request context is cancelled. Subscriber channels have a bounded buffer; events that would block a slow consumer are dropped and a warning is logged.

func (svc *DrawService) StreamSceneChanges(ctx context.Context, _ *connect.Request[drawv1.StreamSceneChangesRequest], stream *connect.ServerStream[drawv1.StreamSceneChangesResponse]) error

StreamSceneChanges streams every subsequent SetScene call as a scene-changes event. Unlike StreamEntityChanges, the current scene metadata is not replayed on connect. The stream ends when the request context is cancelled.

func (svc *DrawService) UpdateEntity(_ context.Context, req *connect.Request[drawv1.UpdateEntityRequest]) (*connect.Response[drawv1.UpdateEntityResponse], error)

UpdateEntity replaces or partially updates an existing entity identified by UUID. When updated_fields is non-empty, only the listed proto field paths are merged into the stored entity; otherwise the incoming entity replaces the stored one wholesale. The kind of the incoming entity must match the kind of the stored entity (transform vs. drawing).

For chunked drawings, UpdateEntity is also the channel for delivering subsequent chunks: each call appends positions, colors, and opacities to the on-disk buffer for the entity.

Returns InvalidArgument for missing or malformed inputs, NotFound when no entity has the given UUID, and Internal if a chunk cannot be persisted.

DrawableChunker is implemented by any drawable type that can produce its data as a series of chunks for progressive delivery.

type DrawableChunker interface {
    // ChunkSize returns the number of elements per chunk.
    ChunkSize() uint32
    // TotalElements returns the total number of elements across all chunks.
    TotalElements() uint32
    // NumChunks returns the number of chunks that will be produced.
    NumChunks() int
    // Chunks returns a channel that yields each chunk. The channel is closed
    // when all chunks have been sent.
    Chunks() <-chan Chunk
}

DrawableOption configures shared identity, placement, and rendering settings for a drawable entity. It is accepted by NewDrawConfig and by the Draw method on every drawable primitive (Arrows, Line, Points, Nurbs, Model, DrawnGeometry, and DrawnPointCloud). When the same field is set by multiple options, the last option in the argument list wins.

type DrawableOption func(*drawableConfig)

func WithAxesHelper(show bool) DrawableOption

WithAxesHelper controls whether the visualizer renders an RGB XYZ axes helper at the entity’s origin. Defaults to true.

func WithCenter(center spatialmath.Pose) DrawableOption

WithCenter sets the local center of the Shape within the Drawing’s own frame. Defaults to the identity pose.

func WithID(id string) DrawableOption

WithID overrides the auto-generated UUID with one derived deterministically from the given string (UUID v5 over a fixed namespace). The same input always produces the same UUID. If both WithUUID and WithID are provided, the last one to appear in the option list wins.

func WithInvisible(invisible bool) DrawableOption

WithInvisible hides the entity from rendering by default when set to true; the user can still toggle visibility on in the visualizer. Defaults to false.

func WithParent(parent string) DrawableOption

WithParent sets the parent reference frame for the Drawing or Transform. Defaults to referenceframe.World.

func WithPose(pose spatialmath.Pose) DrawableOption

WithPose sets the pose of the Drawing or Transform in the parent reference frame. Defaults to the identity pose (origin, no rotation).

func WithUUID(id []byte) DrawableOption

WithUUID overrides the auto-generated UUID with an explicit byte slice. If both WithUUID and WithID are provided, the last one to appear in the option list wins.

Drawing represents a non-physical visualization in 3D space: a Shape positioned at a Pose within a parent reference frame, plus rendering Metadata such as colors. Drawings are purely visual and do not participate in the frame system as physical geometries.

type Drawing struct {
    // UUID is the stable identifier for this drawing.
    UUID []byte
    // Name is the reference-frame name used to identify this drawing.
    Name string
    // Parent is the name of the reference frame this drawing is attached to.
    Parent string
    // Pose is the pose of this drawing expressed in the parent frame.
    Pose spatialmath.Pose
    // Shape is the geometry rendered by this drawing.
    Shape Shape
    // Metadata carries rendering settings such as colors and visibility.
    Metadata Metadata
}

func NewDrawing(config *DrawConfig, shape Shape, metadataOpts ...DrawMetadataOption) *Drawing

NewDrawing returns a Drawing whose identity, placement, and universal metadata fields are taken from config. Type-specific metadata can be overlaid via metadataOpts; see DrawConfig.BuildMetadata for the precedence rules.

func (drawing Drawing) ToProto() *drawv1.Drawing

ToProto converts the Drawing to a drawv1.Drawing proto message. The Shape is serialized via Shape.ToProto, which may be nil if the shape carries no geometry.

DrawnFrameSystem renders an entire reference frame system — every frame and the geometries attached to each — as a flat list of transforms. Frames inherit their render color from a parent frame when no explicit color is provided; the root fallback is magenta.

type DrawnFrameSystem struct {
    // ID is an optional identity prefix included in each emitted transform's
    // UUID derivation. When non-empty, identities are derived from
    // "ID:label:parent" rather than the default "label:parent", which
    // namespaces transforms across batches that share frame or geometry names
    // (e.g., two robots in the same scene). ID does not affect visible labels.
    ID  string
    // FrameSystem is the reference frame system to render.
    FrameSystem *referenceframe.FrameSystem
    // Inputs are the frame system inputs (joint positions and similar) used to
    // resolve each frame's geometry pose.
    Inputs referenceframe.FrameSystemInputs
    // Colors maps frame names to their render color. Frames not present in the map
    // inherit from their parent frame, falling back to magenta at the root.
    Colors map[string]Color
}

func NewDrawnFrameSystem(frameSystem *referenceframe.FrameSystem, inputs referenceframe.FrameSystemInputs, options ...DrawFrameSystemOption) *DrawnFrameSystem

NewDrawnFrameSystem returns a DrawnFrameSystem that will render frameSystem at the configuration described by inputs. Every frame is initially assigned magenta as its color; pass WithFrameSystemColors or WithFrameSystemColor to override.

func (drawnFrameSystem *DrawnFrameSystem) ToTransforms(options ...DrawableOption) ([]*commonv1.Transform, error)

ToTransforms returns a flat slice of transforms covering every geometry attached to every frame in the frame system, sorted by frame name. Each emitted transform is labelled “frameName:geometryLabel”. Of the supplied DrawableOptions, only WithParent is honored (it sets the parent reference frame for every emitted transform; defaults to referenceframe.World). Returns an error if frame system resolution or per-frame transform construction fails.

DrawnFrames is a collection of reference frames rendered as transforms in the visualizer. A frame with no geometry renders as a bare coordinate-axes helper at the frame’s pose; a frame with geometry renders one transform per geometry, with the geometry labels prefixed by “frameName:”.

type DrawnFrames struct {
    // ID is an optional identity prefix included in each emitted transform's
    // UUID derivation. When non-empty, identities are derived from
    // "ID:frameName:parent" (or "ID:label:parent" for the inner geometry
    // transforms) rather than the default "frameName:parent" /
    // "label:parent", which namespaces transforms across batches that share
    // frame or geometry names. ID does not affect visible labels.
    ID  string
    // Frames are the reference frames to render.
    Frames []referenceframe.Frame
    // Colors maps frame names to their render color. Frames not present in the map
    // fall back to DefaultFrameColor.
    Colors map[string]Color
}

func NewDrawnFrames(frames []referenceframe.Frame, options ...DrawFramesOption) *DrawnFrames

NewDrawnFrames returns a DrawnFrames over the given reference frames. When no WithFramesColors option is supplied, every frame renders with DefaultFrameColor.

func (drawnFrames *DrawnFrames) ToTransforms(options ...DrawableOption) ([]*commonv1.Transform, error)

ToTransforms returns a flat slice of transforms covering every frame in the collection. A frame with no geometry contributes a single bare-axes transform named after the frame; a frame with geometry contributes one transform per geometry, each labelled “frameName:geoLabel”. Each transform’s identity is derived from “frameName:parent” (or “label:parent” for the inner geometry transforms), with DrawnFrames.ID prepended when non-empty. The supplied DrawableOptions configure the parent frame and root pose used as the basis for every emitted transform; per-call UUID overrides on the options have no effect. Returns an error if any frame’s transform or geometry resolution fails.

DrawnGeometriesInFrame wraps a referenceframe.GeometriesInFrame as a set of DrawnGeometry values that share a common parent frame, ready to be emitted as transforms.

type DrawnGeometriesInFrame struct {
    // ID is an optional identity prefix included in each emitted transform's
    // UUID derivation. When non-empty, each transform's identity is derived
    // from "ID:label:parent" rather than the default "label:parent", which
    // namespaces transforms across batches that share geometry labels and a
    // parent frame (e.g., two robots whose link geometries collide on label).
    // ID does not affect visible labels.
    ID  string
    // Name is an optional prefix applied to each emitted transform's label. When
    // non-empty, each transform is labelled "Name:geometryLabel"; when empty, the
    // raw geometry label is used.
    Name string
    // Parent is the parent reference frame the geometries are expressed in.
    Parent string
    // DrawnGeometries holds the individual geometries plus their per-geometry
    // render colors.
    DrawnGeometries []*DrawnGeometry
}

func NewDrawnGeometriesInFrame(geometriesInFrame *referenceframe.GeometriesInFrame, options ...DrawGeometriesInFrameOption) (*DrawnGeometriesInFrame, error)

NewDrawnGeometriesInFrame returns a DrawnGeometriesInFrame wrapping every geometry in geometriesInFrame as a colored DrawnGeometry. Returns an error if the configured color count is neither 1 (shared color) nor equal to the number of geometries, or if any per-geometry construction fails (e.g., point-cloud downscaling errors).

func (drawnGeometriesInFrame *DrawnGeometriesInFrame) ToTransforms(options ...DrawableOption) ([]*commonv1.Transform, error)

ToTransforms returns one transform per geometry in the collection. Each transform’s label is the geometry label, optionally prefixed with the receiver’s Name field — see DrawnGeometriesInFrame.Name for the prefixing rules. Each transform’s identity is derived from “label:parent”, or “ID:label:parent” when DrawnGeometriesInFrame.ID is non-empty. The supplied DrawableOptions configure the parent frame and pose used as the basis for every emitted transform; per-call UUID overrides on the options have no effect. Returns an error if any geometry’s transform construction fails.

DrawnGeometry pairs a spatialmath.Geometry with the colors used to render it. It is the input to NewTransform via DrawnGeometry.Draw, which makes the geometry participate in the frame system as a physical entity.

type DrawnGeometry struct {
    // Geometry is the underlying spatial geometry to render.
    Geometry spatialmath.Geometry
    // Colors are the colors used to render the geometry. For simple geometries
    // (boxes, spheres, capsules) supply a single color; for complex geometries
    // such as point clouds, supply either a single color or one color per vertex.
    Colors []Color
}

func NewDrawnGeometry(geometry spatialmath.Geometry, options ...DrawGeometryOption) (*DrawnGeometry, error)

NewDrawnGeometry returns a DrawnGeometry wrapping the given geometry. For non-point-cloud geometries, options other than colors are ignored. For point clouds, a positive WithGeometryDownscaling threshold downsamples the cloud and converts it to a basic octree before storage. Returns an error if the threshold is negative or if octree conversion fails.

func (drawnGeometry *DrawnGeometry) Draw(name string, options ...DrawableOption) (*commonv1.Transform, error)

Draw wraps the DrawnGeometry in a Transform identified by name. If name is empty, the geometry’s existing label is used. The DrawableOptions control placement (parent frame, pose, center), identity (UUID), and visibility — see DrawableOption for the full set.

The error return is currently always nil; it is kept for symmetry with DrawnPointCloud.Draw, where octree conversion can fail.

DrawnGeometryConfig is the resolved option state used internally by NewDrawnGeometry. Most callers do not construct it directly; build a DrawnGeometry by passing DrawGeometryOption values to NewDrawnGeometry instead.

type DrawnGeometryConfig struct {
    // contains filtered or unexported fields
}

DrawnPointCloud pairs a point cloud with the colors used to render it. It is the input to NewTransform via DrawnPointCloud.Draw, which makes the cloud participate in the frame system as a physical entity.

type DrawnPointCloud struct {
    // PointCloud is the underlying point cloud to render.
    PointCloud pointcloud.PointCloud
    // Colors are the colors used to render the cloud. Supply either a single color
    // (applied to every point) or one color per point. If empty, the cloud's
    // per-point color data is used by the visualizer.
    Colors []Color
}

func NewDrawnPointCloud(pointCloud pointcloud.PointCloud, options ...DrawPointCloudOption) (*DrawnPointCloud, error)

NewDrawnPointCloud returns a DrawnPointCloud wrapping the given cloud. A positive WithPointCloudDownscaling threshold downsamples the cloud before storage; a threshold of 0 stores the input unchanged. Returns an error if the threshold is negative or if downscaling fails.

func (drawnPointCloud *DrawnPointCloud) Draw(name string, options ...DrawableOption) (*commonv1.Transform, error)

Draw wraps the DrawnPointCloud in a Transform identified by name. The point cloud is converted to a basic octree before serialization. The DrawableOptions control placement (parent frame, pose, center), identity (UUID), and visibility — see DrawableOption for the full set. Returns an error if octree conversion fails.

DrawnPointCloudConfig is the resolved option state used internally by NewDrawnPointCloud. Most callers do not construct it directly; build a DrawnPointCloud by passing DrawPointCloudOption values to NewDrawnPointCloud instead.

type DrawnPointCloudConfig struct {
    // contains filtered or unexported fields
}

Line represents a polyline (connected line segments) in 3D space, with optional visible dots at each vertex. Useful for drawing paths, trajectories, or connected geometric shapes.

type Line struct {
    // Positions defines the vertices of the line in sequence.
    Positions []r3.Vector

    // LineWidth specifies the thickness of the line segments in millimeters (default: 5mm).
    LineWidth float32

    // DotSize specifies the size of dots rendered at each vertex in millimeters (default: 10mm).
    DotSize float32

    // Colors specifies the colors used for rendering the line segments (default: [blue]).
    // Can be a single color (applied to all segments) or one color per vertex.
    Colors []Color

    // DotColors specifies the colors used for rendering the vertex dots (default: [dark blue]).
    // Can be a single color (applied to all dots) or one color per dot.
    DotColors []Color
}

func NewLine(positions []r3.Vector, options ...DrawLineOption) (*Line, error)

NewLine creates a new Line from the given vertex positions and optional configuration. Returns an error if there are fewer than 2 positions, if the dot size is non-positive, if the line width is non-positive, or if color slice lengths are invalid (must be 1 or equal to number of positions).

func (line Line) Draw(name string, options ...DrawableOption) *Drawing

Draw wraps the Line in a Drawing identified by name. The DrawableOptions control placement (parent frame, pose, center), identity (UUID), and visibility — see DrawableOption for the full set.

Metadata carries the auxiliary rendering information attached to a Drawing or Transform, including per-component colors, axes-helper visibility, default visibility, and inter-entity relationships.

type Metadata struct {
    // Colors holds either a single fill color or one color per geometry component.
    // The exact interpretation depends on the geometry type; see each primitive's
    // documentation.
    Colors []Color
    // ShowAxesHelper controls whether the visualizer renders an RGB XYZ axes helper
    // at the entity's origin.
    ShowAxesHelper bool
    // Invisible hides the entity from rendering by default; the user can still
    // toggle visibility on in the visualizer.
    Invisible bool
    // Relationships expresses links to other entities (such as parent/child
    // references) consumed by the visualizer's relationship inspector.
    Relationships []*drawv1.Relationship
}

func NewMetadata(options ...DrawMetadataOption) Metadata

NewMetadata returns a Metadata configured by the given options. With no options, the result is the zero-value Metadata: empty Colors, ShowAxesHelper false, Invisible false, and nil Relationships.

func StructToMetadata(structPb *structpb.Struct) (Metadata, error)

StructToMetadata converts a Protocol Buffer structpb.Struct to a Metadata object.

func (metadata *Metadata) SetColors(colors []Color)

SetColors replaces the Colors field on the metadata.

func (metadata *Metadata) SetInvisible(invisible bool)

SetInvisible replaces the Invisible field on the metadata.

func (metadata *Metadata) SetRelationships(relationships []*drawv1.Relationship)

SetRelationships replaces the Relationships field on the metadata.

func (metadata *Metadata) SetShowAxesHelper(show bool)

SetShowAxesHelper replaces the ShowAxesHelper field on the metadata.

func (metadata Metadata) ToProto() *drawv1.Metadata

ToProto converts the Metadata to a drawv1.Metadata proto message. When every color shares the same alpha channel, the opacity is stored as a single byte; otherwise, one opacity byte per color is stored.

Model represents a 3D model in various formats (GLB, GLTF, PLY, PCD, etc.). Models can have multiple assets (textures, meshes) and support animations and scaling.

type Model struct {
    // Assets contains the model files and associated resources (textures, etc.).
    Assets []*ModelAsset

    // Scale specifies the scaling factors for each axis (default: [1.0, 1.0, 1.0]).
    Scale r3.Vector

    // AnimationName specifies which animation to play (empty string means no animation).
    AnimationName string
}

func NewModel(options ...DrawModelOption) (*Model, error)

NewModel returns a Model assembled from the given options. Defaults: empty asset list (which causes NewModel to fail), Scale = DefaultModelScale, AnimationName = "". Returns an error if no assets were supplied via WithModelAssets, or if any scale axis is zero.

func (model Model) Draw(name string, options ...DrawableOption) *Drawing

Draw wraps the Model in a Drawing identified by name. The DrawableOptions control placement (parent frame, pose, center), identity (UUID), and visibility — see DrawableOption for the full set.

ModelAsset represents a 3D model asset sourced from either a URL or inline binary data. Use NewURLModelAsset or NewBinaryModelAsset to construct one; that path guarantees exactly one of URLContent or DataContent is populated. Common formats include GLB, GLTF, PLY, and PCD.

type ModelAsset struct {
    // MimeType is the IANA media type of the asset (e.g., "model/gltf-binary").
    MimeType string
    // SizeBytes is the expected payload size in bytes; the visualizer uses it for
    // progress reporting during asset loading. Optional.
    SizeBytes *uint64
    // URLContent is the URL the visualizer should fetch the asset from. Mutually
    // exclusive with DataContent.
    URLContent *string
    // DataContent is the inline binary payload. Mutually exclusive with URLContent.
    DataContent *[]byte
}

func NewBinaryModelAsset(mimeType string, binaryContent []byte, options ...DrawModelAssetOption) (*ModelAsset, error)

NewBinaryModelAsset returns a ModelAsset that carries the given inline binary payload (e.g., an embedded file or a file read from disk). mimeType should be the asset’s IANA media type (e.g., “model/gltf-binary” for GLB). Returns an error if binaryContent is empty.

func NewURLModelAsset(mimeType string, url string, options ...DrawModelAssetOption) (*ModelAsset, error)

NewURLModelAsset returns a ModelAsset that points at a 3D model fetched from url. mimeType should be the asset’s IANA media type (e.g., “model/gltf-binary” for GLB). Returns an error if url is empty.

Nurbs represents a Non-Uniform Rational B-Spline (NURBS) curve in 3D space. NURBS curves are defined by control points, weights, a knot vector, and a polynomial degree. They are commonly used to represent smooth, curved paths and surfaces.

type Nurbs struct {
    // ControlPoints defines the poses that influence the curve's shape.
    ControlPoints []spatialmath.Pose

    // Knots is the knot vector that determines parameter values along the curve.
    // Length must equal len(ControlPoints) + Degree + 1.
    Knots []float64

    // Degree specifies the polynomial degree of the curve (default: 3 for cubic).
    Degree int32

    // Weights controls the influence of each control point on the curve.
    // Defaults to 1.0 for each control point (uniform weighting).
    Weights []float64

    // Colors specifies the rendering colors for the curve. Currently the visualizer
    // only honors a single shared color; per-control-point colors are accepted by
    // NewNurbs but not yet rendered as a gradient.
    Colors []Color

    // LineWidth specifies the thickness of the line segments in millimeters (default: 5mm).
    LineWidth float32
}

func NewNurbs(controlPoints []spatialmath.Pose, knots []float64, options ...DrawNurbsOption) (*Nurbs, error)

NewNurbs returns a Nurbs curve from the given control points, knot vector, and options. Returns an error if controlPoints or knots is empty, if the degree is non-positive, if the configured weights count is non-zero and does not equal len(controlPoints), if the configured colors count is neither 1 nor len(controlPoints), or if len(knots) does not equal len(controlPoints) + degree + 1.

func (nurbs Nurbs) Draw(name string, options ...DrawableOption) *Drawing

Draw wraps the Nurbs in a Drawing identified by name. The DrawableOptions control placement (parent frame, pose, center), identity (UUID), and visibility — see DrawableOption for the full set.

PointCloudChunker is a DrawableChunker that splits a DrawnPointCloud into chunks of points for progressive upload to the draw service. It is the streaming counterpart to DrawnPointCloud.Draw, useful when a cloud is too large to send in a single RPC.

type PointCloudChunker struct {
    // contains filtered or unexported fields
}

func NewPointCloudChunker(pointCloud *DrawnPointCloud, name string, chunkSize int, opts ...DrawableOption) *PointCloudChunker

NewPointCloudChunker returns a PointCloudChunker that streams pointCloud as a series of chunks. name labels the resulting entity in the visualizer. chunkSize sets the maximum number of points per chunk; pass 0 (or any non-positive value) to use the package default. opts apply to the resulting entity as a whole — see DrawableOption for the supported set.

func (chunker *PointCloudChunker) Chunks() <-chan Chunk

Chunks returns a channel that yields each chunk in order. The channel is closed when all chunks have been produced; chunk-generation errors are logged and cause the channel to close early.

func (chunker *PointCloudChunker) NumChunks() int

NumChunks returns the number of chunks that will be produced.

func (chunker *PointCloudChunker) TotalElements() uint32

TotalElements returns the total number of points in the underlying cloud.

Points represents a point cloud or set of discrete points in 3D space. Useful for visualizing sensor data, waypoints, or sparse 3D data.

type Points struct {
    // Positions defines the location of each point.
    Positions []r3.Vector

    // PointSize specifies the size of each point in millimeters (default: 10mm).
    PointSize float32

    // Colors specifies the color for each point. Can be a single color (applied to all points)
    // or one color per point.
    Colors []Color
}

func NewPoints(positions []r3.Vector, options ...DrawPointsOption) (*Points, error)

NewPoints returns a Points at the given positions. Without any color option, every point is rendered with DefaultPointColor at DefaultPointSize. Returns an error if positions is empty, if the configured point size is non-positive, or if the configured color count is neither 1 (shared color) nor len(positions) (per-point colors).

func (points Points) Draw(name string, options ...DrawableOption) *Drawing

Draw wraps the Points in a Drawing identified by name. The DrawableOptions control placement (parent frame, pose, center), identity (UUID), and visibility — see DrawableOption for the full set.

PointsChunker is a DrawableChunker that splits a Points value into chunks of positions for progressive upload to the draw service. It is the streaming counterpart to Points.Draw, useful when a Points value is too large to send in a single RPC.

type PointsChunker struct {
    // contains filtered or unexported fields
}

func NewPointsChunker(points *Points, name string, chunkSize int, opts ...DrawableOption) *PointsChunker

NewPointsChunker returns a PointsChunker that streams points as a series of chunks. name labels the resulting entity in the visualizer. chunkSize sets the maximum number of positions per chunk; pass 0 (or any non-positive value) to use the package default. opts apply to the resulting entity as a whole — see DrawableOption for the supported set.

func (chunker *PointsChunker) Chunks() <-chan Chunk

Chunks returns a channel that yields each chunk in order. The channel is closed when all chunks have been produced; chunk-generation errors are logged and cause the channel to close early.

func (chunker *PointsChunker) NumChunks() int

NumChunks returns the number of chunks that will be produced.

func (chunker *PointsChunker) TotalElements() uint32

TotalElements returns the total number of positions in the underlying Points.

SceneCamera configures the viewpoint for rendering a 3D scene. Set exactly one of PerspectiveCamera or OrthographicCamera; if both are set, PerspectiveCamera wins during proto serialization. Validate (on the parent SceneMetadata) rejects the case where both are nil.

type SceneCamera struct {
    // Position is the camera location in millimeters (world coordinates).
    Position r3.Vector
    // LookAt is the point the camera is aimed at in millimeters (world coordinates).
    LookAt r3.Vector
    // Animated enables camera rotation animation when true.
    Animated bool
    // PerspectiveCamera configures perspective projection (objects appear smaller with distance).
    PerspectiveCamera *drawv1.PerspectiveCamera
    // OrthographicCamera configures orthographic projection (parallel projection, no perspective).
    OrthographicCamera *drawv1.OrthographicCamera
}

func NewSceneCamera(position r3.Vector, lookAt r3.Vector, options ...sceneCameraOption) SceneCamera

NewSceneCamera creates a new camera configuration with the specified position and look-at point (both in millimeters). By default, creates a perspective camera.

func (camera *SceneCamera) ToProto() *drawv1.SceneCamera

ToProto converts the SceneCamera to its drawv1.SceneCamera proto. If PerspectiveCamera is set it is selected as the camera type; otherwise the orthographic camera type is used (even if OrthographicCamera itself is nil).

SceneMetadata contains global configuration for rendering a 3D scene, including camera settings, grid display options, default rendering styles, and visibility flags for different shape types. Sizing fields are in millimeters unless noted.

type SceneMetadata struct {
    // SceneCamera configures the viewpoint used to render the scene.
    SceneCamera SceneCamera
    // Grid toggles the reference grid in the scene.
    Grid bool
    // GridCellSize is the side length of each grid cell in millimeters.
    GridCellSize float32
    // GridSectionSize is the side length of each grid section (a group of cells)
    // in millimeters; section boundaries are typically rendered with thicker lines.
    GridSectionSize float32
    // GridFadeDistance is the world-space distance in millimeters at which the
    // grid fades to transparent.
    GridFadeDistance float32
    // PointSize is the default rendered diameter (millimeters) for entities that
    // do not specify their own point size.
    PointSize float32
    // PointColor is the default color for entities that do not specify their own
    // point color.
    PointColor Color
    // LineWidth is the default rendered thickness (millimeters) for line entities
    // that do not specify their own width.
    LineWidth float32
    // LineDotSize is the default rendered diameter (millimeters) for vertex dots
    // on line entities that do not specify their own dot size.
    LineDotSize float32
    // RenderArmModels controls how robot arm entities are rendered (model only,
    // colliders only, or both).
    RenderArmModels drawv1.RenderArmModels
    // RenderShapes lists the shape categories that are rendered. Categories not
    // listed are hidden.
    RenderShapes []drawv1.RenderShapes
}

func NewSceneMetadata(options ...sceneMetadataOption) SceneMetadata

NewSceneMetadata creates a new scene metadata configuration with sensible defaults (grid enabled, perspective camera, etc.) that can be customized with options.

func (metadata *SceneMetadata) ToProto() *drawv1.SceneMetadata

ToProto converts the SceneMetadata to its Protocol Buffer representation for serialization.

func (metadata *SceneMetadata) Validate() error

Validate checks that all scene metadata values are valid. Returns an error if any values are out of acceptable ranges (e.g., negative sizes) or invalid enum values.

Shape represents a drawable non-physical geometric shape or object in 3D space. A Shape carries exactly one geometry positioned at Center and identified by Label.

Use NewShape to construct a Shape; that path guarantees only one geometry pointer is non-nil. If multiple are set manually, ToProto serializes the first non-nil pointer in the order Arrows, Line, Points, Model, Nurbs.

type Shape struct {
    // Center is the pose of the shape within the parent Drawing's local frame.
    Center spatialmath.Pose
    // Label is a human-readable name for the shape; surfaced in the visualizer UI.
    Label string
    // Arrows, when set, identifies the shape as an Arrows geometry.
    Arrows *Arrows
    // Line, when set, identifies the shape as a Line geometry.
    Line *Line
    // Points, when set, identifies the shape as a Points geometry.
    Points *Points
    // Model, when set, identifies the shape as a 3D Model geometry.
    Model *Model
    // Nurbs, when set, identifies the shape as a NURBS curve geometry.
    Nurbs *Nurbs
}

func NewShape(center spatialmath.Pose, label string, option drawShapeOption) Shape

NewShape creates a new Shape with the given center pose, label, and geometry option. The option must be one of WithArrows, WithLine, WithPoints, WithModel, or WithNurbs.

func (shape Shape) ToProto() *drawv1.Shape

ToProto converts the Shape to a drawv1.Shape proto message. Returns nil if no geometry is set, or for a Model shape if any of its assets has neither URLContent nor DataContent populated.

Snapshot is a self-contained, serializable scene captured at a single point in time: a set of transforms (physical entities in the frame system), a set of drawings (non-physical visualizations), the scene’s render metadata, and a stable UUID. Snapshots are produced by NewSnapshot, populated via the Draw* helpers, and serialized for delivery to the visualizer via MarshalJSON, MarshalBinary, or MarshalBinaryGzip.

type Snapshot struct {
    // contains filtered or unexported fields
}

func NewSnapshot(sceneOptions ...sceneMetadataOption) *Snapshot

NewSnapshot returns an empty Snapshot with a freshly generated UUID and the given scene-metadata options applied. Without any options, the snapshot uses the package-default scene metadata (perspective camera, grid enabled, every shape category visible).

func (snapshot *Snapshot) DrawArrows(name string, parent string, pose spatialmath.Pose, poses []spatialmath.Pose, options ...DrawArrowsOption) error

DrawArrows constructs an Arrows from poses and the supplied DrawArrowsOptions and appends the resulting drawing to the snapshot, positioned at pose within the parent reference frame. Returns the same validation errors NewArrows would return (e.g. mismatched color count).

func (snapshot *Snapshot) DrawFrame(name string, parent string, pose spatialmath.Pose, geometry spatialmath.Geometry, metadata *drawv1.Metadata)

DrawFrame appends a single transform to the snapshot for a named frame attached to parent at pose, optionally carrying an attached geometry. metadata, if non-nil, is converted via MetadataOptionsFromProto and applied to the transform. The transform is given a fresh random UUID.

func (snapshot *Snapshot) DrawFrameSystemGeometries(frameSystem *referenceframe.FrameSystem, inputs referenceframe.FrameSystemInputs, colors map[string]Color) error

DrawFrameSystemGeometries appends a transform per geometry in frameSystem to the snapshot, evaluated at the given inputs. colors maps frame names to render colors; frames not present in the map inherit from their parent (falling back to magenta at the root). Returns an error if frame system resolution fails.

func (snapshot *Snapshot) DrawGeometry(geometry spatialmath.Geometry, pose spatialmath.Pose, parent string, color Color) error

DrawGeometry appends a transform for the given geometry to the snapshot, positioned at pose within the parent reference frame and rendered with color. The transform’s name is taken from the geometry’s existing label. Returns an error if NewDrawnGeometry or the inner Draw call fails.

func (snapshot *Snapshot) DrawLine(name string, parent string, pose spatialmath.Pose, points []r3.Vector, options ...DrawLineOption) error

DrawLine constructs a Line from points and the supplied DrawLineOptions and appends the resulting drawing to the snapshot, positioned at pose within the parent reference frame. Returns the same validation errors NewLine would return (e.g. fewer than 2 points, mismatched color count).

func (snapshot *Snapshot) DrawModel(name string, parent string, pose spatialmath.Pose, options ...DrawModelOption) error

DrawModel constructs a Model from the supplied DrawModelOptions and appends the resulting drawing to the snapshot, positioned at pose within the parent reference frame. Returns the same validation errors NewModel would return (e.g. no assets supplied, zero scale on any axis).

func (snapshot *Snapshot) DrawPoints(name string, parent string, pose spatialmath.Pose, positions []r3.Vector, options ...DrawPointsOption) error

DrawPoints constructs a Points from positions and the supplied DrawPointsOptions and appends the resulting drawing to the snapshot, positioned at pose within the parent reference frame. Returns the same validation errors NewPoints would return (e.g. empty positions, mismatched color count).

func (snapshot *Snapshot) Drawings() []*Drawing

Drawings returns the drawings (non-physical visualizations) the snapshot has accumulated. The returned slice is the snapshot’s own backing storage; callers should not mutate it.

func (snapshot *Snapshot) MarshalBinary() ([]byte, error)

MarshalBinary marshals the snapshot to a compact binary protobuf payload. This is the recommended format when payload size matters but the consumer cannot decompress gzip; otherwise prefer MarshalBinaryGzip.

func (snapshot *Snapshot) MarshalBinaryGzip() ([]byte, error)

MarshalBinaryGzip marshals the snapshot to a gzip-compressed binary protobuf payload. This is the smallest of the three serialization formats and the best choice for transport over the network or storage on disk.

func (snapshot *Snapshot) MarshalJSON() ([]byte, error)

MarshalJSON marshals the snapshot to JSON via protojson, emitting unpopulated fields so the output round-trips faithfully. JSON is the most human-readable format and is convenient for debugging; for delivery to the visualizer, prefer MarshalBinary or MarshalBinaryGzip.

func (snapshot *Snapshot) SceneMetadata() SceneMetadata

SceneMetadata returns the snapshot’s scene-wide render configuration (camera, grid, default styles, and visibility flags).

func (snapshot *Snapshot) ToProto() *drawv1.Snapshot

ToProto converts the snapshot to a drawv1.Snapshot proto, serializing every drawing via Drawing.ToProto and the scene metadata via SceneMetadata.ToProto.

func (snapshot *Snapshot) Transforms() []*commonv1.Transform

Transforms returns the transforms (physical entities in the frame system) the snapshot has accumulated. The returned slice is the snapshot’s own backing storage; callers should not mutate it.

func (snapshot *Snapshot) UUID() []byte

UUID returns the snapshot’s stable identifier as a 16-byte slice.

func (snapshot *Snapshot) Validate() error

Validate checks that the snapshot is well-formed: the receiver itself must be non-nil, the UUID must be exactly 16 bytes, the transforms and drawings slices must be non-nil (empty is fine), every transform must carry a reference frame and an observer-frame pose, every drawing must carry a name and pose, and the scene metadata must pass SceneMetadata.Validate. Returns the first failing condition wrapped with context.

Generated by gomarkdoc