Skip to content

Line Overlay

type: line

Connects two overlays (controls, other lines' anchors, or shapes) with a routed SVG line. Supports automatic or manual routing, attachment side control, gap offsets, state-based color, and rich SVG styling including gradients, patterns, arrows, and dash patterns.


Quick Start

yaml
overlays:
  - id: control1
    type: control
    position: [100, 100]
    size: [120, 40]
    card:
      type: custom:lcards-button
      entity: light.living_room

  - id: control2
    type: control
    position: [300, 200]
    size: [120, 40]
    card:
      type: custom:lcards-button
      entity: light.kitchen

  - id: line1
    type: line
    anchor: control1
    attach_to: control2
    style:
      color: var(--lcars-orange)
      width: 2

Properties

FieldTypeDefaultDescription
idstringUnique identifier (required)
typestringMust be line
anchorstringSource overlay ID, anchor name, or [x, y] (required)
attach_tostringDestination overlay ID, anchor name, or [x, y] (required)
anchor_sidestringautoAttachment side on source — see Attachment Points
attach_sidestringautoAttachment side on destination
anchor_gapnumber0Offset in viewBox units from source edge
attach_gapnumber0Offset in viewBox units from destination edge
anchor_gap_xnumberHorizontal-only offset from source (overrides anchor_gap on X)
anchor_gap_ynumberVertical-only offset from source (overrides anchor_gap on Y)
attach_gap_xnumberHorizontal-only offset from destination
attach_gap_ynumberVertical-only offset from destination
routestringautoRouting mode — see Routing Modes
waypointsarrayExplicit coordinate/anchor-name list for manual routing — a coordinate entry may add a 3rd number, [x, y, radius], to override just that corner's corner_radius (see Manual Routing)
route_hintstringautoInitial segment direction: xy (horizontal first) or yx
route_hint_laststringautoFinal segment direction (same values as route_hint)
route_channelslistChannel IDs this line routes through — see Line Routing & Channels
clearancenumberMin clearance around obstacles in viewBox units (overrides global default)
corner_stylestringroundmiter, round, or bevel — for routed corners
corner_radiusnumber34Arc radius (round) or chamfer size (bevel), in viewBox units. manual routing: overridable per corner via waypoints' optional 3rd number
corner_radius_modestringautoauto or forcedround/bevel only; see Corner Size: Target vs. Forced
corner_anglenumber45bevel only: diagonal cut angle, 0–90°
stub_lengthnumberOverrides the mandatory cardinal departure/arrival stub length (viewBox units) — see Corner Size: Target vs. Forced
smoothing_modestringnonenone or chaikin
smoothing_iterationsnumber0Smoothing pass count (0–5)
entitystringEntity to bind style.color / style.fill to (state-color object) — independent of any control's own entity
state_attributestringAttribute whose value is matched against state-color keys instead of the raw entity state (mirrors the button card's state_attribute)
ranges_attributestringAttribute value compared against above:/below:/between: keys (mirrors the button card's ranges_attribute)
z_indexnumber100Stacking order — default paints below controls (200), above base_svg
tagslistTags for rule targeting
styleobjectSVG style — see Styling
animationsarrayanime.js animations — see Animations in MSD

Attachment Points

Lines connect to any of 9 named sides on an overlay (control, or shape of kind rect/circle) — or to a specific vertex (vertex0, vertex1, ...) of a polyline shape. Omit the side fields and the system picks the closest pair automatically.

SideDescription
topTop edge centre
bottomBottom edge centre
leftLeft edge centre
rightRight edge centre
centerExact centre
top-leftTop-left corner
top-rightTop-right corner
bottom-leftBottom-left corner
bottom-rightBottom-right corner

With specific sides

yaml
- id: h_connection
  type: line
  anchor: card_a
  anchor_side: right
  attach_to: card_b
  attach_side: left

In the MSD Studio editor, entering Connect Mode shows these as clickable dots on every control/shape/anchor — click a source point then a target point to create a line prefilled with the correct anchor/attach_to/*_side. Dragging an existing line's endpoint near a valid point snaps onto it the same way.


Gap System

Gaps offset the line endpoint away from the overlay edge.

SideGap direction
leftLeftward (−X)
rightRightward (+X)
topUpward (−Y)
bottomDownward (+Y)
cornersDiagonally outward
yaml
- id: gap_line
  type: line
  anchor: card_a
  anchor_side: right
  anchor_gap: 20          # 20px out from right edge of card_a
  attach_to: card_b
  attach_side: left
  attach_gap: 20          # 20px out from left edge of card_b

For independent axis control use anchor_gap_x / anchor_gap_y (overrides anchor_gap on that axis).


Routing Modes

ModeDescription
autoDefault — resolves to manhattan for simple layouts; upgrades to smart automatically when obstacles or channels are present
directStraight line between endpoints — never pathfinds
manhattanL-shaped single bend
smartA* pathfinding + refinement — obstacle avoidance, trace bundling, crossing avoidance
gridA* pathfinding without the refinement pass
manualExplicit waypoints list

Routed lines automatically bundle with nearby parallel lines and avoid crossing other lines — see Line Routing & Channels for how that works, how to tune it, and how to guide lines with channels. Note that only smart/grid (or upgraded auto) lines participate: plain manhattan lines never bundle or avoid crossings.

route_hint/route_hint_last steer the first/last segment direction for every pathfinding mode (manhattan, smart, grid, and auto once it upgrades to one of those) — not just manhattan. If you don't set them explicitly, anchor_side/attach_side set to left/right/top/bottom auto-derive the equivalent hint (left/right → horizontal, top/bottom → vertical), even when anchor/attach_to is a plain coordinate or named point anchor with no attachment-point geometry of its own — the side still expresses "leave/arrive from this direction." Corner sides (top-left, etc.) and center are ambiguous for a single axis and fall back to an automatic direction based on which axis has the larger distance between the two endpoints.

yaml
# Straight line
- id: direct_line
  type: line
  anchor: card_a
  attach_to: card_b
  route: direct
  style:
    color: var(--lcars-blue)
    width: 2

# L-shaped (good for flowchart-style diagrams)
- id: manhattan_line
  type: line
  anchor: card_a
  anchor_side: bottom
  attach_to: card_b
  attach_side: top
  route: manhattan
  style:
    color: var(--lcars-orange)
    width: 2

# Manual with waypoints
- id: manual_line
  type: line
  anchor: card_a
  attach_to: card_b
  route: manual
  waypoints:
    - [200, 100]
    - [200, 300]
  style:
    color: var(--lcars-green)
    width: 2

See Manual Routing for the full waypoints syntax.


Styling

Stroke

yaml
style:
  color: var(--lcars-orange)    # Color — CSS variable, hex, rgb/rgba, theme: token, or a state-color object (see Dynamic Styling)
  width: 2                      # Thickness in viewBox units
  opacity: 0.8                  # 0–1

stroke / stroke_width (underscore) are accepted as legacy aliases for color / width — new configs should use color/width.

Dash patterns

yaml
style:
  dash_array: "5,5"       # 5px dash, 5px gap — string "5,5" or array [5, 5]
  dash_offset: 0           # Starting offset
  line_cap: round           # round | square | butt — shapes the ends of every dash segment
  line_join: miter          # miter | round | bevel — at path corners
  miter_limit: 4             # Used when line_join: miter

line_cap has no visible effect on a solid stroke's closed shapes (a filled rect/circle border with no dash_array has no open dash ends to cap). But once a dash_array is set, line_cap shapes every individual dash segment — including on closed or curved paths, like a circle's border.

Round dots, not squares: a "dot" made from a non-zero-length dash (e.g. "2,2") with line_cap: round renders as an elongated pill/stadium shape, not a circle — rounding just softens the ends of an already-sized rectangle. For a true circle, use a zero-length dash: dash_array: "0,4" with line_cap: round. A zero-length dash's two round end-caps coincide into a perfect circle whose diameter equals width — so it scales correctly with stroke width, and you get true dots. The Studio dialog's "Dotted" and "Dash-Dot" presets already do this automatically. For widely-spaced circles, use the "Custom" pattern option: set Dash Length to 0, Gap Length to whatever spacing you want, and Line Cap to round.

Fill (self-intersecting/closed paths)

yaml
style:
  fill: var(--lcars-blue)     # literal/token/CSS value, or a state-color object (see Dynamic Styling)
  fill_opacity: 0.3           # 0–1

fill defaults to none. It matters most on shape overlays (rect/circle/closed polyline), where it's the primary way to shade a room/zone — but it applies to any line style resolution the same way.

Gradients

yaml
style:
  gradient:
    stops:
      - { offset: '0%', color: var(--lcars-blue) }
      - { offset: '100%', color: var(--lcars-orange) }

Renders as a standard left-to-right SVG linearGradient built from stops. A shorthand string form is also accepted: gradient: "var(--lcars-blue)-to-var(--lcars-orange)". type/direction fields are accepted in config but not yet applied to the render (always a horizontal linear gradient regardless of value) — don't rely on type: radial or a non-horizontal direction doing anything yet.

Patterns

yaml
style:
  pattern:
    color: var(--lcars-orange)
    size: 8
    opacity: 0.5

Currently always renders as a repeating dot pattern (a 1-viewBox-unit-radius circle tiled at size spacing) regardless of pattern.typetype: lines/diagonal/grid/custom SVG are accepted in config but not yet implemented differently from dots.

Markers (arrows)

yaml
style:
  marker_end:
    type: arrow            # arrow (alias: triangle) | dot | diamond | line | rect (alias: square)
    size: 10                # viewBox units — a plain numeric size, default 10 (not a small/medium/large preset)
    fill: var(--lcars-orange)   # defaults to line color
    stroke: none                # optional outline
    stroke_width: 0
    align: center                # center (default) | edge — 'edge' pins the shape's back edge (not tip) to the endpoint, so a thick line's cap never pokes past a pointed marker

  marker_start:
    type: dot
    size: 6

Both fill and stroke accept the literal string "match_line" to inherit the line's own resolved color, staying in sync as it changes live (entity-bound or templated). Markers always inherit the line's opacity (not opt-in). marker_mid places the same shape at every interior waypoint/corner.


Dynamic Styling

State-based color and fill

style.color and style.fill accept a state-color object, resolved against the line's own entity — the same pipeline used by buttons and sliders:

yaml
overlays:
  - id: status_line
    type: line
    anchor: card_a
    attach_to: card_b
    entity: binary_sensor.link_active
    style:
      color:
        active: var(--lcars-green)
        inactive: var(--lcars-red)
      width: 2
      marker_end:
        type: arrow
        size: 10

state_attribute matches an attribute's value against the state-color keys instead of the raw entity state; ranges_attribute compares an attribute against above:/below:/between: keys — both scoped per-line, independent of any control's own entity.

Templated values

Style fields also accept Jinja2/JS template expressions, evaluated against data sources:

yaml
data_sources:
  link_status:
    type: entity
    entity: binary_sensor.link_active

overlays:
  - id: status_line
    type: line
    anchor: card_a
    attach_to: card_b
    style:
      color: >
        {link_status == 'on' ? 'var(--lcars-green)' : 'var(--lcars-red)'}
      dash_array: >
        {link_status == 'on' ? 'none' : '5,5'}
      width: 2

Animations

Lines accept an animations: array — anime.js triggers/presets, same syntax as control overlays and base_svg.animations:

yaml
- id: power_line
  type: line
  anchor: reactor
  attach_to: bridge
  style:
    color: var(--lcars-blue)
  animations:
    - trigger: on_load
      preset: march
      duration: 1500
      loop: true

See the Animation Preset Reference (docs site → Core → Animations) for the full list of presets and parameters.


Complete Property Reference

yaml
overlays:
  - id: string                    # Required: Unique identifier
    type: line                    # Required: Must be "line"
    anchor: string                # Required: Source overlay ID, anchor name, or [x, y]
    attach_to: string             # Required: Destination overlay ID, anchor name, or [x, y]

    # Attachment Configuration
    anchor_side: string           # Optional: Source side (default: auto)
    attach_side: string           # Optional: Destination side (default: auto)

    # Gap System
    anchor_gap: number            # Optional: Source offset in viewBox units (default: 0)
    attach_gap: number            # Optional: Destination offset in viewBox units (default: 0)
    anchor_gap_x: number          # Optional: Source horizontal offset
    anchor_gap_y: number          # Optional: Source vertical offset
    attach_gap_x: number          # Optional: Destination horizontal offset
    attach_gap_y: number          # Optional: Destination vertical offset

    # Routing
    route: string                 # Optional: Routing mode (default: "auto")
                                  # Options: auto, direct, manhattan, smart, grid, manual
    waypoints:                    # For route: manual
      - [x, y]                    # or [x, y, radius] to override this corner's corner_radius
    route_hint: string            # Optional: xy | yx (default: auto)
    route_hint_last: string       # Optional: xy | yx (default: auto)
    route_channels: [string]      # Optional: channel IDs to route through
    clearance: number             # Optional: obstacle clearance in viewBox units

    # Corner rendering / smoothing (routed corners, and manual waypoint paths)
    corner_style: string          # miter | round | bevel (default: round)
    corner_radius: number         # viewBox units (default: 34)
    corner_radius_mode: string    # auto | forced (default: auto) — round/bevel only
    corner_angle: number          # bevel only, 0-90 (default: 45)
    stub_length: number           # Optional: overrides mandatory cardinal stub length (viewBox units)
    smoothing_mode: string        # none | chaikin (default: none)
    smoothing_iterations: number  # 0-5 (default: 0)

    # State-color binding
    entity: string                 # entity for style.color / style.fill state keys
    state_attribute: string        # match an attribute instead of raw state
    ranges_attribute: string       # attribute for above:/below:/between: keys

    # Visibility & targeting
    z_index: number               # Optional: Stacking order (default: 100)
    tags: [string]                # Optional: Rule targeting tags

    # Styling
    style:                        # Optional styling
      color: string | object      # Line color — literal/token, or state-color object (default: var(--lcars-white))
      width: number                # Line thickness (default: 2)
      opacity: number               # Transparency 0-1 (default: 1.0)
      line_cap: string               # round | square | butt (default: butt)
      line_join: string              # round | miter | bevel (default: miter)
      miter_limit: number            # Miter limit (default: 4)
      dash_array: string | array     # Dash pattern (e.g. "5,5" or [5, 5])
      dash_offset: number            # Dash offset (default: 0)
      fill: string | object          # Fill color — literal/token, or state-color object (default: none)
      fill_opacity: number           # Fill opacity 0-1 (default: 1)
      gradient: object                # { stops: [{offset, color}, ...] } — always linear
      pattern: object                 # { color, size, opacity } — always dots
      animatable: boolean             # Eligible as an animation target (default: true)

      # Markers
      marker_start:               # Start marker
        type: string              # arrow | dot | diamond | line | rect (aliases: triangle, square)
        size: number               # viewBox units (default: 10)
        fill: string               # Marker fill color, or "match_line"
        stroke: string              # Marker outline color, or "match_line"
        stroke_width: number         # Outline thickness
        align: string                 # center (default) | edge
      marker_mid:                 # Mid-point markers (same shape/fields)
      marker_end:                 # End marker (same shape/fields)

    # Animations
    animations:
      - trigger: string             # on_load | on_tap | on_hold | on_hover | on_leave | on_entity_change
        preset: string

See Also