@crewlethq/icons

中文文档
0.84.2发布于 2026/11/01MIT AND ISCTypeScriptES Module零依赖构建来源已验证

Crewlet signature illustrated icons, vendor marks, and the Lucide glyph set as React components.

原始使用文档
文档目录23 节
  1. Glyphs
  2. The stroke
  3. The filled state
  4. Choosing a glyph from a value
  5. Vendor marks
  6. Product marks
  7. Construction
  8. Colours
  9. Two drawings
  10. Soon
  11. Motion
  12. App tiles
  13. Raw files
  14. Signature illustrations
  15. Raw SVG files
  16. Favicons
  17. CrewletFigure
  18. CrewletCharacter
  19. Stylesheets
  20. Add an illustration
  21. Conventions for source SVGs
  22. Breaking changes in 0.5.0
  23. License

@crewlethq/icons

Everything a Crewlet surface draws that is not text: the Lucide glyph set, the marks of the applications the platform integrates with, and the Crewlet signature illustrations.

All three are React components compiled from SVG files that ship in the package. Nothing here fetches a font, a sprite or an image from another host, so a closed network draws exactly what an open one does.

WhatImport fromLooks like
Glyphs (Lucide, stroke on the 24 grid)@crewlethq/icons/glyphs<XGlyph size="md" />
A glyph chosen from a value@crewlethq/icons/glyphs/registryglyphByName(name)
Vendor marks@crewlethq/icons<VendorMark vendor="slack" />
Signature illustrations@crewlethq/icons<AgentReading />, <Icon name="AgentReading" />
The Crewlet character@crewlethq/icons<CrewletFigure motion="wave" />
The thirty agent characters@crewlethq/icons/characters<CrewletCharacter character="hexlet" />
Product marks@crewlethq/icons/product-mark (also the root)<ProductMark product="assistant" />

Glyphs

import { StarGlyph, XGlyph } from '@crewlethq/icons/glyphs';

<XGlyph size="md" />
<XGlyph size="lg" title="Close" />
<StarGlyph filled={kept} />

Lucide drawings, vendored unchanged from lucide-static and drawn as the approved design draws them: a stroke on the 24 unit grid at a weight of 1.75, with round caps and round joins. glyphs/README.md records which glyphs the set carries and why, their provenance, the checksums and how to add or replace one.

PropTypeDefaultPurpose
size'xs' | 'sm' | 'md' | 'lg' | 'xl' (12, 14, 16, 20, 24), a number of px, or any CSS length'1em'How big it draws.
titlestringnoneNames the glyph for assistive technology. Without one the glyph is aria-hidden and unfocusable, which is right wherever a label sits beside it.
filledbooleanfalsePaints the drawing's inside in the text colour. Only a glyph listed in FILLABLE takes it; see below.

Every other SVG attribute a caller sets on an icon passes through (a class, a style, a colour, a handler, an aria- or data- attribute), and className is added to the component's own crewlet-glyph. What the frame owns does not: viewBox, fill, strokeWidth, strokeLinecap and strokeLinejoin are not props, and the frame keeps them even against a caller the types do not reach, because each changes the drawing rather than where it sits or how big it is.

Names are Lucide's, with a Glyph suffix, because the bare words collide: Timeline, List, Menu, Tag, Link and Code are all @crewlethq/ui components, and a glyph taking one of those names would shadow the component at every import site that wanted both. x is XGlyph, chevron-down is ChevronDownGlyph, columns-3 is Columns3Glyph. GLYPH_NAMES lists every vendored name and GlyphName is the union of them, so a name the package does not ship is a compile error.

The stroke

The weight is 1.75 units of the 24 grid, where Lucide's own files say 2, and it scales with the glyph as the design's does: a 16 px glyph draws a 1.17 px line and a 24 px one a 1.75 px line. --crewlet-glyph-stroke moves it for every glyph beneath the element that sets it, and it is the one way to:

.dense-toolbar {
  --crewlet-glyph-stroke: 2;
}

The glyph carries the weight twice: as a style that reads the variable, and as a plain stroke-width="1.75" attribute beneath it, so markup rendered on a server under a style-src policy that refuses style attributes still draws at the design weight rather than at the SVG default of 1. GLYPH_STROKE is the number, for a drawing of your own that stands beside a glyph.

The filled state

Only a FILLABLE glyph takes filled. A stroke drawing with its inside painted reads as the mark only where the drawing is one closed silhouette: bell has an open clapper and would fill into a blob with a line through it, and compass and target are closed but would fill into a disc with nothing left to say which disc it is. So FILLABLE is a decision about meaning rather than a property of the geometry, the build refuses a name there whose drawing has an open stroke, and the component of every other glyph has no filled prop at all, so passing one is a compile error. It is ['star', 'mouse-pointer-2'] today: the kept state of the Crewlet console's favourite toggle, and a collaborator's live cursor, a solid pointer in their presence hue.

A glyph a surface draws in two states that FILLABLE does not cover changes colour or changes glyph, rather than filling.

Choosing a glyph from a value

import { glyphByName } from '@crewlethq/icons/glyphs/registry';

This entry pulls in every glyph, because a lookup by name is a lookup over all of them. That is the right trade where the name really is data (a navigation table, an event category, a configured integration kind) and the wrong one everywhere else, which is why it is a separate entry: code that imports one glyph never reaches it. The answer is the component registered under the name, with its own type: glyphByName('star') takes filled and glyphByName('x') does not.

Vendor marks

import { VendorMark } from '@crewlethq/icons';

<VendorMark vendor="slack" size={24} />
<VendorMark vendor="datadog" size={24} muted />
PropTypeDefaultPurpose
vendorVendor: 'atlassian' | 'claude' | 'clickup' | 'crewlet' | 'datadog' | 'discord' | 'figma' | 'github' | 'gitlab' | 'mattermost' | 'microsoft-teams' | 'notion' | 'opencode' | 'slack' | 'telegram'requiredWhich mark.
sizeas Glyph'1em'How big it draws.
titlestringnoneNames the mark. Without one it is aria-hidden.
mutedbooleanfalseDrains the colour, for an application that is available but not connected.

This is the one place the design system draws somebody else's colours. Colour here carries state and never identity, and a third-party application's mark is the deliberate exception: identity is exactly what a mark is for, and a recoloured Slack mark is not Slack's. No hue in svg/vendor/ is a token, nothing reads state from a mark, and a mark appears only beside the name of the application it belongs to.

GitHub's, Notion's and OpenCode's marks are monochrome by design and take the current text colour, so they read on either theme. That is each vendor's own instruction rather than an exemption: each publishes one mark, black on a light ground and white on a dark one, so a fixed hex would be wrong in one theme whichever was picked.

claude and opencode name the coding CLI a model runs (Claude Code and OpenCode). Claude's is the Claude Spark (Clay) from Anthropic's press kit at anthropic.com/press-kit; OpenCode's is the logo from opencode.ai/brand. Each mark is its owner's trademark.

crewlet is Crewlet's own mark, for the services built into it (Worklet, Doclet) where a catalogue lists them beside the third-party apps they stand in for. It is drawn from the brand mark the package already carries (svg/crewlet-icon.svg, CrewletIcon), not a second copy, and takes the same size and muted as any other vendor.

A mark keeps its own viewBox, so one that is not square (Figma's is 2:3) is drawn to fit the square size and centred in it, at the aspect ratio the vendor draws. Every drawing fills its viewBox edge to edge, so the marks in a catalogue stand at one weight: GitLab's is cropped to its logo (its press-kit file framed the logo in twice its own width, and drew at half the size of every mark beside it), and Crewlet's is the brand mark framed in the square its own extent fits rather than in the wide file's artwork margins, so it draws the slot's full width.

The marks and the terms on which they may be used are in TRADEMARKS.md, which ships in the package. The Mattermost, Datadog, Notion, Discord, ClickUp, Telegram and Microsoft Teams drawings are Simple Icons' renderings, whose path data is CC0 1.0.

VENDORS lists every mark the package carries.

Product marks

import { ProductMark } from '@crewlethq/icons/product-mark';

<ProductMark product="worklet" size={24} />
<ProductMark product="chat" size="md" soon />
<ProductMark product="assistant" size="sm" title="Ask Crewlet" />

@crewlethq/icons/product-mark is the marks' own entry, with ProductMark, PRODUCTS and their types and nothing else: its import graph reaches the drawings, the glyph frame and ProductMark.css, never the root with its illustrations, vendor marks and their stylesheets, so a first paint that draws one mark (an Ask button) pays for that alone whatever its bundler does with the root's side effects. The root still exports the same functions; test/bundle.test.mjs holds the entry's graph and what a build of it carries (about 6 KB for all eight drawings).

PropTypeDefaultPurpose
productProduct: 'worklet' | 'doclet' | 'chat' | 'assistant'requiredWhich of Crewlet's own products.
sizeas Glyph'1em'How big it draws.
drawingProductMarkDrawing: 'auto' | 'small' | 'master''auto'Which drawing to mount. auto mounts the 16 pixel grid drawing below 24 px and the master from 24 px up (see Two drawings).
titlestringnoneNames the mark. Without one it is aria-hidden.
soonbooleanfalseDraws a product that has not shipped hollow: a faint violet body under a violet keyline and figure. Never grey, which is how a vendor mark says "not connected".

The four services built into Crewlet each have a mark of their own, drawn from the brand mark's construction. PRODUCTS lists them. Pair the Ask Crewlet mark with its name ("Ask Crewlet" on a button, in navigation and in catalogues), because a sparkle alone is also read as "new" or "favourite"; for the same reason, Crewlet's own "new" and "soon" cues never use a four point star.

ProductFigure
worklet (projects and tasks)A large tick for the finished task over one open row: a hollow chamfered box and its line for the task still to do. Done is solid and heavy, open is hollow and light.
doclet (spaces and pages)A page whose corner is folded by the brand's own 45 degree chamfer, with a heading block and two lines of text.
chat (talking with agents)A chamfered speech bubble whose one horizontal window is the crewmate's visor, cut through to the tile. The family's one crew reference, with no eyes and no face.
assistant (asking Crewlet itself, as the signed-in person)A four point concave spark with a small companion spark on the 45 degree axis that points into the octagon's upper right chamfer. No face: Ask Crewlet has no identity of its own, so it is a capability of Crewlet rather than a crew member.

Construction

All four stand on one tile: the crewmate head's octagon on the 48 unit grid, inset 2 units, with 9 unit chamfers at 45 degrees, so its weight sits beside a vendor mark's. A lower facet gives it the brand mark's depth. One white figure tells them apart, every straight edge orthogonal or a true 45 degree diagonal and every curve a circular arc, so no size shows a staircase. Interior detail is always a knockout through to the tile, never a second tone. Each file is a handful of paths, each tagged with the part it plays:

data-partWhat it isIn
bodyThe octagon tile.every drawing
shadeThe lower facet.the master and the app tile
keylineThe soon ring, hidden (fill="none") until the soon rule paints it.the master and the 16 pixel grid drawing
detailThe white figure.every drawing
groundThe full bleed square behind the tile.the app tile

Colours

ColourHexWhere
Brand violet#7c56ffThe tile (body), and the keyline and figure when soon. 4.23:1 on the light ground, 4.25:1 on the dark one.
Deep violet#6a3cffThe lower facet (shade), and the app tile's ground. Decorative: 1.25:1 against the tile, so it never carries the silhouette.
Deepest violet#5c24ffThe app tile's facet alone, one step deeper so it still reads against the tile's ground.
White#ffffffThe figure. 4.53:1 on the tile.

Nothing else: no gradient and no other hue, in any file. The marks keep these colours in both themes, as the brand mark does, because they are its identity. test/products.test.mjs holds every file to them.

Two drawings

Each product has two drawings. The master, svg/product/<product>.svg on 0 0 48 48, serves 24 px and up, where every orthogonal edge lands on a whole pixel. The 16 pixel grid drawing, svg/product/small/<product>.svg on 0 0 16 16, serves 16 to 20 px: the tile goes full bleed with no facet (the master's 2 unit inset would be a blurred two thirds of a pixel), and each figure is redrawn on whole pixels with walls and counters of at least one pixel. It also serves 32 px at 2x. At 20 px it is drawn at 1.25x, slightly soft by design.

drawing="auto" reads size: a step from xs to lg, a number, or a length in px below 24 mounts the 16 pixel grid drawing, and anything from 24 up mounts the master. A size in another unit (the default 1em, a rem) cannot be measured while rendering, so it takes the master; pass drawing="small" where such a mark sits in a line of body text, and drawing="master" to keep the master at any size.

Soon

soon is derived from the drawing that is mounted, at either size, with no second file. ProductMark.css drops the body to an 8 percent tint, hides the facet, and paints the hidden keyline (3 units on the master, one whole pixel on the 16 grid) and the figure in the brand violet. The keyline's inner contour winds against its outer one, so it stays hollow under either fill rule. A part that would come within a pixel of the keyline on the 16 grid declares data-soon="tuck" and is drawn at 0.9 about its own centre (only the Ask Crewlet mark's main spark). The state is a class, crewlet-product-mark--soon, so a strict style-src never refuses it.

Under forced colours (Windows high contrast) a mark draws its one colour form in the reader's system colours: the tile and facet in CanvasText with the figure knocked out to Canvas, which keeps every figure readable on any palette. Soon keeps its hollow keyline and figure in CanvasText, at half strength.

Motion

The marks never move by themselves. The Ask Crewlet mark's main spark carries data-motion="turn" and its companion data-motion="twinkle", in both drawings, so a working state can move them; ThinkingIndicator in @crewlethq/ui owns that motion. Over one period of --motion-duration-spark (1.6s), the spark makes a quarter turn about its own centre, tucking to 0.8 through the middle of the turn so its tip passes the companion with clear violet between them, while the companion dips to 0.7 and half strength; both rest for the other half of the period. Under prefers-reduced-motion: reduce both animations stop and the mark holds a still working pose (the spark at 0.8, the companion at 0.7 and half strength). Any other host that moves these parts pivots them with transform-box: fill-box; transform-origin: center, keeps rotate and scale in one transform, and stops them under reduced motion.

App tiles

A 180 px app tile ships for each product, as a raw file rather than a component, for an apple-touch-icon, a web manifest or a catalogue:

import workletTile from '@crewlethq/icons/svg/product/app-tile/worklet.svg';
<link rel="apple-touch-icon" href="/worklet-180.png" />

All four share one frame on 0 0 180 180: a full bleed #6a3cff ground, the octagon redrawn for 180 px in #7c56ff with its lower facet in #5c24ff, and the master's figure at 80 percent baked into absolute coordinates. Every figure sits inside the 72 px maskable safe zone, so a manifest may list a PNG exported from it as any maskable; a rounded or circle mask crops the octagon's corners, which is expected. Raster pipelines export the PNG from this file, and favicons from the 16 pixel grid drawing (16 px, and 32 px at 2x). A change to a figure is baked into its app tile too.

Raw files

FileUse
@crewlethq/icons/svg/product/<product>.svgThe master, 0 0 48 48.
@crewlethq/icons/svg/product/small/<product>.svgThe 16 pixel grid drawing, 0 0 16 16.
@crewlethq/icons/svg/product/app-tile/<product>.svgThe app tile, 0 0 180 180.

The marks' sources are these files: npm run build compiles the master and the 16 pixel grid drawing of each product into ProductMark, and refuses a product that has one without the other.

Signature illustrations

import { AgentReading, CrewletIcon } from '@crewlethq/icons';

<AgentReading style={{ fontSize: 32 }} />

Each illustration is a named export, and a bundler keeps only the one that is imported. There is also a by-name component:

import { Icon } from '@crewlethq/icons';

<Icon name="AgentReading" size="lg" title="Documentation" />

size accepts 'sm' | 'md' | 'lg' | 'xl' (16, 20, 24 and 32 px), a number of px, or any CSS length. title exposes the icon to assistive technology with role="img"; without it the icon is aria-hidden. name is typed as IconName, so a name the package does not ship is a compile error; ICON_NAMES lists them in file-name order, and it is a set rather than a sequence, because adding or renaming an illustration shifts the order.

Icon carries every illustration into the bundle, which is most of half a megabyte, nearly all of it crewlet-reading. A lookup by name is a lookup over all of them, so use it where the name really is data and import the component everywhere else.

Raw SVG files

The source SVGs ship in the package and are exported as @crewlethq/icons/svg/*, for an <img>, a favicon or any other surface that needs a file rather than a React component:

import markUrl from '@crewlethq/icons/svg/crewlet-icon.svg';

A bundler resolves the import to a URL. Outside a bundler, resolve the same specifier with import.meta.resolve('@crewlethq/icons/svg/crewlet-icon.svg') to get the file on disk. The vendored glyph drawings are exported the same way, as @crewlethq/icons/glyphs/x.svg, and so is the license that travels with them, as @crewlethq/icons/glyphs/LICENSE. A raw file is upstream's drawing at upstream's stroke of 2; the components are what draw it at the design's 1.75.

Favicons

An icon slot is square and the mark is 3:2, so the mark sits in a band across the middle of a tab whichever file is linked: framing cannot make a wide drawing fill a square. What favicon/ carries instead is a square SOURCE, which is what a raster pipeline and a search engine both ask for. Google considers a favicon candidate only if it is square and larger than 48px, and every generator that renders PNGs from the mark takes the padding from its viewBox rather than inventing it. The square frame is also the wide file's own side margins trimmed off, so the same paths draw about 8 percent larger in the same slot.

FileFor
favicon/crewlet.svgAny product's <link rel="icon">. The mark, framed square.
favicon/crewlet-admin.svgAn operator console, in a red that tells a superadmin tab from a tenant tab at a glance.
favicon/crewlet.icoThe raster fallback, at 16, 32 and 48 px, for a browser or a bookmark that asks for one.
<link rel="icon" type="image/svg+xml" href="/crewlet.svg" />
<link rel="icon" sizes="any" href="/favicon.ico" />

All three are one drawing: the square files are svg/crewlet-icon.svg path for path, and differ only in the viewBox that frames them and the fill. test/brand.test.mjs holds that, because four products each kept their own copy of the mark and copies of one drawing drift silently. It also measures the frame against the drawing inside it, so a square viewBox that crops the mark, parks it off centre or leaves it swimming in air fails rather than shipping: a favicon is the one asset nobody looks at closely enough to catch that by eye.

CrewletFigure

CrewletFigure renders the Crewlet character as five separately animated body parts:

import { CrewletFigure } from '@crewlethq/icons';

<CrewletFigure motion="wave" style={{ fontSize: 96 }} />
PropTypeDefaultPurpose
motionCrewletMotion: 'idle' | 'dance' | 'wave' | 'jump' | 'walk' | 'spin''idle'The looping motion.
delaynumber (seconds)0Phase offset, so several figures do not move in lockstep.
colorCSS colour--color-brand-mark, falling back to the crewlet purpleBody fill.
fillGapsbooleantrueBacks each joint with body, so a moving limb never uncovers a gap. false renders the plain trim, where the pieces meet with visible seams.

The figure is sized in em like the icons (set font-size or pass width and height) and is aria-hidden; give the surrounding element an accessible name when the figure carries meaning. Every motion stops when the user prefers reduced motion. The geometry lives in src/crewletParts.ts and the motions in src/CrewletFigure.css, which the component imports.

CrewletCharacter

CrewletCharacter draws one of the thirty Crewlet characters an agent can be drawn as, in the current text colour:

import { CrewletCharacter, CREWLET_CHARACTERS, isCrewletCharacter } from '@crewlethq/icons/characters';

<CrewletCharacter character="hexlet" style={{ fontSize: 64, color: 'var(--color-node-cyan)' }} />
PropTypeDefaultPurpose
characterCrewletCharacterId, one of CREWLET_CHARACTERSrequiredWhich character to draw. crewlet, the first, is the mark itself.
detail'full' | 'compact''full'full draws the keyline floating off the body and the gap round the visor; compact leaves both out, with every other cut as fine as them (the page's fold), and opens the eyes, for a character too small for a hairline gap to read.

Every character is cut from the mark's own rules: every corner chamfered at 45 degrees, a keyline at the mark's own proportions, a visor with two upright slits measured from the visor itself, a V notch on a flat crown and block legs under a flat base.

A character is framed square on its optical centre: the point halfway between the middle of its bounding box and the centre of area of its silhouette, in the smallest square round that point that holds everything it draws, the keyline's mitred corners included. A symmetric silhouette is centred geometrically; a heart over thin legs, a speech bubble over its tail or a triangle over its apex moves half the way toward its mass, so it sits in the middle of any box it is given.

Its face and holes are cut into its own paths, wound against the outline round them, and never painted or masked. A cut shows whatever the character stands on (a badge's plate, a chart's card, a hovered row) in every colour and theme, and nothing a host stylesheet does to the paths in its zone can fill one. It carries no mask and no id, so any number of copies, rendered together or apart, can share a page.

An id is what a configuration stores, so the set is a contract: CREWLET_CHARACTERS lists the ids in the order a picker offers them, CREWLET_CHARACTER_GEOMETRY gives each one's name and a few words on its shape, and isCrewletCharacter tells an id this build draws from anything else read off the wire. The geometry lives in src/crewletCharacters.ts, the union and the cuts in src/region.ts and the frame and the face in src/characterDrawing.ts; the original Crewlet is drawn from svg/crewlet-icon.svg itself, which test/characters.test.mjs holds. @crewlethq/ui's Avatar draws a character on a plate in an agent's hue.

Stylesheets

Two components carry rules, and each imports its own stylesheet as a side effect, so a bundler emits the CSS beside the JavaScript and a consumer gets it without being told to. Nothing here depends on @crewlethq/tokens: a rule that wants a token reads it with the literal value as a fallback.

Loading the built entry in plain Node, with no bundler, therefore fails on the stylesheet import. That is the same contract @crewlethq/ui has.

Add an illustration

  1. Drop <your-icon>.svg into svg/. File names become PascalCase component names (for example, agent-celebrating.svg becomes AgentCelebrating).
  2. Run npm run build.
  3. The new illustration is exported from @crewlethq/icons and appears in ICON_NAMES.

A vendor mark goes into svg/vendor/ instead, and is added to the VENDORS list and the Vendor union in src/VendorMark.tsx. A glyph is vendored rather than drawn; see glyphs/README.md.

Conventions for source SVGs

Four families coexist in this package:

Brand artwork: crewlet-icon (the Crewlet mark) and crewlet-reading (a full-colour illustration of the Crewlet character reading a newspaper), together with CrewletFigure. Filled artwork on its own viewBox; render it as supplied. crewlet-reading is a large, detailed illustration (about 670 KB of SVG), so reserve it for hero and empty-state surfaces rather than inline icon slots. The Crewlet name, mark and character are trademarks that the MIT License does not cover; see TRADEMARKS.md before using them outside an official Crewlet product.

Feature illustrations (80x80): hierarchy, company-as-code, turn-engine, code-sandbox, knowledge and human-in-loop. One per capability the platform leads with, so a reader arriving from the README, the marketing site or the docs meets the same six marks. Self-contained artwork with its own gradients and background disc, so it does not inherit currentColor. The build prefixes every id in a file with that file's name, because inline SVGs share the page's id space; keep gradient and other id references inside the file that defines them.

A gradient in one of these must declare gradientUnits="userSpaceOnUse" and span the 80x80 canvas. Left to the SVG default, objectBoundingBox, a gradient is measured from the box of each shape that paints with it, and a horizontal or vertical stroke has a box with no area: the gradient degenerates and the shape does not paint at all. Several strokes in this set are exactly that, and the failure is silent, so test/gradients.test.mjs holds the rule over every file in svg/. It stops at svg/vendor/, where a gradient is the vendor's own and respanning it would repaint somebody else's logo; what the marks are held to instead is the failure, that no axis-aligned shape there paints from a box-measured gradient.

The gradient stops in these files carry their colour in a style attribute, as the drawings were authored. Rendered through the React component it is a style prop, which React writes through the CSSOM and style-src does not govern, and an SVG referenced as an image is its own document outside the page's policy either way. Inlining one of the raw files into a page served with a strict style-src is the case that loses the colours, so inline the component rather than the file.

Signature illustrations (32x32): the crewlet "agent" character in different contexts (agent-idle, agent-working, agent-thinking, agent-reading, agent-greeting, agent-success, agent-error and agent-loading). The set reads as one character through a shared line style and scale rather than an identical outline: the head and shoulders move, shrink or give way to a torso when the pose needs room for a prop (a book, a desk, a thought bubble). Name new variants agent-<pose>.svg.

Signature illustrations follow these rules so they recolor from CSS and sit on one visual weight:

  • A 0 0 32 32 viewBox.
  • stroke="currentColor" and fill="none".
  • A single 1.6 stroke weight.
  • stroke-linecap="round" and stroke-linejoin="round".
  • No hard-coded width or height attributes (the build strips them).

Vendor marks (svg/vendor/): each application's own drawing in its own colours, on its own viewBox. The root element declares the fill it wants, because the build only supplies currentColor where a source declares none.

Breaking changes in 0.5.0

The glyphs are Lucide's stroke drawings, and the Material Symbols set is gone. The approved design draws every glyph as a stroke on the 24 grid with round caps and joins, and a filled Material Symbol beside one reads as a mark from another set, so @crewlethq/icons/glyphs now carries Lucide drawings under Lucide's names. Every glyph changes drawing, and most change name. The symbols/ tree, its @crewlethq/icons/symbols/* export and scripts/vendor-symbols.mjs are removed; the drawings are in glyphs/, exported as @crewlethq/icons/glyphs/*. The package's license is MIT AND ISC rather than MIT AND Apache-2.0, and the notice an application's third-party notices carry for the glyphs is @crewlethq/icons/glyphs/LICENSE rather than @crewlethq/icons/symbols/LICENSE and NOTICE.

The optical size axis goes with Material: a Lucide drawing is one drawing at every size, so opsz and the two functions that chose it are removed. A filled state is a prop rather than a second glyph, and only on a glyph that can carry one: Material's check_circle-fill, error-fill, info-fill and warning-fill were solid discs and triangles with the mark knocked out, which a stroke drawing cannot be, so they take the outline, and the tone around them carries the state as it already did.

One name survives with a different meaning, and it is not a compile error, so look for it: FullscreenGlyph is Lucide's fullscreen, the corners with a screen inside that succeed Material's fit_screen, and Material's fullscreen, the bare corners, is now MaximizeGlyph. TagGlyph is gone rather than repurposed: Material's tag was a hash sign, which is HashGlyph, and Lucide's own tag is a price label that under the old name would have drawn a different thing without a word.

WasIs
a glyph imported by its Material nameits Lucide successor, from the table below
opsz={20} or opsz={24} on a glyphnothing: remove the prop
glyphOpticalSize(), glyphPixels(), the GlyphOpticalSize and GlyphDrawing typesnothing; cssLength() still says what length a size means
<StarFillGlyph /><StarGlyph filled />
fill="currentColor" or fill in a stylesheet to solidify a glyphfilled on a FILLABLE glyph; a stylesheet fill paints a stroke drawing's inside, so drop it from any rule that reaches a .crewlet-glyph
a stylesheet or strokeWidth changing a glyph's weight--crewlet-glyph-stroke on an ancestor
@crewlethq/icons/symbols/20/<name>.svg or /24/<name>.svg@crewlethq/icons/glyphs/<lucide-name>.svg
@crewlethq/icons/symbols/LICENSE and NOTICE in your third-party notices@crewlethq/icons/glyphs/LICENSE
a license scan expecting MIT AND Apache-2.0MIT AND ISC
glyphByName('close') and the other Material names in a GlyphNamethe Lucide name, from the table below

Every Material Symbols name the package shipped, and its successor. A row's Lucide name is also the GlyphName for glyphByName.

Material Symbols nameWasLucide nameIs
account_treeAccountTreeGlyphnetworkNetworkGlyph
addAddGlyphplusPlusGlyph
apartmentApartmentGlyphbuilding-complexBuildingComplexGlyph
arrow_downwardArrowDownwardGlypharrow-downArrowDownGlyph
arrow_forwardArrowForwardGlypharrow-rightArrowRightGlyph
arrow_outwardArrowOutwardGlypharrow-up-rightArrowUpRightGlyph
arrow_upwardArrowUpwardGlypharrow-upArrowUpGlyph
autorenewAutorenewGlyphrefresh-cwRefreshCwGlyph
blockBlockGlyphbanBanGlyph
boltBoltGlyphzapZapGlyph
book_2Book2Glyphbook-openBookOpenGlyph
bug_reportBugReportGlyphbugBugGlyph
buildBuildGlyphwrenchWrenchGlyph
cableCableGlyphplugPlugGlyph
cachedCachedGlyphrefresh-ccwRefreshCcwGlyph
calendar_clockCalendarClockGlyphcalendar-clockCalendarClockGlyph
calendar_todayCalendarTodayGlyphcalendarCalendarGlyph
chatChatGlyphmessage-squareMessageSquareGlyph
checkCheckGlyphcheckCheckGlyph
check_circleCheckCircleGlyphcircle-checkCircleCheckGlyph
check_circle-fillCheckCircleFillGlyphcircle-checkCircleCheckGlyph
chevron_leftChevronLeftGlyphchevron-leftChevronLeftGlyph
chevron_rightChevronRightGlyphchevron-rightChevronRightGlyph
closeCloseGlyphxXGlyph
codeCodeGlyphcodeCodeGlyph
computerComputerGlyphmonitorMonitorGlyph
content_copyContentCopyGlyphcopyCopyGlyph
create_new_folderCreateNewFolderGlyphfolder-plusFolderPlusGlyph
crownCrownGlyphcrownCrownGlyph
cycleCycleGlyphrepeat-2Repeat2Glyph
dark_modeDarkModeGlyphmoonMoonGlyph
dashboardDashboardGlyphlayout-dashboardLayoutDashboardGlyph
databaseDatabaseGlyphdatabaseDatabaseGlyph
deleteDeleteGlyphtrashTrashGlyph
descriptionDescriptionGlyphfile-textFileTextGlyph
differenceDifferenceGlyphdiffDiffGlyph
dnsDnsGlyphserverServerGlyph
drag_indicatorDragIndicatorGlyphgrip-verticalGripVerticalGlyph
editEditGlyphpencilPencilGlyph
errorErrorGlyphcircle-alertCircleAlertGlyph
error-fillErrorFillGlyphcircle-alertCircleAlertGlyph
exploreExploreGlyphcompassCompassGlyph
fit_screenFitScreenGlyphfullscreenFullscreenGlyph
flagFlagGlyphflagFlagGlyph
folderFolderGlyphfolderFolderGlyph
fork_rightForkRightGlyphsplitSplitGlyph
fullscreenFullscreenGlyphmaximizeMaximizeGlyph
fullscreen_exitFullscreenExitGlyphminimizeMinimizeGlyph
groupGroupGlyphusersUsersGlyph
helpHelpGlyphcircle-question-markCircleQuestionMarkGlyph
inboxInboxGlyphinboxInboxGlyph
infoInfoGlyphinfoInfoGlyph
info-fillInfoFillGlyphinfoInfoGlyph
keyKeyGlyphkeyKeyGlyph
keyboard_arrow_downKeyboardArrowDownGlyphchevron-downChevronDownGlyph
keyboard_arrow_upKeyboardArrowUpGlyphchevron-upChevronUpGlyph
keyboard_double_arrow_leftKeyboardDoubleArrowLeftGlyphchevrons-leftChevronsLeftGlyph
keyboard_double_arrow_rightKeyboardDoubleArrowRightGlyphchevrons-rightChevronsRightGlyph
layersLayersGlyphlayersLayersGlyph
light_modeLightModeGlyphsunSunGlyph
linkLinkGlyphlinkLinkGlyph
listListGlyphlistListGlyph
manufacturingManufacturingGlyphcogCogGlyph
memoryMemoryGlyphcpuCpuGlyph
menuMenuGlyphmenuMenuGlyph
more_vertMoreVertGlyphellipsis-verticalEllipsisVerticalGlyph
move_itemMoveItemGlyphfolder-inputFolderInputGlyph
neurologyNeurologyGlyphbrainBrainGlyph
notificationsNotificationsGlyphbellBellGlyph
open_in_newOpenInNewGlyphexternal-linkExternalLinkGlyph
package_2Package2GlyphpackagePackageGlyph
pausePauseGlyphpausePauseGlyph
personPersonGlyphuserUserGlyph
person_addPersonAddGlyphuser-plusUserPlusGlyph
photo_cameraPhotoCameraGlyphcameraCameraGlyph
power_settings_newPowerSettingsNewGlyphpowerPowerGlyph
redoRedoGlyphredoRedoGlyph
refreshRefreshGlyphrotate-cwRotateCwGlyph
removeRemoveGlyphminusMinusGlyph
saveSaveGlyphsaveSaveGlyph
scheduleScheduleGlyphclockClockGlyph
searchSearchGlyphsearchSearchGlyph
settingsSettingsGlyphsettingsSettingsGlyph
settings_backup_restoreSettingsBackupRestoreGlyphrotate-ccwRotateCcwGlyph
shieldShieldGlyphshieldShieldGlyph
shield_personShieldPersonGlyphshield-userShieldUserGlyph
smart_toySmartToyGlyphbotBotGlyph
starStarGlyphstarStarGlyph
star-fillStarFillGlyphstar<StarGlyph filled />
swap_vertSwapVertGlypharrow-up-downArrowUpDownGlyph
tagTagGlyphhashHashGlyph
targetTargetGlyphtargetTargetGlyph
terminalTerminalGlyphsquare-terminalSquareTerminalGlyph
timelineTimelineGlyphchart-no-axes-ganttChartNoAxesGanttGlyph
tokenTokenGlyphcoinsCoinsGlyph
tuneTuneGlyphsliders-verticalSlidersVerticalGlyph
undoUndoGlyphundoUndoGlyph
unfold_moreUnfoldMoreGlyphchevrons-up-downChevronsUpDownGlyph
view_columnViewColumnGlyphcolumns-3Columns3Glyph
visibilityVisibilityGlypheyeEyeGlyph
visibility_offVisibilityOffGlypheye-offEyeOffGlyph
warningWarningGlyphtriangle-alertTriangleAlertGlyph
warning-fillWarningFillGlyphtriangle-alertTriangleAlertGlyph
zoom_inZoomInGlyphzoom-inZoomInGlyph
zoom_outZoomOutGlyphzoom-outZoomOutGlyph

License

MIT AND ISC.

The package's own code and artwork are MIT; the license text is in LICENSE, which ships in the package. The vendored Lucide drawings in glyphs/ are under the ISC License, and those Lucide derives from Feather are under Feather's MIT License as well; upstream's own glyphs/LICENSE carries both texts and ships beside them.

Both licenses cover copyright only. The Crewlet name, logo and character are trademarks, and so are the third-party marks in svg/vendor/. TRADEMARKS.md, which also ships in the package, says how each may be used.

版本与发布记录

@crewlethq/icons 共发布 129 个版本,首次发布于 2026/09/14;过去 12 个月发布了 129 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.84.2latest2026/11/012 天前
0.84.12026/11/012 天前
0.84.02026/10/313 天前
0.83.02026/10/313 天前
0.82.02026/10/313 天前
0.81.22026/10/313 天前

关于 @crewlethq/icons 的常见问题

@crewlethq/icons 是什么?

Crewlet签名插图图标、供应商标志和Lucide字形设置为React组件。

如何安装 @crewlethq/icons?

在项目目录运行 npm install @crewlethq/icons,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=18)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@crewlethq/icons 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@crewlethq/icons 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@crewlethq/icons 可以商用吗?

@crewlethq/icons 使用 MIT AND ISC 许可。声明的许可为 MIT AND ISC,请阅读许可原文确认使用条件。以上为概括,不构成法律意见,请以许可原文为准。

@crewlethq/icons 还在维护吗?

最新版本 0.84.2 发布于 2026/11/01(2 天前);至今共发布 129 个版本,其中过去 12 个月发布了 129 个;首次发布于 2026/09/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。