diff --git a/editor-packages/editor-canvas/flow-connections/arrow.tsx b/editor-packages/editor-canvas/flow-connections/arrow.tsx
new file mode 100644
index 00000000..617b2f8f
--- /dev/null
+++ b/editor-packages/editor-canvas/flow-connections/arrow.tsx
@@ -0,0 +1,64 @@
+import React from "react";
+import type { XY } from "../types";
+
+export function Arrow({
+ b,
+ color,
+ size,
+ width,
+ direction,
+}: {
+ b: XY;
+ color: React.CSSProperties["color"];
+ size: number;
+ width: number;
+ direction: "n" | "s" | "e" | "w";
+}) {
+ return (
+
+ );
+}
+
+/**
+ *
+ * the result will have 3 modifiers,
+ * if the arrow is facing right, the modifiers will be:
+ * - M - starting point [edge_x - height, edge_y + width / 2]
+ * - L - edge [edge_x, edge_y]
+ * - L - ending point [edge_x - height, edge_y - width / 2]
+ *
+ * @param edge the edge of a arrow (triangle)
+ * @param width
+ */
+function make_arrow_svg_path_data(
+ edge: XY,
+ direction: "n" | "s" | "e" | "w",
+ { width, height }: { width: number; height: number }
+) {
+ const [x, y] = edge;
+ const w = width / 2;
+ switch (direction) {
+ case "e": {
+ return `M${x - height},${y + w} L${x},${y} L${x - height},${y - w}`;
+ }
+ case "w": {
+ return `M${x + height},${y + w} L${x},${y} L${x + height},${y - w}`;
+ }
+ case "n": {
+ return `M${x - w},${y + height} L${x},${y} L${x + w},${y + height}`;
+ }
+ case "s": {
+ return `M${x - w},${y - height} L${x},${y} L${x + w},${y - height}`;
+ }
+ default: {
+ throw new Error(`invalid direction: ${direction}`);
+ }
+ }
+}
diff --git a/editor-packages/editor-canvas/flow-connections/connection-line-bezier-curved.tsx b/editor-packages/editor-canvas/flow-connections/connection-line-bezier-curved.tsx
new file mode 100644
index 00000000..c3392199
--- /dev/null
+++ b/editor-packages/editor-canvas/flow-connections/connection-line-bezier-curved.tsx
@@ -0,0 +1,84 @@
+import { color_connection_line } from "../theme";
+import type { XY } from "../types";
+import { Arrow } from "./arrow";
+import { get_direction } from "./math";
+import type { ConnectionLineStyleProps } from "./props";
+
+export function BezierCurvedLine({
+ a,
+ b,
+ width = 2,
+ color = color_connection_line,
+}: { a: XY; b: XY } & ConnectionLineStyleProps) {
+ const direction = get_direction(a, b);
+
+ return (
+
+ );
+}
+
+const direction_to_axis_map = {
+ n: "v",
+ s: "v",
+ e: "h",
+ w: "h",
+} as const;
+
+/**
+ * make a svg path data to connect point a to point b
+ *
+ * the output will contain 2 commands
+ * - M - starting point
+ * - C - curve
+ *
+ * e.g. for a a[0, 0], b[1000, 500], (1000x500 box)
+ * - `"M 0 0 C 500 0 500 500 1000 500"`
+ * - M a[0], a[1] (start point)
+ * - C0 a[0] + w / 2, a[1]
+ * - C1 a[0] + w / 2, b[1]
+ * - C2 b[0], b[1] (end point)
+ *
+ * @param a - starting point
+ * @param b - ending point
+ */
+function make_bazier_curved_svg_path_data(a: XY, b: XY, axis: "h" | "v" = "h") {
+ const [x0, y0] = a;
+ const [x1, y1] = b;
+ const w = axis === "h" ? x1 - x0 : y1 - y0;
+
+ if (axis === "h") {
+ return `M ${x0},${y0} C ${x0 + w / 2},${y0} ${
+ x0 + w / 2
+ },${y1} ${x1},${y1}`;
+ } else if (axis === "v") {
+ return `M ${x0},${y0} C ${x0},${y0 + w / 2} ${x1},${
+ y0 + w / 2
+ } ${x1},${y1}`;
+ }
+}
diff --git a/editor-packages/editor-canvas/flow-connections/connection-line-edge-curved.tsx b/editor-packages/editor-canvas/flow-connections/connection-line-edge-curved.tsx
new file mode 100644
index 00000000..85cab50a
--- /dev/null
+++ b/editor-packages/editor-canvas/flow-connections/connection-line-edge-curved.tsx
@@ -0,0 +1,91 @@
+import React from "react";
+import type { XY } from "../types";
+import { Arrow } from "./arrow";
+import { get_direction } from "./math";
+
+/**
+ * @deprecated - not implemented
+ * @param param0
+ * @returns
+ */
+export function EdgeCurvedConnectionLine({
+ a,
+ b,
+ width = 2,
+ color = "blue",
+}: { a: XY; b: XY } & {
+ width?: number;
+ color?: React.CSSProperties["color"];
+}) {
+ const direction = get_direction(a, b);
+ return (
+
+ );
+}
+
+function Line({ a, b }: { a: XY; b: XY }) {
+ return ;
+}
+
+/**
+ *
+ * makes the svg path data that connects point a to point b, with extra parameters, curve delta and edge inset
+ *
+ * the shape looks line
+ * ```
+ * (a) ---
+ * |
+ * |
+ * |
+ * |
+ * |
+ * --- (b)
+ * ```
+ *
+ * the line components are..
+ * 0. M | starting point
+ * 1. L L | the line from `a - edge` to `a` - [a - edge, a]
+ * 2. C | the curve to before 3
+ * 3. L | the line from `a` to `b` - [a, b]
+ * 4. C | the curve to after 3
+ * 5. L L | the line from `b` to `b + edge` - [b, b + edge]
+ *
+ * the output command is:
+ * - M - the start point (a)
+ * - L - line start
+ * - L - draw line to the curving point
+ * - C - curve
+ * - L - line between two curves
+ * - C - curve
+ * - L - line start
+ * - L - line end point
+ *
+ * e.g. the output of this function is:
+ * - `"M 0 0 L 0 0 L 8 0 L 8 0 C 17.1638 0 25.4139 5.5525 28.8641 14.042 L 165.907 351.249 C 169.358 359.739 177.608 365.291 186.772 365.291 L 186.772 365.291 L 194.772 365.291"`
+ *
+ * @param a the starting point a
+ * @param b the ending point b
+ * @param curve the curve delta
+ * @param edge the edge (margin) value
+ */
+function make_svg_path_data(a: XY, b: XY, edge) {}
diff --git a/editor-packages/editor-canvas/flow-connections/index.ts b/editor-packages/editor-canvas/flow-connections/index.ts
new file mode 100644
index 00000000..6ea59047
--- /dev/null
+++ b/editor-packages/editor-canvas/flow-connections/index.ts
@@ -0,0 +1,2 @@
+export { EdgeCurvedConnectionLine } from "./connection-line-edge-curved";
+export { BezierCurvedLine } from "./connection-line-bezier-curved";
diff --git a/editor-packages/editor-canvas/flow-connections/knob.tsx b/editor-packages/editor-canvas/flow-connections/knob.tsx
new file mode 100644
index 00000000..5cdf97d4
--- /dev/null
+++ b/editor-packages/editor-canvas/flow-connections/knob.tsx
@@ -0,0 +1,27 @@
+import {
+ color_connection_knob_fill,
+ color_connection_knob_stroke,
+} from "../theme";
+import type { XY } from "../types";
+
+export function Knob({ point, size = 6 }: { point: XY; size: number }) {
+ return (
+
+ );
+}
diff --git a/editor-packages/editor-canvas/flow-connections/line.tsx b/editor-packages/editor-canvas/flow-connections/line.tsx
new file mode 100644
index 00000000..e69de29b
diff --git a/editor-packages/editor-canvas/flow-connections/math.ts b/editor-packages/editor-canvas/flow-connections/math.ts
new file mode 100644
index 00000000..1f540f2a
--- /dev/null
+++ b/editor-packages/editor-canvas/flow-connections/math.ts
@@ -0,0 +1,43 @@
+import type { XY } from "../types";
+
+/**
+ * get the direction based on two points (vector), a and b.
+ * returns the most powerful direction, e.g. [0, 0], [10, 50] -> "s"
+ * if the power is the same, return "e" | "w" first, then "s" | "n".
+ *
+ * examples
+ * - [0, 0], [10, 50] -> "s"
+ * - [0, 0], [10, 0] -> "e"
+ * - [0, 0], [0, 50] -> "s"
+ * - [0, 0], [0, 0] -> "e"
+ * - [0, 0], [-10, 50] -> "n"
+ * - [0, 0], [-10, 0] -> "w"
+ * - [0, 0], [-10, -50] -> "n"
+ * - [0, 0], [-10, 0] -> "w"
+ * - [0, 0], [-100, -100] -> "w"
+ *
+ * @param a
+ * @param b
+ * @returns
+ */
+export function get_direction(a: XY, b: XY): "n" | "s" | "e" | "w" {
+ const [x, y] = a;
+ const [x2, y2] = b;
+
+ const x_diff = x2 - x;
+ const y_diff = y2 - y;
+
+ if (Math.abs(x_diff) >= Math.abs(y_diff)) {
+ if (x_diff > 0) {
+ return "e";
+ } else {
+ return "w";
+ }
+ }
+
+ if (y_diff > 0) {
+ return "s";
+ }
+
+ return "n";
+}
diff --git a/editor-packages/editor-canvas/flow-connections/props.ts b/editor-packages/editor-canvas/flow-connections/props.ts
new file mode 100644
index 00000000..ef0b21f2
--- /dev/null
+++ b/editor-packages/editor-canvas/flow-connections/props.ts
@@ -0,0 +1,6 @@
+import React from "react";
+
+export interface ConnectionLineStyleProps {
+ width?: number;
+ color?: React.CSSProperties["color"];
+}
diff --git a/editor-packages/editor-canvas/theme/default-theme.ts b/editor-packages/editor-canvas/theme/default-theme.ts
index de843bed..a63d4be5 100644
--- a/editor-packages/editor-canvas/theme/default-theme.ts
+++ b/editor-packages/editor-canvas/theme/default-theme.ts
@@ -1,5 +1,8 @@
export const color_layer_highlight = "#0099ff";
export const color_layer_readonly_highlight = "#0099ff";
+export const color_connection_line = "#34AEFF";
+export const color_connection_knob_stroke = "#34AEFF";
+export const color_connection_knob_fill = "white";
export const color_frame_title = {
default: "grey",
highlight: color_layer_highlight,