> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modulex.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Navigating the workflow canvas

> Move around the ModuleX workflow builder: pan, zoom, fit, and select on the canvas, open the Detail Panel, lock the canvas while you work, and read the on-canvas controls.

export const MediaEmbed = ({id, type = 'screenshot', caption = '', ext, ratio = '16 / 9'}) => {
  const isVideo = type === 'video' || type === 'app_video';
  const resolvedExt = ext || (isVideo ? 'mp4' : type === 'screenshot' ? 'webp' : 'svg');
  const src = 'https://media.modulex.dev/' + id + '.' + resolvedExt;
  const [status, setStatus] = useState('loading');
  const [isDev, setIsDev] = useState(false);
  const [inView, setInView] = useState(false);
  const boxRef = useRef(null);
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const h = window.location.hostname;
    setIsDev(h === 'localhost' || h === '127.0.0.1' || h.endsWith('.mintlify.app'));
  }, []);
  useEffect(() => {
    if (inView) return;
    if (typeof IntersectionObserver === 'undefined') {
      setInView(true);
      return;
    }
    const el = boxRef.current;
    if (!el) return;
    const io = new IntersectionObserver(entries => {
      if (entries.some(e => e.isIntersecting)) {
        setInView(true);
        io.disconnect();
      }
    }, {
      rootMargin: '300px'
    });
    io.observe(el);
    return () => io.disconnect();
  }, [inView]);
  if (status === 'missing') {
    if (!isDev) return null;
    return <div style={{
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      gap: '0.4rem',
      padding: '1rem 1.25rem',
      margin: '1.25rem 0',
      width: '100%',
      aspectRatio: ratio,
      boxSizing: 'border-box',
      border: '1px dashed rgba(128,128,128,0.45)',
      borderRadius: '0.75rem',
      background: 'rgba(128,128,128,0.06)',
      color: 'currentColor',
      fontSize: '0.85rem',
      lineHeight: 1.45
    }}>
        <div style={{
      display: 'flex',
      alignItems: 'center',
      gap: '0.5rem',
      opacity: 0.75
    }}>
          <span aria-hidden="true">🎬</span>
          <code style={{
      fontSize: '0.75rem'
    }}>{id}</code>
          <span style={{
      fontSize: '0.65rem',
      textTransform: 'uppercase',
      letterSpacing: '0.04em',
      padding: '0.1rem 0.4rem',
      borderRadius: '0.4rem',
      background: 'rgba(128,128,128,0.18)'
    }}>
            {type}
          </span>
        </div>
        <div style={{
      opacity: 0.9
    }}>{caption || 'Media not uploaded yet.'}</div>
        <div style={{
      fontSize: '0.7rem',
      opacity: 0.5
    }}>
          Upload to R2 as <code>{id}.{resolvedExt}</code> — preview only, hidden in production.
        </div>
      </div>;
  }
  const mediaStyle = {
    display: status === 'loaded' ? 'block' : 'none',
    width: '100%',
    height: 'auto',
    borderRadius: '0.75rem'
  };
  const media = isVideo ? <video src={inView ? src : undefined} autoPlay loop muted playsInline preload="metadata" onLoadedData={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} /> : <img src={inView ? src : undefined} alt={caption} onLoad={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} />;
  return <figure style={{
    margin: '1.25rem 0'
  }}>
      <div ref={boxRef} style={status === 'loaded' ? {
    width: '100%'
  } : {
    width: '100%',
    aspectRatio: ratio,
    borderRadius: '0.75rem',
    background: 'rgba(128,128,128,0.06)'
  }}>
        {media}
      </div>
      {status === 'loaded' && caption ? <figcaption style={{
    marginTop: '0.5rem',
    textAlign: 'center',
    fontSize: '0.85rem',
    opacity: 0.7
  }}>
          {caption}
        </figcaption> : null}
    </figure>;
};

The canvas is where you lay out a workflow as a graph of [nodes](/workflow-builder/nodes/overview)
connected by edges. This page covers getting around it: panning and zooming,
selecting nodes, opening the Detail Panel to configure a step, and locking the
canvas so you can read a workflow without changing it.

If this is your first time in the builder, start with the
[workflow builder overview](/workflow-builder/overview) for the bigger picture,
then come back here for the controls.

<MediaEmbed id="MX-MEDIA-3010" type="screenshot" caption={"The workflow builder with a small workflow on the canvas, the on-canvas Controls toolbar at the bottom-left, and the Detail Panel open on the right."} />

## What you see on the canvas

<CardGroup cols={2}>
  <Card title="The graph" icon="workflow">
    Your workflow, drawn as nodes joined by edges. Every workflow begins at a
    fixed start node, and each step you add becomes a node you can position and
    connect.
  </Card>

  <Card title="The Controls toolbar" icon="sliders-horizontal">
    A small toolbar at the bottom-left of the canvas with buttons to pan, zoom,
    fit the whole workflow to the screen, and lock the canvas.
  </Card>

  <Card title="The Detail Panel" icon="panel-right">
    The panel on the right that shows the selected node's configuration and tabs
    for the [AI Composer](/workflow-builder/composer), outputs, and run history.
  </Card>

  <Card title="Collaborators" icon="users">
    When teammates are editing the same workflow, you see their live cursors,
    avatars, and a connection indicator. See
    [realtime co-editing](/workflow-builder/realtime-coediting).
  </Card>
</CardGroup>

## Pan, zoom, and fit

You move around the canvas the way you would expect from a map: drag to pan,
scroll or pinch to zoom, and use the toolbar when you want precision.

<Steps>
  <Step title="Pan to move the canvas">
    Turn on **pan mode** with the hand button in the Controls toolbar, then drag
    anywhere on the canvas to slide the whole graph into view. Pan mode is a
    toggle — the button stays highlighted while it is on, and you turn it off the
    same way. With pan mode off, dragging on an empty area lets you draw a
    selection instead.
  </Step>

  <Step title="Zoom in and out">
    Use the **zoom in** (`+`) and **zoom out** (`−`) buttons in the toolbar, or
    scroll and pinch over the canvas. Zooming keeps your current view centered so
    you do not lose your place.
  </Step>

  <Step title="Fit the whole workflow to the screen">
    Click **fit view** (the expand button) to frame the entire workflow at once.
    This is the fastest way to get oriented after panning far away or when you
    open a large workflow. The canvas also fits the view automatically the first
    time a workflow loads.
  </Step>
</Steps>

<Note>
  The canvas has a fixed working area, so you cannot pan or zoom endlessly into
  empty space. If a node ever scrolls out of reach, click **fit view** to bring the
  whole workflow back into frame.
</Note>

## Select and move nodes

<CardGroup cols={2}>
  <Card title="Select a node" icon="mouse-pointer-click">
    Click a node to select it. The node gets a highlight ring, and the Detail
    Panel switches to its **Config** tab so you can edit it.
  </Card>

  <Card title="Deselect" icon="square-dashed">
    Click an empty part of the canvas to deselect the current node and close its
    configuration.
  </Card>

  <Card title="Move a node" icon="move">
    Drag a node to reposition it. Edges follow automatically, and your layout is
    saved as part of the workflow.
  </Card>

  <Card title="Connect nodes" icon="spline">
    Drag from a node's handle to another node to create an edge between them. See
    [variables & references](/workflow-builder/variables-and-references) for how
    data flows along those edges.
  </Card>
</CardGroup>

The start node is always present and marks where every run begins. You can
position it, but you cannot delete it — it is the fixed entry point of the
workflow.

## The Detail Panel

The Detail Panel is the dock on the right of the builder. It is context-aware:
when you select a node it shows that node's settings, and it also holds the other
tools you use while building. Selecting any node opens the **Config** tab
automatically.

<AccordionGroup>
  <Accordion title="Config" icon="settings">
    The node inspector. This is where you set everything about the selected node —
    its name, its model or tool, its inputs, and its configuration. The fields you
    see depend on the [node type](/workflow-builder/nodes/overview). A small dot on
    the tab marks that a node is selected and ready to configure.
  </Accordion>

  <Accordion title="Composer" icon="sparkles">
    The [AI Composer](/workflow-builder/composer) copilot. Describe a change in
    plain language and the Composer edits the graph for you — adding, updating, or
    connecting nodes — then you review and save the result. The Composer tab is
    hidden when you are viewing a workflow you cannot edit.
  </Accordion>

  <Accordion title="Output" icon="terminal">
    The results from your most recent run, node by node. A dot on the tab marks
    that new output is available to read. See
    [running workflows](/workflow-builder/execution/running) for how runs stream
    in live.
  </Accordion>

  <Accordion title="Runs" icon="history">
    The run history for this workflow — past executions you can open and inspect.
    This tab is available even when you are only viewing a workflow.
  </Accordion>
</AccordionGroup>

<Note>
  When you open a workflow in view-only mode, the Detail Panel opens on the
  **Output** tab and the Composer tab is hidden, since you are reading the workflow
  rather than editing it.
</Note>

## Lock the canvas to read without editing

The last button in the Controls toolbar **locks the canvas**. When the canvas is
locked, you can still pan, zoom, and select to look around, but nodes can no
longer be dragged, connected, or selected for editing — so you will not move
anything by accident while you read. Click the button again to unlock and resume
editing.

This is different from a node being locked by a teammate. When someone else is
editing a node in a shared workflow, ModuleX prevents you from changing that same
node at the same time and tells you who has it. For how that works across a team,
see [realtime co-editing](/workflow-builder/realtime-coediting) and
[presence, locks & versioning](/realtime/presence-locks).

## Getting around with mouse and trackpad

<CardGroup cols={2}>
  <Card title="Pan" icon="hand">
    Turn on pan mode and drag, or use the toolbar. On a trackpad you can also
    scroll to move around the canvas.
  </Card>

  <Card title="Zoom" icon="zoom-in">
    Scroll or pinch over the canvas, or use the zoom in and zoom out buttons.
  </Card>

  <Card title="Select" icon="mouse-pointer-2">
    Click a node to select it. With pan mode off, drag on an empty area to draw a
    selection over several nodes.
  </Card>

  <Card title="Remove a selected node" icon="trash-2">
    With a node selected, press your <kbd>Delete</kbd> key to start removing it.
    ModuleX confirms before the node is removed, and the fixed start node is never
    deleted.
  </Card>
</CardGroup>

## Next steps

<CardGroup cols={3}>
  <Card title="Workflow builder overview" icon="layout-dashboard" href="/workflow-builder/overview">
    The big picture of the builder and how the pieces fit together.
  </Card>

  <Card title="Node types" icon="boxes" href="/workflow-builder/nodes/overview">
    The nine kinds of step you can add to the canvas and what each one does.
  </Card>

  <Card title="Build with the Composer" icon="wand-sparkles" href="/workflow-builder/composer">
    Let the AI Composer lay out and edit the canvas from a plain-English request.
  </Card>
</CardGroup>
