> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Illustration

> Illustration language for Anvil2: style, color, form, perspective, line work, texture, and character.

Anvil2 illustrations use a shared illustration language: modern, clean, and friendly 2D art with consistent line weight and restrained detail. Apply these rules when creating or reviewing illustration work. Import published SVGs from the [Illustrations overview](https://anvil.servicetitan.com/docs/illustrations).

> **[Illustration language in Figma](https://www.figma.com/design/9AdQ0X9Wgx54HHFPM1xkOT/NEW-Illustration-Library?m=auto\&node-id=2885-4404\&t=95hr7d0TQUiSvJeG-1)**
>
> Design source for style, color, form, perspective, line work, texture, and
> character.

## Style

*Modern, Clean, and Friendly*

Illustrations are designed with clean lines, minimal details, and a balanced mix of muted and vibrant colors. The combination of squared and rounded shapes creates an approachable aesthetic. Consistent line weights enhance clarity, while subtle shadows add depth without disrupting the clean, cohesive style. The foundation is flat, with no skewing or angling of shapes, adhering to a polished 2D style.

## Color palette

*Professional Tones*

Each illustration employs a well-thought-out color palette specific to its application, ensuring a functional and visually engaging hierarchy. Primary tones are complemented by a secondary accent color to highlight details:

| App | Color tones | Meaning |
| - | - | - |
| Desktop and Field | Blue tones with red accents | Professionalism and energy |
| Office | Cool greens and neutral tones | Calmness and balance |
| Inventory | Warm oranges with subtle accents | Vibrancy and focus |

## Form and shapes

*Geometric, Structured, and Flat 2D Foundation*

Elements are simplified and geometric. Circular shapes add softness, while rectangular forms provide stability.

* **Buildings and trucks:** Rectangular forms with rounded edges convey structure and approachability.
* **Details like tools:** Smooth, rounded shapes ensure recognizability without excessive detail.

The balance of shapes ensures versatility across themes, with forms deliberately designed to be intuitive and relatable. By avoiding overly complex contours, the illustrations remain clean and universally accessible.

###### Corner radiuses

To maintain consistency, corner radiuses should adhere to even numbers such as
**2, 4, 6, or 8** pixels. This standardization ensures a cohesive appearance
across all illustrations, balancing sharp and rounded edges for a professional
yet approachable design.

These same published illustrations, reused across contexts, show how the form and shape rules hold up regardless of the scene.

illustrations-kit-form-language

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/illustrations-kit-form-language?file=src/App.tsx)

```tsx lines theme={null}
import {
  AnvilProvider,
  Flex,
  usePrefersColorScheme,
} from "@servicetitan/anvil2";
import {
  EmptyStateError,
  EmptyStateFirstUse,
  EmptyStateNoSearchResults,
  EmptyStateSuccess,
  EmptyStateUserCleared,
} from "@servicetitan/anvil2-illustrations";

function App() {
  const { mode } = usePrefersColorScheme();

  return (
    <AnvilProvider themeData={{ mode }}>
      <Flex gap={4} wrap="wrap">
        <EmptyStateFirstUse aria-hidden="true" width={167} height={140} />
        <EmptyStateError aria-hidden="true" width={167} height={140} />
        <EmptyStateSuccess aria-hidden="true" width={167} height={140} />
        <EmptyStateUserCleared aria-hidden="true" width={167} height={140} />
        <EmptyStateNoSearchResults
          aria-hidden="true"
          width={167}
          height={140}
        />
      </Flex>
    </AnvilProvider>
  );
}

export default App;
```

## Perspective

*Flat with Subtle Depth*

Illustrations maintain a primarily flat appearance, with shadows and layering techniques that suggest depth. This subtle approach enhances scalability and ensures legibility across sizes without leaning into realism.

### Implying depth

*Layering and Shadows*

Although rooted in 2D, the illustrations create depth by:

* **Layering and overlapping:** Objects in the foreground overlap smaller or farther elements in the background.
* **Color adjustments:** Layers with varying opacities (e.g., 50%) or slightly darker shades imply dimension.
* **Subtle shadows:** Strategically placed shadows enhance the perception of depth without adding clutter.

For example, the side of a building may use a slightly darker tone to suggest perspective while maintaining the 2D foundation. This consistent method of implying depth ensures the illustrations remain polished and visually engaging.

illustrations-kit-depth-language

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/illustrations-kit-depth-language?file=src/App.tsx)

```tsx lines theme={null}
import {
  AnvilProvider,
  Flex,
  usePrefersColorScheme,
} from "@servicetitan/anvil2";
import {
  EmptyStateFirstUse,
  EmptyStateNoSearchResults,
  EmptyStateSuccess,
} from "@servicetitan/anvil2-illustrations";

function App() {
  const { mode } = usePrefersColorScheme();

  return (
    <AnvilProvider themeData={{ mode }}>
      <Flex gap={4} wrap="wrap">
        <EmptyStateFirstUse aria-hidden="true" width={167} height={140} />
        <EmptyStateSuccess aria-hidden="true" width={167} height={140} />
        <EmptyStateNoSearchResults
          aria-hidden="true"
          width={167}
          height={140}
        />
      </Flex>
    </AnvilProvider>
  );
}

export default App;
```

## Line work

*Consistent 2pt Strokes*

All strokes are uniformly set to **2pt**, providing subtle detail and a sense of familiarity. This consistent line weight ensures:

* **Clarity and polish:** Maintains visual legibility and refinement at both large and small scales.
* **Consistency:** Applied uniformly across all illustration themes and applications, creating a cohesive visual language.
* **Intentional weight variation:** If a stroke needs to be heavier than 2pt, it should be noticeably thicker, leaning towards a shape rather than a line to maintain visual balance and hierarchy.

This ensures that any variation in stroke weight feels deliberate and reinforces the overall style rather than creating unintended inconsistencies.

illustrations-kit-line-work

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/illustrations-kit-line-work?file=src/App.tsx)

```tsx lines theme={null}
import type { ComponentType, SVGProps } from "react";
import {
  AnvilProvider,
  Flex,
  usePrefersColorScheme,
} from "@servicetitan/anvil2";
import {
  EmptyStateError,
  EmptyStateFirstUse,
  EmptyStateUserCleared,
} from "@servicetitan/anvil2-illustrations";

const ILLUSTRATION_WIDTH = 215;
const ILLUSTRATION_HEIGHT = 180;
const CALLOUT_COLOR = "var(--a2-color-green-500)";

type CalloutPosition = { top: number; left: number };

function Callout({ top, left }: CalloutPosition) {
  return (
    <Flex
      alignItems="center"
      gap={1}
      style={{ position: "absolute", top, left }}
    >
      <div
        style={{
          width: 6,
          height: 6,
          borderRadius: "50%",
          background: CALLOUT_COLOR,
        }}
      />
      <div style={{ width: 56, borderTop: `2px dashed ${CALLOUT_COLOR}` }} />
      <span style={{ color: CALLOUT_COLOR, fontStyle: "italic", fontSize: 12 }}>
        2pt
      </span>
    </Flex>
  );
}

function IllustrationWithCallouts({
  Illustration,
  callouts,
}: {
  Illustration: ComponentType<SVGProps<SVGSVGElement>>;
  callouts: CalloutPosition[];
}) {
  return (
    <div
      style={{
        position: "relative",
        width: ILLUSTRATION_WIDTH + 100,
        height: ILLUSTRATION_HEIGHT,
      }}
    >
      <Illustration
        aria-hidden="true"
        width={ILLUSTRATION_WIDTH}
        height={ILLUSTRATION_HEIGHT}
      />
      {callouts.map((callout) => (
        <Callout key={callout.top} {...callout} />
      ))}
    </div>
  );
}

function App() {
  const { mode } = usePrefersColorScheme();

  return (
    <AnvilProvider themeData={{ mode }}>
      <Flex gap={6} wrap="wrap">
        <IllustrationWithCallouts
          Illustration={EmptyStateFirstUse}
          callouts={[
            { top: 67, left: 181 },
            { top: 110, left: 172 },
          ]}
        />
        <IllustrationWithCallouts
          Illustration={EmptyStateUserCleared}
          callouts={[
            { top: 41, left: 147 },
            { top: 97, left: 94 },
            { top: 116, left: 177 },
          ]}
        />
        <IllustrationWithCallouts
          Illustration={EmptyStateError}
          callouts={[
            { top: 95, left: 93 },
            { top: 122, left: 149 },
          ]}
        />
      </Flex>
    </AnvilProvider>
  );
}

export default App;
```

## Details and textures

*Minimal with Subtle Interest*

Textures and patterns are rarely used, appearing only as light shading or small dashes to suggest depth or surface material. This is achieved by layering colors and adjusting opacities (**50% opacity**), adding just enough visual interest without overcrowding. This minimalism keeps elements clean and highly visible at smaller scales.

* **Light shading:** Adding a sense of material depth.
* **Simple line work or strokes:** Used sparingly to imply otherwise complex details in a subtle and approachable manner.

This approach ensures elements remain clean, highly visible, and engaging without overwhelming the viewer. The minimal texture application is balanced with functional clarity, enhancing the illustration's overall effectiveness.

illustrations-kit-opacity-layering

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/illustrations-kit-opacity-layering?file=src/App.tsx)

```tsx lines theme={null}
import {
  AnvilProvider,
  Text,
  usePrefersColorScheme,
} from "@servicetitan/anvil2";
import { EmptyStateSuccess } from "@servicetitan/anvil2-illustrations";

const ILLUSTRATION_WIDTH = 167;
const ILLUSTRATION_HEIGHT = 140;
const SWATCH_WIDTH = 90;
const SWATCH_HEIGHT = 34;
const SWATCH_OFFSET = 24;
const CALLOUT_COLOR = "var(--a2-color-green-500)";

const SWATCH_COLORS = {
  light: { base: "#113064", overlay: "#B5DEFF" },
  dark: { base: "#D6E5FF", overlay: "#0265DC" },
};

function Dot({ top, left }: { top: number; left: number }) {
  return (
    <div
      style={{
        position: "absolute",
        top: top - 3,
        left: left - 3,
        width: 6,
        height: 6,
        borderRadius: "50%",
        background: CALLOUT_COLOR,
      }}
    />
  );
}

function App() {
  const { mode } = usePrefersColorScheme();

  const swatchColors = SWATCH_COLORS[mode];

  const illustrationDot = { top: 66, left: 68 };
  const swatchDot = { top: 17, left: 57 };
  const bridgeTop = 0;

  return (
    <AnvilProvider themeData={{ mode }}>
      <div style={{ position: "relative", width: 460, height: 160 }}>
        <EmptyStateSuccess
          aria-hidden="true"
          width={ILLUSTRATION_WIDTH}
          height={ILLUSTRATION_HEIGHT}
          style={{ position: "absolute", top: 20, left: 0 }}
        />
        <div
          style={{
            position: "absolute",
            top: 20 + swatchDot.top - SWATCH_HEIGHT / 2,
            left: 175,
            width: SWATCH_WIDTH + SWATCH_OFFSET,
            height: SWATCH_HEIGHT,
          }}
        >
          <div
            style={{
              position: "absolute",
              top: 0,
              left: SWATCH_OFFSET,
              width: SWATCH_WIDTH,
              height: SWATCH_HEIGHT,
              background: swatchColors.base,
            }}
          />
          <div
            style={{
              position: "absolute",
              top: 0,
              left: 0,
              width: SWATCH_WIDTH,
              height: SWATCH_HEIGHT,
              background: swatchColors.overlay,
              opacity: 0.5,
            }}
          />
        </div>
        <Text
          subdued
          style={{
            position: "absolute",
            top: 20 + swatchDot.top + SWATCH_HEIGHT / 2 + 8,
            left: 175,
            width: 210,
            fontStyle: "italic",
            fontSize: 12,
          }}
        >
          Layering two colors with top layer at 50% opacity to create
          depth/shading
        </Text>
        <div
          style={{
            position: "absolute",
            top: 20 + bridgeTop,
            left: 20 + illustrationDot.left,
            width: 1,
            height: 20 + illustrationDot.top - (20 + bridgeTop),
            borderLeft: `1px dashed ${CALLOUT_COLOR}`,
          }}
        />
        <div
          style={{
            position: "absolute",
            top: 20 + bridgeTop,
            left: 20 + illustrationDot.left,
            width: 175 + swatchDot.left - (20 + illustrationDot.left),
            height: 1,
            borderTop: `1px dashed ${CALLOUT_COLOR}`,
          }}
        />
        <div
          style={{
            position: "absolute",
            top: 20 + bridgeTop,
            left: 175 + swatchDot.left,
            width: 1,
            height: 20 + swatchDot.top - (20 + bridgeTop),
            borderLeft: `1px dashed ${CALLOUT_COLOR}`,
          }}
        />
        <Dot top={20 + illustrationDot.top} left={20 + illustrationDot.left} />
        <Dot top={20 + swatchDot.top} left={175 + swatchDot.left} />
      </div>
    </AnvilProvider>
  );
}

export default App;
```

## Character and emotion

*Personable and Professional*

Characters and animals (when included) are designed with:

* **Gentle expressions:** Reflecting friendliness and trust.
* **Minimal facial details:** Simple eyes and neutral expressions align with the professional tone.

For example, the dog in the illustration is shown laying down with a calm posture and no distinct expression, adding a relatable and approachable touch while avoiding any unintended implications.

illustrations-kit-character-dog

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/illustrations-kit-character-dog?file=src/App.tsx)

```tsx lines theme={null}
import { AnvilProvider, usePrefersColorScheme } from "@servicetitan/anvil2";
import { EmptyStateNoSearchResults } from "@servicetitan/anvil2-illustrations";

function App() {
  const { mode } = usePrefersColorScheme();

  return (
    <AnvilProvider themeData={{ mode }}>
      <EmptyStateNoSearchResults aria-hidden="true" width={167} height={140} />
    </AnvilProvider>
  );
}

export default App;
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.