Token导航 LogoToken导航TokenDH.com
前端设计只读github未标认证来源可访问clear审计通过

svelte-flowSvelte flow 前端

Agent Skill

用于辅助前端页面、组件、样式和交互逻辑的开发与维护。它适合让 Agent 生成或审查 React、Next.js、Vue、Tailwind、CSS 等相关代码,整理组件结构,或定位布局和性能问题。使用时需要结合项目现有设计系统、路由和构建方式,避免只生成孤立片段;涉及页面改动时,应配合本地预览和构建检查确认视觉效果。

总安装

808

周安装

33

GitHub Stars

4

下载量

259
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:svelte-flow(Svelte flow 前端)
来源仓库:https://github.com/linehaul-ai/linehaulai-claude-marketplace
仓库路径:skills/svelte-flow
安装命令:
npx skills add https://github.com/linehaul-ai/linehaulai-claude-marketplace --skill svelte-flow
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/linehaul-ai/linehaulai-claude-marketplace --skill svelte-flow

简介

Svelte flow 前端技能提供可视化流程支持。

  • 适合工作流和状态机实现。svelte-flow 属于前端设计类 Skill,可作为该场景下的辅助能力补充。
  • 可生成流程图和数据流转代码。适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。
  • 安装前需确认依赖包版本匹配。
  • 注意浏览器兼容性和交互体验。

SKILL.md

Svelte Flow

Expert guide for building node-based UIs with Svelte Flow (@xyflow/svelte).

Installation

npm install @xyflow/svelte

Core Setup

<script lang="ts">
  import { SvelteFlow, Background } from '@xyflow/svelte';
  import '@xyflow/svelte/dist/style.css';

  // Use $state.raw for nodes and edges (Svelte 5)
  let nodes = $state.raw([
    { id: '1', data: { label: 'Node 1' }, position: { x: 0, y: 0 } },
    { id: '2', data: { label: 'Node 2' }, position: { x: 0, y: 100 } }
  ]);

  let edges = $state.raw([
    { id: 'e1-2', source: '1', target: '2' }
  ]);
</script>

<SvelteFlow bind:nodes bind:edges fitView>
  <Background />
</SvelteFlow>

Key Concepts

Nodes

Each node requires:

  • id: Unique identifier
  • position: {x: number, y: number}
  • data: Object with custom properties (typically includes label)
  • Optional: type, style, hidden, width, height, sourcePosition, targetPosition
const node = {
  id: '1',
  type: 'custom',
  position: { x: 100, y: 100 },
  data: { label: 'My Node', color: '#ff0000' },
  style: 'background: #f0f0f0',
  width: 150,
  height: 100
};

Edges

Each edge requires:

  • id: Unique identifier
  • source: Source node ID
  • target: Target node ID
  • Optional: type, label, animated, markerEnd, markerStart, style, hidden
const edge = {
  id: 'e1-2',
  source: '1',
  target: '2',
  type: 'smoothstep',
  label: 'connects to',
  animated: true,
  markerEnd: { type: MarkerType.ArrowClosed }
};

Built-in Types

Edge Types:

  • default: Straight line
  • smoothstep: Smooth 90-degree turns
  • step: Hard 90-degree turns
  • straight: Alias for default
  • bezier: Curved bezier line

Node Types:

  • default: Basic rectangle node
  • input: Node with only source handles
  • output: Node with only target handles

Custom Nodes

<!-- CustomNode.svelte -->
<script lang="ts" module>
  import type { Node, NodeProps } from '@xyflow/svelte';

  export type CustomNodeType = Node<{
    label: string;
    color?: string;
  }>;
</script>

<script lang="ts">
  import { Handle, Position } from '@xyflow/svelte';

  let { data }: NodeProps<CustomNodeType> = $props();
</script>

<div class="custom-node" style:background={data.color}>
  <Handle type="target" position={Position.Left} />
  <div>{data.label}</div>
  <Handle type="source" position={Position.Right} />
</div>

<style>
  .custom-node {
    padding: 10px;
    border-radius: 5px;
    border: 1px solid #ddd;
  }
</style>

Register custom nodes:

<script lang="ts">
  import CustomNode from './CustomNode.svelte';

  const nodeTypes = {
    custom: CustomNode
  };

  let nodes = $state.raw([
    { id: '1', type: 'custom', data: { label: 'Custom', color: '#ff7000' }, position: { x: 0, y: 0 } }
  ]);
</script>

<SvelteFlow bind:nodes {nodeTypes} bind:edges fitView />

Custom Edges

<!-- CustomEdge.svelte -->
<script lang="ts">
  import { BaseEdge, EdgeLabel, getStraightPath, type EdgeProps } from '@xyflow/svelte';

  let { id, sourceX, sourceY, targetX, targetY, label }: EdgeProps = $props();

  let [edgePath, labelX, labelY] = $derived(
    getStraightPath({ sourceX, sourceY, targetX, targetY })
  );
</script>

<BaseEdge {id} path={edgePath} />
{#if label}
  <EdgeLabel x={labelX} y={labelY}>
    <div class="edge-label">{label}</div>
  </EdgeLabel>
{/if}

Path helpers available:

  • getStraightPath()
  • getBezierPath()
  • getSmoothStepPath()

Register custom edges:

<script lang="ts">
  const edgeTypes = {
    custom: CustomEdge
  };
</script>

<SvelteFlow bind:nodes bind:edges {edgeTypes} fitView />

Updating State

Critical: Nodes and edges are immutable. Create new objects to trigger updates.

<script lang="ts">
  // ❌ Won't work - direct mutation
  nodes[0].position.x = 100;

  // ✅ Works - create new array
  nodes = nodes.map((node) => {
    if (node.id === '1') {
      return { ...node, position: { ...node.position, x: 100 } };
    }
    return node;
  });

  // ✅ Also works - using helper from useSvelteFlow
  import { useSvelteFlow } from '@xyflow/svelte';
  const { updateNode } = useSvelteFlow();

  updateNode('1', (node) => ({
    ...node,
    position: { ...node.position, x: 100 }
  }));
</script>

Event Handling

Common event handlers:

<SvelteFlow
  bind:nodes
  bind:edges
  onnodeclick={(event) => console.log('node clicked', event.targetNode)}
  onnodedrag={(event) => console.log('node dragging', event.targetNode)}
  onnodedragstop={(event) => console.log('drag ended', event.targetNode)}
  onedgeclick={(event) => console.log('edge clicked', event.edge)}
  onconnect={(params) => {
    edges = [...edges, { id: `e${params.source}-${params.target}`, ...params }];
  }}
/>

Available events:

  • onnodeclick, onnodedoubleclick
  • onnodedrag, onnodedragstart, onnodedragstop
  • onedgeclick, onedgedoubleclick
  • onconnect, onconnectstart, onconnectend
  • onbeforedelete (async, can prevent deletion)
  • oninit, onmove, onmovestart, onmoveend

Layout Algorithms

Dagre (Hierarchical)

import dagre from '@dagrejs/dagre';
import { Position } from '@xyflow/svelte';

function getLayoutedElements(nodes: Node[], edges: Edge[], direction = 'TB') {
  const dagreGraph = new dagre.graphlib.Graph();
  dagreGraph.setDefaultEdgeLabel(() => ({}));

  const isHorizontal = direction === 'LR';
  dagreGraph.setGraph({ rankdir: direction });

  const nodeWidth = 172;
  const nodeHeight = 36;

  nodes.forEach((node) => {
    dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
  });

  edges.forEach((edge) => {
    dagreGraph.setEdge(edge.source, edge.target);
  });

  dagre.layout(dagreGraph);

  const layoutedNodes = nodes.map((node) => {
    const nodeWithPosition = dagreGraph.node(node.id);
    return {
      ...node,
      targetPosition: isHorizontal ? Position.Left : Position.Top,
      sourcePosition: isHorizontal ? Position.Right : Position.Bottom,
      position: {
        x: nodeWithPosition.x - nodeWidth / 2,
        y: nodeWithPosition.y - nodeHeight / 2,
      },
    };
  });

  return { nodes: layoutedNodes, edges };
}

Advanced Features

Floating Edges

Edges that dynamically connect to the closest point on node boundaries:

<!-- FloatingEdge.svelte -->
<script lang="ts">
  import { BaseEdge, getBezierPath, type EdgeProps } from '@xyflow/svelte';
  import { getEdgeParams } from './utils';

  let { id, source, target, markerEnd }: EdgeProps = $props();

  const { sx, sy, tx, ty, sourcePos, targetPos } = $derived(
    getEdgeParams(source, target)
  );

  let [edgePath] = $derived(
    getBezierPath({
      sourceX: sx,
      sourceY: sy,
      sourcePosition: sourcePos,
      targetX: tx,
      targetY: ty,
      targetPosition: targetPos,
    })
  );
</script>

<BaseEdge {id} path={edgePath} {markerEnd} />

Register with ConnectionMode.Loose:

<script lang="ts">
  import { ConnectionMode } from '@xyflow/svelte';
</script>

<SvelteFlow
  bind:nodes
  bind:edges
  edgeTypes={{ floating: FloatingEdge }}
  connectionMode={ConnectionMode.Loose}
  fitView
/>

Proximity Connect

Auto-connect nodes when dragged close together:

<script lang="ts">
  const MIN_DISTANCE = 150;

  function getClosestEdge(node: Node, nodes: Node[]) {
    const closestNode = nodes.reduce(
      (res, n) => {
        if (n.id !== node.id) {
          const dx = n.position.x - node.position.x;
          const dy = n.position.y - node.position.y;
          const d = Math.sqrt(dx * dx + dy * dy);

          if (d < res.distance && d < MIN_DISTANCE) {
            res.distance = d;
            res.node = n;
          }
        }
        return res;
      },
      { distance: Number.MAX_VALUE, node: null }
    );

    if (!closestNode.node) return null;

    const closeNodeIsSource = closestNode.node.position.x < node.position.x;

    return {
      id: closeNodeIsSource
        ? `${node.id}-${closestNode.node.id}`
        : `${closestNode.node.id}-${node.id}`,
      source: closeNodeIsSource ? closestNode.node.id : node.id,
      target: closeNodeIsSource ? node.id : closestNode.node.id,
      class: 'temp',
    };
  }

  function onNodeDrag({ targetNode: node }) {
    const closestEdge = getClosestEdge(node, nodes);

    edges = edges.filter(e => e.class !== 'temp');

    if (closestEdge && !edges.some(e => e.source === closestEdge.source && e.target === closestEdge.target)) {
      edges = [...edges, closestEdge];
    }
  }

  function onNodeDragStop() {
    edges = edges.map((edge) =>
      edge.class === 'temp' ? { ...edge, class: '' } : edge
    );
  }
</script>

<SvelteFlow
  bind:nodes
  bind:edges
  onnodedrag={onNodeDrag}
  onnodedragstop={onNodeDragStop}
  fitView
/>

Edge Reconnection

Allow users to drag edge endpoints to different nodes:

<!-- ReconnectableEdge.svelte -->
<script lang="ts">
  import {
    BaseEdge,
    EdgeReconnectAnchor,
    getBezierPath,
    type EdgeProps
  } from '@xyflow/svelte';

  let { sourceX, sourceY, targetX, targetY, selected, ...props }: EdgeProps = $props();

  const [edgePath] = $derived(
    getBezierPath({ sourceX, sourceY, targetX, targetY })
  );

  let reconnecting = $state(false);
</script>

{#if !reconnecting}
  <BaseEdge path={edgePath} {...props} />
{/if}

{#if selected}
  <EdgeReconnectAnchor
    bind:reconnecting
    type="source"
    position={{ x: sourceX, y: sourceY }}
  />
  <EdgeReconnectAnchor
    bind:reconnecting
    type="target"
    position={{ x: targetX, y: targetY }}
  />
{/if}

Delete Node and Reconnect Edges

<script lang="ts">
  import { getIncomers, getOutgoers, getConnectedEdges, type OnBeforeDelete } from '@xyflow/svelte';

  const onbeforedelete: OnBeforeDelete = async ({ nodes: deletedNodes }) => {
    let remainingNodes = [...nodes];

    edges = deletedNodes.reduce((acc, node) => {
      const incomers = getIncomers(node, remainingNodes, acc);
      const outgoers = getOutgoers(node, remainingNodes, acc);
      const connectedEdges = getConnectedEdges([node], acc);

      const remainingEdges = acc.filter((edge) => !connectedEdges.includes(edge));

      const createdEdges = incomers.flatMap(({ id: source }) =>
        outgoers.map(({ id: target }) => ({
          id: `${source}->${target}`,
          source,
          target,
        }))
      );

      remainingNodes = remainingNodes.filter((rn) => rn.id !== node.id);

      return [...remainingEdges, ...createdEdges];
    }, edges);

    nodes = remainingNodes;

    return true;
  };
</script>

<SvelteFlow bind:nodes bind:edges {onbeforedelete} fitView />

Components

Controls

<script lang="ts">
  import { SvelteFlow, Controls } from '@xyflow/svelte';
</script>

<SvelteFlow bind:nodes bind:edges fitView>
  <Controls showLock={false} showFitView={true} showZoom={true} />
</SvelteFlow>

MiniMap

<script lang="ts">
  import { SvelteFlow, MiniMap } from '@xyflow/svelte';
</script>

<SvelteFlow bind:nodes bind:edges fitView>
  <MiniMap />
</SvelteFlow>

Background

<script lang="ts">
  import { SvelteFlow, Background, BackgroundVariant } from '@xyflow/svelte';
</script>

<SvelteFlow bind:nodes bind:edges fitView>
  <Background variant={BackgroundVariant.Dots} gap={12} size={1} />
</SvelteFlow>

Variants: Dots, Lines, Cross

Panel (Custom Controls)

<script lang="ts">
  import { SvelteFlow, Panel } from '@xyflow/svelte';
</script>

<SvelteFlow bind:nodes bind:edges fitView>
  <Panel position="top-left">
    <button>Custom Button</button>
  </Panel>
</SvelteFlow>

Positions: top-left, top-center, top-right, bottom-left, bottom-center, bottom-right

Utility Functions

import {
  getConnectedEdges,
  getIncomers,
  getOutgoers,
  addEdge,
  applyEdgeChanges,
  applyNodeChanges
} from '@xyflow/svelte';

// Get edges connected to nodes
const connectedEdges = getConnectedEdges(nodes, edges);

// Get nodes that connect TO a node
const incomers = getIncomers(targetNode, nodes, edges);

// Get nodes that a node connects TO
const outgoers = getOutgoers(sourceNode, nodes, edges);

// Add edge with validation
edges = addEdge(connection, edges);

Store Management (Alternative)

For centralized state:

// store.svelte.js
let nodes = $state.raw([...]);
let edges = $state.raw([...]);

export const getNodes = () => nodes;
export const getEdges = () => edges;
export const setNodes = (newNodes) => nodes = newNodes;
export const setEdges = (newEdges) => edges = newEdges;
<!-- Component.svelte -->
<script>
  import { getNodes, getEdges, setNodes, setEdges } from './store.svelte.js';
</script>

<SvelteFlow bind:nodes={getNodes, setNodes} bind:edges={getEdges, setEdges} />

Export to Image

<script lang="ts">
  import { useSvelteFlow } from '@xyflow/svelte';

  const { toObject, getViewport } = useSvelteFlow();

  async function downloadImage() {
    const { toPng } = await import('html-to-image');
    const dataUrl = await toPng(document.querySelector('.svelte-flow'));
    const a = document.createElement('a');
    a.setAttribute('download', 'flow.png');
    a.setAttribute('href', dataUrl);
    a.click();
  }
</script>

Performance Tips

  • Use $state.raw for nodes and edges (prevents deep reactivity)
  • For large graphs (1000+ nodes), set elevateNodesOnSelect={false} and elevateEdgesOnSelect={false}
  • Use minZoom and maxZoom to limit zoom levels
  • Consider virtualization for extremely large graphs

Common Props

<SvelteFlow
  bind:nodes
  bind:edges
  nodeTypes={customNodeTypes}
  edgeTypes={customEdgeTypes}
  defaultEdgeOptions={{ animated: true, type: 'smoothstep' }}
  connectionLineType={ConnectionLineType.Straight}
  connectionMode={ConnectionMode.Loose}
  fitView
  minZoom={0.1}
  maxZoom={2}
  snapToGrid={true}
  snapGrid={[15, 15]}
  elevateNodesOnSelect={true}
  elevateEdgesOnSelect={true}
  deleteKeyCode="Delete"
  selectionKeyCode="Shift"
  multiSelectionKeyCode="Meta"
  panOnScroll={true}
  zoomOnScroll={true}
  zoomOnDoubleClick={true}
  zoomOnPinch={true}
  panOnDrag={true}
/>

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Antigravity

28.93%
按下载量换算75

Claude Code

23.35%
按下载量换算60

Gemini CLI

15.33%
按下载量换算40

windsurf

11.02%
按下载量换算29

Codex

8.21%
按下载量换算21

OpenCode

3.35%
按下载量换算9

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

只读

该 Skill 主要提供规则、说明或参考内容,本身偏只读;真正读写文件、联网或执行命令仍取决于宿主 Agent 的任务。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

来源信息

继续浏览同类 Skills