diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
new file mode 100644
index 00000000..d4e1a95f
--- /dev/null
+++ b/packages/ui/src/index.ts
@@ -0,0 +1 @@
+export * from './unocss'
diff --git a/packages/ui/src/unocss/index.ts b/packages/ui/src/unocss/index.ts
new file mode 100644
index 00000000..31039fe2
--- /dev/null
+++ b/packages/ui/src/unocss/index.ts
@@ -0,0 +1,50 @@
+import type { WebFontsOptions } from '@unocss/preset-web-fonts'
+import type { Theme } from '@unocss/preset-wind4'
+import {
+ definePreset,
+ mergeDeep,
+ presetAttributify,
+ presetIcons,
+ presetTypography,
+ presetWebFonts,
+ presetWind4,
+ transformerDirectives,
+ transformerVariantGroup,
+} from 'unocss'
+import { shortcuts } from './shortcuts'
+import { theme } from './theme'
+
+export interface PresetDevToolsUIOptions {
+ webFonts?: WebFontsOptions
+}
+
+export const presetDevToolsUI = definePreset
((options) => {
+ return {
+ name: '@vitejs/devtools-ui/preset',
+ shortcuts,
+ extendTheme(defaultTheme) {
+ return mergeDeep(defaultTheme, theme)
+ },
+ presets: [
+ presetWind4(),
+ presetAttributify(),
+ presetIcons({
+ scale: 1.2,
+ }),
+ presetTypography(),
+ presetWebFonts(mergeDeep(
+ {
+ fonts: {
+ sans: 'DM Sans:200,400,700',
+ mono: 'DM Mono',
+ },
+ },
+ options?.webFonts ?? {},
+ )),
+ ],
+ transformers: [
+ transformerDirectives(),
+ transformerVariantGroup(),
+ ],
+ }
+})
diff --git a/packages/ui/src/unocss/shortcuts.ts b/packages/ui/src/unocss/shortcuts.ts
new file mode 100644
index 00000000..d2f9a83e
--- /dev/null
+++ b/packages/ui/src/unocss/shortcuts.ts
@@ -0,0 +1,62 @@
+import type { UserShortcuts } from '@unocss/core'
+import type { Theme } from '@unocss/preset-wind4'
+
+export const shortcuts: UserShortcuts = [
+ {
+ 'color-base': 'color-neutral-800 dark:color-neutral-300',
+ 'bg-base': 'bg-white dark:bg-#111',
+ 'bg-secondary': 'bg-#eee dark:bg-#222',
+ 'border-base': 'border-#8884',
+
+ 'border-flow': 'border-#8885',
+ 'border-flow-line': 'border-#ccc dark:border-#222',
+ 'border-flow-active': 'border-primary-700/50 dark:border-primary-300/50',
+ 'border-flow-line-active': 'border-primary-700/30 dark:border-primary-300/30',
+
+ 'fg-flow-line': 'color-#ccc dark:color-#222',
+ 'fg-flow-line-active': 'color-primary-700/30 dark:color-primary-300/30',
+
+ 'bg-tooltip': 'bg-white:75 dark:bg-#111:75 backdrop-blur-8',
+ 'bg-code': 'bg-gray-500:5',
+
+ 'bg-gradient-more': 'bg-gradient-to-t from-white via-white:80 to-white:0 dark:from-#111 dark:via-#111:80 dark:to-#111:0',
+
+ 'color-active': 'color-primary-600 dark:color-primary-300',
+ 'border-active': 'border-primary-600/25 dark:border-primary-400/25',
+ 'bg-active': 'bg-#8881',
+
+ 'btn-action': 'border border-base rounded flex gap-2 items-center px2 py1 op75 hover:op100 hover:bg-active disabled:pointer-events-none disabled:op30!',
+ 'btn-action-sm': 'btn-action text-sm',
+ 'btn-action-active': 'color-active border-active! bg-active op100!',
+
+ 'icon-catppuccin': 'light:filter-invert-100 light:filter-hue-rotate-180 light:filter-brightness-80',
+
+ 'z-flowmap-line': 'z--1',
+ 'z-graph-bg': 'z-5',
+ 'z-graph-link': 'z-10',
+ 'z-graph-node': 'z-11',
+ 'z-graph-link-active': 'z-12',
+ 'z-graph-node-active': 'z-13',
+
+ 'z-panel-no-mobile': 'z-55',
+ 'z-panel-nav': 'z-60',
+ 'z-panel-content': 'z-65',
+ 'z-panel-goto': 'z-70',
+ 'z-panel-terminal': 'z-80',
+
+ 'op-fade': 'op65 dark:op55',
+ 'op-mute': 'op30 dark:op25',
+ 'color-deprecated': 'text-op85 text-[#b71c1c] dark:text-[#f87171]',
+
+ 'color-scale-neutral': 'text-gray-700:75 dark:text-gray-300:75!',
+ 'color-scale-low': 'text-lime-700:75 dark:text-lime-300:75! dark:saturate-50',
+ 'color-scale-medium': 'text-amber-700:85 dark:text-amber-300:85! dark:saturate-80',
+ 'color-scale-high': 'text-orange-700:95 dark:text-orange-300:95!',
+ 'color-scale-critical': 'text-red-700:95 dark:text-red-300:95!',
+
+ 'page-padding': 'pt-24 pl-112 pr-8 pb-8',
+ 'page-padding-collapsed': 'pt-24 pl-14 pr-8 pb-8',
+ },
+ [/^badge-color-(\w+)$/, ([, color]) => `bg-${color}-400:20 dark:bg-${color}-400:10 text-${color}-700 dark:text-${color}-300 border-${color}-600:10 dark:border-${color}-300:10`],
+ [/^bg-glass(:\d+)?$/, ([, opacity = ':75']) => `bg-white${opacity} dark:bg-#111${opacity} backdrop-blur-5`],
+]
diff --git a/packages/ui/src/unocss/theme.ts b/packages/ui/src/unocss/theme.ts
new file mode 100644
index 00000000..8555ece4
--- /dev/null
+++ b/packages/ui/src/unocss/theme.ts
@@ -0,0 +1,20 @@
+import type { Theme } from '@unocss/preset-wind4'
+
+export const theme: Theme = {
+ colors: {
+ primary: {
+ 50: '#fcf4ff',
+ 100: '#f7e5ff',
+ 200: '#f0d0ff',
+ 300: '#e5acff',
+ 400: '#d577ff',
+ DEFAULT: '#d577ff',
+ 500: '#c543ff',
+ 600: '#bd34fe',
+ 700: '#9f0fe1',
+ 800: '#8512b7',
+ 900: '#6d1093',
+ 950: '#4d006e',
+ },
+ },
+}
diff --git a/packages/vite/package.json b/packages/vite/package.json
index 4e49f625..4a8600e7 100644
--- a/packages/vite/package.json
+++ b/packages/vite/package.json
@@ -39,6 +39,7 @@
"@rolldown/debug": "catalog:deps",
"@vitejs/devtools-kit": "workspace:*",
"@vitejs/devtools-rpc": "workspace:*",
+ "@vitejs/devtools-ui": "workspace:*",
"ansis": "catalog:deps",
"birpc": "catalog:deps",
"cac": "catalog:deps",
diff --git a/packages/vite/src/app/app.vue b/packages/vite/src/app/app.vue
index 04fe89fb..f2a38fc0 100644
--- a/packages/vite/src/app/app.vue
+++ b/packages/vite/src/app/app.vue
@@ -1,6 +1,7 @@