@comfyorg/design-system 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/LICENSE +674 -0
  2. package/package.json +43 -0
  3. package/src/css/_palette.css +55 -0
  4. package/src/css/base.css +8 -0
  5. package/src/css/comfyIconSet.js +30 -0
  6. package/src/css/fonts.css +17 -0
  7. package/src/css/iconifyDynamicPlugin.ts +49 -0
  8. package/src/css/lucideStrokePlugin.js +88 -0
  9. package/src/css/style.css +1909 -0
  10. package/src/icons/3d-decomp.svg +3 -0
  11. package/src/icons/README.md +363 -0
  12. package/src/icons/ai-model.svg +1 -0
  13. package/src/icons/anthropic.svg +1 -0
  14. package/src/icons/batch-images-node.svg +3 -0
  15. package/src/icons/bfl.svg +10 -0
  16. package/src/icons/bria.svg +18 -0
  17. package/src/icons/brightness-contrast.svg +3 -0
  18. package/src/icons/bytedance.svg +13 -0
  19. package/src/icons/canny-to-image.svg +3 -0
  20. package/src/icons/canny-to-video.svg +3 -0
  21. package/src/icons/canny.svg +3 -0
  22. package/src/icons/channels.svg +5 -0
  23. package/src/icons/chromatic-aberration.svg +3 -0
  24. package/src/icons/claude.svg +1 -0
  25. package/src/icons/comfy-c.svg +4 -0
  26. package/src/icons/comfy-logo.svg +3 -0
  27. package/src/icons/credits.svg +3 -0
  28. package/src/icons/depth-to-image.svg +3 -0
  29. package/src/icons/depth-to-video.svg +3 -0
  30. package/src/icons/dial.svg +3 -0
  31. package/src/icons/elevenlabs.svg +1 -0
  32. package/src/icons/extensions-blocks.svg +1 -0
  33. package/src/icons/file-output.svg +3 -0
  34. package/src/icons/frames-to-video.svg +3 -0
  35. package/src/icons/gemini.svg +25 -0
  36. package/src/icons/get-video-components.svg +3 -0
  37. package/src/icons/glow.svg +4 -0
  38. package/src/icons/grain.svg +4 -0
  39. package/src/icons/grok.svg +10 -0
  40. package/src/icons/hitpaw.svg +10 -0
  41. package/src/icons/ideogram.svg +3 -0
  42. package/src/icons/image-ai-edit.svg +5 -0
  43. package/src/icons/image-batch.svg +3 -0
  44. package/src/icons/image-blur.svg +3 -0
  45. package/src/icons/image-canny.svg +3 -0
  46. package/src/icons/image-captioning.svg +3 -0
  47. package/src/icons/image-collage.svg +3 -0
  48. package/src/icons/image-compare.svg +3 -0
  49. package/src/icons/image-depth.svg +3 -0
  50. package/src/icons/image-edit.svg +3 -0
  51. package/src/icons/image-inpaint.svg +3 -0
  52. package/src/icons/image-invert.svg +3 -0
  53. package/src/icons/image-outpaint.svg +3 -0
  54. package/src/icons/image-outpainting.svg +3 -0
  55. package/src/icons/image-remove-background.svg +3 -0
  56. package/src/icons/image-rotate.svg +3 -0
  57. package/src/icons/image-select-object-segmentation.svg +3 -0
  58. package/src/icons/image-shader.svg +3 -0
  59. package/src/icons/image-sharpen.svg +3 -0
  60. package/src/icons/image-to-3d.svg +3 -0
  61. package/src/icons/image-to-image.svg +3 -0
  62. package/src/icons/image-to-layers.svg +3 -0
  63. package/src/icons/image-to-video.svg +3 -0
  64. package/src/icons/image-upscale.svg +3 -0
  65. package/src/icons/image-vectorize.svg +3 -0
  66. package/src/icons/kling.svg +38 -0
  67. package/src/icons/load-3d.svg +3 -0
  68. package/src/icons/load-audio.svg +3 -0
  69. package/src/icons/load-video.svg +3 -0
  70. package/src/icons/lora-loader.svg +3 -0
  71. package/src/icons/ltxv.svg +10 -0
  72. package/src/icons/luma.svg +35 -0
  73. package/src/icons/magnific.svg +14 -0
  74. package/src/icons/mask.svg +14 -0
  75. package/src/icons/meshy.svg +33 -0
  76. package/src/icons/minimax.svg +14 -0
  77. package/src/icons/moonvalley-marey.svg +18 -0
  78. package/src/icons/node.svg +1 -0
  79. package/src/icons/open-ai-chat-node.svg +3 -0
  80. package/src/icons/openai.svg +10 -0
  81. package/src/icons/pin.svg +4 -0
  82. package/src/icons/pixverse.svg +15 -0
  83. package/src/icons/play.svg +1 -0
  84. package/src/icons/pose-to-image.svg +3 -0
  85. package/src/icons/pose-to-video.svg +3 -0
  86. package/src/icons/quiver.svg +3 -0
  87. package/src/icons/recraft.svg +11 -0
  88. package/src/icons/reve.svg +10 -0
  89. package/src/icons/rodin.svg +18 -0
  90. package/src/icons/runway.svg +10 -0
  91. package/src/icons/save-3d.svg +3 -0
  92. package/src/icons/save-audio.svg +3 -0
  93. package/src/icons/save-video.svg +3 -0
  94. package/src/icons/send.svg +3 -0
  95. package/src/icons/sora.svg +9 -0
  96. package/src/icons/stability-ai.svg +15 -0
  97. package/src/icons/template.svg +1 -0
  98. package/src/icons/tencent.svg +23 -0
  99. package/src/icons/text-prompt-enhance.svg +3 -0
  100. package/src/icons/text-to-3d.svg +3 -0
  101. package/src/icons/text-to-audio.svg +5 -0
  102. package/src/icons/text-to-image.svg +3 -0
  103. package/src/icons/text-to-video.svg +3 -0
  104. package/src/icons/topaz.svg +10 -0
  105. package/src/icons/tripo.svg +16 -0
  106. package/src/icons/veo.svg +13 -0
  107. package/src/icons/video-captioning.svg +3 -0
  108. package/src/icons/video-edit.svg +3 -0
  109. package/src/icons/video-enhance.svg +3 -0
  110. package/src/icons/video-extract-frame.svg +3 -0
  111. package/src/icons/video-inpaint.svg +3 -0
  112. package/src/icons/video-interpolation.svg +3 -0
  113. package/src/icons/video-select-object-segmentation.svg +3 -0
  114. package/src/icons/video-slice.svg +3 -0
  115. package/src/icons/video-split-screen.svg +3 -0
  116. package/src/icons/video-trim.svg +3 -0
  117. package/src/icons/video-upscale.svg +3 -0
  118. package/src/icons/vidu.svg +24 -0
  119. package/src/icons/voice-clone.svg +3 -0
  120. package/src/icons/wan.svg +13 -0
  121. package/src/icons/wavespeed.svg +12 -0
  122. package/src/icons/workflow.svg +1 -0
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@comfyorg/design-system",
3
+ "version": "1.0.0",
4
+ "description": "Shared design system for ComfyUI Frontend",
5
+ "homepage": "https://comfy.org",
6
+ "license": "MIT",
7
+ "author": {
8
+ "name": "Comfy Org",
9
+ "email": "support@comfy.org",
10
+ "url": "https://www.comfy.org"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/Comfy-Org/ComfyUI_frontend.git"
15
+ },
16
+ "files": [
17
+ "src/css",
18
+ "src/icons"
19
+ ],
20
+ "type": "module",
21
+ "exports": {
22
+ "./css/*": "./src/css/*",
23
+ "./icons/*": "./src/icons/*"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "dependencies": {
29
+ "@iconify-json/lucide": "^1.1.178",
30
+ "@iconify/tailwind4": "^1.2.3",
31
+ "@iconify/tools": "^5.0.3",
32
+ "@iconify/utils": "^3.1.0",
33
+ "tailwindcss-primeui": "^0.6.1",
34
+ "tw-animate-css": "^1.3.8"
35
+ },
36
+ "devDependencies": {
37
+ "tailwindcss": "^4.3.2",
38
+ "typescript": "^6.0.3"
39
+ },
40
+ "scripts": {
41
+ "typecheck": "tsc --noEmit"
42
+ }
43
+ }
@@ -0,0 +1,55 @@
1
+ @theme {
2
+ /* Font Families */
3
+ --font-inter: 'Inter', sans-serif;
4
+
5
+ /* Palette Colors */
6
+ --color-charcoal-100: #55565e;
7
+ --color-charcoal-200: #494a50;
8
+ --color-charcoal-300: #3c3d42;
9
+ --color-charcoal-400: #313235;
10
+ --color-charcoal-500: #2d2e32;
11
+ --color-charcoal-600: #262729;
12
+ --color-charcoal-700: #202121;
13
+ --color-charcoal-800: #171718;
14
+
15
+ --color-neutral-550: #636363;
16
+
17
+ --color-ash-300: #bbbbbb;
18
+ --color-ash-500: #828282;
19
+ --color-ash-800: #444444;
20
+
21
+ --color-smoke-100: #f3f3f3;
22
+ --color-smoke-200: #e9e9e9;
23
+ --color-smoke-300: #e1e1e1;
24
+ --color-smoke-400: #d9d9d9;
25
+ --color-smoke-500: #c5c5c5;
26
+ --color-smoke-600: #b4b4b4;
27
+ --color-smoke-700: #a0a0a0;
28
+ --color-smoke-800: #8a8a8a;
29
+
30
+ /* Plum */
31
+ --color-plum-300: #afa3db;
32
+ --color-plum-400: #8d7fc5;
33
+ --color-plum-500: #6b5ca8;
34
+ --color-plum-600: #49378b;
35
+
36
+ /* Ink */
37
+ --color-ink-100: #5c5362;
38
+ --color-ink-200: #4f4754;
39
+ --color-ink-300: #413b45;
40
+ --color-ink-400: #353139;
41
+ --color-ink-500: #312c34;
42
+ --color-ink-600: #29252c;
43
+ --color-ink-700: #232025;
44
+ --color-ink-800: #19161a;
45
+ --color-ink-900: #151317;
46
+
47
+ --color-white: #ffffff;
48
+ --color-black: #000000;
49
+
50
+ /* Brand Colors */
51
+ --color-electric-400: #f0ff41;
52
+ --color-sapphire-700: #172dd7;
53
+ --color-brand-yellow: var(--color-electric-400);
54
+ --color-brand-blue: var(--color-sapphire-700);
55
+ }
@@ -0,0 +1,8 @@
1
+ /*
2
+ * Design System Base — Brand tokens + fonts only.
3
+ * For marketing sites that don't use PrimeVue or the node editor.
4
+ * Import the full style.css instead for the desktop app.
5
+ */
6
+
7
+ @import './fonts.css';
8
+ @import './_palette.css';
@@ -0,0 +1,30 @@
1
+ import { cleanupSVG, importDirectorySync, runSVGO } from '@iconify/tools'
2
+ import { resolve } from 'node:path'
3
+
4
+ export const COMFY_ICON_PREFIX = 'comfy'
5
+
6
+ const COMFY_ICONS_DIR = resolve(import.meta.dirname, '../icons')
7
+
8
+ let cached
9
+
10
+ export function loadComfyIconSet() {
11
+ if (cached) return cached
12
+ const iconSet = importDirectorySync(COMFY_ICONS_DIR)
13
+ iconSet.forEachSync((name, type) => {
14
+ if (type !== 'icon') return
15
+ const svg = iconSet.toSVG(name)
16
+ if (!svg) {
17
+ iconSet.remove(name)
18
+ return
19
+ }
20
+ try {
21
+ cleanupSVG(svg)
22
+ runSVGO(svg)
23
+ iconSet.fromSVG(name, svg)
24
+ } catch {
25
+ iconSet.remove(name)
26
+ }
27
+ })
28
+ cached = iconSet.export()
29
+ return cached
30
+ }
@@ -0,0 +1,17 @@
1
+ /* Inter Font Family */
2
+
3
+ @font-face {
4
+ font-family: 'Inter';
5
+ src: url('/fonts/inter-latin-normal.woff2') format('woff2');
6
+ font-weight: 100 900;
7
+ font-style: normal;
8
+ font-display: swap;
9
+ }
10
+
11
+ @font-face {
12
+ font-family: 'Inter';
13
+ src: url('/fonts/inter-latin-italic.woff2') format('woff2');
14
+ font-weight: 100 900;
15
+ font-style: italic;
16
+ font-display: swap;
17
+ }
@@ -0,0 +1,49 @@
1
+ import { loadIconSet } from '@iconify/tailwind4/lib/helpers/loader.js'
2
+ import { getDynamicCSSRules } from '@iconify/tailwind4/lib/plugins/dynamic.js'
3
+ import { getIconsCSSData } from '@iconify/utils/lib/css/icons'
4
+ import { matchIconName } from '@iconify/utils/lib/icon/name'
5
+ import plugin from 'tailwindcss/plugin'
6
+
7
+ import { COMFY_ICON_PREFIX, loadComfyIconSet } from './comfyIconSet.js'
8
+
9
+ const SCALE = 1.2
10
+
11
+ const options = {
12
+ iconSets: { [COMFY_ICON_PREFIX]: loadComfyIconSet() },
13
+ scale: SCALE
14
+ }
15
+
16
+ function getModeCSSRules(icon: string, mode: 'mask' | 'background') {
17
+ const nameParts = icon.split(/--|:/)
18
+ if (nameParts.length !== 2) return {}
19
+
20
+ const [prefix, name] = nameParts
21
+ if (!(prefix.match(matchIconName) && name.match(matchIconName))) return {}
22
+
23
+ const iconSet =
24
+ prefix === COMFY_ICON_PREFIX ? loadComfyIconSet() : loadIconSet(prefix)
25
+ if (!iconSet) return {}
26
+
27
+ const generated = getIconsCSSData(iconSet, [name], {
28
+ iconSelector: '.icon',
29
+ mode
30
+ })
31
+ if (generated.css.length !== 1) return {}
32
+
33
+ const size = { width: `${SCALE}em`, height: `${SCALE}em` }
34
+ return { ...generated.common?.rules, ...size, ...generated.css[0].rules }
35
+ }
36
+
37
+ export default plugin(({ matchComponents }) => {
38
+ matchComponents({
39
+ icon: (icon) => {
40
+ try {
41
+ return getDynamicCSSRules(icon, options)
42
+ } catch {
43
+ return {}
44
+ }
45
+ },
46
+ 'icon-img': (icon) => getModeCSSRules(icon, 'background'),
47
+ 'icon-mask': (icon) => getModeCSSRules(icon, 'mask')
48
+ })
49
+ })
@@ -0,0 +1,88 @@
1
+ import { getIconsCSSData } from '@iconify/utils/lib/css/icons'
2
+ import { matchIconName } from '@iconify/utils/lib/icon/name'
3
+ import { loadIconSet } from '@iconify/tailwind4/lib/helpers/loader.js'
4
+ import plugin from 'tailwindcss/plugin'
5
+
6
+ import { COMFY_ICON_PREFIX, loadComfyIconSet } from './comfyIconSet.js'
7
+
8
+ /**
9
+ * Tailwind 4 plugin that provides icon variants with configurable
10
+ * stroke-width via class prefix. Supports lucide and comfy icon sets.
11
+ *
12
+ * Usage in CSS:
13
+ * @plugin "./lucideStrokePlugin.js";
14
+ *
15
+ * Usage in templates:
16
+ * <i class="icon-s1-[lucide--settings]" /> <!-- stroke-width: 1 -->
17
+ * <i class="icon-s1.5-[lucide--settings]" /> <!-- stroke-width: 1.5 -->
18
+ * <i class="icon-s2.5-[comfy--workflow]" /> <!-- stroke-width: 2.5 -->
19
+ *
20
+ * The plain `icon-[...]` class keeps each icon's native stroke-width.
21
+ */
22
+
23
+ const STROKE_WIDTHS = ['1', '1.3', '1.5', '2', '2.5']
24
+
25
+ const LUCIDE_PREFIX = 'lucide'
26
+ const SUPPORTED_PREFIXES = new Set([LUCIDE_PREFIX, COMFY_ICON_PREFIX])
27
+
28
+ const SCALE = 1.2
29
+
30
+ const STROKE_WIDTH_ATTR_RE = /stroke-width="[^"]*"/g
31
+
32
+ class InvalidIconProbeError extends Error {}
33
+
34
+ function resolveIconSet(prefix) {
35
+ if (prefix === COMFY_ICON_PREFIX) return loadComfyIconSet()
36
+ return loadIconSet(prefix)
37
+ }
38
+
39
+ function getDynamicCSSRulesWithStroke(icon, strokeWidth) {
40
+ const nameParts = icon.split(/--|:/)
41
+ if (nameParts.length !== 2) {
42
+ throw new InvalidIconProbeError(`Invalid icon name: "${icon}"`)
43
+ }
44
+ const [prefix, name] = nameParts
45
+ if (!SUPPORTED_PREFIXES.has(prefix)) {
46
+ throw new InvalidIconProbeError(`Unsupported icon prefix: "${prefix}"`)
47
+ }
48
+ if (!(prefix.match(matchIconName) && name.match(matchIconName))) {
49
+ throw new InvalidIconProbeError(`Invalid icon name: "${icon}"`)
50
+ }
51
+ const iconSet = resolveIconSet(prefix)
52
+ if (!iconSet) {
53
+ throw new Error(
54
+ `Cannot load icon set for "${prefix}". Install "@iconify-json/${prefix}" as dev dependency?`
55
+ )
56
+ }
57
+ const generated = getIconsCSSData(iconSet, [name], {
58
+ iconSelector: '.icon',
59
+ customise: (content) =>
60
+ content.replace(STROKE_WIDTH_ATTR_RE, `stroke-width="${strokeWidth}"`)
61
+ })
62
+ if (generated.css.length !== 1) {
63
+ throw new Error(`Cannot find "${icon}". Bad icon name?`)
64
+ }
65
+ if (SCALE && generated.common?.rules) {
66
+ generated.common.rules.height = SCALE + 'em'
67
+ generated.common.rules.width = SCALE + 'em'
68
+ }
69
+ return {
70
+ ...generated.common?.rules,
71
+ ...generated.css[0].rules
72
+ }
73
+ }
74
+
75
+ export default plugin(({ matchComponents }) => {
76
+ for (const sw of STROKE_WIDTHS) {
77
+ matchComponents({
78
+ [`icon-s${sw}`]: (icon) => {
79
+ try {
80
+ return getDynamicCSSRulesWithStroke(icon, sw)
81
+ } catch (err) {
82
+ if (err instanceof InvalidIconProbeError) return {}
83
+ throw err
84
+ }
85
+ }
86
+ })
87
+ }
88
+ })