From c91cafb0f936ce2e0d0302c1155daabcf33de691 Mon Sep 17 00:00:00 2001 From: Karsa Date: Tue, 25 Aug 2026 00:24:11 +0200 Subject: [PATCH] feat(docs): added new contribution guide --- docs/.vitepress/config.ts | 4 +- docs/.vitepress/markdown/example.ts | 204 +++++++++ docs/.vitepress/sidebar/resources.ts | 30 +- docs/.vitepress/theme/style.css | 130 ++++++ .../icons/affinity-designer-guide.md | 2 +- docs/contribute/icons/code-conventions.md | 67 +-- docs/contribute/icons/design-principles.md | 412 +++++++++++++++--- docs/contribute/icons/figma-guide.md | 2 +- docs/contribute/icons/illustrator-guide.md | 2 +- docs/contribute/icons/index.md | 31 +- docs/contribute/icons/inkscape-guide.md | 14 +- docs/contribute/icons/metadata-conventions.md | 296 ++++++++++++- docs/contribute/icons/naming-conventions.md | 224 ++++++++++ docs/contribute/icons/specification.md | 95 ++++ docs/images/0px-padding.svg | 63 +++ docs/images/1px-border-radius.svg | 167 ++++--- docs/images/1px-element-spacing.svg | 69 +++ docs/images/1px-inner-gap.svg | 61 +++ docs/images/1px-inner-spacing.svg | 86 ++++ docs/images/1px-padding.svg | 120 +++-- docs/images/24px-24px-violation.svg | 9 + docs/images/24px-24px.svg | 76 +--- docs/images/2px-border-radius.svg | 129 +++--- .../images/2px-element-spacing-abrupt-cut.svg | 76 +++- docs/images/2px-element-spacing-connected.svg | 68 ++- docs/images/2px-element-spacing.svg | 141 +++--- docs/images/2px-inner-gap.svg | 61 +++ docs/images/2px-inner-spacing.svg | 86 ++++ docs/images/2px-stroke-violation.svg | 60 +++ docs/images/2px-stroke.svg | 133 +++--- docs/images/border-radius-90deg.svg | 65 +++ docs/images/border-radius-arbitrary.svg | 63 +++ docs/images/border-radius-correct.svg | 73 ++++ .../border-radius-line-join-violation.svg | 65 +++ docs/images/border-radius-line-join.svg | 63 +++ docs/images/border-radius-violation.svg | 61 +++ docs/images/centered-strokes-violation.svg | 70 +++ docs/images/centered-strokes.svg | 143 +++--- docs/images/curvature-smooth.svg | 119 +++-- docs/images/curvature-uneven.svg | 116 +++-- docs/images/density-optimal.svg | 21 + docs/images/density-too-dense.svg | 29 ++ docs/images/established-shapes-base-do.svg | 14 + docs/images/established-shapes-base-dont.svg | 14 + .../established-shapes-consistency-do.svg | 14 + .../established-shapes-consistency-dont.svg | 12 + docs/images/established-shapes-sub-do.svg | 14 + docs/images/established-shapes-sub-dont.svg | 11 + docs/images/pixel-perfection-bad.svg | 136 +++--- docs/images/pixel-perfection-ideal.svg | 138 +++--- docs/images/round-caps-violation.svg | 70 +++ docs/images/round-caps.svg | 139 +++--- docs/images/round-joints-violation.svg | 73 ++++ docs/images/round-joints.svg | 139 +++--- docs/images/visual-weight-consistent.svg | 20 + docs/images/visual-weight-uneven.svg | 20 + docs/images/visually-centered-bad.svg | 70 --- docs/images/visually-centered-do.svg | 57 +++ docs/images/visually-centered-dont.svg | 57 +++ .../visually-centered-symmetrical-do.svg | 58 +++ .../visually-centered-symmetrical-dont.svg | 57 +++ docs/images/visually-centered.svg | 69 --- package.json | 1 + 63 files changed, 3826 insertions(+), 1163 deletions(-) create mode 100644 docs/.vitepress/markdown/example.ts create mode 100644 docs/contribute/icons/naming-conventions.md create mode 100644 docs/contribute/icons/specification.md create mode 100644 docs/images/0px-padding.svg create mode 100644 docs/images/1px-element-spacing.svg create mode 100644 docs/images/1px-inner-gap.svg create mode 100644 docs/images/1px-inner-spacing.svg create mode 100644 docs/images/24px-24px-violation.svg create mode 100644 docs/images/2px-inner-gap.svg create mode 100644 docs/images/2px-inner-spacing.svg create mode 100644 docs/images/2px-stroke-violation.svg create mode 100644 docs/images/border-radius-90deg.svg create mode 100644 docs/images/border-radius-arbitrary.svg create mode 100644 docs/images/border-radius-correct.svg create mode 100644 docs/images/border-radius-line-join-violation.svg create mode 100644 docs/images/border-radius-line-join.svg create mode 100644 docs/images/border-radius-violation.svg create mode 100644 docs/images/centered-strokes-violation.svg create mode 100644 docs/images/density-optimal.svg create mode 100644 docs/images/density-too-dense.svg create mode 100644 docs/images/established-shapes-base-do.svg create mode 100644 docs/images/established-shapes-base-dont.svg create mode 100644 docs/images/established-shapes-consistency-do.svg create mode 100644 docs/images/established-shapes-consistency-dont.svg create mode 100644 docs/images/established-shapes-sub-do.svg create mode 100644 docs/images/established-shapes-sub-dont.svg create mode 100644 docs/images/round-caps-violation.svg create mode 100644 docs/images/round-joints-violation.svg create mode 100644 docs/images/visual-weight-consistent.svg create mode 100644 docs/images/visual-weight-uneven.svg delete mode 100644 docs/images/visually-centered-bad.svg create mode 100644 docs/images/visually-centered-do.svg create mode 100644 docs/images/visually-centered-dont.svg create mode 100644 docs/images/visually-centered-symmetrical-do.svg create mode 100644 docs/images/visually-centered-symmetrical-dont.svg delete mode 100644 docs/images/visually-centered.svg diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 3b8db057a..5ca18f1a2 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -4,6 +4,7 @@ import { groupIconMdPlugin, groupIconVitePlugin } from 'vitepress-plugin-group-i import sidebar from './sidebar'; import snackPlayer from './markdown/snackPlayer'; import sandpackPlugin from './markdown/sandpack'; +import examplePlugin from './markdown/example'; import { readFile } from 'node:fs/promises'; import { resourcesSidebar } from './sidebar/resources'; import llmstxt from 'vitepress-plugin-llms'; @@ -31,6 +32,7 @@ export default defineConfig({ config(md) { md.use(groupIconMdPlugin); md.use(snackPlayer); + md.use(examplePlugin); md.use(sandpackPlugin, { defaultFiles: { '/styles.css': { @@ -96,7 +98,7 @@ export default defineConfig({ text: 'Resources', items: [ ...resourcesSidebar[0].items, - { text: 'Design icons', link: '/contribute/icons/' }, + { text: 'Contributing icons', link: '/contribute/icons/' }, ], }, { text: 'Packages', link: '/packages' }, diff --git a/docs/.vitepress/markdown/example.ts b/docs/.vitepress/markdown/example.ts new file mode 100644 index 000000000..a5f3c18ab --- /dev/null +++ b/docs/.vitepress/markdown/example.ts @@ -0,0 +1,204 @@ +import { readFileSync } from 'node:fs'; +import { dirname, isAbsolute, resolve } from 'node:path'; +import type MarkdownIt from 'markdown-it'; +import type { RenderRule } from 'markdown-it/lib/renderer.mjs'; +import container from 'markdown-it-container'; + +type ContainerArgs = [typeof container, string, { render: RenderRule }]; + +const parseInfo = (info: string, marker: string) => info.trim().slice(marker.length).trim(); + +const stripWrappingQuotes = (value: string) => { + const quote = value[0]; + + if ((quote === '"' || quote === "'") && value.at(-1) === quote) { + return value.slice(1, -1); + } + + return value; +}; + +const isRawSvgUrl = (url: string) => { + const [filePath, query = ''] = url.split('?'); + const params = new URLSearchParams(query); + + return filePath.endsWith('.svg') && params.get('raw') === 'true'; +}; + +const isImageUrl = (value: string) => { + const [filePath] = value.split('?'); + + return /\.(avif|gif|jpe?g|png|svg|webp)$/i.test(filePath); +}; + +const resolveMarkdownPath = (env: Record) => + (env.path as string | undefined) ?? + (env.file as string | undefined) ?? + (env.realPath as string | undefined); + +const renderImage = ( + url: string, + env: Record, + escapeAttr: (value: string) => string, +) => { + if (!isRawSvgUrl(url)) { + return ``; + } + + const [filePath] = url.split('?'); + const markdownPath = resolveMarkdownPath(env); + const resolvedPath = isAbsolute(filePath) + ? resolve(process.cwd(), `.${filePath}`) + : resolve(markdownPath ? dirname(markdownPath) : process.cwd(), filePath); + const svg = readFileSync(resolvedPath, 'utf8'); + const replacedSvg = svg + .replaceAll(/(#000(000)?|black)/g, 'currentColor') + .replaceAll(' stroke="#D8D8D9"', 'style="stroke: currentColor; stroke-opacity: .25;"'); + + return `
${replacedSvg}
`; +}; + +const renderPreview = ( + value: string, + env: Record, + escapeHtml: (value: string) => string, + renderInline: (value: string) => string, +) => { + if (isImageUrl(value)) { + return renderImage(value, env, escapeHtml); + } + + return `
${renderInline(value)}
`; +}; + +const hasTopLevelContent = (tokens: Parameters[0], index: number) => { + let guidanceDepth = 0; + + for (let i = index + 1; i < tokens.length; i += 1) { + const token = tokens[i]; + + if (token.type === 'container_example_close') { + return false; + } + + if (token.type === 'container_do_open' || token.type === 'container_dont_open') { + guidanceDepth += 1; + continue; + } + + if (token.type === 'container_do_close' || token.type === 'container_dont_close') { + guidanceDepth -= 1; + continue; + } + + if (guidanceDepth === 0) { + return true; + } + } + + return false; +}; + +const hasGuidance = (tokens: Parameters[0], index: number) => { + for (let i = index + 1; i < tokens.length; i += 1) { + const token = tokens[i]; + + if (token.type === 'container_example_close') { + return false; + } + + if (token.type === 'container_do_open' || token.type === 'container_dont_open') { + return true; + } + } + + return false; +}; + +const isFirstGuidance = (tokens: Parameters[0], index: number) => { + for (let i = index - 1; i >= 0; i -= 1) { + const token = tokens[i]; + + if (token.type === 'container_example_open') { + return true; + } + + if (token.type === 'container_do_open' || token.type === 'container_dont_open') { + return false; + } + } + + return true; +}; + +const getExampleOpenIndex = (tokens: Parameters[0], index: number) => { + for (let i = index; i >= 0; i -= 1) { + if (tokens[i].type === 'container_example_open') { + return i; + } + } + + return index; +}; + +export default function examplePlugin(md: MarkdownIt) { + const escapeHtml = md.utils.escapeHtml; + + const createExampleContainer = (): ContainerArgs => [ + container, + 'example', + { + render(tokens, idx) { + const token = tokens[idx]; + + if (token.nesting === 1) { + const hasContent = hasTopLevelContent(tokens, idx); + const guidanceOnlyClass = hasContent ? '' : ' example-block--guidance-only'; + const contentOpen = hasContent ? '
\n' : ''; + + return `
\n${contentOpen}`; + } + + const exampleOpenIndex = getExampleOpenIndex(tokens, idx); + const contentClose = + hasTopLevelContent(tokens, exampleOpenIndex) && !hasGuidance(tokens, exampleOpenIndex) + ? '
\n' + : ''; + + return `${contentClose}\n`; + }, + }, + ]; + + const createGuidanceContainer = (type: 'do' | 'dont'): ContainerArgs => [ + container, + type, + { + render(tokens, idx, _options, env) { + const token = tokens[idx]; + + if (token.nesting === 1) { + const exampleOpenIndex = getExampleOpenIndex(tokens, idx); + const preview = stripWrappingQuotes(parseInfo(token.info, type)); + const media = renderPreview(preview, env, escapeHtml, md.renderInline.bind(md)); + const contentClose = + hasTopLevelContent(tokens, exampleOpenIndex) && isFirstGuidance(tokens, idx) + ? '\n' + : ''; + const label = + type === 'do' + ? ` Do` + : ` Don't`; + + return `${contentClose}
${media}
${label}
\n`; + } + + return '
\n'; + }, + }, + ]; + + md.use(...createExampleContainer()); + md.use(...createGuidanceContainer('do')); + md.use(...createGuidanceContainer('dont')); +} diff --git a/docs/.vitepress/sidebar/resources.ts b/docs/.vitepress/sidebar/resources.ts index 7a43ba9ba..be84a6354 100644 --- a/docs/.vitepress/sidebar/resources.ts +++ b/docs/.vitepress/sidebar/resources.ts @@ -25,7 +25,7 @@ export const resourcesSidebar = [ text: 'Contribute', items: [ { - text: 'Contributing', + text: 'Contribution guide', link: '/contribute/', }, @@ -39,26 +39,41 @@ export const resourcesSidebar = [ link: '/contribute/icons/', }, { - text: 'Design Principles', + text: 'Design Language', link: '/contribute/icons/design-principles', + desc: 'Learn the visual principles that make Lucide icons consistent and recognizable.', }, { - text: 'SVG Code conventions', - link: '/contribute/icons/code-conventions', + text: 'Design Specification', + link: '/contribute/icons/specification', + desc: 'Reference the concrete requirements that Lucide icons must or should follow.', }, { - text: 'Writing icon metadata', + text: 'Naming conventions', + link: '/contribute/icons/naming-conventions', + desc: 'Learn how to choose clear, consistent, and predictable names for Lucide icons.', + }, + { + text: 'Metadata conventions', link: '/contribute/icons/metadata-conventions', + desc: 'Learn how to write tags, categories, aliases, and other metadata for Lucide icons.', + }, + { + text: 'SVG conventions', + link: '/contribute/icons/code-conventions', + desc: 'Learn how SVG files should be structured and written for the Lucide repository.', }, { text: 'Design software guides', collapsed: false, + desc: 'Learn how to design and export Lucide icons using common vector design tools.', items: [{ - text: 'Illustrator', + text: 'Adobe Illustrator', link: '/contribute/icons/illustrator-guide', + desc: '', }, { - text: ' Inkscape', + text: 'Inkscape', link: '/contribute/icons/inkscape-guide', }, { @@ -71,7 +86,6 @@ export const resourcesSidebar = [ } ], }, - ], }, ]; diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css index 42dc8c796..cc66df2c7 100644 --- a/docs/.vitepress/theme/style.css +++ b/docs/.vitepress/theme/style.css @@ -183,3 +183,133 @@ html { background: transparent; border: none; } + +.custom-block.success { + border-color: transparent; + color: var(--vp-c-text-1); + background-color: var(--vp-c-success-soft); +} +/* Example guidance blocks */ +.example-block { + margin: 32px 0; +} + +.example-block__title { + margin: 0 0 12px; + font-size: 20px; + line-height: 1.4; +} + +.example-block > :first-child { + margin-top: 0; +} + +.example-block > :last-child { + margin-bottom: 0; +} + +.example-block__content > :first-child { + margin-top: 0; +} + +.example-block__content > :last-child { + margin-bottom: 0; +} + +.example-guidance__image { + display: block; + width: 100%; + height: auto; + background-color: var(--vp-c-bg-soft); + border-bottom: 4px solid var(--vp-c-divider); + border-top-left-radius: 16px; + border-top-right-radius: 16px; + overflow: hidden; +} + +.example-guidance__image--raw svg { + display: block; + width: 100%; + height: auto; +} + +.example-guidance__text { + display: flex; + flex-direction: row; + gap: 8px; + align-items: center; + justify-content: center; + min-height: 160px; + padding: 24px; + background-color: var(--vp-c-bg-alt); + border-bottom: 1px solid var(--vp-c-divider); + border-top-left-radius: 16px; + border-top-right-radius: 16px; + color: var(--vp-c-text-1); + font-size: 20px; + line-height: 1.4; + text-align: center; +} + +.example-guidance__caption { + color: var(--vp-c-text-1); +} + +.example-guidance__caption > p { + margin: 0; + padding: 0 16px 16px; +} + +.example-guidance__label { + display: flex; + gap: 8px; + padding: 12px; + margin: 0 0 8px; + background-color: var(--example-guidance-label-bg); + color: var(--vp-c-neutral-inverse); + border-bottom-left-radius: 16px; + border-bottom-right-radius: 16px; +} + +.example-guidance--do { + --example-guidance-label-bg: var(--vp-c-success-1); +} + +.example-guidance--dont { + --example-guidance-label-bg: var(--vp-c-danger-1); +} + +@media (min-width: 640px) { + .example-block { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 24px; + } + + .example-block__content { + grid-column: 1 / -1; + } + + .example-guidance { + margin: 0; + } +} + +@media (min-width: 960px) { + .example-block { + grid-template-columns: minmax(0, 0.9fr) repeat(2, minmax(0, 1fr)); + } + + .example-block--guidance-only { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .example-block__content { + grid-column: 1; + } + + .example-guidance { + grid-column: auto; + grid-row: auto; + } +} diff --git a/docs/contribute/icons/affinity-designer-guide.md b/docs/contribute/icons/affinity-designer-guide.md index be7e1c951..743ea404a 100644 --- a/docs/contribute/icons/affinity-designer-guide.md +++ b/docs/contribute/icons/affinity-designer-guide.md @@ -14,5 +14,5 @@ This guide describes how to use the Affinity Designer template for Lucide. 2. Follow the [Icon Design Principles](design-principles.md) while you use the template (to ensure integrity with the Lucide icon pack). 3. Export the file as SVG (`File > Export`). Make sure that _Rastering_ is set to _Nothing_, _Export text as curves_ is checked (hopefully, you won't need this), _Use hex colors_ is checked, and _Flatten transforms_ is checked. - ![SVG export options in Affinity Designer](../images/affinity-designer-export-options.png?raw=true) + ![SVG export options in Affinity Designer](../../images/affinity-designer-export-options.png?raw=true) 4. Optimize the exported SVG file further with [SVGOMG](https://jakearchibald.github.io/svgomg/) or [`svgo`](https://github.com/svg/svgo) (using `svgo --multipass exported_icon.svg`). diff --git a/docs/contribute/icons/code-conventions.md b/docs/contribute/icons/code-conventions.md index f9b80d15b..fbe778329 100644 --- a/docs/contribute/icons/code-conventions.md +++ b/docs/contribute/icons/code-conventions.md @@ -31,13 +31,14 @@ We recommend to use [Lucide Studio](https://studio.lucide.dev/?utm_source=lucide SVG files may only contain simple path and shape elements, which may not have any attributes other than sizing and spacing.\ In practice only the following elements and attributes are allowed: -* `` -* `` -* `` -* `` -* `` -* `` -* `` + +- `` +- `` +- `` +- `` +- `` +- `` +- `` This also means that no transforms, filters, fills or explicit strokes are allowed. @@ -45,24 +46,40 @@ Never use [``](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use ## JSON metadata descriptor - +Each icon added must also come with a matching JSON file listing contributors, use cases, tags and categories for the icon. -Each icon added must also come with a matching JSON file listing tags and categories for the icon. -Please use the following template: +Please use consult [our metadata conventions page](./metadata-conventions.md) for more information about this file. -```json -{ - "$schema": "../icon.schema.json", - "contributors": [ - "github-username", - "another-github-username" - ], - "tags": [ - "foo", - "bar" - ], - "categories": [ - "devices" - ] -} +## Validation + +Before submitting SVG changes, format and validate the icon files: + +```sh +pnpm run lint:icons ``` + +You can automatically format SVG files with Prettier: + +```sh +pnpm run lint:icons-fix +``` + +To check icon names, categories, metadata, and SVG structure together, run: + +```sh +pnpm run lint:icons:all +``` + +## Checklist + +Before opening a PR, confirm that: + +- The SVG uses the standard `24` by `24` viewBox. +- The SVG uses `fill="none"` and `stroke="currentColor"`. +- Stroke width, line caps, and line joins match the Lucide defaults. +- Paths are tidy and use appropriate numeric precision. +- Only allowed SVG elements and attributes are used. +- The SVG does not use transforms, filters, fills, explicit strokes, or ``. +- The icon has a matching JSON metadata file. +- `pnpm run lint:icons` passes. +- `pnpm run lint:json:icons` passes. diff --git a/docs/contribute/icons/design-principles.md b/docs/contribute/icons/design-principles.md index 5f23420eb..d9827d560 100644 --- a/docs/contribute/icons/design-principles.md +++ b/docs/contribute/icons/design-principles.md @@ -1,132 +1,402 @@ --- -description: Guidelines and best practices for designing icons for the Lucide icon library. +description: Learn the visual principles that make Lucide icons consistent and recognizable. --- -# Icon Design Principles -Guidelines and best practices for designing icons for the Lucide icon library. +# Lucide Design Language -## Icon Design Principles +Lucide is designed as a consistent icon set, not just a collection of individual icons. Every icon should feel like it belongs alongside the rest of the library. -Here are rules that should be followed to keep quality and consistency when making icons for Lucide. +This guide explains the visual principles behind Lucide icons and how to apply them when designing new icons. -### 1. Icons must be designed on a **24 by 24 pixels** canvas. +For concrete requirements such as canvas size, stroke width, spacing, and corner radii, see the [Icon Design Specification](./specification). -![24px-24px](../images/24px-24px.svg?raw=true "24px-24px") -### 2. Icons must have at least **1 pixel padding** within the canvas. +## 1. Use a 24 × 24 pixel canvas -![1px-padding](../images/1px-padding.svg?raw=true "1px-padding") +:::: example -### 3. Icons must have a **stroke width of 2 pixels**. +Icons **must** be designed on a 24 × 24 pixel canvas. -![2px-stroke](../images/2px-stroke.svg?raw=true "2px-stroke") +::: do ../../images/24px-24px.svg?raw=true +Use a **24 × 24 pixel** canvas. +::: -### 4. Icons must use **round joins**. +::: dont ../../images/24px-24px-violation.svg?raw=true +Use a larger or smaller canvas, or one that's not square. +::: -![round-joints](../images/round-joints.svg?raw=true "round-joints") +:::: -### 5. Icons must use **round caps**. -![round-caps](../images/round-caps.svg?raw=true "round-caps") +## 2. Keep 1 pixel of safe zone -### 6. Icons must use **centered strokes**. +:::: example -![centered-strokes](../images/centered-strokes.svg?raw=true "centered-strokes") +Icons **must** have at least 1 pixel of padding between their strokes and the edge of the canvas. -### 7. Shapes (such as rectangles) must have a **border radius of** +::: do ../../images/1px-padding.svg?raw=true +Keep at least **1 pixel of padding** around the icon. +::: -#### A. **2 pixels** if they are at least 8 pixels in size +::: dont ../../images/0px-padding.svg?raw=true +Failing to keep this safe zone will result in trimmed visuals. +::: -![2px-border-radius](../images/2px-border-radius.svg?raw=true "2px-border-radius") +:::: -#### B. **1 pixel** if they are smaller than 8 pixels in size +## 3. Use 2 pixel strokes -![1px-border-radius](../images/1px-border-radius.svg?raw=true "1px-border-radius") +:::: example -### 8. Distinct elements must have **2 pixels of spacing between each other** +Strokes **must** be 2 pixels wide. -![2px-element-spacing](../images/2px-element-spacing.svg?raw=true '2px-element-spacing') +::: do ../../images/2px-stroke.svg?raw=true +Use a **2 pixel stroke width**. +::: -![2px-element-spacing-connected](../images/2px-element-spacing-connected.svg?raw=true '2px-element-spacing-connected') +::: dont ../../images/2px-stroke-violation.svg?raw=true +Avoid thicker or thinner strokes. +::: -![2px-element-spacing-abrupt-cut](../images/2px-element-spacing-abrupt-cut.svg?raw=true '2px-element-spacing-abrupt-cut') +:::: -### 9. Icons should have a similar optical volume to `circle` and `square`. -![optical-volume-ideal](../images/optical-volume-ideal.svg?raw=true "optical-volume-ideal") +## 4. Use round line joins -![optical-volume-low](../images/optical-volume-low.svg?raw=true "optical-volume-low") +:::: example -![optical-volume-high](../images/optical-volume-high.svg?raw=true "optical-volume-high") +Strokes **must** use round line joins. -**Tip:** place your icon next to the circle or square icon and blur them both; your icon should not feel much darker than the base shape. +::: do ../../images/round-joints.svg?raw=true +Use **round line joins**. +::: -### 10. Icons should be visually centered by their center of gravity. +::: dont ../../images/round-joints-violation.svg?raw=true +You **must not** use **miter or bevel** line joins. +::: -![visually-centered](../images/visually-centered.svg?raw=true "visually-centered") +:::: -![visually-centered-bad](../images/visually-centered-bad.svg?raw=true "visually-centered-bad") +## 5. Use round line caps -**Tip:** place your icon both above/below and next to the square or circle icon and check if it feels off center. Symmetrical icons should always be aligned to the center. +:::: example -### 11. Icons should have similar visual density and level of detail. +Open paths **must** use round line caps. -![density-ideal](../images/density-ideal.svg?raw=true "density-ideal") +::: do ../../images/round-caps.svg?raw=true +Use **round line caps** on open paths. +::: -![density-high](../images/density-high.svg?raw=true "density-high") +::: dont ../../images/round-caps-violation.svg?raw=true +You **must not** use **butt or square** line caps. +::: -**Tip:** try to make abstractions to dense elements. Blur your icon, and when blurred it should not feel overly dark. +:::: -### 12. Continuous curves should join smoothly. +## 6. Use centered strokes -![curvature-smooth](../images/curvature-smooth.svg?raw=true "curvature-smooth") +:::: example -![curvature-uneven](../images/curvature-uneven.svg?raw=true "curvature-uneven") +Strokes **must** be centered on their paths. -**Tip:** make sure to use arcs or quadratic curves. When using cubic curves control points should have mirrored angles for smooth curves. +::: do ../../images/centered-strokes.svg?raw=true +Keep strokes **centered** on their paths. +::: -### 13. Icons should aim to be pixel perfect so that they will be sharp on low DPI displays. +::: dont ../../images/centered-strokes-violation.svg?raw=true +You **must not** use **inside or outside** strokes. +::: -![pixel-perfection-ideal](../images/pixel-perfection-ideal.svg?raw=true "pixel-perfection-ideal") +:::: -![pixel-perfection-bad](../images/pixel-perfection-bad.svg?raw=true "pixel-perfection-bad") +## 7. Use consistent corner radii -**Tip:** whenever possible align elements and arc centers to the grid. +:::: example -### 14. Icons should share common shapes +Almost all sharp corners **should** be rounded: -You should try to create consistent groups and variants, reuse and try to create uniformity. -Consistency inside groups and variants has a lower priority than the rules above. +::: do ../../images/border-radius-correct.svg?raw=true +Use rounded corners. +::: -**Example:** All `-off` icons should look the same unless it for example violates the optical volume rule. +::: dont ../../images/border-radius-violation.svg?raw=true +Avoid sharp corners. +::: -**Tip:** Try to not move the base shape to enable better use in a toggle context. +:::: -## Naming conventions +:::: example -1. Icon names use lower kebab case.\ - For example: `arrow-up` instead of `Arrow Up`. +The corner radius depends on the size of the element and the angle. For 90° angles you should: -2. Icon names use International English names, as opposed to local variants.\ - For example: `color` instead of `colour`. +::: do ../../images/2px-border-radius.svg?raw=true +Use a **2 pixel corner radius** for shapes that are at least 8 pixels wide or tall. +::: -3. Icons should be named for what they depict rather than their use case or what they represent.\ - For example: `floppy-disk` instead of `save` and `circle-slash` rather than `ban`. +::: do ../../images/1px-border-radius.svg?raw=true +Use a **1 pixel corner radius** for shapes smaller than 8 pixels. +::: -4. Icons that are part of a group are named `-`.\ - For example: `badge-plus` is based on `badge`. +:::: -5. Icon names for alternate icons should represent what makes the alternate unique instead of being numbered.\ - For example: `send-horizontal` instead of `send-2`. +:::: example -6. Names containing numerals are not allowed, unless the number itself is represented in the icon.\ - For example: `arrow-down-0-to-1` contains both numerals. +But there are always exceptions to the rule. -7. Icons depicting multiple elements (e.g. a person and a circle) of different sizes must list these elements in decreasing order of size.\ - For example: if the circle is bigger, it should be `circle-person`, if the person is bigger, it should be `person-circle`. +::: do ../../images/border-radius-90deg.svg?raw=true +Diagonal lines meeting at a right angle are usually rounded to 2.41 pixels in order to be perfectly grid aligned. +::: -8. Icons depicting multiple elements of roughly equal sizes (e.g. a `ruler` and a `pencil`) must list these elements front to back in case one element is in front of the other, otherwise in English reading order (top to bottom, left to right).\ - For example: if the `pencil` is either in front of, above or left of `ruler`, it should be `pencil-ruler`, otherwise, it should be `ruler-pencil`. +::: do ../../images/border-radius-arbitrary.svg?raw=true +Even very sharp corners should have a minor amount of rounding applied, but how much exactly will vary on the geometry of the icon. +::: -9. Icons depicting some sort of variation of an element must use the `[element]-[modifier]` naming scheme, with modifiers being applied to each element respectively.\ - For example: a dashed circle must be named `circle-dashed`, not `dashed-circle`, and in coordination with the previous guidelines, a dashed circle containing a broken heart would be named `circle-dashed-heart-broken`, due to the heart being smaller than the circle. +:::: + +:::: example + +Again, _almost_ every sharp corner should be rounded, but there are exceptions to the rule. + +::: do ../../images/border-radius-line-join.svg?raw=true +Keep corners sharp if multiple lines meet. +::: + +::: dont ../../images/border-radius-line-join-violation.svg?raw=true +Make icons consistent at different scales by not rounding these corners. +::: + +:::: + +## 8. Keep 2 pixels of gap + +:::: example + +Distinct elements **must** have at least 2 pixels of visual spacing between them. + +::: do ../../images/2px-element-spacing.svg?raw=true +Keep **2 pixels of spacing** between distinct elements. +::: + +::: dont ../../images/1px-element-spacing.svg?raw=true +Never use gaps smaller than **2 pixels** between distinct elements. +::: + +:::: + +:::: example + +This includes the inside of shapes, so most inner gaps **should** be at least 2 pixels wide. + +::: do ../../images/2px-inner-spacing.svg?raw=true +Keep at least **2 pixels of spacing** inside shapes. +::: + +::: dont ../../images/1px-inner-spacing.svg?raw=true +Avoid inner gaps smaller than **2 pixels**. +::: + +:::: + +:::: example + +You can visualize this by trying to place a 2 pixel wide circle within your shape. + +::: do ../../images/2px-inner-gap.svg?raw=true +If a **2 pixel wide circle** fits inside the shape without overlapping, the gap is wide enough. +::: + +::: dont ../../images/1px-inner-gap.svg?raw=true +If a **2 pixel wide circle** overlaps the shape, the inner gap should be wider. +::: + +:::: + + +:::: example + +The 2 pixel spacing also applies when elements visually connect or intersect. + +::: dont ../../images/2px-element-spacing-connected.svg?raw=true +Maintain 2 pixels of spacing where elements visually connect. +::: + +::: dont ../../images/2px-element-spacing-abrupt-cut.svg?raw=true +Avoid abrupt cuts where one element meets another. +::: + +:::: + +## 9. Aim for uniform volume + +:::: example + +Icons should have a similar visual weight when viewed alongside each other. + +::: do ../../images/visual-weight-consistent.svg?raw=true +Match the visual weight of `circle` and `square`. +::: + +::: dont ../../images/visual-weight-uneven.svg?raw=true +The second icon is **too large**, the fourth is **too small**. +::: + +:::: + +::: tip + +The amount and distribution of strokes affect how heavy an icon appears. An icon with many closely spaced elements can appear much heavier than a simpler icon, even when both use the same stroke width. + +Place your icon next to `circle` or `square` and blur them. Your icon should not appear significantly lighter or darker than the reference icon. + +::: + +## 10. Balance icons visually + +:::: example + +Icons should appear centered and balanced within the canvas. + +::: do ../../images/visually-centered-do.svg?raw=true +Keep your icons visually centered. +::: + +::: dont ../../images/visually-centered-dont.svg?raw=true +The optical volume of this icon is offset to the top left. +::: + +:::: + +:::: example +Symmetrical icons should remain geometrically centered. + +::: do ../../images/visually-centered-symmetrical-do.svg?raw=true +::: + +::: dont ../../images/visually-centered-symmetrical-dont.svg?raw=true +::: + +:::: + + +::: tip +Geometric centering does not always produce a visually centered icon. Asymmetrical shapes may need to be moved slightly to compensate for their visual center of gravity. + +Compare your icon with `circle` or `square` both side by side and vertically. If it appears shifted in either direction, adjust its position. +::: + +## 11. Keep density low + +:::: example + +Lucide icons should have a similar visual density and level of detail. + +::: do ../../images/density-optimal.svg?raw=true +Simplify complex subjects, preserving the features that make them identifiable. +::: + +::: dont ../../images/density-too-dense.svg?raw=true +Avoid adding unnecessary details that make the design dense. +::: + +:::: + +::: tip + +Dense areas and closely spaced strokes can also make an icon appear heavier than surrounding icons. + +View the icon at its intended size and try blurring it. Areas that become noticeably dark may contain too much detail. + +::: + +## 12. Use smooth, simple curves + + +:::: example + +Curves should be smooth and use the simplest geometry that accurately describes the shape. + +::: do ../../images/curvature-smooth.svg?raw=true +Prefer simple arcs and quadratic curves where possible. +::: + +::: dont ../../images/curvature-uneven.svg?raw=true +Avoid uneven or unnecessarily complex curves. +::: +:::: + +::: tip +When cubic Bézier curves are necessary, keep their control points aligned appropriately to avoid visible changes in curvature. + +Avoid unnecessary control points. They make shapes harder to maintain and can introduce subtle irregularities. +::: + +## 13. Design for the pixel grid + +:::: example +Lucide icons should appear sharp and intentional at small sizes, including on low-density displays. +::: do ../../images/pixel-perfection-ideal.svg?raw=true +Align coordinates and the centers of arcs and other geometric elements to the pixel grid where possible. +::: +::: dont ../../images/pixel-perfection-bad.svg?raw=true +Avoid placing geometry off the pixel grid without a visual reason. +::: +:::: + +::: tip +Pixel alignment should support the overall appearance of the icon rather than come at the expense of recognizable shapes, smooth curves, or visual balance. +::: + +## 14. Reuse established shapes + +:::: example +When creating variant icons, preserve the geometry of the base icon unless the new concept requires a change. +::: do ../../images/established-shapes-base-do.svg?raw=true +Reuse existing base icons exactly as they appear. +::: +::: dont ../../images/established-shapes-base-dont.svg?raw=true +Avoid altering the **geometry, placement and orientation** of base shapes. +::: +:::: + +:::: example +Related icons should share the same shapes and visual patterns wherever possible. +::: do ../../images/established-shapes-sub-do.svg?raw=true +Reuse elements from existing icons without change. +::: +::: dont ../../images/established-shapes-sub-dont.svg?raw=true +Avoid creating new designs for existing elements. +::: +:::: + +:::: example +Common modifiers and elements should behave consistently across both icon sets and the library. +::: do ../../images/established-shapes-consistency-do.svg?raw=true +Maintain consistency between the placement and size of addons. +::: +::: dont ../../images/established-shapes-consistency-dont.svg?raw=true +Avoid using irregular placements and sizes compared to existing icons. +::: +:::: + +::: tip +Preserving the base shape also makes related icons work better when switching between them in an interface. + +Consistency with an existing icon should not override the other principles of the design language. Adjust the shape when necessary to maintain visual weight, balance, clarity, or readability. +::: + +## TL;DR + +When designing a Lucide icon: + +1. **Use a 24 × 24 pixel canvas** with at least **1 pixel of safe zone**. +2. **Use 2 pixel centered strokes** with **round caps and joins**. +3. **Round sharp corners** using consistent radii appropriate for their size and geometry. +4. **Keep at least 2 pixels of gap** between distinct elements and, where possible, inside shapes. +5. **Match the optical volume** of `circle` and `square`. +6. **Center icons visually**, accounting for their center of gravity. +7. **Keep visual density low** and remove unnecessary detail. +8. **Use smooth, simple curves** without unnecessary control points. +9. **Align geometry to the pixel grid** where possible. +10. **Reuse established shapes and geometry** from existing Lucide icons. + +When these guidelines conflict, prioritize **clarity, visual balance, and consistency with the rest of Lucide**. diff --git a/docs/contribute/icons/figma-guide.md b/docs/contribute/icons/figma-guide.md index e11a03cfa..ac04b9ded 100644 --- a/docs/contribute/icons/figma-guide.md +++ b/docs/contribute/icons/figma-guide.md @@ -28,7 +28,7 @@ Set the following: 1. Stroke width: 2px 2. Stroke alignment: center -![Figma Stroke Options](../images/figma-stroke-options.png) +![Figma Stroke Options](../../images/figma-stroke-options.png) ## Export Or Copy Your Icon Once you have completed your icon, you can export it. diff --git a/docs/contribute/icons/illustrator-guide.md b/docs/contribute/icons/illustrator-guide.md index 3def4e8e2..986e61be3 100644 --- a/docs/contribute/icons/illustrator-guide.md +++ b/docs/contribute/icons/illustrator-guide.md @@ -24,7 +24,7 @@ The Illustrator template is created following guidelines from the [Icon Design G 5. Export the file with the export menu under: `Export > Export As..` then save the file as SVG. Select the following options in the SVG Options dialog: -![SVG export options in Illustrator](../images/illustrator-svg-options.png?raw=true "Setting Page Size") +![SVG export options in Illustrator](../../images/illustrator-svg-options.png?raw=true "Setting Page Size") After that, double check that the [code conventions and SVG global attributes](code-conventions.md) are correct. diff --git a/docs/contribute/icons/index.md b/docs/contribute/icons/index.md index 481470db8..ca91591dd 100644 --- a/docs/contribute/icons/index.md +++ b/docs/contribute/icons/index.md @@ -2,11 +2,34 @@ title: Contributing Icons description: Guidelines and instructions for contributing icons to Lucide. --- + -# Contributing Icons +# Designing icons for Lucide -Before contributing an icon, review the [icon design principles](./design-principles.md), [SVG code conventions](./code-conventions.md), and [metadata conventions](./metadata-conventions.md). +Within any icon set, every icon should feel like it belongs alongside the rest of the library. -You can also use one of the design software guides for [Illustrator](./illustrator-guide.md), [Inkscape](./inkscape-guide.md), [Figma](./figma-guide.md), or [Affinity Designer](./affinity-designer-guide.md). +This guide explains how to design and prepare icons for contribution to Lucide. -For the complete contribution workflow, see the [contribution guide](../index.md). \ No newline at end of file +## What's in this guide? + + + + + +## Designing icons with your preferred software + +You do not need to use any particular design software, you can design Lucide icons with any vector graphics editor that can export SVG. + +We provide step-by-step guides for the following common tools: + + + + + +These guides explain how to set up your document, work within the Lucide design constraints, and export an SVG suitable for contribution. + +Regardless of which tool you use, the same design and SVG requirements apply. diff --git a/docs/contribute/icons/inkscape-guide.md b/docs/contribute/icons/inkscape-guide.md index 666eb9a17..90bb1c3a7 100644 --- a/docs/contribute/icons/inkscape-guide.md +++ b/docs/contribute/icons/inkscape-guide.md @@ -13,11 +13,11 @@ When opening a new document, Inkscape will create a canvas of a default size. T 1. Open the Document Properties dialog (File -> Document Properties). 2. On the “Page Size” tab, under “Custom Size” set the Units to `px` and set both Height and Width to 24. -![Setting Page Size](../images/page-size.png?raw=true "Setting Page Size") +![Setting Page Size](../../images/page-size.png?raw=true "Setting Page Size") 3. On the “Grid” tab, select `Rectangular Grid` and click “New Grid”. -![Setting Grid Properties](../images/grid-1.png?raw=true "Setting Grid Properties") +![Setting Grid Properties](../../images/grid-1.png?raw=true "Setting Grid Properties") 4. Set the Grid Units to `px` and set Spacing X and Spacing Y both to 1. -![Setting Grid Properties](../images/grid-2.png?raw=true "Setting Grid Properties") +![Setting Grid Properties](../../images/grid-2.png?raw=true "Setting Grid Properties") 5. Close the Document Properties dialog. 6. To center the canvas in the viewport, select View -> Zoom -> Drawing. @@ -25,17 +25,17 @@ When opening a new document, Inkscape will create a canvas of a default size. T 1. Create a path or shape. 2. With the path selected, open the Stroke and Fill panel by pressing `Ctrl+Shift+F` on your keyboard. -![Stroke Style Properties](../images/strokes.png?raw=true "Setting Grid Properties") +![Stroke Style Properties](../../images/strokes.png?raw=true "Setting Grid Properties") 3. On the “Stroke Style” tab: * Set Stroke Width to `2px`. * Select the rounded join type. * Select the rounded cap type. 4. If the shape is a rectangle, select the rectangle and in the top of the screen below the menu bar, set `Rx` and `Ry` to `2px`. -![Rectangle Radius Properties](../images/corner-radius.png?raw=true "Rectangle Radius Properties") +![Rectangle Radius Properties](../../images/corner-radius.png?raw=true "Rectangle Radius Properties") ## Saving A File 1. When ready to save the file, click Save As and select “Optimized SVG” as the file type. -![Save As](../images/save-as.png?raw=true "Save as") +![Save As](../../images/save-as.png?raw=true "Save as") 2. After clicking Save, to conform with the other icons in the package, set Pretty Printing to use spaces and set the indentation depth to 2. -![Optimize](../images/optimize-settings.png?raw=true "Optimize") +![Optimize](../../images/optimize-settings.png?raw=true "Optimize") diff --git a/docs/contribute/icons/metadata-conventions.md b/docs/contribute/icons/metadata-conventions.md index f92b688a5..a897e3673 100644 --- a/docs/contribute/icons/metadata-conventions.md +++ b/docs/contribute/icons/metadata-conventions.md @@ -1,12 +1,36 @@ --- -title: Writing Icon Metadata -description: Metadata conventions for icons in the Lucide icon library. +description: Learn how to write clear and consistent metadata for Lucide icons. --- -# Writing Icon Metadata +# Metadata conventions -Each icon added must also come with a matching JSON file listing tags and categories for the icon. -Please use the following template: +Every Lucide icon has a matching JSON metadata file. Metadata helps credit contributors, categorize icons, improve search, and explain where an icon is useful. + +Use this guide when adding a new icon or reviewing metadata for an existing icon. + +## Metadata file location + +Each icon metadata file must live next to its SVG file in the `icons` directory. + +The JSON file must use the same base name as the SVG file: + +- `home.svg` -> `home.json` +- `arrow-up.svg` -> `arrow-up.json` +- `square-parking.svg` -> `square-parking.json` + +All icon metadata files are validated against `icon.schema.json`. + +## Required fields + +Every icon metadata file must include: + +- `$schema` +- `contributors` +- `use-cases` +- `tags` +- `categories` + +A minimal metadata file looks like this: ```json { @@ -15,6 +39,9 @@ Please use the following template: "github-username", "another-github-username" ], + "use-cases": [ + "Representing example items in an interface" + ], "tags": [ "foo", "bar" @@ -23,4 +50,261 @@ Please use the following template: "devices" ] } -``` \ No newline at end of file +``` + +## Contributors + +The `contributors` field is a list of GitHub usernames for people who created or meaningfully contributed to the icon: + +1. If you create a new icon based on existing ones, add all contributors from all base icons. + +2. Add a username when someone made a significant contribution to the SVG itself. + +3. Do not add people for minor review comments, metadata-only edits, or unrelated discussion. + +## Use cases + +The `use-cases` field explains where and why an icon would be used in a real interface. + +Use cases should be short phrases, not full sentences. Start with a present participle verb such as: + +- Representing... +- Indicating... +- Marking... +- Showing... +- Confirming... +- Toggling... +- Categorizing... +- Searching... + +Keep each use case focused on one idea. Prefer 1 to 4 strong use cases over a long list of weak or repetitive ones. + +:::: example + +### Write from the interface's perspective + +Describe what the interface communicates to the user. Do not write from the contributor's personal point of view. + +::: do Indicating a device is offline or unreachable +This describes the role the icon plays in an interface. +::: + +::: dont I need an icon for my offline device screen +This explains the contributor's situation, not the icon's reusable purpose. +::: +:::: + +:::: example + +### Describe real usage, not the icon name + +A use case should explain what the icon means in context. Do not repeat the icon name or describe only the drawing. + +::: do Representing processors, chips, or embedded hardware +This makes `microchip` useful in search and documentation without restating the name. +::: + +::: dont microchip +This duplicates the icon name and does not explain where the icon would be used. +::: +:::: + +:::: example + +### Add context when it clarifies meaning + +Some icons have broad meanings. Add a short context when it makes the use case easier to understand. + +::: do Applying a level-2 heading in text editors +The phrase explains both the action and the product area. +::: + +::: dont Applying a heading +This is understandable, but less useful because it omits the level and interface context. +::: +:::: + +:::: example + +### Keep each use case focused + +Each entry should contain one clear idea. Split genuinely different meanings into separate entries. + +::: do Marking parking locations on maps +This is short, concrete, and focused on one interface function. +::: + +::: dont Marking parking, transport, maps, cars, garages, and places +This reads like a tag list and mixes several concepts into one use case. +::: +:::: + +:::: example + +### Write variant-specific use cases + +Related icons should describe what makes each variant different. + +::: do Indicating a low battery charge level +This is specific to `battery-low` and distinguishes it from other battery icons. +::: + +::: dont Representing battery status +This is too generic and could apply to every battery variant. +::: +:::: + +:::: example + +### Avoid references that only make sense in a PR + +Use cases should stand on their own after the PR is merged. + +::: do Signifying a deal, agreement, or partnership +This preserves the useful meaning without depending on outside context. +::: + +::: dont Same as above in #1234 +This depends on a discussion that readers may never see. +::: +:::: + +:::: example + +### Keep entries concise + +Use cases should usually be 4 to 12 words. Prefer one strong phrase over a long explanation. + +::: do Searching files by name or content +This is short enough to scan and specific enough to understand. +::: + +::: dont This icon can be used when users want to search through all of their files and folders to find something +This is too long and reads like product copy instead of metadata. +::: +:::: + +:::: example + +### Do not end with punctuation + +Use cases are metadata phrases, not full sentences. + +::: do Confirming a successful payment +This matches the phrase style used across icon metadata. +::: + +::: dont Confirming a successful payment. +The period adds unnecessary punctuation and makes entries inconsistent. +::: +:::: + +:::: example + +### Avoid markdown and emoji + +Use plain text only. Formatting belongs in documentation, not metadata values. + +::: do Warning users about a destructive action +This works in search, generated pages, and other metadata consumers. +::: + +::: dont **Warning** users about a destructive action ⚠️ +Markdown and emoji can leak into generated UI and make metadata harder to reuse. +::: +:::: + +:::: example + +### Avoid implementation details + +Use cases should describe meaning, not how the SVG was built. + +::: do Representing cropped or trimmed content +This explains the icon's interface meaning. +::: + +::: dont Showing a rectangle with two path cuts and adjusted Bezier handles +This describes construction details that do not help users find or understand the icon. +::: +:::: + +## Tags + +The `tags` field is a list of search terms for the icon. + +Tags should describe concepts, synonyms, related terms, and common contexts that help people find the icon. + +Use existing tags in the repository as a reference before adding new ones. This keeps search behavior consistent and avoids unnecessary duplicates. + +### Tag rules + +- Use lowercase tags. +- Prefer single words where possible. +- Multi-word tags are allowed when they are clearer, such as `magnifying glass`. +- Do not include the icon name as a tag. +- Do not add generic tags like `icon`. +- Do not add unrelated concepts just to increase search coverage. + +For example, a `mail-search` icon can use tags such as `email`, `message`, `letter`, `find`, and `filter`, but it should not include `mail-search` as a tag. + +## Categories + +The `categories` field groups icons into broad areas of use. + +Categories must come from the allowed category list in `icon.schema.json`. + +Choose categories based on what the icon represents and where it is commonly used. Use existing icon metadata as a reference for similar icons. + +### Category rules + +- Use only categories allowed by `icon.schema.json`. +- Use lowercase category names. +- Do not invent new categories in icon metadata. +- Choose relevant categories only. + +## Variants and related icons + +Related icons should have related metadata, but they should not blindly share identical use cases. + +Write metadata for the specific variant: + +- `battery-low` -> `Indicating a low battery charge level` +- `battery-full` -> `Indicating a full battery charge level` +- `square-arrow-right-enter` -> sign in, enter, or join contexts +- `square-arrow-right-exit` -> sign out, exit, or export contexts + +When a request covers several icons at once, only assign a use case to the icon it actually describes. Do not let metadata from one icon leak into another icon in the same group. + +## Aliases + +Some icons can include an optional `aliases` field for alternate names. + +For the present, we only add aliases to icons when renaming them from non-compliant names. + +## Validation + +Before submitting metadata changes, validate the icon JSON files: + +```sh +pnpm run lint:json:icons +``` + +You can also format changed files with Prettier: + +```sh +pnpm exec prettier "icons/*.json" --check +``` + +## Checklist + +Before opening a PR, confirm that: + +- The JSON file name matches the SVG file name. +- The file includes all required fields. +- Contributors are GitHub usernames. +- Use cases describe real interface usage. +- Tags are lowercase and useful for search. +- Categories are allowed by `icon.schema.json`. +- Metadata is specific to the icon and its variants. +- `pnpm run lint:json:icons` passes. diff --git a/docs/contribute/icons/naming-conventions.md b/docs/contribute/icons/naming-conventions.md new file mode 100644 index 000000000..30b24420f --- /dev/null +++ b/docs/contribute/icons/naming-conventions.md @@ -0,0 +1,224 @@ +--- +description: Learn how to choose clear and consistent names for Lucide icons. +--- + + +# Naming conventions + +Learn how to choose clear and consistent names for Lucide icons. + +This section covers general naming rules, word order, modifiers, variants, related icons, and other conventions used to keep icon names predictable across the library. + +Use this when naming a new icon or reviewing a proposed name. + +## 1. Use lowercase kebab-case + +Icon names **must** use lowercase kebab-case. + +:::: example +::: do `arrow-up-0-1` +Use lowercase kebab-case. +::: +::: dont `Arrow Up 0-1` or `arrowUp01` +Avoid other naming schemes. +::: +:::: + +## 2. Use American English + +Icon names **must** use American English names, as opposed to local variants. + +:::: example +::: do `color`, `maximize`, `center` +::: +::: dont `colour`, `maximise`, `centre` +::: +:::: + +## 3. Name icons for what they depict + +Icon names **must** describe what the icon depicts, not its intended use or meaning. + +:::: example +::: do `floppy-disk` +The icon **depicts** a floppy disk. +::: +::: dont `save` +Save is a use case. +::: +:::: + +:::: example +::: do `circle-slash` +The icon **depicts** a circle with a slash across it. +::: +::: dont `ban` +Ban is an action. +::: +:::: + +::: tip +An icon can represent different actions or concepts depending on where and how it is used. Naming icons for their visual appearance keeps names unambiguous and independent of their use case. +::: + +## 4. Name related icons consistently + +Icons that belong to the same group **must** use the `-` naming scheme. + +The group name comes first, followed by the part that distinguishes the icon from the rest of the group. + +:::: example +::: do `badge-plus` & `badge-check` +`badge` is the group. +::: +::: dont `plus-badge` & `check-badge` +`plus` and `check` are not the group. +::: +:::: + +## 5. Describe alternate icons + +Alternate versions of an icon **must** be named for what makes them visually distinct. They **must not** use numbers merely to distinguish one version from another. + +:::: example +::: do `send-horizontal` +The icon depicts a horizontal "send" symbol. +::: +::: dont `send-2` or `send-alt` +"send no. 2" or "alternative send" are not descriptive names. +::: +:::: + +## 6. Only use numerals when depicted + +Icon names **must not** contain numerals unless the numeral itself is depicted in the icon. + +:::: example +::: do `arrow-down-0-1` +The arrow points from 0 to 1. +::: +::: dont `send-2` +The icon doesn't feature the number 2. +::: +:::: + +:::: example +::: do `clock-3` +The hands point to 3 o'clock. +::: +::: dont `user-3` +The icon doesn't feature the number 3. +::: +:::: + + +Numerals must not be used to distinguish between otherwise similarly named icons. + +## 7. Order elements by size + +When an icon depicts multiple elements of different sizes, their names **must** be ordered from largest to smallest. + +For an icon containing a circle and a person: + +:::: example +::: do `circle-person` +The circle is larger. +::: +::: dont `person-circle` +The person is **not** larger. +::: +:::: + +## 8. Order equally sized elements by position + +When an icon depicts multiple elements of roughly equal size, their names **must** be ordered according to their visual position. + +If elements overlap, name them from front to back. + +If they do not overlap, name them in English reading order: top to bottom, then left to right. + +:::: example +::: do `pencil-ruler` +The pencil is in front of the ruler. +::: +::: dont `ruler-pencil` +The ruler is **not** in front of the pencil. +::: +:::: + +:::: example +::: do `pencil-ruler` +The pencil is left of the ruler. +::: +::: dont `ruler-pencil` +The ruler is **not** above the pencil. +::: +:::: + +## 9. Place modifiers after the element they describe + +Modifiers **must** follow the element they describe, using the `-` naming scheme. + +:::: example +::: do `circle-dashed` +::: +::: dont `dashed-circle` +::: +:::: + +:::: example +::: do `heart-broken` +::: +::: dont `broken-heart` +::: +:::: + +When an icon contains multiple modified elements, each modifier follows its respective element. + +For example, a dashed circle containing a smaller broken heart is named: + +`circle-dashed-heart-broken` + +This follows both the element ordering and modifier rules: + +- `circle` comes before `heart` because it is larger. +- `dashed` follows `circle` because it modifies the circle. +- `broken` follows `heart` because it modifies the heart. + +## TL;DR + +When naming an icon: + +1. **Describe what you see**, not what the icon could mean or be used for. +2. **Use American English** and **lowercase kebab-case**. +3. **Keep related icons together** using `-`. +4. **Describe what makes an alternate unique** instead of numbering it. +5. **Only use numerals when they are depicted** in the icon. +6. **Order elements from largest to smallest**. +7. If elements are roughly the same size, order them **front to back**, or otherwise in **English reading order**. +8. **Place modifiers after the element they describe**: `-`. + +For example, a dashed circle containing a smaller broken heart becomes: + +`circle-dashed-heart-broken` diff --git a/docs/contribute/icons/specification.md b/docs/contribute/icons/specification.md new file mode 100644 index 000000000..b09f34617 --- /dev/null +++ b/docs/contribute/icons/specification.md @@ -0,0 +1,95 @@ +--- +description: Technical specification and conformance requirements for Lucide icons. +--- + +# Icon Design Specification + +This document defines the requirements for icons included in Lucide. + +For explanations, examples, and guidance on applying these requirements, see the [Lucide Design Language](./design-principles). + +## Conformance + +The words **must**, **must not**, **should**, and **should not** indicate the requirement level of each rule: + +- **Must** and **must not** define requirements that an icon is expected to meet. +- **Should** and **should not** define requirements that may be deviated from when necessary to produce a better icon. + +Any deviation should be intentional and consistent with the [Lucide Design Language](./design-principles). + +## Canvas + +1. Icons **must** use a 24 × 24 pixel canvas. +2. The canvas **must** be square. +3. Icon strokes **must** remain at least 1 pixel from the edge of the canvas. + +## Strokes + +1. Strokes **must** be 2 pixels wide. +2. Strokes **must** use round line joins. +3. Open paths **must** use round line caps. +4. Strokes **must** be centered on their paths. + +## Corners + +1. Sharp corners **should** be rounded unless the geometry of the icon requires otherwise. +2. Elements at least 8 pixels wide or tall **should** use a 2 pixel corner radius for 90° corners. +3. Elements smaller than 8 pixels **should** use a 1 pixel corner radius for 90° corners. +4. Diagonal lines meeting at a 90° angle **should** use a radius that preserves pixel-grid alignment. This radius is typically approximately 2.41 pixels. +5. Acute corners **should** use an appropriate amount of rounding based on their geometry. +6. Corners where multiple lines meet **should** remain sharp when rounding would cause the icon to render inconsistently at different sizes. + +## Spacing + +1. Distinct elements **must** have at least 2 pixels of visual separation. +2. Gaps between distinct elements **must not** be smaller than 2 pixels. +3. Inner gaps **should** be at least 2 pixels wide. +4. Spacing **should** remain visually consistent where elements connect or intersect. +5. Elements **should not** terminate with an abrupt cut where another element visually continues or intersects them. + +## Optical volume + +1. Icons **should** have an optical volume comparable to the `circle` and `square` icons. +2. Icons **should not** appear substantially larger, smaller, heavier, or lighter than comparable Lucide icons. + +## Alignment and balance + +1. Icons **should** be visually centered within the canvas. +2. Asymmetrical icons **may** be positioned off their geometric center to compensate for their visual center of gravity. +3. Symmetrical icons **should** be geometrically centered. + +## Visual density + +1. Icons **should** maintain a level of visual density comparable to other Lucide icons. +2. Details **should** be simplified when they cause an icon to appear substantially denser than comparable icons. +3. Details that are not necessary for recognition **should** be omitted. + +## Curves + +1. Continuous curves **should** have smooth curvature. +2. Curves **should not** contain unintended or abrupt changes in curvature. +3. Arcs and quadratic Bézier curves **should** be preferred where they can accurately represent the intended geometry. +4. Cubic Bézier curves **may** be used where necessary. +5. Control points of adjoining cubic Bézier curves **should** be aligned where required to maintain continuous curvature. +6. Curves **should not** contain unnecessary control points. + +## Pixel alignment + +1. Coordinates **should** align to the pixel grid where possible. +2. Centers of arcs and other geometric elements **should** align to the pixel grid where possible. +3. Off-grid geometry **may** be used when required for visual balance, recognizable geometry, or smooth curvature. +4. Pixel alignment **should not** take precedence over the visual quality of the icon. + +## Shared geometry + +1. Variants of an existing icon **should** preserve the geometry, placement, and orientation of the base icon. +2. Elements that already exist in other Lucide icons **should** reuse established geometry where applicable. +3. Related icons **should** use consistent representations of shared elements. +4. Common modifiers and addons **should** use consistent geometry, size, and placement across related icons. +5. Existing geometry **may** be modified when necessary to satisfy other requirements of the Lucide Design Language. + +## Priority of requirements + +When two non-mandatory requirements conflict, visual clarity and consistency with the Lucide Design Language should take precedence over mechanical adherence to an individual rule. + +Requirements marked **must** or **must not** may only be deviated from where an exception is explicitly defined by the project. diff --git a/docs/images/0px-padding.svg b/docs/images/0px-padding.svg new file mode 100644 index 000000000..554fbca94 --- /dev/null +++ b/docs/images/0px-padding.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/1px-border-radius.svg b/docs/images/1px-border-radius.svg index c9dc80e3b..273a5386d 100644 --- a/docs/images/1px-border-radius.svg +++ b/docs/images/1px-border-radius.svg @@ -1,92 +1,85 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/docs/images/1px-element-spacing.svg b/docs/images/1px-element-spacing.svg new file mode 100644 index 000000000..e7461269e --- /dev/null +++ b/docs/images/1px-element-spacing.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/1px-inner-gap.svg b/docs/images/1px-inner-gap.svg new file mode 100644 index 000000000..83776bc6e --- /dev/null +++ b/docs/images/1px-inner-gap.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/1px-inner-spacing.svg b/docs/images/1px-inner-spacing.svg new file mode 100644 index 000000000..4863e30db --- /dev/null +++ b/docs/images/1px-inner-spacing.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/1px-padding.svg b/docs/images/1px-padding.svg index 2f95201c6..4c08aafb9 100644 --- a/docs/images/1px-padding.svg +++ b/docs/images/1px-padding.svg @@ -1,67 +1,57 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + diff --git a/docs/images/24px-24px-violation.svg b/docs/images/24px-24px-violation.svg new file mode 100644 index 000000000..cfd8b0aab --- /dev/null +++ b/docs/images/24px-24px-violation.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/docs/images/24px-24px.svg b/docs/images/24px-24px.svg index 5ed0597b5..549204db1 100644 --- a/docs/images/24px-24px.svg +++ b/docs/images/24px-24px.svg @@ -1,74 +1,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/docs/images/2px-border-radius.svg b/docs/images/2px-border-radius.svg index 72a1ffb90..9105ebfa3 100644 --- a/docs/images/2px-border-radius.svg +++ b/docs/images/2px-border-radius.svg @@ -1,72 +1,67 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + - - + + diff --git a/docs/images/2px-element-spacing-abrupt-cut.svg b/docs/images/2px-element-spacing-abrupt-cut.svg index f04e2d326..d4923169a 100644 --- a/docs/images/2px-element-spacing-abrupt-cut.svg +++ b/docs/images/2px-element-spacing-abrupt-cut.svg @@ -1 +1,75 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/2px-element-spacing-connected.svg b/docs/images/2px-element-spacing-connected.svg index 45c60ac26..672e50969 100644 --- a/docs/images/2px-element-spacing-connected.svg +++ b/docs/images/2px-element-spacing-connected.svg @@ -1 +1,67 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/2px-element-spacing.svg b/docs/images/2px-element-spacing.svg index 1666b93f1..20852a263 100644 --- a/docs/images/2px-element-spacing.svg +++ b/docs/images/2px-element-spacing.svg @@ -1,76 +1,69 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/2px-inner-gap.svg b/docs/images/2px-inner-gap.svg new file mode 100644 index 000000000..e45c97449 --- /dev/null +++ b/docs/images/2px-inner-gap.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/2px-inner-spacing.svg b/docs/images/2px-inner-spacing.svg new file mode 100644 index 000000000..ca418d7c9 --- /dev/null +++ b/docs/images/2px-inner-spacing.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/2px-stroke-violation.svg b/docs/images/2px-stroke-violation.svg new file mode 100644 index 000000000..01c358173 --- /dev/null +++ b/docs/images/2px-stroke-violation.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/2px-stroke.svg b/docs/images/2px-stroke.svg index eaa09caba..21c7891bd 100644 --- a/docs/images/2px-stroke.svg +++ b/docs/images/2px-stroke.svg @@ -1,71 +1,66 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/docs/images/border-radius-90deg.svg b/docs/images/border-radius-90deg.svg new file mode 100644 index 000000000..9369df245 --- /dev/null +++ b/docs/images/border-radius-90deg.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/border-radius-arbitrary.svg b/docs/images/border-radius-arbitrary.svg new file mode 100644 index 000000000..f42485646 --- /dev/null +++ b/docs/images/border-radius-arbitrary.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/border-radius-correct.svg b/docs/images/border-radius-correct.svg new file mode 100644 index 000000000..069a31a3a --- /dev/null +++ b/docs/images/border-radius-correct.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/border-radius-line-join-violation.svg b/docs/images/border-radius-line-join-violation.svg new file mode 100644 index 000000000..7c1a6dc3d --- /dev/null +++ b/docs/images/border-radius-line-join-violation.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/border-radius-line-join.svg b/docs/images/border-radius-line-join.svg new file mode 100644 index 000000000..86a960ebe --- /dev/null +++ b/docs/images/border-radius-line-join.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/border-radius-violation.svg b/docs/images/border-radius-violation.svg new file mode 100644 index 000000000..71a8b70e8 --- /dev/null +++ b/docs/images/border-radius-violation.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/centered-strokes-violation.svg b/docs/images/centered-strokes-violation.svg new file mode 100644 index 000000000..f05831cb6 --- /dev/null +++ b/docs/images/centered-strokes-violation.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/centered-strokes.svg b/docs/images/centered-strokes.svg index 452262261..10737a906 100644 --- a/docs/images/centered-strokes.svg +++ b/docs/images/centered-strokes.svg @@ -1,78 +1,69 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/curvature-smooth.svg b/docs/images/curvature-smooth.svg index b4d977e49..f09da4098 100644 --- a/docs/images/curvature-smooth.svg +++ b/docs/images/curvature-smooth.svg @@ -1,71 +1,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + - - + + - - + + diff --git a/docs/images/curvature-uneven.svg b/docs/images/curvature-uneven.svg index 0a1e0866b..edf41cdea 100644 --- a/docs/images/curvature-uneven.svg +++ b/docs/images/curvature-uneven.svg @@ -1,68 +1,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - - + + - - + + diff --git a/docs/images/density-optimal.svg b/docs/images/density-optimal.svg new file mode 100644 index 000000000..39af6d6e0 --- /dev/null +++ b/docs/images/density-optimal.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/density-too-dense.svg b/docs/images/density-too-dense.svg new file mode 100644 index 000000000..e3cd16651 --- /dev/null +++ b/docs/images/density-too-dense.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/established-shapes-base-do.svg b/docs/images/established-shapes-base-do.svg new file mode 100644 index 000000000..8b1caab9d --- /dev/null +++ b/docs/images/established-shapes-base-do.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs/images/established-shapes-base-dont.svg b/docs/images/established-shapes-base-dont.svg new file mode 100644 index 000000000..4eb7e0823 --- /dev/null +++ b/docs/images/established-shapes-base-dont.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs/images/established-shapes-consistency-do.svg b/docs/images/established-shapes-consistency-do.svg new file mode 100644 index 000000000..53e0c4e64 --- /dev/null +++ b/docs/images/established-shapes-consistency-do.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs/images/established-shapes-consistency-dont.svg b/docs/images/established-shapes-consistency-dont.svg new file mode 100644 index 000000000..2700d4291 --- /dev/null +++ b/docs/images/established-shapes-consistency-dont.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/docs/images/established-shapes-sub-do.svg b/docs/images/established-shapes-sub-do.svg new file mode 100644 index 000000000..8b1caab9d --- /dev/null +++ b/docs/images/established-shapes-sub-do.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs/images/established-shapes-sub-dont.svg b/docs/images/established-shapes-sub-dont.svg new file mode 100644 index 000000000..c83a8d165 --- /dev/null +++ b/docs/images/established-shapes-sub-dont.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/docs/images/pixel-perfection-bad.svg b/docs/images/pixel-perfection-bad.svg index efb35aece..ecea4e1c9 100644 --- a/docs/images/pixel-perfection-bad.svg +++ b/docs/images/pixel-perfection-bad.svg @@ -1,67 +1,81 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - + + + + - - + + + + + + + + + + + + + + + + diff --git a/docs/images/pixel-perfection-ideal.svg b/docs/images/pixel-perfection-ideal.svg index 7a1271955..f3bd203a6 100644 --- a/docs/images/pixel-perfection-ideal.svg +++ b/docs/images/pixel-perfection-ideal.svg @@ -1,62 +1,86 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/round-caps-violation.svg b/docs/images/round-caps-violation.svg new file mode 100644 index 000000000..03a4fe65e --- /dev/null +++ b/docs/images/round-caps-violation.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/round-caps.svg b/docs/images/round-caps.svg index d4affc793..c41269b2e 100644 --- a/docs/images/round-caps.svg +++ b/docs/images/round-caps.svg @@ -1,74 +1,69 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/round-joints-violation.svg b/docs/images/round-joints-violation.svg new file mode 100644 index 000000000..7964757da --- /dev/null +++ b/docs/images/round-joints-violation.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/round-joints.svg b/docs/images/round-joints.svg index 72b7174a1..cbac76bce 100644 --- a/docs/images/round-joints.svg +++ b/docs/images/round-joints.svg @@ -1,72 +1,69 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/visual-weight-consistent.svg b/docs/images/visual-weight-consistent.svg new file mode 100644 index 000000000..f31e3666f --- /dev/null +++ b/docs/images/visual-weight-consistent.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/visual-weight-uneven.svg b/docs/images/visual-weight-uneven.svg new file mode 100644 index 000000000..a14f418bd --- /dev/null +++ b/docs/images/visual-weight-uneven.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/visually-centered-bad.svg b/docs/images/visually-centered-bad.svg deleted file mode 100644 index 6ed8757ba..000000000 --- a/docs/images/visually-centered-bad.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/images/visually-centered-do.svg b/docs/images/visually-centered-do.svg new file mode 100644 index 000000000..e36a51638 --- /dev/null +++ b/docs/images/visually-centered-do.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/visually-centered-dont.svg b/docs/images/visually-centered-dont.svg new file mode 100644 index 000000000..fcd350033 --- /dev/null +++ b/docs/images/visually-centered-dont.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/visually-centered-symmetrical-do.svg b/docs/images/visually-centered-symmetrical-do.svg new file mode 100644 index 000000000..71e77d3fd --- /dev/null +++ b/docs/images/visually-centered-symmetrical-do.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/visually-centered-symmetrical-dont.svg b/docs/images/visually-centered-symmetrical-dont.svg new file mode 100644 index 000000000..882fbdd63 --- /dev/null +++ b/docs/images/visually-centered-symmetrical-dont.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/visually-centered.svg b/docs/images/visually-centered.svg deleted file mode 100644 index c0e235307..000000000 --- a/docs/images/visually-centered.svg +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/package.json b/package.json index b08a35bb8..91ba1f93e 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "lint:json:icons": "ajv --spec=draft2020 -s icon.schema.json -d 'icons/*.json' > /dev/null", "lint:json:categories": "ajv --spec=draft2020 -s category.schema.json -d 'categories/*.json' > /dev/null", "lint:json": "pnpm run lint:json:icons && pnpm run lint:json:categories", + "lint:icons:all": "pnpm run lint:icons && pnpm run lint:json:icons", "lint": "pnpm lint:es && pnpm lint:format && pnpm lint:json && pnpm lint:icons", "format": "prettier \"**/*.{js,mjs,ts,jsx,tsx,html,css,scss,json,yml,yaml}\" --write", "prepare": "husky install",