---
title: Automation
description: An automation editor with a flow canvas, node settings, and a run log.
category: TemplateData
status: beta
since: 0.6.0
tags: [template, automation, workflow, flowchart, ocr]
syncStatus: reviewed
verified: false
---

## Usage

### Clipboard OCR → Translate
:::TuffDemoWrapper{demo="TemplateAutomationDemo" code-lang="vue" description="Runs once in view; change a node's settings and press Run again."}
---
code: |
  <script setup lang="ts">
  import { computed, reactive, ref } from 'vue'
  import TemplateFrame from './TemplateFrame.vue'

  const states = reactive({ trigger: 'idle', ocr: 'idle', fallback: 'idle', translate: 'idle', notify: 'idle' })
  const flight = ref<string | null>(null) // the edge carrying the payload right now
  const config = reactive({ ocr: { engine: 'vision', minConfidence: 80 }, translate: { rateLimit: false } })

  const edges = computed(() => [
    ['trigger', 'ocr'], ['ocr', 'translate'], ['ocr', 'fallback'], ['fallback', 'translate'], ['translate', 'notify'],
  ].map(([from, to]) => ({ from, to, dashed: flight.value === `${from}>${to}` })))

  // Pressing Run lays out one cancellable setTimeout chain from the current config
  function run() {
    const reread = OCR_CONFIDENCE < config.ocr.minConfidence
    schedule(0, () => (states.trigger = 'running'))
    schedule(400, () => {
      states.trigger = 'done'
      flight.value = 'trigger>ocr'
    })
    // … recognition, then either the AI re-read or states.fallback = 'skipped' …
  }
  </script>

  <template>
    <TemplateFrame title="Automation" @enter="run">
      <template #default="{ width, height }">
        <TxFlowchart
          :nodes="layout(width, height)" :edges="edges" :height="height - 56"
          :node-width="212" draggable
          @node-move="keepOffset" @node-click="({ id }) => (selected = id)"
        >
          <template #node="{ node }">
            <div class="flow-node" :class="`is-${states[node.id]}`">
              <span class="flow-node__title">{{ titles[node.id] }}</span>
              <TxWorkingIndicator v-if="states[node.id] === 'running'" variant="dots" :show-elapsed="false" />
              <TxStatusBadge v-else-if="states[node.id] === 'done'" size="sm" status="success" text="Done" />
            </div>
          </template>
        </TxFlowchart>

        <aside class="flow__rail">
          <TxFlatSelect v-model="config.ocr.engine">
            <TxFlatSelectItem value="vision" label="Apple Vision" />
            <TxFlatSelectItem value="windows" label="Windows OCR" />
          </TxFlatSelect>
          <TxScrubField v-model="config.ocr.minConfidence" label="≥" :min="50" :max="99" suffix="%" />
          <TxTaskRows variant="list" :rows="taskRows" />
          <TxCodeStream :code="log" :revealed-lines="revealed" :min-height="0" />
        </aside>
      </template>
    </TemplateFrame>
  </template>

  <style scoped>
  /* TxFlowchart's only edge variant is `dashed`; the template uses it for "in flight" */
  .flow :deep(.tx-bui-flowchart__edge.is-dashed) { stroke: var(--tx-bui-accent); }
  @media (prefers-reduced-motion: no-preference) {
    .flow :deep(.tx-bui-flowchart__edge.is-dashed) { animation: march 0.6s linear infinite; }
  }
  @keyframes march { to { stroke-dashoffset: -8; } }
  </style>
---
:::

## Overview

Tuff's screenshot OCR flow as an automation you can edit and run: an AI re-read when native OCR isn't confident enough, then a translation back to the clipboard.

- The first time it scrolls into view it runs once (about 3.3 seconds), and the edges the data travels along move; reduced motion shows the finished run with no timers.
- Click a node to edit it for the next run; set Native OCR's minimum confidence to 94% or more (the sample reads 93%) and the run detours through the AI re-read.
- With Simulate rate limit (429) on the Translate node, translation fails first and succeeds on a retry 600ms later.
- Stop marks the step in progress as cancelled and adds a `cancelled by user` log line.
- Nodes drag and snap to the dot grid; a drag is kept as an offset, so it survives full screen.
- Wide (≥ 960px) shows the run history, four-step progress, and the log pane; in the column and on narrow screens, Node and This run become tabs.

## Customization

- For your own flow, nodes and edges are plain arrays and `flowNodes()` only computes coordinates; edges always run from a node's bottom to the next node's top, so offset branch nodes sideways.
- For a real runner, replace the timed steps in `buildPlan()` with backend events (SSE or WebSocket); each event calls `setNode()` once and appends a log line.
- TxFlowchart has no per-edge styling API: the template borrows `dashed` for "in flight" and keeps the color and motion inside `prefers-reduced-motion: no-preference`.
- TxFlatSelect and the fine-tune card's type menu don't teleport; keep them clear of `overflow: hidden` ancestors and away from the container's bottom edge.

## Related components

| Region | Components | Role |
|---|---|---|
| Top bar | [TxWorkingIndicator](/docs/dev/components/working-indicator), [TxStatusBadge](/docs/dev/components/status-badge), [TxSteps](/docs/dev/components/steps), [TxSwitch](/docs/dev/components/switch), [TxButton](/docs/dev/components/button) | State, progress, and Run / Stop |
| Canvas | [TxFlowchart](/docs/dev/components/flowchart), [TxStatusBadge](/docs/dev/components/status-badge), [TxWorkingIndicator](/docs/dev/components/working-indicator), [TxDotIndicator](/docs/dev/components/dot-indicator) | Five nodes and moving edges |
| Node settings | [TxFlatSelect](/docs/dev/components/flat-select), [TxScrubField](/docs/dev/components/scrub-field), [TxSwitch](/docs/dev/components/switch), [TxFineTuneCard](/docs/dev/components/fine-tune-card), [TxToastPanel](/docs/dev/components/toast-panel) | A form per node |
| This run | [TxTaskRows](/docs/dev/components/task-rows), [TxCodeStream](/docs/dev/components/code-stream) | Step states and run log |
| Run history (wide) | [TxTimeline](/docs/dev/components/timeline) | Recent runs, newest first |
| Log pane (wide) | [TxSplitter](/docs/dev/components/splitter) | Canvas and log heights |
| Completion | [TxToastPanel](/docs/dev/components/toast-panel) | Result card for four seconds |
