
These are complete dashboard compositions, translated from EvilCharts' original ECharts blocks.
Each install copies editable Svelte source into your project.

## Latency percentiles

### Latency percentiles

```svelte
<script lang="ts">
	import { EvilAreaChart } from '../../charts/layerchart-area-chart/index.js';
	import type { ChartConfig } from '../../ui/layerchart-chart/index.js';

	const series = [
		{ key: 'p99', label: 'P99', color: '#d41f12', latest: 204 },
		{ key: 'p95', label: 'P95', color: '#f37a00', latest: 98 },
		{ key: 'p75', label: 'P75', color: '#62c9d4', latest: 46 },
		{ key: 'p50', label: 'P50', color: '#007292', latest: 21 }
	] as const;

	const data = [
		{ time: 'Today 13:06', p99: 188, p95: 92, p75: 44, p50: 20 },
		{ time: 'Today 13:07', p99: 196, p95: 95, p75: 46, p50: 21 },
		{ time: 'Today 13:08', p99: 181, p95: 89, p75: 43, p50: 20 },
		{ time: 'Today 13:09', p99: 192, p95: 94, p75: 47, p50: 22 },
		{ time: 'Today 13:10', p99: 205, p95: 99, p75: 45, p50: 21 },
		{ time: 'Today 13:11', p99: 187, p95: 91, p75: 44, p50: 20 },
		{ time: 'Today 13:12', p99: 179, p95: 88, p75: 42, p50: 19 },
		{ time: 'Today 13:13', p99: 198, p95: 96, p75: 46, p50: 21 },
		{ time: 'Today 13:14', p99: 210, p95: 101, p75: 48, p50: 22 },
		{ time: 'Today 13:15', p99: 194, p95: 93, p75: 45, p50: 21 },
		{ time: 'Today 13:16', p99: 202, p95: 97, p75: 47, p50: 22 },
		{ time: 'Today 13:17', p99: 215, p95: 104, p75: 49, p50: 23 },
		{ time: 'Today 13:18', p99: 231, p95: 112, p75: 52, p50: 23 },
		{ time: 'Today 13:19', p99: 278, p95: 131, p75: 57, p50: 24 },
		{ time: 'Today 13:20', p99: 306, p95: 142, p75: 61, p50: 25 },
		{ time: 'Today 13:21', p99: 289, p95: 135, p75: 58, p50: 24 },
		{ time: 'Today 13:22', p99: 247, p95: 118, p75: 53, p50: 23 },
		{ time: 'Today 13:23', p99: 216, p95: 105, p75: 49, p50: 22 },
		{ time: 'Today 13:24', p99: 201, p95: 97, p75: 46, p50: 21 },
		{ time: 'Today 13:25', p99: 193, p95: 94, p75: 45, p50: 21 },
		{ time: 'Today 13:26', p99: 186, p95: 90, p75: 44, p50: 20 },
		{ time: 'Today 13:27', p99: 199, p95: 96, p75: 46, p50: 21 },
		{ time: 'Today 13:28', p99: 207, p95: 100, p75: 47, p50: 22 },
		{ time: 'Today 13:29', p99: 191, p95: 92, p75: 45, p50: 20 },
		{ time: 'Today 13:30', p99: 184, p95: 89, p75: 43, p50: 20 },
		{ time: 'Today 13:31', p99: 196, p95: 95, p75: 46, p50: 21 },
		{ time: 'Today 13:32', p99: 209, p95: 101, p75: 48, p50: 22 },
		{ time: 'Today 13:33', p99: 198, p95: 96, p75: 46, p50: 21 },
		{ time: 'Today 13:34', p99: 204, p95: 98, p75: 46, p50: 21 }
	];

	const config = {
		p99: { label: 'P99', colors: { light: ['#f87171'], dark: ['#d41f12'] } },
		p95: { label: 'P95', colors: { light: ['#fbbf24'], dark: ['#f37a00'] } },
		p75: { label: 'P75', colors: { light: ['#60a5fa'], dark: ['#62c9d4'] } },
		p50: { label: 'P50', colors: { light: ['#93c5fd'], dark: ['#007292'] } }
	} satisfies ChartConfig;

	let selected = $state<string | null>(null);

	function toggle(key: string) {
		selected = selected === key ? null : key;
	}
</script>

<section
	class="@container/block flex size-full min-h-0 flex-col overflow-hidden p-3 sm:p-4"
	data-block="latency-area-chart"
>
	<div class="grid shrink-0 grid-cols-2 gap-y-2 @sm/block:grid-cols-4">
		{#each series as item (item.key)}
			<button
				type="button"
				onclick={() => toggle(item.key)}
				class="flex min-w-0 items-center gap-1.5 border-border px-2 text-left transition-opacity @sm/block:flex-col @sm/block:items-start @sm/block:gap-1 @sm/block:border-l @sm/block:first:border-l-0"
				class:opacity-35={selected !== null && selected !== item.key}
				aria-pressed={selected === item.key}
			>
				<span class="flex items-center gap-1.5 text-[11px] font-medium text-foreground">
					<span class="size-2 rounded-[2px]" style:background-color={item.color}></span>
					{item.label}
				</span>
				<span class="leading-none">
					<span class="text-sm font-medium tracking-tight @sm/block:text-xl">{item.latest}</span>
					<span class="ml-0.5 text-[10px] text-muted-foreground @sm/block:text-xs">ms</span>
				</span>
			</button>
		{/each}
	</div>

	<div class="mt-2 min-h-0 flex-1 overflow-hidden @sm/block:mt-4">
		{#key selected}
			<EvilAreaChart
				{data}
				{config}
				xDataKey="time"
				class="size-full"
				curveType="linear"
				defaultSelectedDataKey={selected}
				onSelectionChange={(key) => (selected = key)}
			>
				<EvilAreaChart.Grid />
				<EvilAreaChart.XAxis
					dataKey="time"
					tickFormatter={(value) => String(value).replace('Today ', '')}
				/>
				<EvilAreaChart.YAxis />
				<EvilAreaChart.Tooltip />
				<EvilAreaChart.Area dataKey="p50" variant="gradient" strokeVariant="solid" isClickable />
				<EvilAreaChart.Area dataKey="p75" variant="gradient" strokeVariant="solid" isClickable />
				<EvilAreaChart.Area dataKey="p95" variant="gradient" strokeVariant="solid" isClickable />
				<EvilAreaChart.Area dataKey="p99" variant="gradient" strokeVariant="solid" isClickable />
			</EvilAreaChart>
		{/key}
	</div>
</section>
```
### npm

```bash
npx shadcn-svelte@latest add @evilcharts/latency-area-chart
```

### yarn

```bash
yarn dlx shadcn-svelte@latest add @evilcharts/latency-area-chart
```

### bun

```bash
bunx --bun shadcn-svelte@latest add @evilcharts/latency-area-chart
```

### pnpm

```bash
pnpm dlx shadcn-svelte@latest add @evilcharts/latency-area-chart
```

## Portfolio comparison

### Portfolio comparison

```svelte
<script lang="ts">
	import { EvilAreaChart } from '../../charts/layerchart-area-chart/index.js';
	import type { ChartConfig } from '../../ui/layerchart-chart/index.js';

	const series = [
		{ key: 'robinhood', label: 'Robinhood', color: '#c3f000', pct: -4.41, delta: -2377.66 },
		{ key: 'coinbase', label: 'Coinbase', color: '#2f6bff', pct: 1.15, delta: 617.22 }
	] as const;
	const data = [
		{ date: 'Dec 22', robinhood: 53916, coinbase: 53670 },
		{ date: 'Dec 23', robinhood: 54380, coinbase: 53080 },
		{ date: 'Dec 24', robinhood: 54760, coinbase: 52460 },
		{ date: 'Dec 25', robinhood: 54480, coinbase: 51880 },
		{ date: 'Dec 26', robinhood: 54060, coinbase: 51340 },
		{ date: 'Dec 27', robinhood: 53820, coinbase: 50900 },
		{ date: 'Dec 28', robinhood: 53520, coinbase: 50520 },
		{ date: 'Dec 29', robinhood: 53240, coinbase: 50200 },
		{ date: 'Dec 30', robinhood: 53080, coinbase: 49960 },
		{ date: 'Dec 31', robinhood: 52840, coinbase: 49760 },
		{ date: 'Jan 1', robinhood: 52700, coinbase: 49640 },
		{ date: 'Jan 2', robinhood: 52520, coinbase: 49600 },
		{ date: 'Jan 3', robinhood: 52420, coinbase: 49720 },
		{ date: 'Jan 4', robinhood: 52340, coinbase: 49980 },
		{ date: 'Jan 5', robinhood: 52240, coinbase: 50360 },
		{ date: 'Jan 6', robinhood: 52140, coinbase: 50820 },
		{ date: 'Jan 7', robinhood: 52080, coinbase: 51340 },
		{ date: 'Jan 8', robinhood: 52020, coinbase: 51900 },
		{ date: 'Jan 9', robinhood: 51960, coinbase: 52440 },
		{ date: 'Jan 10', robinhood: 51900, coinbase: 52960 },
		{ date: 'Jan 11', robinhood: 51860, coinbase: 53420 },
		{ date: 'Jan 12', robinhood: 51800, coinbase: 53780 },
		{ date: 'Jan 13', robinhood: 51740, coinbase: 54040 },
		{ date: 'Jan 14', robinhood: 51700, coinbase: 54200 },
		{ date: 'Jan 15', robinhood: 51640, coinbase: 54300 },
		{ date: 'Jan 16', robinhood: 51580, coinbase: 54320 },
		{ date: 'Jan 17', robinhood: 51538, coinbase: 54287 }
	];
	const config = {
		robinhood: { label: 'Robinhood', colors: { light: ['#a6cc00'], dark: ['#c3f000'] } },
		coinbase: { label: 'Coinbase', colors: { light: ['#2f6bff'], dark: ['#4c86ff'] } }
	} satisfies ChartConfig;
	const money = (value: number) =>
		Math.abs(value).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
</script>

<section
	class="@container/block flex size-full min-h-0 flex-col overflow-hidden pt-3 sm:pt-4"
	data-block="portfolio-area-chart"
>
	<div class="grid shrink-0 grid-cols-2 gap-x-5 px-3 sm:gap-x-8 sm:px-4">
		{#each series as item (item.key)}
			<div class="flex min-w-0 flex-col gap-0.5 @sm/block:gap-1">
				<div
					class="flex items-center gap-1.5 truncate text-[11px] text-muted-foreground @sm/block:text-sm"
				>
					<span class="size-2.5 shrink-0 rounded-full border-2" style:border-color={item.color}
					></span>
					{item.label}
				</div>
				<div class="text-xl font-semibold tracking-tight @sm/block:text-3xl">
					{item.pct > 0 ? '+' : '−'}{Math.abs(item.pct).toFixed(2)}%
				</div>
				<div class={item.delta < 0 ? 'text-rose-500' : 'text-emerald-500'}>
					{item.delta < 0 ? '−' : '+'}${money(item.delta)}
				</div>
			</div>
		{/each}
	</div>
	<div class="mt-2 min-h-0 flex-1 overflow-hidden @sm/block:mt-4">
		<EvilAreaChart {data} {config} xDataKey="date" class="size-full" curveType="step">
			<EvilAreaChart.Tooltip variant="frosted-glass" />
			<EvilAreaChart.Area dataKey="robinhood" variant="dotted" strokeVariant="solid">
				<EvilAreaChart.ActiveDot variant="colored-border" />
			</EvilAreaChart.Area>
			<EvilAreaChart.Area dataKey="coinbase" variant="dotted" strokeVariant="solid">
				<EvilAreaChart.ActiveDot variant="colored-border" />
			</EvilAreaChart.Area>
		</EvilAreaChart>
	</div>
</section>
```
### npm

```bash
npx shadcn-svelte@latest add @evilcharts/portfolio-area-chart
```

### yarn

```bash
yarn dlx shadcn-svelte@latest add @evilcharts/portfolio-area-chart
```

### bun

```bash
bunx --bun shadcn-svelte@latest add @evilcharts/portfolio-area-chart
```

### pnpm

```bash
pnpm dlx shadcn-svelte@latest add @evilcharts/portfolio-area-chart
```

## Signup benchmark

### Signup benchmark

```svelte
<script lang="ts">
	import { EvilAreaChart } from '../../charts/layerchart-area-chart/index.js';
	import type { ChartConfig } from '../../ui/layerchart-chart/index.js';

	const data = [
		{ date: 'Jan 1', actual: 240, target: 125 },
		{ date: 'Jan 8', actual: 240, target: 125 },
		{ date: 'Jan 15', actual: 175, target: 200 },
		{ date: 'Jan 22', actual: 175, target: 200 },
		{ date: 'Feb 1', actual: 175, target: 200 },
		{ date: 'Feb 8', actual: 260, target: 125 },
		{ date: 'Feb 15', actual: 260, target: 125 },
		{ date: 'Feb 22', actual: 260, target: 125 },
		{ date: 'Mar 1', actual: 260, target: 190 },
		{ date: 'Mar 8', actual: 335, target: 190 },
		{ date: 'Mar 15', actual: 335, target: 190 },
		{ date: 'Mar 22', actual: 335, target: 390 },
		{ date: 'Apr 1', actual: 335, target: 390 },
		{ date: 'Apr 8', actual: 335, target: 390 },
		{ date: 'Apr 15', actual: 190, target: 390 },
		{ date: 'Apr 22', actual: 215, target: 305 },
		{ date: 'May 1', actual: 215, target: 305 },
		{ date: 'May 8', actual: 215, target: 175 },
		{ date: 'May 15', actual: 215, target: 175 },
		{ date: 'May 22', actual: 275, target: 175 },
		{ date: 'Jun 1', actual: 275, target: 245 }
	];
	const config = {
		actual: { label: 'Actual', colors: { light: ['#0a0a0a'], dark: ['#ffffff'] } },
		target: { label: 'Target', colors: { light: ['#a1a1aa'], dark: ['#666666'] } }
	} satisfies ChartConfig;
	const latest = data.at(-1)!;
	const delta = ((latest.actual - latest.target) / latest.target) * 100;
</script>

<section
	class="flex size-full min-h-0 flex-col overflow-hidden p-3 sm:p-4"
	data-block="benchmark-area-chart"
>
	<header class="flex shrink-0 items-start justify-between gap-4">
		<div class="flex flex-col gap-0.5">
			<span class="text-[11px] text-muted-foreground">Weekly signups</span>
			<div class="flex items-baseline gap-2">
				<strong class="text-2xl tracking-tight sm:text-3xl">{latest.actual}</strong>
				<span class="text-[11px] font-medium text-emerald-500 sm:text-sm"
					>+{delta.toFixed(1)}% vs target</span
				>
			</div>
		</div>
		<div class="flex flex-col items-end gap-1 pt-1 text-[10px] text-muted-foreground sm:text-xs">
			<span class="flex items-center gap-2"><i class="h-0.5 w-4 bg-foreground"></i>Actual</span>
			<span class="flex items-center gap-2"><i class="w-4 border-t border-dashed"></i>Target</span>
		</div>
	</header>
	<div class="mt-2 min-h-0 flex-1 overflow-hidden sm:mt-4">
		<EvilAreaChart {data} {config} xDataKey="date" class="size-full" curveType="monotone">
			<EvilAreaChart.Grid />
			<EvilAreaChart.XAxis
				dataKey="date"
				tickFormatter={(value) => (String(value).endsWith(' 1') ? String(value).split(' ')[0] : '')}
			/>
			<EvilAreaChart.YAxis />
			<EvilAreaChart.Tooltip />
			<EvilAreaChart.Area dataKey="target" variant="solid" strokeVariant="dashed" />
			<EvilAreaChart.Area dataKey="actual" variant="lines" strokeVariant="solid" />
		</EvilAreaChart>
	</div>
</section>
```
### npm

```bash
npx shadcn-svelte@latest add @evilcharts/benchmark-area-chart
```

### yarn

```bash
yarn dlx shadcn-svelte@latest add @evilcharts/benchmark-area-chart
```

### bun

```bash
bunx --bun shadcn-svelte@latest add @evilcharts/benchmark-area-chart
```

### pnpm

```bash
pnpm dlx shadcn-svelte@latest add @evilcharts/benchmark-area-chart
```

## Audience reach

### Audience reach

```svelte
<script lang="ts">
	import { EvilAreaChart } from '../../charts/layerchart-area-chart/index.js';
	import type { ChartConfig } from '../../ui/layerchart-chart/index.js';

	const data = [
		{ month: 'Jan', listeners: 2980 },
		{ month: 'Feb', listeners: 3120 },
		{ month: 'Mar', listeners: 3460 },
		{ month: 'Apr', listeners: 3380 },
		{ month: 'May', listeners: 3720 },
		{ month: 'Jun', listeners: 4180 },
		{ month: 'Jul', listeners: 4560 }
	];
	const config = {
		listeners: {
			label: 'Listeners',
			colors: { light: ['#10b981', '#0ea5e9', '#8b5cf6'], dark: ['#34d399', '#38bdf8', '#a78bfa'] }
		}
	} satisfies ChartConfig;
	const total = data.reduce((sum, row) => sum + row.listeners, 0);
</script>

<section class="flex size-full min-h-0 flex-col overflow-hidden" data-block="audience-area-chart">
	<header class="flex shrink-0 items-start justify-between gap-3 px-3 pt-3 sm:px-4 sm:pt-4">
		<div class="flex min-w-0 flex-col gap-1">
			<strong class="text-base font-medium tracking-tight sm:text-lg">Listeners</strong>
			<span class="max-w-[26ch] text-[11px] leading-snug text-muted-foreground sm:text-xs">
				Monthly reach across every show and episode
			</span>
		</div>
		<div class="flex shrink-0 flex-col items-end gap-1">
			<strong class="text-2xl tracking-tight sm:text-4xl">{total.toLocaleString('en-US')}</strong>
			<span class="text-[10px] text-muted-foreground sm:text-xs">Total listeners</span>
		</div>
	</header>
	<div class="relative mt-1 min-h-0 flex-1 overflow-hidden sm:mt-2">
		<EvilAreaChart {data} {config} xDataKey="month" class="size-full" curveType="monotone">
			<EvilAreaChart.Tooltip variant="frosted-glass" />
			<EvilAreaChart.Area
				dataKey="listeners"
				variant="gradient"
				strokeVariant="solid"
				strokeWidth={2.5}
			>
				<EvilAreaChart.ActiveDot variant="colored-border" />
			</EvilAreaChart.Area>
		</EvilAreaChart>
		<div
			class="pointer-events-none absolute inset-x-0 bottom-0 flex justify-between px-3 pb-2 text-[10px] text-muted-foreground sm:px-4 sm:text-xs"
		>
			{#each data as row (row.month)}<span>{row.month}</span>{/each}
		</div>
	</div>
</section>
```
### npm

```bash
npx shadcn-svelte@latest add @evilcharts/audience-area-chart
```

### yarn

```bash
yarn dlx shadcn-svelte@latest add @evilcharts/audience-area-chart
```

### bun

```bash
bunx --bun shadcn-svelte@latest add @evilcharts/audience-area-chart
```

### pnpm

```bash
pnpm dlx shadcn-svelte@latest add @evilcharts/audience-area-chart
```
