npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cardenelabs/cdl

v0.14.0

Published

CDL (Chainome Diagram Language). Mermaid-like declarative DSL that compiles to animated SVG diagrams. Built for blockchain / Solidity flows, generic enough for sequence / flow / state / ER / topology diagrams.

Readme

@cardenelabs/cdl

Declarative TypeScript DSL for animated React + SVG diagrams. UML / ER / state machine / topology / sequence / flow を 1 行で書く OSS library。

npm license

Documentation

| 目的 | リンク | |---|---| | repo root | github.com/cardene777/cdl | | 5 分で動かす | README quickstart (本 file 下部) | | playground demo | pnpm dev → http://localhost:4321 (apps/playground) | | 全 API + preset 一覧 | playground /docs/reference | | Text DSL spec | apps/playground/src/content/cdl-docs/text-dsl-spec.md | | LLM prompt guide | apps/playground/src/content/cdl-docs/text-dsl-llm-guide.md | | contribute | CONTRIBUTING.md |

なぜ cdl

mermaid / PlantUML はテキストから静止画像を生成する。 cdl は TypeScript → animated React + SVG component で、 phase / state / tween / progress glow 等の動きを宣言的に書ける。

| 形式 | mermaid | cdl | |---|---|---| | sequence | 静止 | animated + phase 切替 | | ER 図 | 静止 | animated + cardinality + sub label | | state diagram | 静止 | animated + initial/final marker + guard | | flow | 静止 | animated + dotted-flow 進行点 glow | | 構成図 / deployment | 限定的 | animated + container group + connection | | 自由レイアウト | 限定的 | lane + node + edge で自由構成 |

Quickstart

pnpm add @cardenelabs/cdl react react-dom

diagram declare

import { sequence } from "@cardenelabs/cdl";

export const authSeq = sequence({
  id: "auth",
  topic: "User Login",
  actors: ["User", "API", "DB"],
})
  .step({ from: "User", to: "API", label: "POST /login", sub: "email + password" })
  .step({ from: "API", to: "DB", label: "SELECT credentials" })
  .step({ from: "DB", to: "API", label: "rows", tone: "success", style: "dotted-flow" })
  .step({ from: "API", to: "User", label: "200 OK", sub: "JWT token", tone: "success" })
  .build();

React で render

import { CdlDiagramView } from "@cardenelabs/cdl";
import { authSeq } from "./auth-seq";

export function AuthSequenceDemo() {
  return <CdlDiagramView diagram={authSeq} />;
}

これで UML sequence diagram が phase 切替 + state diff + 進行点 glow で animated に表示。

6 つの preset

低位 API (lane / node / edge 個別宣言) + 高位 preset (1 行で典型図生成)。

swimlane

横並び 3 lane 自動配置 + slug 自動。

swimlane({ id, topic, lanes: ["送信元", "Contract", "出力"] })
  .node("alice", { lane: "送信元", stack: 0, kind: "actor", title: "Alice" })
  .node("fn", { lane: "Contract", stack: 0, kind: "function", title: "transfer(...)" })
  .edge("alice", "fn", { id: "call", label: "call", tone: "accent", style: "dotted-flow" })
  .build()

flow

1 lane 縦 stack、 前 step → 次 step 自動 edge。

flow({ id, topic, laneLabel: "Auth Flow", defaultTone: "teal" })
  .step({ id: "user", kind: "person", title: "User" })
  .step({ id: "api", kind: "api", title: "POST /login" }, "ログイン要求")
  .step({ id: "db", kind: "database", title: "users 表" }, "credential 検証")
  .build()

sequence

UML sequence diagram (actor lifeline + 時系列 message)。

sequence({ id, topic, actors: ["User", "API", "DB"] })
  .step({ from: "User", to: "API", label: "POST /login" })
  .step({ from: "API", to: "DB", label: "SELECT" })
  .step({ from: "API", to: "User", label: "200 OK", tone: "success" })
  .build()

topology

構成図 / deployment diagram (group + container + connection)。

topology({ id, topic })
  .group("aws", { label: "AWS" })
    .add({ id: "alb", kind: "service", title: "ALB" })
    .add({ id: "ecs", kind: "service", title: "ECS Task" })
    .add({ id: "rds", kind: "database", title: "RDS" })
  .group("client", { label: "Client" })
    .add({ id: "browser", kind: "frontend", title: "Browser" })
  .connect("browser", "alb", { label: "HTTPS" })
  .connect("ecs", "rds", { label: "TCP 5432", tone: "success" })
  .build()

er

ER 図 (entity + cardinality)。

er({ id, topic })
  .entity({ id: "user", title: "User", rows: ["id: PK", "email: string", "createdAt: timestamp"] })
  .entity({ id: "order", title: "Order", rows: ["id: PK", "userId: FK", "total: number"] })
  .relation({ from: "user", to: "order", cardinality: "1:N", label: "places" })
  .build()

cardinality 6 種 ... "1:1" | "1:N" | "N:1" | "N:M" | "0..1" | "1..*"

stateMachine

FSM / workflow (state + transition trigger + guard)。

stateMachine({ id, topic })
  .state({ id: "idle", title: "Idle", initial: true })
  .state({ id: "loading", title: "Loading" })
  .state({ id: "done", title: "Done", final: true })
  .state({ id: "error", title: "Error" })
  .transition({ from: "idle", to: "loading", trigger: "submit" })
  .transition({ from: "loading", to: "done", trigger: "success", tone: "success" })
  .transition({ from: "loading", to: "error", trigger: "fail", tone: "error" })
  .transition({ from: "error", to: "idle", trigger: "retry", guard: "if attempts < 3" })
  .build()

低位 API

preset で表現しきれない自由レイアウトは低位 API で。

import { diagram } from "@cardenelabs/cdl";

export const custom = diagram("custom", { topic: "Custom" })
  .lane("left", { x: 0, width: 400 })
  .lane("right", { x: 500, width: 400 })
  .node("a", { lane: "left", stack: 0, kind: "actor", title: "Alice" })
  .node("b", { lane: "right", stack: 0, kind: "function", title: "Bob" })
  .edge("a", "b", { id: "e", label: "msg", tone: "accent", style: "solid" })
  .state("counter", { initial: 0 })
  .phase("p1", { duration: 1500, title: "Phase 1", body: "tween counter" },
    (p) => p.activate("a", "b", "e").tween("counter", 0, 100).badge("running"))
  .build();

NodeKind 29 種

| 系統 | kinds | |---|---| | 基本 5 | actor / function / storage / event / card | | 人系 5 | person / user-group / admin / developer / external-user | | インフラ 6 | database / cache / queue / message-bus / cloud / cdn | | アプリ系 6 | service / api / frontend / backend / webhook / microservice | | blockchain 8 | wallet / validator / miner / blockchain-node / mempool / block / bridge-node / relayer | | 暗号 / データ 4 | signer / oracle / merkle-tree / decision |

各 kind は shape / color / icon が異なる。 基本 5 は専用 component、 残り 24 種は GenericNode で汎用描画。

EdgeStyle + Tone

| EdgeStyle | 動き | |---|---| | solid | 実線 + 矢頭 marker、 progress 連動で path が伸びる | | dotted-flow | 点線 + 進行点 glow (3 重円) が path 上を流れる、 node 貫通自動判定 |

| Tone | 色 (hex) | 用途 | |---|---|---| | accent | #c17f3e | default | | teal | #4a8b7f | 補助動作 | | success | #6b9e5a | 成功 path | | error | #c15a4a | 失敗 path | | warning | #c9a23e | 警告 | | info | #5a8ec1 | 情報 |

phase / state / tween / set / badge

phase 内で state を tween / set し、 badge を出す。

.state("amount", { initial: 0 })
.state("status", { initial: "idle" })
.phase("p1", { duration: 1800, title: "Phase 1", body: "tween + set" },
  (p) => p
    .activate("a", "b")
    .tween("amount", 0, 100)    // 数値の線形補間
    .set("status", "running")    // 文字列の即時切替
    .badge("processing"))         // header に badge 表示

state placeholder は node の title / subtitle / eyebrow / value 内で {stateId} 記法で参照。

.node("a", { lane: "l", stack: 0, kind: "function", title: "Process", subtitle: "status: {status}" })

phase 切替に連動して status: idlestatus: running のように描画される。

CdlDiagramView props

<CdlDiagramView
  diagram={d}
  hideHeader={false}   // header (phase indicator + state diff) 表示
  focusPhaseId="p1"    // 特定 phase に固定 (autoplay は維持)
  debug={false}        // bbox + collision を半透明で重ね描き (開発用)
/>

見た目を当てる (role selector)

cdl は形だけを描き、 色や影は持たない (geometry only、 style 不干渉、 CAR-643 SSOT)。 描かれる各部品には data-cdl-role が付くので、 consumer app 側が selector で見た目を当てる。

[data-cdl-role="node-body"] {
  fill: #ffffff;
  stroke: #57534b;
  stroke-width: 1.75;
}

明暗の切替は consumer 側の仕組み (html の class 等) で行う = cdl は明暗の概念を持たない。

CdlRole 型は実装にある role の全部ではない。 実装には 32 種の role があり、 型に載っているのは 12 種。 残り 20 種 (chart-line / tree-edge / funnel-stage / edge-glow 等) は型を持たないが、 属性は付くので selector は書ける。

型の内外は「共通か kind 固有か」 では分かれていない (共通の描画で使う edge-glow が型の外に あり、 枝分かれ図でしか使わない mind-edge も型の外にある)。 型に載っているかどうかは selector を書けるかとは無関係なので、 一覧が要る時は source を data-cdl-role= で検索する。

role が付かない小さな部品もある (kind が自前で描く目盛や軸など)。 それらは CSS 変数で色を渡す。

:root {
  --cdl-node-fill: #f2f1ec;
  --cdl-text: #191714;
  --cdl-tone-accent: #2c68ae;
}

CdlDiagramThumbnail

thumbnail として表示、 click で viewport いっぱい (94vw x 94vh) のモーダルで拡大。

import { CdlDiagramThumbnail } from "@cardenelabs/cdl";

<CdlDiagramThumbnail diagram={d} hideHeader />

close は Escape / 背景クリック / × の 3 経路。

Architecture

src/
├── builder.ts        — DSL builder
├── compile.ts        — DSL → CdlDiagram normalization
├── validate.ts       — schema validation
├── layout/           — layout engine (6 file)
│   ├── tokens.ts     — DESIGN TOKENS SSOT
│   ├── lanes.ts      — lane 配置 + auto width
│   ├── nodes.ts      — node cy/cx/w/h 確定
│   ├── edges.ts      — orthogonal routing + label
│   ├── collisions.ts — bbox + clearance + Liang-Barsky
│   └── viewbox.ts    — auto viewBox 計算
├── render/           — React + SVG (7 file)
│   ├── stage.tsx     — SVG defs + 3 pass
│   ├── nodes.tsx     — NodeKind 別 switch
│   ├── edges.tsx     — solid / dotted-flow
│   ├── header.tsx    — phase indicator + state diff
│   ├── utils.ts      — interpolate / pathSubpath / shrinkPathEnd
│   └── tone.ts       — TONE 6 色
├── kinds/            — 専用 component (actor/function/storage/event/card/generic)
├── presets.ts        — 6 preset
├── thumbnail.tsx     — モーダル拡大
└── types.ts          — public types

Testing

pnpm test

vitest で 36 test (builder / compile / layout / sequence preset / snapshot) を実行、 全 pass 確認。

Performance baseline

packages/cdl/test/bench.test.ts の vitest bench で 5 case (small / medium / large / huge / animation-heavy) × 3 stage (parse / compile / layout) を計測する。

pnpm --filter @cardenelabs/cdl exec vitest bench --run

baseline (mean ms、 Apple Silicon / node 24)。

| case (node / edge / phase) | parse | compile | layout (旧) | layout (最適化後) | | --- | --- | --- | --- | --- | | small (10 / 5 / 0) | 0.002 | 0.020 | 0.260 | 0.192 | | medium (100 / 50 / 5) | 0.022 | 1.488 | 25.014 | 0.807 | | large (500 / 200 / 20) | 0.092 | 29.953 | 492.96 | 11.63 | | huge (1000 / 500 / 50) | 0.200 | 129.88 | 2424.39 | 53.74 | | animation-heavy (100 node / 100 phase / 50 tween) | 0.105 | 1.582 | 24.586 | 0.819 |

最適化内容 ... detectCollisions / detectNearCollisions を全 pair O(n²) から spatial hash (cell size 200px、 max clearance 70px margin) に変更。 巨大 bbox (edge-path 等) は fallback 経路で全件比較。 huge case で約 46x 高速化、 1000 node でも 60ms 以下で完了。

stage 内訳。 parse = parseTextDslV05 (Text DSL → DslDocument)、 compile = compileToCdl (DslDocument → CdlDiagram)、 layout = layout (CdlDiagram → LaidDiagram)。 raw 出力は .context/scratch/bench-baseline.{txt,json} (vitest --outputJson 形式)。

License

MIT