5분 AI.
← 5분 AI 뉴스

다이어그램 연결선 컬렉션

연결선(edge) 하나를 표현하는 방법을 모은 참고 라이브러리 — 모양 · 질감 · 라우팅 · 움직임 · 빛. 항목마다 강조색을 바꿔 보고 SVG · PNG · GIF · HTML로 꺼내 쓸 수 있습니다. 다크 모드로 보면 그대로 다크로 내보내집니다.

31수집 항목
6표현 축
3.56%움직임 예산 상한
4내보내기 포맷
0외부 의존성
모았다고 다 쓰라는 게 아닙니다 — 한 다이어그램에 동시에 쓰는 건 2~3종 + 강조 1종이 상한. 사람이 범례 없이 즉시 구분하는 시각 부호가 3~4개가 한계라서, 넘어가면 "읽는" 다이어그램이 아니라 "해독하는" 다이어그램이 됩니다.
이 컬렉션은 고르기 위한 목록입니다.
항목 우상단 버튼으로 개별 저장 — SVG · HTML은 애니메이션이 살아 있고, PNG는 현재 프레임, GIF는 한 사이클. 위 바의 전체 SVG 받기로 한 번에 내려받을 수도 있습니다.
① 경로 모양선이 지나가는 길 — 직선 · 엘보 · 원호 · 곡선. 한 다이어그램에서 하나로 통일 (01)
② 획 스타일 · 질감선에 의미와 톤을 싣는 곳 — 점선 · 굵기 · 색 · 손그림 (01)
③ 끝점 · 라벨방향과 부가정보 — 화살촉 종류 · 선 위 라벨 (02)
④ 라우팅선 여러 개를 어디로 지나가게 할지 — 겹침 회피 8규칙 (03)
⑤ 움직임 · 빛흐름을 시간과 밝기로 — 굵기 · 통과 · 생성 · 상태 · 빛 (04)
⑥ 반응사람이 건드릴 때만 꺼내 보이기 — 호버 · 선택 · 디밍 (05)

01표현 기법 카탈로그 — 27종

경로 모양 12 + 의미 표현 11 + 획 질감 4. 앞의 둘은 조합해서 쓰고, 질감은 문서 전체에 하나만 정합니다.

경로 모양 (하나만 골라 통일)
A B

직선 straight

가장 짧고 그리기 쉬움. 노드가 적을 때만 — 많아지면 선끼리 겹쳐 금방 지저분해짐.

A B

직각 엘보 orthogonal

공학 도면의 정돈된 인상. 아키텍처 다이어그램의 표준. 겹치는 경로 관리가 필요.

A B

둥근 엘보 rounded

엘보의 질서 + 부드러운 인상. 요즘 도구들의 기본값(FigJam, Mermaid 등). 무난한 1순위.

A B

곡선 bezier

유기적인 흐름 강조. 마인드맵·데이터 흐름도에 어울림. 격자 정렬 느낌은 약해짐.

제어점은 감이 아니라 규칙으로 잡습니다 — 현의 중점에서 수직으로 현 길이의 10~20%. 그리고 제어점 둘은 현의 같은 쪽에 둬야 합니다(CQ든 하나만) — 곡률이 한 방향으로만 가고 변곡점이 안 생겨야 "휘어 간다"로 읽혀요. S자(꺾임 둘)는 진짜 장애물을 피할 때만 쓰고 기본 모양으로 삼지 않습니다. 테두리를 얕은 각도로 스치는 곡선도 피하세요 — 지나가는 건지 붙은 건지 안 읽힙니다.

SVC POD 1 POD 2 처짐 d = 24 + |Δx|×.08 + |Δy|×.14 — 접선은 늘 아래

행잉 케이블 hanging cable / patch cord

잭에서 나가는 접선이 늘 아래를 향합니다 — 상대가 위에 있어도 케이블은 먼저 처졌다가 올라가요. 같은 베지어 명령인데 곡선(bezier) 카드와 제어점 규칙이 다릅니다. 곡선은 두 상자를 잇는 선이라 접선이 진행 방향을 따르고, 이건 두 잭을 잇는 물건이라 접선이 중력을 따릅니다. 끝은 화살촉이 아니라 굵기×0.95 지름의 플러그 점. 패치 보드 · 배전반 · 모듈 구성도처럼 "꽂혀 있다"를 말할 때.

기록 재생 쓰기 헤드 1 · 읽기 헤드 3 — 다들 쓰기 뒤를 따라 읽음

순환 벨트 closed belt loop

두 노드 사이의 왕복을 화살표 두 개가 아니라 한 획의 폐곡선(스타디움)으로. 대시가 돌면 방향이 보이고, 멈추면 "멈춘 순환"이 됩니다. 라우팅의 ⑤ 자기 참조 루프가 노드 하나의 재귀라면 이건 둘 사이의 끝없는 순환이고, 획이 하나라 "끊기지 않음"이 형태로 보여요. 복제 로그 · 큐 소비 · 폴링 루프. 다섯 중 가장 약한 후보라 둘의 차이가 안 보이면 빼도 됩니다.

Q 베지어 — 참 원(점선)보다 바깥으로 최대 6.07% 부풂 근사 모서리 — 반지름이 일정하지 않음 A 명령 — 오차 0 참 원호 — R이 도면에 적을 수 있는 값

참 원호 엘보 true arc · A command

우리 "둥근 엘보"는 Q 베지어라 모서리 반지름이 일정하지 않습니다 — 90° 모서리에서 참 원보다 최대 6.07% 바깥으로 부풀어요. 화면용 다이어그램이면 아무도 모르지만, 도면처럼 읽히거나 R값을 치수로 적는 그림이면 A r r 0 0 1 x y로 진짜 원호를 써야 합니다. 굳이 베지어를 써야 하면 3차 + 핸들 0.5523×R이 오차 0.03%로 사실상 같습니다. 같이 지킬 것 둘 — 반지름 종류는 문서 전체에 1~2개, 그리고 모든 접합은 의도한 모서리이거나 접선 연속이어야 합니다(둘 다 아니면 그건 실수).

A B 직각 — 이미 있음 A B 45° 직행 — 꺾임 1회 A B 45° 모따기 — 모서리만 깎음

45° 사선 · 모따기 octilinear / chamfer

지금 경로 축은 직선 · 직각 · 둥근 · 곡선 · 참 원호 5종인데, 대각선이 없습니다. 지하철 노선도와 PCB 아트워크가 공통으로 쓰는 규칙이 이거예요 — 선은 가로 · 세로 · 45° 세 방향만. 각도 종류를 3개로 못 박으니 밀집해도 눈이 안 지칩니다.

둘은 성격이 다릅니다. 직행은 꺾임을 1회로 줄이는 최단 경로(노선도용), 모따기는 직각을 그대로 두고 모서리만 8px 깎는 것(회로도·기존 도면에 섞어 쓰기용). 둥근 엘보와 달리 격자에 딱 맞아서 여러 선을 나란히 놓기 쉬워요.

① 평면 격자에서 경로 찾기 — A* 8방향 가로 · 세로 · 대각 네 이동만 ② 매트릭스 한 번 — 각도 계산 없음 −30° · +30° · 0° · 90° 넷으로 떨어짐 matrix(.707,−.409,.707,.409,0,0) 라벨을 투영 안에 넣으면 — 기울고 늘어남 DB 복제 투영 밖에서 — 위치만 계산, 글자는 정면 DB 복제

아이소메트릭 연결선 isometric projection

선을 30°로 그리는 게 아닙니다. 평범한 정사각 격자 위에서 A*로 경로를 찾고(가로·세로·대각 8방향), 다 끝난 뒤 매트릭스 하나를 딱 한 번 먹입니다 — matrix(.707, −.409, .707, .409, 0, 0). 각도를 손으로 계산하는 코드가 아예 없어요.

이 매트릭스가 좋은 이유는 네 이동이 정확히 네 각도로 떨어지기 때문입니다 — 타일 +x는 −30°, +y는 +30°, 대각 둘은 0°와 90°. 즉 화면에 나올 수 있는 각도가 넷뿐이라 45° 옥틸리니어와 같은 종류의 규율이 공짜로 따라옵니다. 라우팅 로직은 2D 그대로 재사용하고, 투영만 갈아끼우면 같은 다이어그램을 평면과 아이소메트릭 양쪽으로 뽑을 수 있어요.

라벨은 같은 매트릭스에 넣으면 안 됩니다. 이 행렬에는 전단(skew)이 들어 있어서, 글자를 함께 투영하면 기울고 늘어나 읽을 수 없게 돼요. 원본 구현도 라벨을 변환 밖의 별도 레이어에 그립니다 — 경로의 가운데 타일을 투영해 화면 좌표만 얻고, 글자 자체는 정면으로 세웁니다. CSS 모션 패스 카드의 offset-rotate: 0deg와 같은 원칙이에요 — 모양은 변환을 따라가고, 글자는 따라가지 않는다.

그래도 이건 포기해야 합니다 — 깊이가 생기니까 선이 노드 뒤로 지나갈 수 있고, 그러면 z-순서를 타일 좌표로 정렬해야 합니다. 케이싱이나 교차 홉으로는 해결이 안 돼요. 인프라·랙 구성도처럼 공간 배치 자체가 정보일 때만 값을 합니다.

출발 쪽 18% — 부챗살 중간 50% — 지금 직각 엘보 도착 쪽 88% — 빗 모양

꺾이는 지점 curveStep / taxi-turn

지금 직각 엘보는 항상 중간에서 꺾습니다. 그런데 어디서 꺾느냐가 밀집도를 바꿔요. 표준 시각화 라이브러리는 curveStep(중간) · curveStepBefore · curveStepAfter 세 개로, 다른 그래프 라이브러리는 taxi-turn 하나의 숫자로 노출합니다. 그래프 엔진의 curvePosition도 같은 값이에요.

고르는 기준은 하나 — 가로줄과 세로줄 중 어느 쪽을 겹치게 만들 것인가. 출발 쪽으로 밀면 세로줄이 한 곳에 모이고 가로줄이 흩어져 부챗살이 되고, 도착 쪽으로 밀면 가로줄이 길게 나란히 붙어 빗처럼 됩니다. 트리·조직도처럼 도착지가 여럿이면 도착 쪽이 훨씬 정돈돼 보입니다. 중간 50%는 그 둘의 최악을 반씩 가져가는 값이라, 기본값으로는 나쁜 선택이에요.

부모 세로 흐름 + 세로 접선 — 갈라지는 지점이 보임 부모 세로 흐름 + 가로 접선 — 왜 옆으로 새는지 모름

접선 축 맞추기 curveBumpX/Y · cubic-horizontal/vertical

지금 곡선 카드는 "베지어"라고만 되어 있고 어느 축으로 휘는지가 없습니다. 그런데 이건 취향이 아니라 규칙이에요 — 양 끝의 접선 방향은 레이아웃이 흐르는 축과 같아야 합니다.

한쪽은 curveBumpX/curveBumpY로, 다른 쪽은 cubic-horizontal/cubic-vertical똑같은 쌍을 따로 내놓은 게 근거입니다. 두 라이브러리가 독립적으로 같은 구분을 노출했다는 건 실무에서 계속 틀린다는 뜻이에요. 오른쪽처럼 어긋나면 선이 노드 옆구리에서 출발해 가로로 한 번 튀었다가 내려가서, 부모-자식 관계가 아니라 우회로처럼 보입니다.

방사형 링크 — 각도 고정 · 반지름만 중간 코드 리본 — 화살 머리 = 방향, 폭 = 양

원형 배치의 연결선 linkRadial · ribbon / ribbonArrow

둘 다 노드가 원 위에 있을 때만 성립하는 선입니다. 왼쪽 방사형 링크는 제어점을 "각도는 양 끝 그대로, 반지름만 두 링의 중간"으로 잡습니다 — 그래서 선이 항상 중심을 향해 휘고, 링 사이 간격이 눈에 보여요. 직교좌표 베지어로 그리면 이 성질이 깨집니다.

오른쪽 코드 리본은 정량 리본(Sankey)의 원형판인데 다른 게 하나 있어요 — ribbonArrow도착 쪽만 안으로 들여서 화살촉을 만듭니다. 그래서 같은 그림 안에서 "A→B 얼마"와 "A↔B 얼마"를 섞어 표현할 수 있습니다(초록은 화살 없는 양방향). 솔직히 조건부예요 — 아키텍처 다이어그램엔 못 쓰고, 닫힌 집합의 교환량(트래픽 매트릭스·이동·호출 통계)일 때만 맞습니다.

의미 표현 (2~3개까지만 동시 사용)
A B 동기 호출 A B 비동기 · 보조

점선 dash

"실선과 성질이 다르다"는 신호 — 비동기, 선택적, 참조. 실선과 짝을 이룰 때만 의미가 생김.

A B 보조 · 낮은 빈도 A B 주 흐름 · 대량

굵기 weight

양·중요도를 싣는 축. 즉시 구분되는 건 2단계(가늘게/굵게)까지 — 3단계부터는 애매해짐.

소스 집계 로그

색상 color

계열·상태 구분. 3색 이하 + 중립색 1개. 색맹 대비로 색에만 의존하지 말고 점선 등과 병행. 색에는 두 가지 다른 일이 있습니다강조는 "이걸 먼저 봐라"라서 반드시 1개(둘이면 초점이 사라짐), 분류는 "이것들은 서로 다른 종류다"라서 색이 곧 이름이고 3~5개까지 됩니다. 둘을 한 그림에 섞으면 독자가 어느 쪽인지 몰라요. 분류색을 썼으면 강조는 굵기나 움직임으로 하세요.

A B 활성 경로

흐름 애니메이션 animated

"지금 흐르는 경로"를 보여줌. 화면 전용(인쇄 불가). 변형들은 아래 04 섹션에서 다양한 움직임 비교.

100 A B C 65% 32% 3% 들어온 폭 = 나간 폭의 합. 3%는 3%로 보여야 하고, 그래서 거의 안 보입니다. 굵기가 값 자체 — 눈금 없이 비율이 읽힘

정량 리본 flow ribbon추천

같은 그룹의 "굵기"는 굵다/가늘다 두 단계의 질적 구분일 뿐입니다. 이건 폭이 값 그 자체이고, 갈라질 때 폭의 합이 보존돼요. 선이 아니라 이 되는 순간이라 새 등급입니다. 트래픽·예산·전환율·물량 배분에. 지킬 규칙은 하나 — 입력 폭 = 출력 폭 합. 눈대중으로 그리면 데이터가 아니라 삽화가 됩니다.

확정 — 실선 + 촉 추정 — 물결선, 촉은 있음 미정 — 끝이 사라짐, 촉 없음

확신의 정도 certainty

아키텍처 초안에서 제일 자주 필요한데 표기법이 없는 것 — 이 연결이 확정인지 추정인지 아직 모르는지. 점선은 이미 "비동기"로 예산을 써버렸으니 다른 축이 필요합니다. 물결선은 "대충 이렇게 갈 것", 그라데이션으로 끝을 지우면 "여기까지만 정해졌음". 촉이 없는 게 핵심 — 도착지가 없다는 뜻이니까. 구현 함정 둘: 그라데이션은 style=로 줘야 클래스 stroke를 이기고, 가로선은 bbox 높이가 0이라 gradientUnits="userSpaceOnUse"가 아니면 아예 안 그려집니다.

주 흐름 비동기 참조 복제 배치 색 없이 5계열 — 흑백 인쇄·색맹 모두 통과

색맹 안전 패턴 세트 pattern encoding

"색에만 의존하지 말라"는 말은 옆 카드에 이미 있는데 대안이 없었습니다. 실제로 서로 구분되는 대시 패턴 5종: 실선 · 10 6 · 2 3 · 16 4 3 4 · 8 3 8 9. 핵심은 주기와 리듬을 둘 다 다르게 하는 것 — 8 49 5처럼 길이만 다르면 두 개 아니라 하나로 보입니다.

세 가지 획 — 굵기 2px 실선 대시 — 굵기×2, 굵기×2 점 — 0, 굵기×1.8 + 둥근 캡 굵기만 5px로 올리면 대시 4 4 그대로 — 거의 실선 점 간격 그대로 — 점이 뭉침 대시도 같이 스케일하면 10 10 — 같은 스타일 유지 0, 9 — 점이 점으로 남음

대시 스케일 · 점 스타일 width-relative dash

대시 값을 고정 숫자로 박아 두면 굵기를 바꾸는 순간 스타일이 바뀝니다. 4 4짜리 점선을 5px로 올리면 칸이 메워져서 거의 실선으로 읽혀요. 대시는 절대값이 아니라 굵기의 배수로 잡아야 합니다 — 대시 = 굵기×2, 굵기×2.

점(dotted)은 별개 스타일입니다. 짧은 대시로 흉내내지 말고 stroke-dasharray: 0, 굵기×1.8stroke-linecap: round를 겁니다 — 길이 0짜리 선분이 둥근 캡 때문에 완전한 원으로 찍혀요. 지금 컬렉션의 점선·색맹 패턴은 전부 대시라서 이 모양이 없었습니다. 실선 · 대시 · 점 셋이면 색 없이도 세 등급을 만들 수 있습니다.

① 같은 모티프를 그대로 줄이면 100%50%25% 대시가 실선이 되고 점이 사라짐 — 규칙이 통째로 없어짐 ② 요소 수를 줄이고 남은 걸 상대적으로 키우면 점 3 · 대시 6 4점 2 · 대시 5 4점 1 · 실선 25%에서도 "선 위를 뭔가 지나간다"가 남음 ③ 굵기의 바닥 — 1px 밑으로는 자기 색을 못 냄 1.8 1.0 0.6 0.35 같은 강조색인데 0.35px는 배경에 먹혀 버림

작아질 때 small-size redesign

대시 스케일 카드가 "굵어질 때"를 다뤘는데, 반대쪽은 대칭이 아닙니다 — 키울 때는 같이 늘리면 되지만, 줄일 때는 같이 줄이면 안 됩니다. 규칙은 줄이지 말고 빼라예요. 점 3개를 각각 1/4로 줄이면 셋 다 안 보이는데, 하나만 남기고 그 하나를 상대적으로 키우면 "선 위를 뭔가 지나간다"는 남습니다.

이걸 제대로 하는 곳은 큰 크기와 작은 크기를 배율이 아니라 별도 설계로 잡습니다 — 작은 쪽은 요소 수를 1/4로 줄이고 남은 요소의 반지름 배율을 1.5~2.5배로 올려요. 반지름 자체도 크기에 선형이 아니라 (크기 ÷ 300)0.6로 줄입니다 — 지수를 1보다 작게 두는 게 핵심이고, 그래야 작아질수록 마크가 상대적으로 커집니다. 2차원 격자처럼 개수가 쌍으로 오는 건 각 변에 √배율씩 나눠 주고요.

굵기만은 공식이 아니라 하한으로 막습니다 — 계산 결과가 얼마든 max(0.6, 계산값). 이유는 재 보면 나옵니다. 1배 화면에서 #d6453d 선을 굵기만 바꿔 그리면 1.8px는 rgb(214,69,61) 원색 그대로인데, 0.6px는 rgb(241,196,193), 0.35px는 rgb(245,219,216)거의 배경색입니다. 안 사라지고 연해지는 게 함정이에요. 선은 남아 있는데 색으로 실어둔 의미가 사라집니다.

같은 측정에서 하나 더 — 1배 화면의 1px 선은 픽셀 격자에 어디 걸리느냐로 색이 달라집니다. 중심이 반픽셀(y = 38.5)이면 원색인데 정수(y = 38)면 두 줄에 반씩 걸려 rgb(233,159,154)로 옅어져요. 가는 선은 좌표를 x.5에 두는 게 정석입니다. 2배 화면에서는 1px까지 안전하고, 0.6px부터 같은 현상이 시작됩니다.

실무에서 이게 걸리는 곳은 셋 — 썸네일, 인쇄 축소, 확대·축소되는 캔버스. 마지막 경우는 vector-effect:non-scaling-stroke로 굵기만 화면 좌표에 고정하는 게 답이지만, 대시 간격과 점 개수는 여전히 사람이 따로 정해줘야 합니다 — 그건 자동으로 안 따라옵니다.

화살촉 — 방향은 끝에만 있음 테이퍼 — 어느 지점을 봐도 방향이 읽힘

테이퍼 방향선 tapered edge / straight-triangle

출발점에서 두껍고 도착점에서 0으로 얇아지는 삼각형. 화살촉 없이 선 전체가 방향이 됩니다. 화살촉은 정보가 끝점 6px에만 몰려 있어서, 선이 겹치면 어느 촉이 어느 선 것인지 잃어버려요. 테이퍼는 아무 데나 잘라 봐도 굵은 쪽이 출발입니다. 주요 그래프 라이브러리가 straight-triangle이라는 이름으로 기본 제공합니다.

단, 근거가 갈립니다. 노드-링크 그래프 사용자 연구에서는 테이퍼가 화살촉보다 빨랐지만, 지도학 쪽 흐름도 연구는 반대로 "화살촉이 테이퍼보다 방향을 잘 나타낸다"고 결론냅니다 — 길이가 길고 굵기가 제각각인 흐름에서는 테이퍼의 굵기가 방향인지 수량인지 헷갈리기 때문. 짧고 굵기가 균일한 그래프용으로 쓰세요.

App API 단선 — 논리적 호출 DC-A DC-B 이중선 — 물리 회선 · 전용 채널 굵은 단선 = 양이 많다 이중선 = 종류가 다르다

이중선 레일 double stroke / conduit

같은 경로를 굵게 한 번(6.5px), 배경색으로 가늘게 한 번(3px) 덮으면 속이 빈 관이 됩니다. P&ID·배선도에서 "이건 신호가 아니라 물리적 통로"를 뜻하는 오래된 관행이에요.

넣을 값어치는 굵기와 의미가 안 겹친다는 데 있습니다. 굵기는 이미 을 맡고 있어서, "전용선 / VPN 터널 / 물리 케이블"처럼 종류가 다른 연결을 굵기로 표시하면 값과 충돌해요. 이중선은 굵기 축을 비워둔 채 종류만 바꿉니다. 색맹 안전 패턴 세트와 같은 계열의 도구.

획 질감 — 문서 톤을 정함. 전체에 하나만, 섞지 말 것
A B 정밀 — 기본 A B 손그림 러프 — 시드 고정

손그림 러프 sketchy / rough

같은 선을 2번 겹쳐 긋고 양 끝·제어점을 2px 안에서 흔듦(roughness 1, bowing 1). 화살촉만 흔들림을 0.6으로 낮춰야 방향이 안 뭉갬. 시드를 고정해야 다시 그려도 같은 모양 — 안 하면 매 렌더마다 손떨림이 달라집니다. 문서 전체에 하나만: 정밀과 섞으면 미완성으로 보임.

A B 도형만 필터 · 글자는 밖 — 정상 A B 글자까지 필터 — 못 읽음

손그림 · 필터 방식 feTurbulence + feDisplacementMap

경로를 다시 계산하는 손그림 알고리즘 방식과 달리 필터 한 줄로 도형 전체를 흔듭니다(baseFrequency .02 / scale 1.5~2.4). 대신 글자에 걸면 못 읽게 되니 텍스트는 반드시 필터 그룹 밖에. 지오메트리가 안 바뀌어 정렬은 유지되지만, 시드가 지오메트리에 안 박혀 렌더러마다 미세하게 달라집니다.

같은 수평선 하나에 필터만 다르게 걸었습니다 필터 없음 — 기준 점선 = 있어야 할 자리 퍼센트 영역 — 사라짐 userSpaceOnUse — 정상 수평선은 objectBoundingBox 높이가 0 — 퍼센트 영역이 0으로 접힙니다

필터가 선을 지운다 filter region trap

이 컬렉션에도 필터 쓰는 카드가 셋 있습니다 — 손그림, 구이 브리지, 발광. 그런데 필터를 연결선에 걸 때만 나오는 함정이 하나 있어요. SVG 필터 영역의 기본 단위는 objectBoundingBox인데, 수평선의 바운딩 박스는 높이가 0입니다 — 획 굵기는 박스에 안 들어가거든요. 그러면 height="120%"0의 120%라 0이 되고, 크롬은 그 획을 아예 안 그립니다.

직접 재 봤습니다. 굵기 3px 수평선 하나에 x="-10%" y="-10%" width="120%" height="120%"짜리 흐림 필터를 걸면 잉크 0. 같은 선에 filterUnits="userSpaceOnUse"와 명시 영역을 주면 9321, 필터 없는 기준이 5760이니 정상 쪽은 번짐까지 제대로 얹힌 값입니다. 완전히 같은 선상에 놓인 선 두 개를 <g>로 묶어도 결과는 똑같이 0이에요 — 묶어서 해결되는 게 아니라 박스가 2차원이 되어야 삽니다.

고치는 법은 셋 — ① 그 획에는 필터를 안 건다, ② filterUnits="userSpaceOnUse"에 명시 영역을 준다, ③ 2차원 도형과 함께 묶는다. 셋째는 우연히 되는 것이라 규칙으로 삼으면 안 됩니다 — 나중에 누가 그 그룹에서 사각형 하나를 빼면 선이 통째로 사라지니까요.

퍼센트 영역을 쓰더라도 여백이 번짐 반경보다 커야 합니다. stdDeviation이 6이면 눈에 보이는 번짐은 대략 3σ = 18px인데, 기본값 −10%는 높이 44px 상자에서 4.4px밖에 안 돼요. 이 파일도 점검했습니다 — 발광 필터 둘은 처음부터 userSpaceOnUse라 안전했고, 손그림·구이는 내용이 2차원이라 영역을 전체 캔버스로 넓혀 다시 렌더해도 픽셀 차이 0이었습니다. 운이 좋았던 게 아니라 확인한 결과로 적어 둡니다.

A B C D 그림자 = 같은 경로 (+1.5, +2.5) · 굵기 +1.4 · 어둡고 옅게

드롭 섀도 — 떠 있는 선 offset shadow / lift

같은 경로를 살짝 밀어 어둡고 옅게 한 번 더 그린 뒤 본선을 얹습니다. 선이 판 위에 떠 보이고, 교차에서 어느 선이 위인지를 그림자가 말해 줘요 — 위 그림에선 빨강이 파랑 위. 라우팅의 ⑰ 케이싱이 바탕색 테두리로 을 만들어 아래 선을 지운다면, 이건 어둠으로 깊이를 만들어 아래 선을 남깁니다. 겹침 자체가 정보일 때(케이블 다발 · 배선) 케이싱보다 덜 잃어요. 질감이라 문서 전체에 한 번 정합니다 — 어떤 선엔 있고 어떤 선엔 없으면 위아래가 거짓말이 됩니다.

02끝점 · 라벨 · 주석 — 9종

기법이라기보다 마감. 화살촉은 한 다이어그램에 1종(+무방향)이면 충분하고, 라벨과 주석에는 각자 규칙이 있습니다.

채운 화살표 — 기본 열린 화살표 — 가벼운 인상 다이아몬드 — UML 집계/소유 화살표 없음 — 무방향 관계 HTTPS 선 위 라벨 — 짧게
API 화살촉 없음 · 점선 4,3 · 착지는 점 여기서 유실됨

리더 라인 annotation callout

노드를 잇는 선이 아니라 한 지점을 가리키는 선. 흐름 화살표와 헷갈리면 안 되니 세 가지를 반드시 다르게 — 화살촉 대신 착지 점, 실선 대신 점선(4,3), 산세리프 대신 이탤릭 세리프. 여백에만, 한 장에 최대 2개.

DB POST /orders 선이 글자를 관통 · 끝이 노드를 뚫고 나옴 POST /orders DB 불투명 마스크(여백 6px) · 선 먼저, 노드 나중

라벨 마스킹 · z-순서 masking / z-order

선 위 라벨은 배경색 사각형을 깔고 그 위에 글자를 얹습니다(좌우 여백 6px) — 반투명은 안 됩니다. 그리고 선을 전부 그린 뒤 노드를 그리면 선 끝을 정확히 맞출 필요가 없어집니다. 노드 채움이 알아서 잘라주니까요.

"선 먼저, 노드 나중"을 네 층으로 확장하면 다이어그램 전체의 규칙이 됩니다 — 캔버스 → 컨테이너 배경·테두리 → 연결선과 마커 → 노드 표면 → 아이콘·글자·라벨·범례. 여기서 미묘한 부분 하나. 선이 밑으로 지나가야 하는 노드는 자기 끝점의 노드뿐입니다. 무관한 노드 밑을 지나가는 건 가려진 것이고, 그건 페인트 순서 문제가 아니라 라우팅 실패예요 (⑱ 참조 — "그 선은 기하학적으로는 존재하는데 끊어진 것으로 읽힙니다").

그래서 가려짐은 기하와 따로 검사해야 합니다. 경로가 노드를 안 뚫는지(기하)와 연결선보다 나중에 그려진 불투명 면이 그 선을 덮는지(가려짐)는 다른 질문이고, 후자는 좌표만 봐서는 절대 안 잡힙니다. 캔버스 바탕만 예외로 두고 나머지 불투명 면은 전부 대상이에요.

브레이크 — 길이는 생략, 연결은 유지 허브 워커 ×12 다중 생략 — 같은 선 12개를 한 줄로

생략 기호 break / ×N

도면 표준에서 가져온 둘. 브레이크는 "이 선은 실제로 훨씬 길지만 지면상 잘랐다" — 길이를 속이지 않고 줄이는 유일한 정직한 방법. 이중 사선 + ×N은 동일한 선 열두 개를 한 줄로 접습니다. 워커 12대에 선 12개를 그리는 건 정보가 아니라 노동이에요.

끝 화살촉만 — 촉을 찾아야 방향을 앎 경로 셰브런 — 아무 데나 봐도 방향이 있음

경로 셰브런 marker-mid chevrons

선 위에 꺾쇠(>)를 일정 간격으로 얹습니다. SVG의 marker-mid가 정확히 이걸 위한 기능인데, 곡선을 폴리라인으로 나눠 놓으면 중간 정점마다 마커가 접선 방향으로 자동 회전해서 붙어요.

넣어야 하는 진짜 이유는 정지 이미지입니다. 지금 방향을 표현하는 카드는 대부분 애니메이션(알갱이·혜성·패킷)인데, PNG로 내보내거나 인쇄하면 방향이 통째로 사라집니다. 셰브런은 흐름 애니메이션과 같은 인상을 주면서 한 프레임에 다 들어가요. 간격 규칙만 지키면 됩니다 — 선 굵기의 8~12배. 더 촘촘하면 점선으로 보이고, 더 성기면 방향이 끊깁니다.

① 같은 마커를 획 1.5px와 3px에 걸었을 때 markerUnits 기본값 markerUnits=userSpaceOnUse 촉 13.5 촉 27 굵기를 바꿨더니 촉이 두 배 11.25 11.25 굵기와 무관하게 고정 ② 보이는 촉 ≈ 획의 3배 2배 — 방향이 약함 3배 — 맞음 4.5배 — 촉만 보임 V 글리프는 뷰박스 12 중 8 → 보이는 촉 = markerWidth × 8/12

화살촉 크기 계약 marker footprint

markerUnits기본값이 strokeWidth라는 게 첫 함정입니다. markerWidth="9"는 "9px"가 아니라 "획 굵기의 9배"예요 — 3px 획에 걸면 27px짜리 촉이 나옵니다. "굵기를 올렸더니 촉만 커지더라"의 정체가 이겁니다. markerUnits="userSpaceOnUse"를 기본으로 쓰고, refX를 뷰박스 오른쪽 끝에 두면 촉 끝이 경로 끝점에 정확히 옵니다.

둘째, markerWidth는 보이는 촉 크기가 아닙니다. 뷰박스 안에서 글리프가 실제로 차지하는 비율을 곱해야 해요. 흔한 열린 V M2 2 L10 6 L2 10은 뷰박스 12 중 8을 쓰니 보이는 촉 = markerWidth × 8/12. 계약은 보이는 촉 ≈ 획의 3배이고, 4배를 넘으면 촉만 보이고 2.5배 밑이면 방향이 약해집니다. 역산하면 markerWidth ≈ 획 × 4.5 — 획 2.0이면 9, 2.5면 11.25, 3.0이면 13.5.

셋째, 촉만 볼 게 아니라 축까지 같이 예산에 넣어야 합니다. 통로 = (목표의 시각적 왼쪽) − (출발의 시각적 오른쪽) — 그림자와 획까지 포함한 값이고, 여기서 양쪽 여백과 촉 길이와 카드에 가려지는 구간을 다 뺀 뒤에도 보이는 축이 12~16px은 남아야 합니다. "끝점 간격 8~12px은 맞췄는데 축이 거의 0"은 통과가 아니라 실패예요.

통로가 좁으면 촉을 줄이지 말고 형태를 바꿉니다 — 표준 화살표 → 컴팩트 화살표 → 전이 셰브런(선 없이 방향만) → 레이아웃 리플로우. 셰브런은 선이 의미를 안 실을 때 고르는 의도적인 선택이지, 축이 잘려서 도망칠 자리가 아닙니다. 손그림 처리에서는 변위가 촉을 얇아 보이게 해서 목표 비율을 3.5배(허용 3.0~4.5)로 올려 잡습니다.

① 중심끼리 그으면 A B 선이 도형을 가로지르고 촉이 안에 묻힌다 채운 점 = 중심 ② 경계에서 자르고 8px 물러나면 A B 촉이 테두리 밖에 선다 빈 점 = 경계 교차점 · t = min(hw/|dx|, hh/|dy|)

경계에서 자르기 boundary clip

중심끼리 이으면 선이 도형 위로 올라타고 화살촉이 채움 아래 묻힙니다 — 손으로 그린 다이어그램에서 제일 흔한 결함이에요. 끝점은 중심이 아니라 경계와의 교점이어야 합니다. 사각형이면 나눗셈 두 번이면 끝 — 중심에서 상대 중심으로 향하는 방향 d에 대해 t = min(hw/|dx|, hh/|dy|), 교점은 C + t·d. 둘 중 작은 쪽이 먼저 만나는 면입니다. 거기서 방향 단위벡터만큼 4~8px 더 물러나 촉 끝을 놓으면 테두리에 눌린 느낌이 사라집니다. 원이면 반지름 하나(C + r·d̂), 둥근 모서리는 사각형 값으로 잘라도 눈에 안 띕니다 — 오차가 모서리 반지름 안쪽이라서요.

① 고정 — 포트가 한 점에 박힘 A B C 왼쪽 노드에도 오른쪽 면에서 나가 되돌아온다 ② 떠다님 — 나갈 면을 그때그때 고름 A B C 상대 위치에 따라 윗면 · 아랫면으로 갈린다

고정 포트 vs 떠다니는 포트 fixed / floating anchor

연결점을 한 점에 박을지, 상대를 보고 매번 다시 고를지는 먼저 정해야 하는 갈림길인데 대개 그냥 기본값으로 흘러갑니다. 고정은 그 자리가 의미를 가질 때만 — 회로의 3번 핀, 서비스의 특정 입력구처럼요. 대신 노드를 옮기면 위 왼쪽처럼 반대편으로 돌아 들어옵니다. 떠다님처럼 상대 중심 방향으로 경계를 다시 잘라 나갈 면이 바뀝니다 — 일반 상자에는 이쪽이 기본값이어야 합니다. 계산은 경계에서 자르기와 같은 식 하나뿐이고, 달라지는 건 언제 다시 푸느냐입니다. 포트를 좌표가 아니라 0~1 비율로 적어두면 도형 크기가 바뀌어도 자리가 유지됩니다.

① 마커 1개 · fill=context-stroke 촉이 선 색을 따라옴 ② 마커 1개 · 촉 색 고정 선만 바뀌고 촉은 그대로 ①의 셋째 줄은 열린 V — 채움이 없으니 stroke="context-stroke" currentColor는 대안이 아닙니다 선은 초록, 촉은 보라 경로에 color를 줘도 안 따라옴 마커 안의 currentColor는 마커 자신이 상속한 color를 봅니다 — 참조한 선이 아니라

화살촉 색 상속 context-stroke

선 색을 바꾸는 순간 화살촉만 원래 색으로 남습니다. 마커 안쪽은 자기를 부른 도형에서 상속을 못 받기 때문이에요. 그래서 다들 색깔 수만큼 마커를 복제합니다 — 이 컬렉션의 공용 defs에도 같은 삼각형이 여섯 벌 있고, 상태가 바뀔 때 marker-end를 통째로 갈아끼우는 게 흔한 처방입니다.

값 하나로 끝납니다. fill="context-stroke"를 마커 내용에 주면 자기를 부른 선의 stroke를 씁니다. 채움이 없는 열린 V는 stroke="context-stroke"로 같은 일을 해요. 마커는 하나면 됩니다. 실측(Chromium 141): 클래스만 바꿔 선 색을 옮기면 촉이 같이 따라오고, var(--accent)도 해석되며, 직렬화해 <img>로 래스터해도 유지됩니다 — 이 컬렉션의 PNG·GIF 내보내기에서도 그대로라는 뜻입니다. 그러니 강조색 다이얼을 돌리면 촉까지 같이 물듭니다.

함정 하나. currentColor는 이걸 대신하지 못합니다. 위 ③가 실측인데, 선에 color를 줘도 촉은 그 색이 아니라 마커가 상속한 color(대개 SVG 루트나 defs)로 칠해집니다. "선마다 다른 색"을 의도했다면 조용히 무너지는 쪽입니다.

폴백이 눈에 띕니다. 지원하지 않는 엔진에서 이 값은 그냥 무효값이고, 무효값을 넣어 재보면 채운 촉은 검정(fill 초기값)으로, 열린 촉은 아예 안 그려집니다(stroke 초기값 none). SVG 2 기능이라 엔진마다 도입 시점이 갈렸으니, 내보낸 파일이 어디서 열릴지 모르면 대상 브라우저에서 한 번 확인하고, 아니면 복제를 유지하세요. 크기 규칙은 옆의 화살촉 크기 계약과 함께 갑니다 — 색이 따라온다고 촉이 알맞아지진 않습니다.

03여러 선이 겹칠 때 — 라우팅 20종

여기까지는 "선 하나를 어떻게 그리나"였고, 실제 다이어그램이 지저분해지는 진짜 원인은 선 여러 개를 어디로 지나가게 하느냐입니다. 왼쪽이 방치, 오른쪽이 규칙 적용 — 선 종류는 하나도 안 늘었는데 읽히는 정도가 달라집니다. 스무 장 전부 정적이라 SVG·PNG로 그대로 씁니다.

겹침을 푸는 배치 — 그리는 방법 15
방치 — 한 점에 몰림 API A B C 규칙 — 포트를 14px씩 벌림 API A B C

① 포트 분산 port spread

한 노드에서 n개가 나가면 출발점을 (k − (n−1)/2) × 14px만큼 벌립니다. 한 점에서 부챗살로 퍼지면 시작 부분이 뭉쳐서 몇 개인지 안 세어지고, 화살표 근처도 마찬가지 — 들어오는 쪽도 같이 벌려야 합니다.

세 가지가 더 붙습니다. 면의 양 끝에는 16px 여백을 남기고(모서리에 붙으면 어느 면 소속인지 흐려짐), 간격은 14px과 (남는 폭 ÷ n−1) 중 작은 쪽이라 선이 많아지면 알아서 좁아집니다. 그리고 via·채널을 사람이 직접 지정한 관계는 자동 분산에서 빼야 해요 — 손으로 정한 좌표를 라우터가 다시 밀면 안 되니까. 벌린 결과가 서로 몇 px 차이로 어긋나면 ⑳ 경로 예산의 계단 문제로 넘어갑니다.

겹쳐 그리면 — 3개가 들어갔는데 1개로 보임(맨 위 색만 남음) 같은 복도 · 간격 6px 고정 평행 노선 — 복도는 공유, 가닥은 유지 붙고 떨어지는 구간만 45° · 사이는 완전 평행 · 복도 안에서 가닥 순서를 바꾸지 않기

② 평행 노선 metro parallel strands

여러 연결이 같은 구간을 지날 때, 겹쳐 그리지 말고 6px씩 어긋난 가닥으로 나란히 보냅니다. 복도로 들어올 때와 나갈 때만 45°로 붙였다 떨어지고, 그 사이는 완전 평행. 지하철 노선도의 핵심 문법이에요.

지금 ① 포트 분산이 있지만 그건 노드 한 개의 접점을 벌리는 규칙이고, 이건 구간 전체를 벌리는 규칙입니다. 노드에서만 벌리면 중간에서 다시 겹쳐요. 핵심 제약 두 가지 — 복도 안에서 순서를 바꾸지 말 것(꼬면 추적 불가), 간격은 선 굵기의 약 2배로 고정할 것. 앞의 45° 사선 카드와 짝으로 씁니다.

방치 — 노드 위를 가로지름 1 2 3 규칙 — 전용 레인 + 36px 층 1 2 3

③ 우회 채널 skip lane

한 단계를 건너뛰는 선(1→3)은 본류에 두면 반드시 노드 위를 지납니다. 위쪽에 전용 레인을 파고, 그런 선이 여러 개면 36px씩 층을 쌓아 서로도 안 겹치게. 레인 높이는 가장 높은 노드보다 위에서 시작.

방치 — 본류와 뒤엉킴 1 2 3 규칙 — 바깥 레인 + 점선 1 2 3 36px

④ 루프백 레인 loop lane

되돌아가는 선(재시도·피드백)을 본류 사이로 통과시키면 방향을 잃습니다. 도형 바깥 아래(세로 배치면 옆)로 빼고, 점선으로 "역방향"임을 표시하고, 여러 개면 역시 층을 쌓습니다. 회귀선이 본류를 한 번도 안 건너는 게 목표.

재시도 위쪽 루프 — 기본(−45°) 가장 안 부딪힘 폴링 오른쪽 루프 위가 라벨로 막혔을 때 양쪽 루프가 2개면 방향을 갈라야 함 — 같은 각도로 겹치면 하나로 보임

⑤ 자기 참조 루프 self-loop / loop-sweep

노드가 자기 자신으로 돌아오는 선. 재시도·폴링·재귀·상태 유지처럼 흔한데 지금 컬렉션에 없습니다. ④ 루프백 레인이 있지만 그건 다른 노드로 되돌아가는 경로예요 — 출발=도착인 경우는 기하가 아예 다릅니다.

파라미터가 둘입니다 — 방향(루프가 어느 쪽으로 튀어나갈지)과 벌림(나가는 점과 들어오는 점 사이 각). 그래프 라이브러리들이 loop-direction / loop-sweep으로 정확히 이 둘을 노출합니다(기본 −45° / −90°). 루프가 2개 이상이면 반드시 방향을 갈라야 하고, 라벨은 루프 바깥쪽에 둡니다.

API 한 줄에 촉만 둘 방치 — 완전히 겹침 API 요청 응답 규칙 — ±7px 오프셋, 각자 라벨

⑥ 왕복 쌍 bidirectional pair

같은 두 노드 사이 왕복은 한 줄에 화살촉만 둘 달면 "한 관계"로 읽혀 요청·응답을 못 나눕니다. ±7px씩 벌려 두 줄로 만들고 각자 라벨·스타일을 주면 왕복임이 보입니다. 응답 쪽을 점선으로 낮추면 주·부도 같이 표현됩니다.

A B read · write · delete 관계 3개인데 선 1개로 보임 — 라벨도 겹침 A B read write delete curveOffset −28 / 0 / +28 — 라벨 자리도 생김

⑦ 다중 엣지 curveOffset / curvePosition

같은 두 노드 사이에 관계가 여러 개일 때. 지금 ⑥ 왕복 쌍이 있지만 그건 A→B와 B→A 딱 2개인 특수 경우고, 같은 방향으로 3개 이상이면 규칙이 없습니다. 그냥 그리면 선도 라벨도 완전히 포개져서 관계 하나로 보여요.

한 그래프 엔진이 이걸 두 숫자로 정리해 뒀습니다 — curveOffset(현에서 제어점이 떨어진 거리 = 휘는 정도)과 curvePosition(0~1, 제어점이 현의 어디쯤인지). k번째 엣지에 offset = (k − (n−1)/2) × 28을 주면 끝. 포트 분산과 공식이 똑같은데 적용 축이 다릅니다 — 포트 분산은 노드 접점을 벌리고, 이건 선의 배를 벌려요. 덤으로 각 호의 꼭대기가 라벨 자리가 되어서, 관계 이름을 겹치지 않게 놓을 수 있습니다.

Core A B 읽기 쓰기 방치 — 테두리를 비스듬히 관통 Core A B 읽기 쓰기 규칙 — 교차는 밖에서, 진입은 수직으로

⑧ 그룹 경계 통과 container crossing

그룹 박스가 있으면 선이 테두리를 어디로 뚫는지가 새 변수가 됩니다. 비스듬히 관통하면 그룹이 껍데기로 보여요. 교차는 그룹 밖에서 끝내고, 경계는 수직으로 넘고, 통과 지점(빨간 눈금)을 맞추면 그룹이 경계로 읽힙니다.

A B 방치 — 옆구리로 찌르고 들어감 A B 규칙 — 위아래로 이동하면 위아래 면으로

⑨ 포트 면 선택 port face

①이 "같은 면에서 몇 개를 어떻게 벌리나"였다면, 이건 어느 면으로 드나드나입니다. 주로 위아래로 가는 선이 옆면으로 들어오면 노드 얼굴을 찌르는 것처럼 보입니다. 수직 이동은 top/bottom, 수평 이동만 left/right — 좌우 포트를 기본값으로 두지 마세요.

한 발 더 나가면 면을 고르는 것그 면으로 수직으로 드나드는 것은 다른 문제입니다. top으로 들어오기로 정해놓고 마지막 구간이 비스듬히 들어오거나 테두리에 접하면서 들어오면, 선언한 면이 아무 뜻이 없어져요. 규칙은 한 줄 — 첫 구간과 마지막 구간은 정한 면에 수직. 끝점은 상자 테두리 위의 점이 아니라 방향 약속입니다. 자동 라우터라면 이 조건을 통과 못 하는 후보를 아예 버리는 게 낫습니다. 이상한 화살표가 나중에 사람 눈에 발견되는 것보다 싸요.

① 선언 순서 그대로 A X Y Z 교차 2 ② 상대 노드의 y로 정렬 A X Y Z 교차 0 — 선은 하나도 안 바뀜

⑩ 포트 순서 port order

①가 얼마나 벌리나, ⑨가 어느 면인가였다면 이건 그 면에서 위아래 순서입니다 — 셋 중 제일 안 챙기는 축이고, 공짜로 교차가 사라지는 축이에요. 포트를 코드에 적은 순서대로 붙이면 상대 노드의 위치와 어긋나 선끼리 꼬입니다. 상대 노드의 y로 정렬해서 붙이면 두 판 모두 선 개수도 경로 모양도 그대로인데 교차만 0이 됩니다. 층별 배치의 교차 최소화(barycenter)를 한 면 안으로 줄인 것이고, 상대가 여럿이면 y의 평균을 쓰면 됩니다. 가로로 드나드는 면이면 x로 정렬합니다.

방치 — 스파게티 묶기 — 허리 하나로 모았다 품

⑪ 다발 묶기 edge bundling

앞의 일곱 규칙이 다루지 못한 마지막 경우 — 레인으로도 정리가 안 되는 다대다. 중간 허리로 당겼다 풀면 선 개수가 아니라 흐름의 부피가 보입니다. 대가가 분명한 기법이라 같이 적어야 해요: 개별 경로 추적은 포기하는 대신 전체 구조를 얻습니다. 한 선을 끝까지 따라가야 하는 그림이면 쓰면 안 됩니다.

β = 0 — 직선(안 묶음) β = 0.85 — 권장 기본값 β = 1 — 완전 밀착 · 추적 불가

⑫ 묶음 강도 β bundling strength · FDEB

지금 ⑩ 다발 묶기는 켜고 끄는 스위치인데, 실제로는 0에서 1까지 도는 다이얼입니다. 표준 시각화 라이브러리의 curveBundle.beta(β)가 정확히 이 값이에요 — β=0이면 완전 직선, β=1이면 제어점이 허리에 완전히 붙습니다. 권장 기본값은 0.85이고, 이유가 명확합니다 — β=1은 예뻐 보이지만 허리에서 네 선이 한 덩어리가 돼서 어느 선이 어디로 가는지 추적이 안 됩니다. 0.85는 묶임을 보여주면서 각 선의 출입 각도를 남겨둬요.

두 번째로 필요한 게 "어떤 선끼리 묶어도 되나"인데, 그래프 엔진의 edge-bundling 플러그인이 이걸 bundleThreshold(기본 0.6)로 노출합니다 — 방향·길이·위치가 비슷한 호환 가능한 선끼리만 묶고, 값을 올릴수록(0.8) 까다로워져 묶이는 선이 줄어요. 나머지 파라미터도 뜻이 있습니다 — K(0.1, 당기는 힘) · cycles(6, 반복 라운드) · divisions(3, 선을 나눈 마디 수). 엉뚱한 선까지 묶이면 β가 아니라 임계값을 올릴 것.

개별 배선 — 6노드 완전연결 = 선 15개 버스 백본 — 같은 관계를 선 7개로

⑬ 버스 백본 bus-style routing

서로 다 연결된 노드 뭉치를 선 하나(백본) + 짧은 지선(스텁)으로 바꿉니다. n개 노드가 완전연결이면 선이 n(n−1)/2개인데, 버스는 항상 n+1개. 6개면 15 → 7. 상용 레이아웃 엔진이 BusRouter라는 이름으로, 회로도가 데이터 버스로 100년 쓰던 방식입니다.

지금 있는 ⑩ 다발 묶기와 다릅니다. 다발은 가는 길이 같은 선들을 시각적으로 모을 뿐 선 개수는 그대로인데, 버스는 "이 집합 안에서는 다 통한다"를 한 줄로 선언해서 선을 실제로 없앱니다. 쓸 수 있는 조건이 명확해요 — 관계가 완전연결(또는 브로드캐스트)일 때만. 개별 쌍을 강조해야 하면 못 씁니다.

전체 그리기 — 교차 6회 부분 그리기 — 양끝 25%만, 교차 0회

⑭ 부분 그리기 · 스텁 partial edge drawing (PED)

선을 끝까지 안 그립니다. 양쪽 끝에서 각각 25%만 그리고 가운데는 비워요. 그러면 교차가 구조적으로 0이 됩니다. 사람은 남은 두 토막의 각도를 연장해서 짝을 찾습니다 — 실제로 됩니다.

실험에서 나온 조건이 하나 있는데 중요합니다 — "균질성이 교차 수나 잉크 양보다 중요하다". 즉 모든 선이 똑같은 비율(25%면 전부 25%)로 잘려야 하고, 선마다 다른 길이로 자르면 오히려 전체 그리기보다 나빠집니다. 밀집 그래프에서 다발 묶기가 실패하는 경우(묶을 공통 경로가 없는 랜덤 그래프)에 남는 마지막 카드예요. 스텁 끝에 앞의 테이퍼를 붙이면 방향까지 살아납니다.

SVC POD 케이블 3개 · 처짐 40 · 40 · 40 처짐이 같아 3개가 1개로 보임 — 색도 마지막 것만 SVC POD 처짐 34 · 41 · 48 — index % 4 × 7 끝점은 한 점 그대로, 배만 갈라져 3개가 보임

⑮ 처짐 차등 sag stagger

같은 두 잭을 잇는 케이블이 여럿이면 처짐 깊이를 7씩 달리합니다. 옆으로 벌리지 않고 아래로 벌려요. ⑦ 다중 엣지(curveOffset)는 끝점부터 좌우로 갈라 놓는데, 이건 끝점을 한 점에 모아 둔 채 중간만 갈라집니다 — "한 잭에 여러 개 꽂힘"이 정보일 때 쓰는 분리법이라 축이 다릅니다. 행잉 케이블(경로 모양)과 짝이고, 보통 곡선에도 제어점 y 만 바꾸면 그대로 됩니다.

교차를 못 피할 때 — 3
방치 — 이어진 건지 지나친 건지 홉 r=8~11 규칙 — 덜 중요한 쪽만 넘어감

⑯ 교차 홉 bridge / hop

레인으로 다 뺐는데도 남는 교차는 덜 중요한 선만 반원으로 넘깁니다(a 8 8 0 0 1 0 16). 둘 다 넘기면 의미가 사라지니 한쪽만 — 점선·가는 선·되돌아가는 선이 넘어가는 쪽입니다. 교차는 홉, 연결은 점 — 이 둘을 구분해야 T자 지점에서 오독이 없습니다.

그냥 교차 — 누가 위인지 없음 교차 홉 — 이미 있음(넘어감) 케이싱 — 배경색 밑칠로 지나감

⑰ 케이싱 casing / halo stroke

같은 선을 두 번 그립니다 — 먼저 배경색으로 7px, 그 위에 본색으로 1.8px. 아래 선이 자동으로 끊겨 보여서 위/아래가 생깁니다. 지도에서 도로 입체교차를 그리는 표준 방식.

솔직히 말하면 ⑭ 교차 홉과 같은 문제를 푸는 다른 답입니다. 차이는 이래요 — 홉은 넘어가는 선이 튀어서 SVG 경로가 복잡해지고 교차점 좌표를 미리 계산해야 하는데, 케이싱은 경로를 안 건드리고 렌더 순서만으로 해결됩니다(교차점 계산 0). 대신 배경이 단색일 때만 통해요. 노드 밑을 지나가는 선에도 그대로 씁니다.

얼마나 두껍게 깔 것인가는 두 갈래입니다. 배경색으로 불투명하게 3~4배(여기 예시는 1.8px 위에 7px)를 깔면 아래 선이 확실히 끊기지만 다발 안쪽에도 흰 틈이 생겨요. 반대로 1.4배에 불투명도 0.7만 주면 아래 선이 비쳐 보이면서도 위/아래는 읽힙니다 — 아이소메트릭 도구들이 쓰는 튜닝이고, 선이 촘촘할수록 이쪽이 낫습니다.

얕은 교차 — 어느 쪽으로 이어지는지 잃음 53° 깊은 교차 — 눈이 자동으로 갈라냄

⑱ 교차각 확보 crossing angle rule

교차를 없애는 규칙은 이미 여러 개 있는데(우회 채널·홉·다발), 피할 수 없는 교차를 어떻게 교차시킬지는 없습니다. 답은 각도예요 — 교차각이 30°보다 작아지면 읽는 시간이 지수적으로 늘어납니다(흐름도 설계 연구가 정리한 실험 결과). 직각에 가까울수록 눈이 두 선을 자동으로 분리합니다.

실무 규칙 세 줄. ① 교차를 못 없애면 둘 중 하나를 더 휘어서 각을 벌린다(선을 줄이는 것보다 각을 키우는 게 싸다). ② 노드에서 나가는 선들도 방사형으로 고르게 벌린다 — 좁은 각으로 몰리면 노드 근처에서 같은 문제가 생김. ③ 연결되지 않은 노드 밑으로는 선을 통과시키지 않는다. 이 셋은 앞 카드들과 달리 그림이 아니라 검사 항목입니다.

잘 됐는지 확인하기 — 2. 그리는 법이 아니라 다 그린 뒤에 걸러내는 항목. 자동 라우팅을 돌렸을 때 눈으로 제일 놓치기 쉬운 것들
① 끝점을 공유하지 않는 두 선이 나란히 달릴 때 A B C D 8px 이상 겹침 — 한 선의 분기로 읽힘 S C D 끝점을 공유하면 진짜 분기 — ⑫ 버스 백본 ② 컨테이너 테두리를 복도로 쓸 때 그룹 테두리와 구분이 안 됨 그룹 8px만 밖으로 비켜도 해결

⑲ 우연히 합쳐 보이는 선 corridor / border run

⑫ 버스 백본은 여러 선을 일부러 한 줄기로 모으는 기법이었죠. 그런데 끝점을 공유하지 않는 두 선이 우연히 같은 복도를 8px 이상 나란히 달리면, 그림은 똑같은데 뜻이 거짓말이 됩니다 — A→D와 B→C가 "A·B가 합쳐졌다 갈라진다"로 읽혀요. 기법과 버그를 가르는 건 그림이 아니라 끝점을 공유하느냐 하나입니다.

둘째는 컨테이너 테두리를 복도로 빌려 쓰는 것. 선이 그룹 상자의 변을 따라 붙어 달리면 테두리가 굵어진 건지 선이 지나가는 건지 못 가립니다. 테두리를 가로지르는 건 괜찮아요 — 따라 달리는 게 문제고, 같은 방향으로 겹치는 길이가 조금이라도 있으면 실패로 봅니다. 고치는 값은 쌉니다 — 8px만 비켜 놓으면 됩니다.

이 둘은 앞 카드들과 성격이 달라서 그리는 법이 아니라 확인하는 법입니다. 노드를 뚫고 지나가는 선은 바로 눈에 띄는데, 이 둘은 그럴듯해 보여서 그냥 넘어갑니다.

① 얼마나 돌아가도 되나 A B 꺾임 6 · 스트레치 1.8배 A B 꺾임 2 · 스트레치 1.0배 ② 포트 두 개가 7px 어긋났을 때 A B 7px 계단 — 사고처럼 보임 A B 16px 안쪽이면 축을 맞춰 직선

⑳ 경로 예산 route budget / rhythm

경로가 "좋다"를 숫자로 두면 자동 라우팅을 기계가 검사할 수 있습니다. 네 개면 충분해요 — 꺾임은 관계당 2번까지, 스트레치(실제 경로 길이 ÷ 직선 맨해튼 거리)는 1.35배까지, 모든 구간은 8px 이상, 끝점 스텁을 뺀 안쪽 구간은 16px 이상.

뒤의 두 개가 실무에서 더 자주 걸립니다. 포트를 벌리다 보면(① 포트 분산) 두 포트가 몇 px 차이로 어긋나고, 그러면 라우터가 7px짜리 계단을 하나 만듭니다. 이건 디자인이 아니라 렌더링 사고처럼 보여요. 답은 두 갈래 — 어긋남이 16px 안쪽이고 한쪽 끝만 벌어진 상태면 두 포트를 한 축에 맞춰 직선으로 만들고, 양쪽 다 벌어져서 못 맞추면 작은 계단 대신 24px 스텁 → 바깥 채널로 크게 돌아갑니다. 어느 쪽이든 작은 계단은 안 만든다가 규칙이에요.

스트레치 1.35라는 값이 의외로 관대합니다 — 되돌아가지 않는 직각 경로는 몇 번을 꺾어도 맨해튼 길이가 그대로라 대개 1.0배입니다. 1.35를 넘긴다는 건 경로 안에 되돌아가는 구간이 있다는 뜻이고, 실제로 꺾임 수보다 이쪽이 더 아프게 읽힙니다.

반대 방향 검사도 하나 있습니다 — 곧게 갈 수 있었는데 굽힌 경우. 두 노드의 포트 구간이 32px 이상 겹치고 그 사이에 다른 노드가 없으면, 꺾임은 몇 번이든 오류입니다. ⑲의 나머지가 "너무 돌아갔다"를 잡는다면 이건 "돌아갈 이유가 없었다"를 잡아요.

포트를 옮겨서 피할 때는 최소 변위가 원칙입니다 — 8px짜리 방해에는 8px로 답하고, 넓은 구간의 한가운데로 점프하지 않습니다. 몇 px을 수십 px의 이동으로 갚으면 "치운 선"이 아니라 "잘못 그린 선"으로 읽히거든요. 바라던 좌표에서 +12, −12, +24, −24 …로 바깥으로 훑어 나가면 결과도 결정론적입니다.

순서를 뒤집기 — 라우팅이 레이아웃에 공간을 청구한다
위 18개는 전부 이미 놓인 노드 사이를 어떻게 지나갈까였습니다. 그런데 자동 라우팅 결과가 늘 지저분한 진짜 이유는 기법이 부족해서가 아니라 순서예요 — 레이아웃을 먼저 확정하고 남은 틈에 선을 밀어 넣으면, 아무리 좋은 라우터를 써도 노드 관통과 겹침으로 끝납니다.

뒤집으면 이렇게 됩니다. 배치하기 전에 "이 선들을 그리려면 어디에 얼마의 공간이 필요한가"를 먼저 답하고, 레이아웃이 그 청구서를 반영해 폭을 넓힙니다. 한 줄 건너뛰는 선은 바깥 채널 한 칸, 같은 줄에서 이웃이 아닌 두 노드는 줄 안쪽 우회 레인 한 칸, 역방향 선은 반대편 채널 — 이렇게 세어서 복도 높이(첫 레인 28px, 이후 레인당 +12px)와 채널 폭(첫 레인 40px, 이후 +12px)을 계산해 넘깁니다. 한 발 더 가면 라우팅이 배치 순서까지 바꿉니다 — 주 흐름이 직선이 되도록 같은 줄 안에서 노드 자리를 맞바꾸는 것. 좌표를 임의로 옮기는 게 아니라 줄 안에서 자리만 교환하니 등간격은 그대로 유지됩니다.

그리고 못 그리면 그리지 않습니다. 후보를 다 시도해도 합격이 없으면 겹쳐 그리는 대신 왜 실패했는지를 코드로 남기고 아무것도 안 그려요("실패한 근거 자체가 영수증"). 그다음이 저하 사다리인데 순서가 좋습니다 — ① 선 위 라벨을 범례로 내리고, ② 부차 연결선을 뺍니다(단 절반 이상이 남을 때만 — "뜻의 절반 넘게 잃는 건 성공이 아니다"), ③ 그래도 안 되면 "한 장에는 안 들어간다"고 답하고 페이지를 나눕니다. 글자나 화살촉을 줄여서 억지로 맞추는 건 사다리에 아예 없습니다.

비용 함수도 인상적입니다 — 가중치가 하나도 없어요. 후보를 (꺾임 수 → 모양 등급 → 이동량) 순으로 정렬해 두고 위에서부터 첫 합격을 그냥 채택합니다. 탈락은 점수가 아니라 참/거짓이라, "왜 이 선이 이렇게 갔나"에 항상 한 줄로 답할 수 있어요. 포트를 옮길 때도 최소 변위가 원칙입니다 — 8px 방해에는 8px로 답하지, 넓은 구간의 한가운데로 점프하지 않습니다. 몇 px의 방해를 수십 px의 이동으로 갚으면 "치운 선"이 아니라 "잘못 그린 선"으로 읽히니까요.

04흐름 애니메이션 — 스타일별 27종

출처가 아니라 무엇이 변하는가로 묶었습니다. 다섯 축(굵기 · 통과 · 생성 · 상태 · 빛)이 서로 겹치지 않아, 한 다이어그램에서 고를 때는 축을 먼저 정하고 그 안에서 하나만 쓰면 됩니다.

A. 굵기가 변한다 — 선 자체가 두꺼워졌다 얇아짐. 방향보다 "살아있음 · 양"을 말함

① 맥박 pulse

선 전체가 부풀었다 줄어듦. "살아있다"는 신호만 주고 방향은 못 보여줌. 비용 0 — CSS 한 줄.

② 꿀렁 한 덩이 traveling bulge 추천

볼록한 덩어리가 관을 타고 이동 — 방향과 속도가 다 보임. 엘보든 곡선이든 경로를 그대로 따라감. 구현도 쌈.

③ 연속 꿀렁 peristalsis

여러 덩이가 줄지어 흐름 — 펌프질, 대량·연속 전송 느낌. 여러 선에 걸면 금방 시끄러워지니 1~2개까지만.

④ 가변 굵기 리본 variable-width

선 자체가 물결치며 부풀었다 좁아짐 — 가장 문자 그대로의 꿀렁꿀렁. 매 프레임 다시 그리는 JS라, 강조할 선 몇 개에만.

B. 무언가 지나간다 — 선은 그대로, 그 위를 물체 · 대시 · 글자가 이동. 방향과 속도가 보임

⑤ 알갱이 최소 형태

점만 지나가고 선은 안 부풂 — 꿀렁이 아니라 "패킷 하나"의 느낌. 개별 이벤트를 보여줄 때는 이쪽이 맞음.

⑥ 혜성 comet

머리 하나 + 뒤로 갈수록 작아지고 옅어지는 꼬리. ⑤ 알갱이의 상위 버전으로, 방향감이 훨씬 셈. 원본의 물리 spark(튀는 불똥)는 Canvas 전용이라 뺐습니다.

⑦ 몸통+머리 대시 패킷 rail pair

반투명 몸통 대시(16 25) 위에 진한 머리 대시(6 35)를 위상차 10으로 겹침 — "머리 달린 패킷"이 흐름. 원본은 어두운 배경에 밝은 머리, 밝은 배경에선 반대로 머리를 진하게. 굵기는 고정.

WEB DB INSERT

⑧ 라벨 패킷 token train / card 실무 추천

흐르는 게 무엇인지를 패킷에 적어서 보냄 — JWT, Request ID, INSERT, 이벤트명. 선 종류를 늘리지 않고 정보를 더하는 유일한 방법이라, 규칙 개수 예산을 안 씁니다.

POST /api/orders → 201 Created

⑨ 경로 위 텍스트 textPath

선 위에 라벨을 얹는 게 아니라 선을 따라 흐르게 함. SVG 네이티브 <textPath>라 Canvas보다 오히려 쉬움. 긴 페이로드·프로토콜 표기에 적합.

대시가 아니라 그라데이션이 이동 — 펄스는 언제나 하나 머리는 강조색, 꼬리는 다른 색 — 색만으로 방향이 읽힘

그라데이션 펄스 animated gradient

대시를 움직이는 게 아니라 그라데이션 좌표 자체를 이동시킵니다. 대시는 패턴이 반복돼 여러 개가 보이지만 이건 펄스가 언제나 정확히 하나고, 머리·꼬리에 다른 색을 줄 수 있어 색만으로 방향이 읽혀요. 좌표 시작·끝을 도형 바깥까지 빼는 게 요령 — 그래야 되감기는 순간이 화면에 안 걸립니다.

허브 Mini Pro Max 쉴 때도 색으로 구분 · 켜질 때 자기 색으로 흐름

계열색 순환 branch identity + cycling

두 가지가 겹쳐 있습니다. 하나는 분기마다 고유색 — 쉬는 동안에도 옅게 깔려 있어 어느 갈래가 뭔지 색만으로 압니다. 다른 하나는 한 번에 하나만 켜고 돌아가기 — 셋 다 동시에 움직이면 예산을 세 배 쓰지만, 번갈아 켜면 같은 예산으로 "셋 다 살아 있다"를 말할 수 있어요. 켜짐 구간은 주기의 1/n 남짓(원본은 분기당 2.2초). 여기 색은 강조가 아니라 이름이라 3색이 규칙 위반이 아닙니다 — 아래 참조.

offset-rotate: auto — 경로 기울기를 따라감 (화살촉·차량) LOG offset-rotate: 0 — 수평 유지 (라벨은 반드시 이쪽) JS·SMIL 없이 CSS만 — 내보낸 SVG도 돌고 PNG로도 굳음

CSS 모션 패스 offset-path추천

⑤⑥⑧처럼 경로를 따라 물체를 보내는 걸 CSS 한 줄로 합니다 — offset-path:path("…") + offset-distance 애니메이션. 이 컬렉션의 다른 이동 계열은 라이브는 JS, 내보낼 땐 SMIL로 변환하는데 이건 둘 다 필요 없습니다. 갈림길은 offset-rotate 하나 — 화살촉·차량은 auto(경로 기울기를 따라 눕고), 라벨은 0deg(안 그러면 뒤집혀서 못 읽습니다).

요청 WEB 나감 → 돌아옴 초록 OK / 빨강 오류 → 출발점 등에 남음

왕복 이벤트 펄스 round trip / request–response

점 하나가 나갔다가 같은 선으로 돌아옵니다. 돌아오는 점의 색이 결과이고, 출발점 표시등이 그 색으로 남아요. ⑤ 알갱이 · ⑥ 혜성은 끝없이 흐르는 이고 라우팅의 ⑥ 왕복 쌍은 선 두 개인데, 이건 한 번 일어난 사건을 선 하나로 — 방향이 뒤집히고, 색이 결과를 싣고, 흔적(표시등)이 남습니다. 요청·응답 · 헬스체크 · 지연 시간. 여러 홉이면 0 · 240 · 500 · 740ms 시차로 이어 붙입니다. 라이브는 JS, 내보낸 SVG·HTML은 SMIL 로 같은 3주기(OK · OK · 오류)를 돕니다.

C. 선이 생겨난다 — 없던 선이 그려지며 등장. 순서 · 인과 · 확산을 말함
요청 처리 응답

⑩ 드로우온 → 정착 → 흐름 draw-on

dasharray를 "경로길이 경로길이"로 두고 offset을 줄이면 선이 그려짐. 순서대로 등장 → 도착 시 화살표 → 그 위로 패킷 스트림 → 리셋. 내보낸 SVG/HTML은 한 번 그려진 뒤 계속 흐릅니다.

⑪ 그라데이션 누적 gradient chain

지나간 자리에 색이 남으면서 경로를 따라 색상이 변함 — 흐름의 "단계"를 색으로 표시. 원본은 Canvas 누적 페인트, 여기선 pathLength="100" + 그라데이션 stroke로 동일한 인상.

LB WEB-01 WEB-02 WEB-03

⑫ 분기 폭죽 fan-out

1:N 분산을 동시가 아니라 아주 짧은 시차로 뻗게 하면 "퍼져나간다"로 읽힘. 로드밸런서·브로드캐스트·팬아웃 큐. 시차 0이면 그냥 세 선이라 효과가 죽습니다.

linear — 등속. 반복 흐름은 이게 정답 ease-in-out — 무난하지만 끝이 단조로움 cubic-bezier(.16,1,.3,1) — 빨리 튀어나가 길게 안착 셋 다 같은 시각에 출발·도착 — 지금 어디까지 왔는지가 다름

이징 — 속도 곡선 value graph = cubic-bezier

모션그래픽의 값 그래프가 CSS의 cubic-bezier()와 같은 것입니다 — 곡선의 기울기가 곧 속도라, 펜 툴로 패스 만지듯 감가속을 직접 빚습니다(속도 그래프는 속도를 y축에 직접 그리는 방식이고, CSS로 흉내 내려면 linear()에 점을 찍어야 합니다). 규칙은 둘로 갈립니다끝없이 도는 흐름은 반드시 등속(이징을 걸면 루프 이음매에서 눈에 띄게 튐), 한 번 일어나는 전이는 이징. 그리고 전이에서는 끝이 단조롭지 않게 — 대칭 ease-in-out보다 빨리 튀어나가 길게 안착하는 곡선이 무게가 느껴집니다.

A B 가까워지면 목이 생기고, 붙으면 하나가 됨 blur → 알파 대비 → atop · 라벨이 필터 안에 있어도 또렷

구이 브리지 gooey / metaball

선이 그려지는 게 아니라 두 덩어리가 액체처럼 이어붙는 연결. 흐림(feGaussianBlur)을 준 뒤 feColorMatrix로 알파 대비를 극단으로 올려 경계를 되살리면, 가까워질 때만 목이 생깁니다. 화살표가 어울리지 않는 관계 — 병합 · 흡수 · 같은 그룹이 됨에 씁니다. 방향이 없는 게 특징이자 한계. 선이 아니라 노드가 통째로 움직여서 이 컬렉션에서 가장 비싼 효과(4.9%)입니다 — 정말 중요한 관계 하나에만.

두 숫자는 따로 놀면 안 됩니다. 알파 대비의 기울기(22)를 올리면 절편도 같이 내려야 임계값이 제자리에 있습니다 — 절편 = 0.5 − 기울기 × 5/12. 고전적인 18 −7 짝이 이 식에서 나오고, 기울기 22면 −8.67이에요. 임의로 −10을 쓰면 임계 알파가 0.42에서 0.48로 올라가 목이 얇아집니다 — 간격 6px에서 재 보니 14px → 9px로 35% 얇아졌습니다.

마지막 feComposite operator="atop"원본을 흐린 실루엣 위에 다시 얹습니다. 이게 없으면 필터 안의 글자·아이콘이 전부 뭉개져서, 구이 효과는 장식용 원에만 쓸 수 있게 돼요. 하나 더 — 필터는 SVG 콘텐츠에 걸어야 합니다. HTML 요소에 CSS filter:url()로 거는 방식은 WebKit이 다르게 그립니다.

반대편 근거도 적어 둡니다. 같은 구이 효과를 만들어 놓고 필터를 버린 사례가 있습니다 — 이유는 크롬·사파리·파이어폭스에서 같은 픽셀이 나온다고 보장할 수 없다는 것이고, 그래서 흐림+임계값 대신 그냥 원을 그렸습니다. 기하는 그대로 두고 경계만 안티에일리어싱에 맡기는 방식이에요. 거기 달린 주석이 이 카드에서 제일 쓸모 있습니다 — "그렇다고 반지름을 줄여서 보정하지 마라. 그러면 마크가 진짜로 작아진다." 필터가 만들어 주던 단단한 경계가 사라지면 조금 물러 보이는데, 그걸 크기로 벌충하면 튜닝해 둔 값이 통째로 무너집니다. 내보내기를 여러 브라우저에서 열게 할 거라면 필터 없는 쪽을 고르고, 모양을 정확히 지켜야 하면 필터를 고르세요.

D. 선의 상태가 바뀐다 — 선의 의미가 도중에 변함. 장애 · 차단 · 분기 · 재연결 같은 사건을 말함
요청 WEB-01 WEB-02

⑬ 장애 우회 failover reroute

죽은 경로는 지우지 말고 빨갛게 흐려서 남기고, 대체 경로를 새로 그림 — "무엇이 죽었는지"가 같이 보여야 장애도가 읽힘. 장애 시나리오·재해복구 문서에서 가장 값어치 있는 한 장.

요청 WAF WEB 도달 없음

⑭ 차단 · 소멸 blocked

선이 목적지까지 못 가고 경계에서 끝남 — 우회로가 있는 ⑬과 달리 여기서 끝. 뒷구간은 옅은 점선으로 남겨 "원래 가려던 곳"을 보여줍니다. WAF·정책 거부·권한 차단·rate limit.

요청 CACHE DB 응답 HIT MISS

⑮ 조건 분기 HIT / MISS

같은 요청이 조건에 따라 두 갈래 — 짧은 길과 긴 길이 번갈아 활성. ⑬처럼 하나가 죽는 게 아니라 둘 다 정상 경로라 쓰지 않는 쪽을 지우지 않고 흐리게 둡니다. 캐시·샤딩·A/B·폴백.

글로우 호흡 — 넓은 면적이 밝아짐 25.07% — 예산(3.56%)의 7배 코어 투명도만 2.57% 굵기 호흡 — 1.4 ↔ 2.8px 2.45% 점 하나만 박동 — 선은 가만히 0.33% — 같은 뜻, 76분의 1

⑯ 하트비트 idle heartbeat

상태 계열이 지금 장애 · 차단 · 조건 분기 셋인데 전부 사고입니다. "정상인데 지금은 조용함"이 없어요. 흐름 애니메이션은 "지금 트래픽이 있다"는 뜻이라 유휴 상태에 쓰면 거짓말이 됩니다. 하트비트는 연결이 살아 있다만 말합니다. 주기 2.3초, 밝아지는 데 0.6초 · 어두워지는 데 0.5초로 살짝 비대칭 — 심장 박동처럼 빨리 차고 천천히 빠지는 게 아니라 그 반대여야 기계 신호로 읽힙니다.

여기서 진짜 배울 건 비용입니다. 넷 다 "살아 있음"이라는 같은 뜻인데 변화율이 25.07% / 2.57% / 2.45% / 0.33%로 76배 벌어집니다. 호흡시키는 게 면적이냐 이냐의 차이예요. 그리고 하트비트는 흐름 애니메이션과 결정적으로 다릅니다 — 흐름은 강조하고 싶은 한 경로에만 걸지만, 하트비트는 살아 있는 링크 전부에 걸립니다. 링크가 20개면 예산을 20으로 나눠야 하니, 실질적으로 쓸 수 있는 건 점 박동뿐입니다.

원래 획 — 5 5 점선 = "보안 채널" 무한 반복 흐름 흐르는 내내 5 5가 지워짐 한 번 흐르고 획을 돌려줌 지나간 뒤 5 5로 복귀 정지를 누르면 — 혜성은 실선 강조로 굳고, 선을 타던 토큰은 아예 지움

끝난 자리 settled flow

이 섹션의 나머지가 전부 무한 반복입니다. 그런데 흐름을 대시로 표현하는 계열(⑦ 대시 패킷 같은)은 흐르는 동안 선이 원래 갖고 있던 점선의 뜻을 덮어씁니다 — 5 5가 "보안 채널"이었다면 흐르는 내내 그 정보가 사라져요. 이 컬렉션의 기존 답은 "그러면 대시 대신 굵기 계열을 써라"였는데, 다른 답이 있습니다.

한 번만 흐르고 원래 획으로 돌려주는 것. 페이지가 열리면 대시가 한 바퀴 지나가고, 끝나면서 빌려 썼던 10 8을 놓고 원래의 5 5로 복귀합니다. 흐름도 보여주고 뜻도 안 지우고, 예산은 한 번만 씁니다. 무한 반복이 기본값이어야 할 이유는 사실 없어요 — 계속 도는 건 "지금 이게 살아 움직인다"를 말할 때만 필요합니다.

여기서 규칙이 하나 더 나옵니다 — 멈출 때 무엇이 남는가를 기법마다 따로 정해야 해요. 혜성은 대시를 없애 실선 강조로 굳히고(경로가 그대로 남아서 쓸모가 있음), 선을 타고 가던 토큰은 아예 지웁니다(경로 중간에 멈춰 선 패킷은 아무 뜻도 없으니까). 그냥 일시정지시키면 둘 다 "고장 난 화면"이 됩니다.

움직임 최소화 설정에도 같은 질문이 그대로 옵니다. 흔한 처리는 "그 자리에서 멈춤"인데, 그러면 사용자마다 다른 순간의 그림을 보게 돼요. 더 나은 답은 대표 프레임 하나를 미리 고르는 것 — 시각 t를 상수로 박아 그 한 장을 그립니다. 크기·속도·상태에 상관없이 같은 순간이라 결과가 예측 가능해져요. 다만 정직하게 말하면 고른 순간이 모든 기법에 좋을 수는 없습니다 — 어떤 기법은 그 시각에 하필 "가장 흐트러진" 상태일 수 있어서, 기법마다 대표 시각을 따로 두거나 최소한 한 번은 확인해 보고 정해야 합니다.

» Action » Action 수집 connected +3 연결된 소스에서 대상을 모아 레코드 형식을 통일한다 보강 connected +2 기업 · 직무 · 의도 신호를 붙여 다음 단계로 넘긴다 Orbit Morph Slide 가운데 ⇄ 를 눌러보세요 — 자리가 바뀌는 동안 선은 끊깁니다 orbit 720ms · slide 520ms · morph 640ms

카드 스왑 — 재연결되는 선 Card Swap / reconnecting edge

두 노드의 순서를 뒤집을 때 연결선이 끊겼다가 새 위치에서 다시 이어집니다. Orbit · Morph · Slide 세 연출. 이 컬렉션의 주제가 선이니 볼 것은 카드의 움직임이 아니라 선이 없는 그 0.5초예요 — 자리가 확정되기 전에 선을 남겨 두면 존재하지 않는 연결을 그리는 셈이라, 끊는 게 정직한 처리입니다.

세 연출의 차이는 겹치는 순간 누가 앞인가에서 갈립니다. Orbit은 앞으로 나오는 카드를 위쪽 호로(scale 1.05), 뒤로 가는 카드를 아래쪽 호로(.94 · 투명도 .8) 보내 깊이로 답합니다. Slide는 수평 교차라 가장 싸지만 겹치는 프레임에서 앞뒤가 모호해요. Morph는 아예 자리를 안 옮깁니다 — blur 6px · 투명도 .35로 가장 흐려진 정점에서 내용만 맞바꿉니다. 그래서 Morph만 선을 끊지 않고 .35로 흐리기만 해요. 위치가 안 변하니 끊을 이유가 없습니다.

구현에서 걸리는 건 하나입니다 — 이동량을 transform에 누적하면 세 번째 스왑부터 자리가 어긋납니다. 애니메이션이 끝나면 transform을 0으로 되돌리고 자리 자체(x)를 맞바꿔 확정해야 해요. 실측으로 세 모드 각각 5회 연속 스왑 뒤에도 슬롯 좌표가 12 / 278 그대로였습니다. 전환 중의 두 번째 클릭은 무시합니다 — 안 막으면 애니메이션 두 개가 같은 카드에 겹쳐 위치가 꼬입니다. 움직임 최소화 설정에서는 연출 없이 즉시 교환합니다.

— 원본은 DOM·CSS 컴포넌트였고, 이 컬렉션은 모든 항목이 SVG라 내보내기가 SVG를 복제·래스터합니다. 그대로 넣으면 이 항목만 SVG·PNG·GIF로 못 나가서, 같은 인터랙션을 순수 SVG로 다시 구현했습니다. 데모용 껍데기(테마 버튼 · 색 스와치 · 전체화면 무대)는 컬렉션에 이미 있어 가져오지 않았습니다.

E. 빛난다 — 밝기로 강조. 상시 · 순간 · 이동, 세 가지뿐
밝은 배경 — 헛수고 어두운 배경 — 제 값

⑰ 발광 레일 glow

같은 경로를 넓게(16~18px) · 낮은 불투명도(.16~.26)로 한 번 더 깔고 위에 또렷한 심선을 얹으면 끝 — 원본 Canvas도 정확히 이 방식입니다. 핵심은 어두운 배경에서만 값어치가 있다는 것. 밝은 배경에선 그냥 선이 두꺼워 보일 뿐입니다.

발신 수신 도착하는 순간에만 번쩍 — 나머지 시간은 조용

⑱ 도착 플래시 arrival flash

패킷이 닿는 순간 링이 퍼지고 노드 테두리가 한 번 번쩍입니다. 흐름 애니메이션은 "가는 중"만 보여주는데, 이건 "도착했다"는 사건을 찍어줘서 인과가 읽힙니다. 계속 깜빡이면 경고등이 되니 사건에만.

번짐 있는 넓은 띠 + 또렷한 심 — 같은 주기, 위상 −10

⑲ 스캔 스윕 scan sweep

⑦ 대시 패킷과 같은 기법인데 넓은 쪽을 흐리게(feGaussianBlur) 처리하면 "패킷"이 아니라 "빛이 훑고 지나감"으로 읽힙니다. 점검·스캔·인덱싱처럼 대상이 아니라 행위가 지나가는 흐름에.

제대로 하려면 두 가지가 더 필요합니다. 하나는 가장자리를 딱 끊지 않는 것 — 띠의 밝기를 계단이 아니라 가우시안으로 떨어뜨리면(반폭 25° 남짓) 훑는 느낌이 나고, 각도로 도는 스캔이라면 차이를 atan2(sin Δ, cos Δ)로 계산해야 한 바퀴 도는 자리에 이음매가 안 생깁니다. 다른 하나는 훑지 않은 부분을 죽이는 것 — 훑는 쪽만 밝히면 대비가 부족해서, 나머지를 45% 정도로 내려야 띠가 확실히 읽힙니다. 05 포커스 디밍의 사다리와 정확히 같은 원리예요 — 강조는 밝히는 게 아니라 나머지를 죽이는 것입니다.

움직임 예산 — 실제 제작물이 지키는 숫자
널리 도는 시스템 설계 뉴스레터 GIF 6개를 실측한 값: 루프 2.10~2.75초, 20 또는 33.3fps 균일, 그리고 한 루프 동안 캔버스의 1.20~3.56%만 변합니다 — 프레임은 전부 서로 다르고(죽은 프레임 0), 노드·라벨·카메라는 미동도 안 합니다. 조용해 보이는 이유가 취향이 아니라 예산이었던 거죠. 그래서 이 컬렉션의 애니메이션 25종도 전부 실측해 카드마다 %를 붙였습니다(한 번만 흐르는 항목은 % 대신 "1회"로 표시).

결과가 규칙을 하나 알려줍니다 — 선 전체가 동시에 변하는 기법이 예산을 혼자 다 먹습니다. 스캔 스윕(4.2%)과 맥박(3.8%)만 상한을 넘겼고, 작은 물체가 지나가는 계열(알갱이 0.8% · 혜성 2.3% · 패킷 2.7%)은 훨씬 쌉니다. 계열색 순환은 분기 셋을 쓰고도 0.8% — 번갈아 켜는 게 예산에 얼마나 유리한지 숫자로 나옵니다. 카드 하나에 기법 하나인 이 페이지에서도 그런데, 노드 수십 개짜리 실제 다이어그램이라면 움직이는 선은 정말 하나여야 합니다. 상한을 넘는 항목은 %가 빨갛게 표시됩니다.

예산을 비율이 아니라 소유권으로 관리하는 방법도 있습니다 — 동시에 움직일 수 있는 건 하나로 정해놓고, 더 강한 의도가 들어오면 앞의 것을 끄고 가져갑니다(경로를 고르는 중 > 항목 선택 > 단순 호버 순). 둘을 같이 쓰면 좋아요 — 비율은 "이 기법 하나가 얼마나 시끄러운가", 소유권은 "몇 개가 동시에 시끄러운가"를 잡습니다. 그리고 대상이 너무 많을 때는 흐리게 그리는 게 아니라 아예 안 그리는 쪽이 낫습니다. 한 번에 24개가 넘는 선이 동시에 흐르면 어느 것도 안 읽히니까, 그 수를 넘으면 애니메이션을 통째로 생략하는 겁니다.

경로가 여러 개라 하나만 고를 수 없다면 순환 활성(한 번에 하나씩 돌아가며)이 답입니다.
쓰임새 규칙
전부 화면 전용입니다 — 인쇄·정적 이미지에서는 화살표 + 굵기 차등으로 대체하세요. 한 화면에서는 한 경로에만 — 위 예산이 그 근거입니다. "선 규칙 2~3개 + 강조 1개" 셈법에서 애니메이션이 강조 1개 자리를 차지합니다. 점선을 이미 "비동기" 의미로 쓰고 있다면 B 계열의 대시 패킷 대신 A 계열(굵기)을 쓰면 의미 충돌이 없습니다. 움직임 최소화 설정을 켠 사용자에게는 전부 멈춥니다(prefers-reduced-motion) — 이건 취향이 아니라 접근성 요건이라 내보낸 SVG에도 같이 실립니다. 여러 선을 동시에 움직일 때는 선마다 위상 오프셋을 다르게 주고 루프 길이를 정수배로 맞추세요 — 전부 같은 박자로 뛰면 다이어그램이 아니라 전광판이 되고, 루프가 정수가 아니면 GIF 이음매가 튑니다. 반복은 등속, 일회성 전이만 이징 — 도는 흐름에 이징을 걸면 매 바퀴 이음매에서 튀어 보입니다.
위상 — 같은 뜻은 맞추고, 다른 뜻은 어긋나게 뜻이 다른 셋 — 어긋나게 읽기 쓰기 복제 서로 다른 트래픽으로 읽힘 뜻이 같은 셋 — 맞춰서 웹 1 웹 2 웹 3 한 덩어리(=한 서비스)로 읽힘
쓰임새 규칙에 "선마다 위상 오프셋을 다르게 주라"고 적어놨는데, 그건 절반이었습니다. 뜻이 다른 선끼리는 어긋나게, 뜻이 같은 선끼리는 맞춰서 — 왼쪽은 셋이 각각 다른 트래픽으로 읽히고, 오른쪽은 셋이 한 서비스의 세 대로 읽힙니다. 한 화면에 둘 다 나올 수 있고, 어느 쪽이든 의도여야 합니다.

그런데 맞추는 쪽이 생각보다 어렵습니다. CSS 애니메이션의 위상은 "시작 이후 경과 시간"이라, 잠깐 멈췄다 켜면 맞춰둔 위상이 깨집니다. 화면 밖 카드를 animation-play-state:paused로 멈추는 이 페이지도 그래요 — 재 보니 370ms 멈춘 선이 안 멈춘 선보다 정확히 그만큼 뒤처집니다. 답은 위상을 경과가 아니라 시계에서 읽는 것: t = performance.now()/1000 × 속도로 매 프레임 위치를 계산하면, 멈췄다 켜도 시계가 있는 자리로 바로 복귀합니다. 화면 밖에서 애니메이션을 멈추는 최적화와 위상 규칙을 둘 다 지키려면 이 방법밖에 없어요.

같은 발상을 한 단계 더 밀면 애니메이션 전체가 시간의 순수 함수가 됩니다. 패킷이 매번 다른 경로를 타게 하고 싶을 때, 난수를 저장하는 대신 floor(t)시드로 쓰고 frac(t)경로 위 위치로 쓰면 상태를 하나도 안 들고도 순회마다 경로가 바뀝니다. 이렇게 두면 되감기 · 정지 · 재개 · GIF 인코딩 · 렌더러 간 비교가 전부 공짜로 따라와요 — 어떤 시각 t의 그림이 항상 같으니까요.
SVG로는 안 되는 것 — 이건 Canvas가 맞습니다
수천 개 파티클(먼지·불똥), 물리 상태를 가지는 spark(속도·중력·감쇠), 지우지 않고 계속 덧칠하는 누적 텍스처 — 이 셋은 SVG로 흉내 내면 노드 수가 폭발하고 내보내기도 깨집니다. 처음엔 여기에 발광·블러도 넣었는데 오판이었습니다 — 원본 Canvas의 glow는 같은 경로를 넓게·옅게 한 번 더 그리는 게 전부였고 SVG에는 feGaussianBlur가 있습니다. 그래서 E 계열로 회수했습니다. 필요하면 SVG는 좌표 엔진, Canvas는 렌더러로 나누는 구조가 맞습니다. 반대로 사전 샘플링(매 프레임 getPointAtLength()를 부르지 않고 미리 계산)과 시맨틱 메타데이터(선에 role / stage / kind를 붙여두면 연출이 데이터가 됨)는 렌더러와 무관한 원칙이라 이 파일도 같은 방식(data-xa-*)을 씁니다.

05반응 — 마우스에 반응하는 선 7종

지금까지는 스스로 움직이는 선이었고, 이건 사람이 건드리면 반응하는 선입니다. 정보를 처음부터 다 보여주지 않고 물어볼 때 꺼내 놓을 수 있어서, 밀도 문제를 근본에서 줄입니다. 아래 카드의 선 위에 마우스를 올려보세요 — 내보낸 SVG를 브라우저에서 열어도 그대로 반응합니다.

히트 영역 = 선 두께 그대로 — 잘 안 잡힘 투명 히트 패스 16px — 쉽게 잡힘 선택된 상태(항상 강조) 키보드 — 여기까지 Tab으로 오면 포커스 레일이 켜집니다

호버 · 선택 3상태 hover / selected

기본 1.5px 옅은 선 → 호버 시 강조색 3px → 선택 시 고정 강조. 전환은 150ms, stroke와 stroke-width에만. 핵심은 보이지 않는 굵은 히트 패스(16px, stroke:transparent)를 밑에 깔아두는 것 — 안 깔면 1.5px 선을 마우스로 맞춰야 해서 고장 난 것처럼 느껴집니다. 단 보이는 선이 히트 패스를 덮으므로 형제 선택자 대신 둘을 <g>로 묶어 그룹 호버로 받아야 정중앙에서도 잡힙니다.

히트 패스는 마우스 얘기고, 키보드는 답이 따로 필요합니다. 사각형이면 브라우저 기본 포커스 링이 그려지는데 선에는 그릴 테두리가 없어요. 방법은 포커스 레일 — 히트 패스와 같은 경로에 6px 점선(2 4)을 34% 투명도로 깔아두고 :focus-visible에서만 켭니다. 선을 따라가는 점선 띠라 어느 선이 잡혔는지 바로 보이고, vector-effect:non-scaling-stroke를 주면 확대해도 두께가 안 변합니다. 위 네 번째 줄에 Tab으로 들어가 보세요 — 내보낸 SVG에서도 그대로 동작합니다.

두 가지가 더 붙습니다. 터치·굵은 포인터에서는 히트 패스를 24px까지 넓히고 (@media (pointer: coarse)), 렌즈나 포커스 모드가 켜져 있는 동안에는 히트 패스를 pointer-events:none으로 꺼야 합니다 — 안 끄면 모드끼리 서로 클릭을 뺏습니다.

계획 실행 관계 정의 평소 35% · 선에 올리면 100%

라벨 지연 노출 deferred label

라벨을 평소엔 35%로 죽여두고 선에 마우스를 올릴 때만 살립니다. 선이 20개인 다이어그램에서 라벨 20개를 항상 띄우면 못 읽는데, 이러면 밀도를 안 올리고 정보를 다 담을 수 있습니다. 종이로 낼 거면 못 쓰는 기법.

API 서버 노드에 올려야 연결점이 나타남

연결점 지연 노출 port reveal

연결 가능한 지점을 평소엔 완전히 숨기고(opacity 0) 노드에 올렸을 때만 띄웁니다. 안 그러면 노드마다 점 네 개가 상시로 붙어 다이어그램이 회로도처럼 보여요. 편집 가능한 캔버스의 기본 예의.

LB A B C 한 선에 올리면 나머지는 16%로

포커스 디밍 focus dim

한 선에 올리면 나머지를 16%까지 죽여 그 경로만 남깁니다. 선이 많을 때 "이 요청이 어디로 가는가"를 레이아웃을 안 바꾸고 답해줘요. — 원본에는 없고, 위 셋과 같은 축이라 채워 넣은 확장입니다.

죽이는 정도를 한 값으로 두지 않고 질문이 좁을수록 더 깊게 가져가면 한 단계 좋아집니다. 실제로 쓰이는 사다리는 대략 이래요 — 아직 목적지를 고르는 중이면 24%, 그냥 지나가는 호버는 20%, 선 하나를 집었으면 16%, 노드 하나에 집중이면 13%, 종류로 걸러낸 상태면 11%, 상·하류 전체를 물었으면 9%. 답이 정확할수록 배경을 더 지운다는 한 줄이 전부입니다.

노드 A 가운데 원 위에 마우스를 올려보세요 — 노드는 그대로, 선만 비켜납니다 (렌즈 반경 46px)

엣지 렌즈 EdgeLens

커서 주변의 선만 밀어내고 노드는 안 움직입니다. 레이아웃(=사용자가 외운 위치)을 안 건드리면서 가려진 것만 드러내는 게 핵심 — 노드를 같이 밀면 매번 지도가 달라져서 오히려 헤맵니다. 시각화 연구 그룹에서 나온 기법이고, 여러 렌즈를 동시에 쓸 수 있습니다.

구현이 생각보다 쌉니다. 직선도 큐빅으로 미리 써두면(C 명령 개수만 같으면) CSS d 속성이 그대로 트랜지션됩니다 — JS 없이 :has(.hit:hover) 한 줄. 지금 포커스 디밍이 "관계없는 걸 흐리게"라면, 이건 "가리는 걸 치운다"라 반대쪽 답입니다. 흐리면 정보가 없어지는데, 밀면 다 남아요.

가운데에 마우스를 올려보세요 — both 모드: 양 끝이 모두 안에 있는 선만 남김 (12 → 4)

엣지 필터 렌즈 edge filter lens

지난번에 넣은 엣지 렌즈와 이름이 비슷한데 반대입니다 — 그건 선을 밀어내서 가린 걸 드러냈고, 이건 선을 지워서 남길 걸 고릅니다. 밀어내기는 밀도가 낮을 때, 지우기는 밀도가 아주 높을 때 씁니다.

진짜 배울 점은 nodeType 옵션 하나예요 — 무엇을 "안에 있다"고 볼 것인가를 네 가지로 나눕니다. both(양 끝이 다 안) · either(한쪽만 안이어도) · source(출발점이 안) · target(도착점이 안). 같은 원을 올려도 묻는 질문이 완전히 달라져요 — both는 "이 동네 안에서 무슨 일이 있나", either는 "이 동네가 바깥과 어떻게 엮이나", source는 "여기서 나가는 게 어디로 가나". 렌즈를 만들 때 반경보다 이 선택을 먼저 정해야 합니다.

편집 경로 공개 읽기 칩에 마우스를 올리거나 Tab으로 들어가 보세요 인증 안쪽 브라우저 게이트 문서 DO 방문자 캐시 저장소 1 2 3 1 2 켜진 것만 100% · 선 13% · 노드 30% · 영역 45% — 역할마다 다르게 죽입니다 번호는 디밍이 답하지 못하는 것을 답합니다 — 몇 번째 홉인가

경로 켜기 route highlight

앞의 포커스 디밍이 "이 선 하나"를 남긴다면, 이건 미리 정해둔 여러 홉을 한 덩어리로 켭니다. 질문이 "이 선이 어디로 가나"가 아니라 "이 요청은 어떤 길로 지나가나"일 때 쓰는 쪽이에요. 경로는 정의해 두는 것이지 계산하는 게 아닙니다 — 아무 노드나 골라 최단경로를 찾아주는 건 이 컬렉션 밖(자동 경로탐색)입니다.

배울 점은 죽이는 깊이를 하나로 두지 않는다는 겁니다. 실측된 배분은 선 13% · 노드 30% · 영역 45%. 노드를 선만큼 죽이면 경로가 어디를 지나는지가 같이 사라지고, 배경 경계까지 죽이면 사용자가 외운 지도가 없어져서 켤 때마다 위치를 다시 찾습니다. 포커스 디밍 카드의 사다리가 "질문이 좁을수록 깊게"라면, 이건 같은 상태 안에서 역할별로 나누는 축입니다.

그리고 켜는 것만으로는 순서가 안 나옵니다. 원본 아티팩트는 순서를 그림 밖 단계 목록으로 뺐는데 (재보면 그림 안 번호 배지용 CSS는 만들어져 있고 끝내 쓰이지 않았습니다), 그러면 눈이 그림과 목록을 왕복해요. 홉마다 번호를 선 위 중간에 얹으면 한 번에 읽히고, 정지 이미지에도 순서가 남습니다 — 행진 대시로 방향을 주는 방식은 PNG로 내보내는 순간 사라지니까요.

마지막 함정. 켤 때 stroke만 바꾸면 화살촉은 원래 색으로 남습니다. 원본은 마커를 두 벌 만들어 marker-end를 갈아끼웠고, 이 카드는 화살촉 색 상속 카드의 값 하나로 처리했습니다 — 지금 이 그림에서 켜질 때 촉이 같이 물드는 게 그겁니다.

06이 컬렉션이 하지 않는 것

항목마다 "왜 넣었나"는 카드에 적혀 있습니다. 여기는 그 반대 — 봤는데 안 넣은 것과 그 이유입니다. 고르는 목록이 쓸모 있으려면 고르지 않은 이유도 같이 있어야 하니까요.

추가하지 않는 기준
기법이 같고 값만 다른 것은 항목이 아닙니다. 굵기 숫자가 다르거나 색이 다르거나 곡률 파라미터가 다른 건 이미 있는 카드의 사용법이지 새 기법이 아니에요. 화살촉 모양 일곱 가지, 베지어 보간 다섯 가지, 이름만 다른 흐르는 대시가 전부 이 기준에서 걸러졌습니다. 컬렉션이 커지는 게 목적이 아니라 고를 수 있는 게 목적입니다.
범위 밖이라 뺀 것
순수 SVG로 안 되는 것 — 수천 개 파티클, 물리 기반 스파크, 누적 텍스처. 노드 수가 폭발합니다. Canvas가 맞습니다.
DOM 전용인 것conic-gradient+마스크, radial-gradient 여러 겹으로 쌓는 글로우. SVG 도형을 채우거나 칠하지 못합니다.
연결선이 아닌 것 — 노드 테두리 장식, 아이콘 라이브러리, 레이아웃 배치 알고리즘, 씬 편집 UI. 자동 경로탐색·자동 배치는 결과물의 생김새 규칙만 가져오고 계산은 가져오지 않았습니다.
업무와 무관한 표기 — ER 다이어그램의 카디널리티(까마귀발) 같은 도메인 전용 기호.
만들어보고 뺀 것 · 틀렸다가 고친 것
합집합 외곽선(feMorphology로 다발 전체를 감싸는 테두리)은 두 번 만들었는데 데모에서 개별 케이싱과 차이가 안 보여서 뺐습니다 — 선 간격이 팽창 반경의 2배 안일 때만 달라지는데, 그 조건이 실제 도면에서 드뭅니다. 보이지 않는 이점은 카드로 만들지 않았습니다.
구이 브리지의 알파 대비는 처음에 22 −10이었는데, 절편이 기울기를 따라가야 한다는 걸 나중에 알고 22 −8.67로 고쳤습니다(목 두께 9px → 14px 실측). 다발 묶기도 사실상 β=1로 그려져 있던 걸 뒤늦게 확인해 강도 다이얼 카드를 따로 세웠습니다. 발광은 한때 "Canvas 전용"으로 잘못 분류했다가 회수했습니다.
SVG 인포그래픽 생성 스킬에서는 9종 다이어그램 타입팩(승인 게이트 · 로드맵 · 결정 매트릭스 등)을 뺐습니다 — 다이어그램 종류지 연결선 표현이 아니라서요. 점선 어휘도 안 가져왔습니다. 거기는 5 4 하나로 고정인데, 이 컬렉션의 굵기 상대 대시(대시 = 굵기×2)와 충돌하고 고정값은 획이 2~3px일 때만 맞는 값이거든요. 라벨 처리도 "선 옆에 두고 24px 띄운다"는 회피 규칙만 있고 마스크·헤일로 규격이 없어서, 기존 라벨 마스킹 카드 쪽이 낫다고 판단했습니다.
상태 표시 컴포넌트에서는 구체 위 3D 점 배치(궤도 · 위경도 격자 · 땋기 · 리본)를 통째로 뺐습니다 — 연결선이 아니라 마크라서요. 땋기의 "각도는 그대로 두고 반지름만 2배 주파수로 흔들어 교차처럼 보이게" 하는 착시는 예뻤지만, 다이어그램에서 없는 교차를 만드는 건 오독이라 뺐습니다. 골든 벡터 회귀 테스트(정해둔 네 시각의 드로우 리스트를 숫자로 비교)는 좋은 방법론이지만 표현 기법이 아니라 검증 방식이라 카드로 세우지 않았습니다.
다이어그램 자동 생성 도구의 라우팅 검사 규칙집에서는 프리셋 4종(획 끝 · 글로우 · 굵기 · 대시 밀도 · 지속시간을 한 번에 바꾸는 스타일 묶음)을 보고도 뺐습니다 — 제품의 톤 설정이지 연결선 표현 축이 아니라서요. pathLength="1" + 분수 대시로 길이를 정규화하는 방식도 좋았지만 이미 있는 pathLength="100"같은 아이디어라 카드를 세우지 않았습니다.
하트비트는 넣긴 했지만 네 가지 구현의 비용이 25.07% / 2.57% / 2.45% / 0.33%로 76배 벌어져서, 실질적으로 쓸 수 있는 건 점 박동 하나뿐이라는 걸 카드에 같이 적었습니다.
에이전트용 HTML 아티팩트 스킬 묶음(다이어그램·와이어프레임·프로토타입 지침 + 예제 아티팩트)에서는 두 개만 가져왔습니다. 거기 아키텍처 아티팩트는 상태가 바뀔 때 marker-end두 번째 마커로 갈아끼워 화살촉 색을 맞추고 있었는데, 같은 문제를 마커 하나로 푸는 값(context-stroke)이 있어서 화살촉 색 상속을 세웠고 — 복제는 이 컬렉션의 공용 defs에도 여섯 벌 있던 문제라 남 얘기가 아니었습니다 — 경로별 하이라이트에서 죽이는 깊이를 요소 역할별로 나눈 배분(선 13 / 노드 30 / 영역 45)을 읽어 경로 켜기를 세웠습니다. 거기서 순서 배지용 CSS가 만들어져 있는데 그림에는 한 번도 안 쓰이고 순서가 그림 밖 목록으로 나가 있는 것도 확인해서, 카드에서는 번호를 그림 안으로 넣었습니다.
같은 자료에서 뺀 것은 이렇습니다. 씬 팬·줌 규칙(컨테이너 <g> 하나만 변환 · 커서 밑의 점 고정 · 드래그 임계값으로 클릭 억제 · grab 커서 · 배율 표시와 리셋)은 잘 정리돼 있지만 연결선이 아니라 씬 조작 UI라 범위 밖입니다. 질문 → 다이어그램 문법 매핑표(토폴로지 · 시퀀스 · 프로세스 · 상태 · 계층 · 타임라인 · 매트릭스)와 매체 고르기(HTML/CSS · SVG · Canvas · WebGL)도 좋은 지침이지만 다이어그램 종류·설계 쪽이라, 예전에 9종 타입팩을 뺀 것과 같은 이유로 안 가져왔습니다. "똑같은 라운드 박스 벽지를 피하라"와 존·경계 박스는 노드 표현이고, 코디네이티드 뷰·레이어 토글은 화면 구성입니다.
카드 스왑 데모(두 카드의 자리를 맞바꾸는 인터랙션)에서는 연결선이 끊겼다 다시 붙는 구간만 가져왔습니다. 원본은 DOM·CSS 컴포넌트였는데 이 컬렉션은 모든 항목이 SVG이고 내보내기가 그 SVG를 복제·래스터하는 구조라, 그대로 옮기면 그 항목만 SVG·PNG·GIF로 못 나갑니다 — 그래서 같은 인터랙션을 순수 SVG로 다시 구현했고, 데모용 껍데기(테마 버튼 · 색 스와치 · 전체화면 무대)는 컬렉션에 이미 있어 안 가져왔습니다. 구현하면서 원본에 없던 문제도 하나 나왔습니다 — 원본은 자리를 CSS([data-pos=b])로 잡아서 morph 가 속성 하나만 바꾸면 자리도 바뀌었는데, SVG 에서는 자리가 좌표(x)라 같은 코드가 흐려지기만 하고 안 바뀝니다. "위치는 건드리지 않는다"를 문자 그대로 옮기면 깨지는 자리라 카드에 함께 적었습니다.
쿠버네티스를 신디사이저 랙으로 그린 사이트(kubernetes3d)에서는 패치 케이블에서 다섯을 가져왔습니다 — 행잉 케이블 · 처짐 차등 · 드롭 섀도 · 왕복 이벤트 펄스 · 순환 벨트. 그 사이트의 나머지는 뺐어요. 발진기 옆 파형 신호선은 전기 회로 기호(도메인 전용), 해칭 단면 · 코일은 노드 장식, 앞·뒤·단면으로 케이블을 세 겹 다시 그리는 것은 카드 스왑(재연결되는 선)의 사용법, 데이터면·관리면을 색으로 가르는 것은 색상 카드의 사용법입니다. 폭 1600px 고정 + 가로 스크롤은 반면교사로만 — 이 컬렉션은 카드마다 viewBox 라 그 문제가 없습니다.
출처
전부 기법과 수치를 읽고 다시 구현한 것이며 원본 코드를 복제하지 않았습니다. 참고한 자료는 그래프 드로잉 사용자 연구, 지도학 흐름도 설계 원칙, 오픈소스 다이어그램·그래프 엔진과 그 플러그인 문서, 지하철 노선도·회로도의 오래된 관행, 에이전트용 HTML 아티팩트 스킬 묶음의 다이어그램 지침, 그리고 널리 도는 제작물과 그 예제 아티팩트를 직접 실측한 값입니다. 공개본에서는 개별 출처명을 적지 않았습니다.
새 항목을 추가할 때
① 다섯 축 중 어디인지 먼저 정하고(안 정해지면 그건 새 축이거나 기존 항목의 변형입니다), ② 순수 SVG로 되는지 확인하고 — 안 되면 버리거나 "Canvas가 맞다"에 적고, ③ 카드에 data-catdata-export(고유 ID)를 달고, ④ 움직이면 data-anim + sampleCycle()에 한 사이클 길이를 등록하고, ⑤ 06에 버린 것까지 적습니다. 기존 항목과 기법이 같고 상황만 다르면 추가하지 않습니다 — 컬렉션이 커지는 게 목적이 아니라 고를 수 있는 게 목적입니다.
단일 HTML · 다크 모드와 강조색은 내보내기에 그대로 반영됨 · 외부 의존성 0 (GIF 인코더 gifenc, ZIP writer 내장 · 둘 다 MIT) · 내보내기: SVG · HTML은 애니메이션 내장, PNG는 현재 프레임 2배 해상도, GIF는 20fps 한 사이클 · 전체 SVG는 ZIP 파일. 제외 목록과 원칙은 06 참조.
라이선스 — 이 컬렉션(HTML · SVG · 설명 문안)은 MIT License로 배포합니다. 마음대로 쓰고 고치고 재배포해도 됩니다.
Copyright (c) 2026 · Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
포함된 서드파티 — GIF 인코더 gifenc (MIT, Copyright (c) 2017 Matt DesLauriers). 전문은 소스 상단 주석에 있습니다. MIT는 저작권 고지 유지를 요구하므로 이 항목은 익명화 대상이 아닙니다.