mcpField
G
grove-ui-design

grove-ui-design

github.com/autumnsgrove设计与 UI676 次安装5 天前更新
代码仓库

关于 grove-ui-design

Grove UI Design Skill 为 Grove 网站的页面设计和实现提供规范,适用于构建者与设计者。内容覆盖 Grove 术语切换、玻璃效果、季节主题、自然装饰及无障碍与移动端设计。

主要功能

  1. 01按模式切换 Grove 术语
  2. 02应用玻璃质感组件与样式
  3. 03使用四季配色和天气效果
  4. 04生成随机森林装饰
  5. 05遵循 Lucide 图标规范

适用场景

  1. 01设计 Grove 网站页面
  2. 02制作故事与路线图页面
  3. 03构建移动端导航
  4. 04为背景装饰添加可读内容层

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/autumnsgrove/lattice --skill grove-ui-design

安装后在 Claude Code 中输入/grove-ui-design确认已加载。

详细介绍

Grove UI 设计技能

何时启用

在以下情况启用此技能:

  • 为 Grove 网站创建或改进页面
  • 添加装饰性的自然元素(树木、云朵、天气效果)
  • 实现玻璃拟态效果以提升可读性
  • 使用季节主题系统
  • 构建导航模式(导航栏、移动端溢出菜单)
  • 创建引导用户浏览内容的“故事”页面
  • 确保 UI 适配移动设备且无障碍
  • 选择图标或视觉元素

Grove 美学

Grove 是一个地方。它以自然为主题,温暖而宜人,就像一家午夜营业、文档完善的茶馆。

核心原则
Warm, introspective, queer, unapologetically building something meaningful.
Write with the warmth of a midnight tea shop and the clarity of good documentation.

每个设计选择都应让人感到:

  • 热情友好 — 像走进一处舒适的空间
  • 自然有机 — 自然,不刻板,也不显得企业化
  • 易于阅读 — 内容优先,装饰起到增强作用,绝不遮挡内容
  • 充满生机 — 有细微动画、季节变化和随机效果
Grove 模式与术语(GroveTerm V2)

Grove 具有一个术语系统,可根据用户的 Grove 模式设置,在 Grove 风格术语和标准术语之间自动切换。始终使用 GroveTerm 组件,不要在 UI 中硬编码 Grove 术语。

新访客的 Grove 模式默认关闭。他们会看到熟悉的术语:“文章”而不是“花朵”,“控制面板”而不是“树屋”,“支持”而不是“门廊”。用户通过页脚切换开关选择启用后,便会看到完整的自然主题词汇及其交互式定义。

组件套件:

import {(GroveTerm, GroveSwap, GroveText, GroveSwapText, GroveIntro)} from '@autumnsgrove/lattice/ui';
import groveTermManifest from '$lib/data/grove-term-manifest.json';
组件使用场景行为
GroveTerm带弹出定义的交互式术语启用时显示彩色下划线,点击后弹出说明。关闭时显示标准术语。
GroveSwap静默替换文本响应式替换文本。无下划线,也无交互。
GroveText解析数据字符串中的 [[term]] 语法将 [[bloom|posts]] 渲染为交互式 GroveTerm 组件。
GroveSwapText静默解析 [[term]] 语法使用相同的解析方式,但静默替换(不弹出说明)。
GroveIntro“我们称之为 X”页面横幅在页面标题下方显示标准化介绍。

用法:


<GroveTerm term="bloom" manifest={groveTermManifest} />


<GroveTerm term="wanderer" manifest={groveTermManifest}>wanderers</GroveTerm>


<GroveSwap term="arbor" manifest={groveTermManifest} />


<GroveText
	content="Your [[bloom|posts]] live in your [[garden|blog]]."
	manifest={groveTermManifest}
/>


<GroveTerm term="meadow" />


<GroveTerm term="meadow" icon />

关键规则:

  • 切勿在面向用户的 UI 中硬编码 Grove 术语。 始终使用 GroveTerm 组件。
  • 新访客的默认设置为关闭。 优先显示标准、熟悉的术语。
  • URL 始终使用 Grove 术语(/porch、/garden),不受显示模式影响。
  • 品牌术语(Grove)和订阅层级(Seedling/Sapling/Oak/Evergreen)始终按原样显示。
  • 数据驱动内容(FAQ 条目、定价细则、功能列表)使用 [[term]] 语法。
  • Grove 模式存储:@autumnsgrove/lattice/ui/stores 中的 groveModeStore。切换开关位于页脚。

完整的身份语言文档请参阅 docs/grove-user-identity.md,组件源代码请参阅 libs/engine/src/lib/ui/components/ui/groveterm/。


玻璃拟态模式

玻璃效果在展现背景装饰元素的同时,提升内容的可读性。

分层公式
Background (gradients, vines, nature)
    ↓
Decorative Elements (trees, clouds, particles)
    ↓
Glass Surface (translucent + blur)
    ↓
Content (text, cards, UI)
玻璃组件
import {(Glass, GlassCard, GlassButton, GlassOverlay)} from '@lattice/ui/ui';


<Glass variant="tint" class="p-6 rounded-xl">
	<p>Readable text over busy backgrounds</p>
</Glass>


<GlassCard title="Settings" variant="default" hoverable>Content here</GlassCard>


<GlassButton variant="accent">Subscribe</GlassButton>
玻璃变体
变体使用场景浅色模式深色模式
surface标题栏、导航栏95% 白色95% 石板色
tint背景上的文本60% 白色50% 石板色
card内容卡片80% 白色70% 石板色
accent提示、重点内容30% 强调色20% 强调色
overlay模态框背景遮罩50% 黑色60% 黑色
muted微妙的背景40% 白色30% 石板色
CSS 工具类

<div class="glass rounded-xl p-4">Basic glass</div>
<div class="glass-tint p-6">Text container</div>
<div class="glass-accent p-4">Highlighted section</div>
<nav class="glass-surface sticky top-0">Navbar</nav>
关键模式:粘性导航
<nav
	class="sticky top-[73px] z-30 bg-white/80 dark:bg-slate-900/80 backdrop-blur-sm border-b border-divider"
>
	
</nav>

季节主题系统

Grove 使用四季主题,每个季节都有独特的颜色、天气效果和氛围。

季节检测
import {season} from '$lib/stores/season'; const isSpring = $derived($season === 'spring'); const isAutumn
= $derived($season === 'autumn'); const isWinter = $derived($season === 'winter'); // Summer is the default
(no flag needed)
调色板系统

从 @autumnsgrove/lattice/ui/nature 或 $lib/components/nature/palette 导入

核心调色板(全年适用)

**强调色:**这些调色板中的十六进制颜色值用于自然主题 SVG、插画和品牌用途。对于使用强调色的 CSS 表面样式(按钮、链接、高亮),请改用 var(--grove-accent-*) 令牌——用户的强调色可能不是绿色。请参阅强调色阶:var(--grove-accent)(纯色)、var(--grove-accent-dark)(悬停)、var(--grove-accent-N)(不透明度色调,级别为 5-80)。提交前钩子会强制执行此规则。

import { greens, bark, earth, natural } from "@autumnsgrove/lattice/ui/nature";

// Greens - organized dark-to-light for atmospheric depth
// NOTE: Use these for nature components and brand illustrations.
// For accent-colored UI surfaces, use var(--grove-accent-*) instead.
greens.darkForest; // #0d4a1c - Background trees
greens.deepGreen; // #166534 - Mid-distance
greens.grove; // #16a34a - Grove brand primary
greens.meadow; // #22c55e - Standard foliage
greens.spring; // #4ade80 - Bright accent
greens.mint; // #86efac - Light accent
greens.pale; // #bbf7d0 - Foreground highlights

// Bark - warm wood tones
bark.darkBark; // #3d2817 - Oak, older trees
bark.bark; // #5d4037 - Standard trunk
bark.warmBark; // #6B4423 - Pine, cedar
bark.lightBark; // #8b6914 - Young trees

// Earth - ground elements
(earth.soil, earth.mud, earth.clay, earth.sand, earth.stone, earth.pebble, earth.slate);

// Natural - cream and off-whites
(natural.cream, natural.aspenBark, natural.bone, natural.mushroom, natural.birchWhite);
春季调色板
import {
	springFoliage,
	springSky,
	wildflowers,
	cherryBlossoms,
	cherryBlossomsPeak,
} from "@autumnsgrove/lattice/ui/nature";

// Spring Foliage - yellow-green new growth
springFoliage.sprout; // #65a30d - Distant new growth
springFoliage.newLeaf; // #84cc16 - Classic spring lime
springFoliage.freshGreen; // #a3e635 - Bright foreground
springFoliage.budding; // #bef264 - Pale new leaf
springFoliage.tender; // #d9f99d - Very pale

// Spring Sky
springSky.clear; // #7dd3fc - Clear morning
springSky.soft; // #bae6fd - Pale sky

// Wildflowers - unified meadow flower colors
wildflowers.buttercup; // #facc15 - Yellow
wildflowers.daffodil; // #fde047 - Pale yellow
wildflowers.crocus; // #a78bfa - Purple crocus
wildflowers.violet; // #8b5cf6 - Wild violets
wildflowers.purple; // #a855f7 - Lupine, thistle
wildflowers.lavender; // #c4b5fd - Distant masses
wildflowers.tulipPink; // #f9a8d4 - Pink tulips
wildflowers.tulipRed; // #fb7185 - Red tulips
wildflowers.white; // #fefefe - Daisies, trillium

// Cherry Blossoms - summer standard
cherryBlossoms.deep; // #db2777 - Dense centers
cherryBlossoms.standard; // #ec4899 - Standard blossom
cherryBlossoms.light; // #f472b6 - Light petals
cherryBlossoms.pale; // #f9a8d4 - Pale blossoms
cherryBlossoms.falling; // #fbcfe8 - Falling petals

// Cherry Blossoms Peak - vibrant spring (one shade brighter!)
cherryBlossomsPeak.deep; // #ec4899
cherryBlossomsPeak.standard; // #f472b6
cherryBlossomsPeak.light; // #f9a8d4
cherryBlossomsPeak.pale; // #fbcfe8
cherryBlossomsPeak.falling; // #fce7f3
统一花卉调色板(新增!)

flowers 命名空间将所有花卉颜色整合到一个结构清晰的结构中:

import { flowers } from "@autumnsgrove/lattice/ui/nature";

// Meadow wildflowers (yellows, purples, pinks, whites)
flowers.wildflower.buttercup; // #facc15 - Yellow
flowers.wildflower.daffodil; // #fde047 - Pale yellow
flowers.wildflower.crocus; // #a78bfa - Purple crocus
flowers.wildflower.violet; // #8b5cf6 - Wild violets
flowers.wildflower.purple; // #a855f7 - Lupine, thistle
flowers.wildflower.lavender; // #c4b5fd - Distant masses
flowers.wildflower.tulipPink; // #f9a8d4 - Pink tulips
flowers.wildflower.tulipRed; // #fb7185 - Red tulips
flowers.wildflower.white; // #fefefe - Daisies, trillium

// Cherry blossoms - standard summer
flowers.cherry.deep; // #db2777
flowers.cherry.standard; // #ec4899
flowers.cherry.light; // #f472b6
flowers.cherry.pale; // #f9a8d4
flowers.cherry.falling; // #fbcfe8

// Cherry blossoms at peak bloom - vibrant spring
flowers.cherryPeak.deep; // #ec4899
flowers.cherryPeak.standard; // #f472b6
flowers.cherryPeak.light; // #f9a8d4
flowers.cherryPeak.pale; // #fbcfe8
flowers.cherryPeak.falling; // #fce7f3

请使用 flowers.wildflower,而非 accents.flower——后者已弃用。

秋季和冬季调色板
import { autumn, autumnReds, winter } from "@autumnsgrove/lattice/ui/nature";

// Autumn - warm fall foliage (dark-to-light for depth)
autumn.rust; // #9a3412 - Deep background
autumn.ember; // #c2410c - Oak-like
autumn.pumpkin; // #ea580c - Maple mid-tones
autumn.amber; // #d97706 - Classic fall
autumn.gold; // #eab308 - Aspen/birch
autumn.honey; // #facc15 - Bright foreground
autumn.straw; // #fde047 - Pale dying leaves

// Autumn Reds - cherry/maple fall foliage
autumnReds.crimson; // #be123c - Deep maple
autumnReds.scarlet; // #e11d48 - Bright cherry
autumnReds.rose; // #f43f5e - Light autumn
autumnReds.coral; // #fb7185 - Pale accent

// Winter - frost, snow, ice + frosted evergreens
(winter.snow, winter.frost, winter.ice, winter.glacier);
(winter.frostedPine, winter.winterGreen, winter.coldSpruce);
(winter.winterSky, winter.twilight, winter.overcast);
(winter.bareBranch, winter.frostedBark, winter.coldWood);
(winter.hillDeep, winter.hillMid, winter.hillNear, winter.hillFront);
强调色调色板
import { accents, wildflowers } from "@autumnsgrove/lattice/ui/nature";

// Mushrooms - fairy tale pops of color
(accents.mushroom.redCap, accents.mushroom.orangeCap, accents.mushroom.brownCap);
(accents.mushroom.spots, accents.mushroom.gill);

// Firefly - bioluminescence
(accents.firefly.glow, accents.firefly.warmGlow, accents.firefly.body);

// Berry - rich saturated
(accents.berry.ripe, accents.berry.elderberry, accents.berry.red);

// Water - cool blue spectrum
(accents.water.surface, accents.water.deep, accents.water.shallow, accents.water.lily);

// Sky - time of day
(accents.sky.dayLight, accents.sky.dayMid, accents.sky.sunset, accents.sky.night, accents.sky.star);

// Birds - species-specific colors
(accents.bird.cardinalRed, accents.bird.cardinalMask, accents.bird.cardinalBeak);
(accents.bird.chickadeeCap, accents.bird.chickadeeBody, accents.bird.chickadeeBelly);
(accents.bird.robinBody, accents.bird.robinBreast, accents.bird.robinBeak);
(accents.bird.bluebirdBody, accents.bird.bluebirdWing, accents.bird.bluebirdBreast);

// NOTE: accents.flower is deprecated - use flowers.wildflower instead
季节辅助函数
import {
	getSeasonalGreens,
	getCherryColors,
	isTreeBare,
	pickRandom,
	pickFrom,
} from "@autumnsgrove/lattice/ui/nature";

// Get foliage colors mapped to season
const foliage = getSeasonalGreens(season);
// spring → springFoliage colors
// summer → greens
// autumn → autumn palette
// winter → frosted evergreen colors

// Get cherry tree colors by season
const cherryColors = getCherryColors(season);
// spring → cherryBlossomsPeak (vibrant!)
// summer → cherryBlossoms (standard)
// autumn → autumnReds
// winter → null (bare tree)

// Check if deciduous tree is bare
if (isTreeBare("cherry", "winter")) {
	/* no foliage */
}

// Random color selection for natural variation
const randomGreen = pickRandom(greens);
const specificGreen = pickFrom(greens, ["grove", "meadow"]);
已弃用的别名(仍可使用)
// These work but will be removed in v1.0:
import { spring, pinks, springBlossoms } from "@autumnsgrove/lattice/ui/nature";

// spring → use springFoliage, wildflowers, springSky instead
// pinks → use cherryBlossoms instead
// springBlossoms → use cherryBlossomsPeak instead
// accents.flower → use flowers.wildflower instead
季节氛围概览
季节主要颜色氛围
春季springFoliage、cherryBlossomsPeak、wildflowers新生、希望
夏季greens、cherryBlossoms生长、温暖
秋季autumn、autumnReds丰收、沉思
冬季winter(霜、雪、覆霜的松树)休憩、静谧
季节性天气效果

{#if isWinter}
	<SnowfallLayer count={40} zIndex={5} opacity={{ min: 0.4, max: 0.8 }} spawnDelay={8} />
{/if}


{#if isSpring}
	<FallingPetalsLayer count={80} zIndex={100} opacity={{ min: 0.5, max: 0.9 }} />
{/if}


{#if isAutumn}
	<FallingLeavesLayer
		trees={forestTrees}
		season={$season}
		minLeavesPerTree={2}
		maxLeavesPerTree={4}
	/>
{/if}
季节性背景渐变
<main class="min-h-screen transition-colors duration-1000
  {isWinter ? 'bg-gradient-to-b from-slate-200 via-slate-100 to-slate-50 dark:from-slate-900 dark:via-slate-800 dark:to-slate-700' : ''}
  {isAutumn ? 'bg-gradient-to-b from-orange-100 via-amber-50 to-yellow-50 dark:from-slate-900 dark:via-amber-950 dark:to-orange-950' : ''}
  {isSpring ? 'bg-gradient-to-b from-pink-50 via-sky-50 to-lime-50 dark:from-slate-900 dark:via-pink-950 dark:to-lime-950' : ''}
  {/* Summer default */} 'bg-gradient-to-b from-sky-100 via-sky-50 to-emerald-50 dark:from-slate-900 dark:via-slate-800 dark:to-emerald-950'
">
何时使用季节主题
  • 路线图页面——通过季节隐喻展现进展
  • 故事/关于页面——营造氛围并建立情感联系
  • 交互式演示——让用户切换季节(如 /forest)
  • 帮助文章——可考虑加入季节装饰,让长内容更易阅读
  • 任何想增添魔法感的地方——根据页面用途自行判断

随机化森林

森林应充满生机,并在每次访问时呈现不同的面貌。

树木生成模式
interface GeneratedTree {
	id: number;
	x: number; // percentage from left (5-93% to avoid edges)
	size: number; // base width in pixels
	aspectRatio: number; // height = size * aspectRatio (1.0-1.5 range)
	treeType: TreeType; // 'logo' | 'pine' | 'cherry' | 'aspen' | 'birch'
	opacity: number; // 0.5-0.9 for depth
	zIndex: number; // larger trees = higher z-index
}

// Aspect ratio creates natural height variation
const TREE_ASPECT_RATIO_RANGE = { min: 1.0, max: 1.5 };

function generateSectionTrees(count: number): GeneratedTree[] {
	const trees: GeneratedTree[] = [];
	const usedPositions: number[] = [];

	for (let i = 0; i < count; i++) {
		// Find non-overlapping position
		let x: number;
		let attempts = 0;
		do {
			x = 5 + Math.random() * 88;
			attempts++;
		} while (usedPositions.some((pos) => Math.abs(pos - x) < 8) && attempts < 20);
		usedPositions.push(x);

		const size = 80 + Math.random() * 80;
		const aspectRatio = 1.0 + Math.random() * 0.5;
		const opacity = 0.5 + Math.random() * 0.4;
		const zIndex = size > 130 ? 3 : size > 100 ? 2 : 1;

		trees.push({
			id: i,
			x,
			size,
			aspectRatio,
			treeType: pickRandom(treeTypes),
			opacity,
			zIndex,
		});
	}

	return trees.sort((a, b) => a.x - b.x);
}
重新生成时机
  • 挂载时——页面加载时生成一次树木
  • 调整大小时(显著变化)——仅当视口范围发生明显变化时
  • 滚动时绝不重新生成——阅读期间保持森林稳定
渲染树木
{#each forestTrees as tree (tree.id)}
	<div
		class="absolute"
		style="
      left: {tree.x}%;
      bottom: 0;
      width: {tree.size}px;
      height: {tree.size * tree.aspectRatio}px;
      opacity: {tree.opacity};
      z-index: {tree.zIndex};
      transform: translateX(-50%);
    "
	>
		{#if tree.treeType === "logo"}
			<Logo class="w-full h-full" season={$season} animate />
		{:else if tree.treeType === "pine"}
			<TreePine class="w-full h-full" season={$season} animate />
		{:else if tree.treeType === "cherry"}
			<TreeCherry class="w-full h-full" season={$season} animate />
		{:else if tree.treeType === "aspen"}
			<TreeAspen class="w-full h-full" season={$season} animate />
		{:else if tree.treeType === "birch"}
			<TreeBirch class="w-full h-full" season={$season} animate />
		{/if}
	</div>
{/each}
响应式密度
function calculateDensity(): number {
	const width = window.innerWidth;
	if (width < 768) return 1; // Mobile: base count
	if (width < 1024) return 1.3; // Tablet
	if (width < 1440) return 1.8; // Desktop
	if (width < 2560) return 2.5; // Large desktop
	return 3.5; // Ultrawide
}

自然主题组件

Grove 提供了丰富的装饰组件库。可通过以下方式探索:

# Trees
ls landing/src/lib/components/trees/
ls landing/src/lib/components/nature/trees/

# Weather (seasonal particles)
ls landing/src/lib/components/nature/weather/

# Sky (clouds, stars, moon)
ls landing/src/lib/components/nature/sky/

# Botanical (leaves, petals, vines)
ls landing/src/lib/components/nature/botanical/

# Ground (flowers, grass, mushrooms)
ls landing/src/lib/components/nature/ground/

# Structural (lattice, lanterns, paths)
ls landing/src/lib/components/nature/structural/

# Birds (cardinals, robins, bluebirds)
ls landing/src/lib/components/nature/creatures/
核心组件
组件用途属性示例
LogoGrove 树,随季节变化season、animate、breathing
TreePine常青树,秋季依然翠绿season、animate
TreeCherry春季开花,冬季枝叶凋零season、animate
TreeAspen / TreeBirch落叶树,呈现季节色彩season、animate
Cloud装饰性天空元素variant、animate、speed、direction
SnowfallLayer冬季粒子效果count、opacity、spawnDelay
FallingPetalsLayer春季樱花花瓣count、opacity、fallDuration
FallingLeavesLayer秋季落叶(与树木关联)trees、season
Cardinal / Chickadee冬季鸟类facing
Robin / Bluebird春季鸟类facing
Vine装饰性常春藤/藤蔓各不相同
Lantern温暖的发光点各不相同
按季节分类的鸟类

{#if isWinter}
	<Cardinal facing="right" style="..." />
	<Chickadee facing="left" style="..." />
{/if}


{#if isSpring}
	<Robin facing="right" style="..." />
	<Bluebird facing="left" style="..." />
{/if}

午夜绽放配色

适用于梦幻、遥远未来、神秘风格的内容。那家坐落在明日边缘的茶馆。

import { midnightBloom } from "$lib/components/nature/palette";

// Available colors:
midnightBloom.deepPlum; // #581c87 - Night sky depth
midnightBloom.purple; // #7c3aed - Soft purple glow
midnightBloom.violet; // #8b5cf6 - Lighter accent
midnightBloom.amber; // #f59e0b - Lantern warmth
midnightBloom.warmCream; // #fef3c7 - Tea steam, page glow
midnightBloom.softGold; // #fcd34d - Fairy lights
午夜绽放样式
<section class="bg-gradient-to-b from-orange-950/50 via-purple-950 to-slate-950">
	
	<StarCluster count={12} class="absolute top-12 left-[10%]" />

	
	<Moon phase="waning-crescent" class="absolute top-20 right-[15%] w-16 h-16 opacity-60" />

	
	<Firefly count={8} class="absolute inset-0" />

	
	<blockquote class="bg-purple-900/30 backdrop-blur-sm border border-purple-700/30 rounded-lg p-6">
		<p class="text-purple-200 italic">Dreamy quote here...</p>
	</blockquote>
</section>

图标:仅使用 Lucide

绝不使用表情符号。始终使用 Lucide 图标。

import {(MapPin, Check, Leaf, Trees, Mail)} from '@lucide/svelte';


<MapPin class="w-4 h-4" />
<Check class="w-5 h-5 text-green-500" />



标准化图标映射

在整个项目中统一使用以下图标:

概念图标说明
导航
首页Home
关于Info
愿景Telescope展望未来
路线图Map旅程/方向
定价HandCoins金钱/货币
知识BookOpen学习/文档
森林Trees社区博客
博客PenLine写作
功能
电子邮件Mail
存储HardDrive
主题Palette自定义
身份验证ShieldCheck安全
云Cloud远程/无服务器
搜索SearchCode代码/高级搜索
归档Archive备份
上传Upload
视频Video
评论MessagesSquare用户讨论
GitHubGithub指向 GitHub 的外部链接
状态
成功Check已完成/有效
错误X失败/关闭
加载中Loader2使用 animate-spin
内容
帖子FileText博客帖子
标签Tag分类
成长SproutGrove 品牌,新起点
心形Heart爱、关怀
外部ExternalLink在新标签页中打开
位置MapPin当前位置
阶段
即将推出Seedling正在生长的事物
精炼Gem润色、品质
梦想Sparkles神秘(谨慎使用!)
夜晚Star午夜主题
操作
入门Compass指引
最新动态Megaphone公告
后续步骤Lightbulb想法
文件中的图标映射表

在每个使用图标的组件/页面顶部创建一致的图标映射表:

// landing/src/lib/utils/icons.ts - Centralized icon registry
import {
	Mail,
	HardDrive,
	Palette,
	ShieldCheck,
	Cloud,
	SearchCode,
	Archive,
	Upload,
	MessagesSquare,
	Github,
	Check,
	X,
	Loader2,
	FileText,
	Tag,
	Sprout,
	Heart,
	ExternalLink,
	MapPin, // ... etc
} from "@lucide/svelte";

export const featureIcons = {
	mail: Mail,
	harddrive: HardDrive,
	palette: Palette,
	shieldcheck: ShieldCheck,
	cloud: Cloud,
	searchcode: SearchCode,
	// ... all mapped icons
} as const;

export const stateIcons = {
	success: Check,
	error: X,
	loading: Loader2,
} as const;

然后在组件中使用:

<script lang="ts">
	import { featureIcons } from "$lib/utils/icons";
</script>

{#each features as feature}
	<svelte:component this={featureIcons[feature.icon]} class="w-5 h-5" />
{/each}

优点:

  • 为所有图标提供唯一可信来源
  • 避免出现未定义图标错误
  • 易于维护和扩展
  • 可在整个项目中重复使用
图标使用指南
  1. 始终使用图标映射表——不要在每个组件中硬编码图标导入
  2. 避免过度使用 Sparkles——仅在真正神秘/魔幻的场景中使用
  3. 保持一致——同一概念在任何地方都使用相同图标
  4. 语义明确——选择能够传达含义而非仅作装饰的图标
  5. 从中央工具模块导出——所有图标集都使用 landing/src/lib/utils/icons.ts
图标尺寸

<span class="inline-flex items-center gap-1.5">
	<Leaf class="w-4 h-4" /> Feature name
</span>


<button class="p-2">
	<Menu class="w-5 h-5" />
</button>


<Gem class="w-8 h-8 text-amber-400" />

图标组合(构建块模式)

理念:“无需绘制树林,只需将它们排列起来。”

要创建自定义徽标、插图或装饰元素,可组合现有的 Lucide 图标,而不是从头绘制自定义 SVG。这样可以确保视觉风格与图标系统保持一致。

为什么采用这种模式?
  • 保持一致 — 图标符合 Lucide 的美学风格(24x24 网格、2px 描边、圆形端点)
  • 尽量减少自定义代码 — 让 Lucide 承担繁重的工作
  • 易于维护 — 更新 Lucide 时,组合也会随之更新
  • 采用 MIT 许可证 — 所有路径均来自开源图标
如何提取 Lucide 路径

Lucide 图标使用 24×24 的 viewBox 和 2px 描边。直接从源代码中提取路径:

# Find icon paths in Lucide source
curl -s https://raw.githubusercontent.com/lucide-icons/lucide/main/icons/tree-pine.svg
# Look for the <path d="..." /> elements

适用于 Grove 组合的关键 Lucide 图标路径:

// TreePine - conifer silhouette
const treePine = {
	canopy:
		"m17 14 3 3.3a1 1 0 0 1-.7 1.7H4.7a1 1 0 0 1-.7-1.7L7 14h-.3a1 1 0 0 1-.7-1.7L9 9h-.2A1 1 0 0 1 8 7.3L12 3l4 4.3a1 1 0 0 1-.8 1.7H15l3 3.3a1 1 0 0 1-.7 1.7H17Z",
	trunk: "M12 22v-3",
};

// TreeDeciduous - deciduous/round tree
const treeDeciduous = {
	canopy:
		"M8 19a4 4 0 0 1-2.24-7.32A3.5 3.5 0 0 1 9 6.03V6a3 3 0 1 1 6 0v.04a3.5 3.5 0 0 1 3.24 5.65A4 4 0 0 1 16 19Z",
	trunk: "M12 19v3",
};

// Moon - crescent moon
const moon =
	"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401";

// Flame - campfire/hearth
const flame =
	"M12 3q1 4 4 6.5t3 5.5a1 1 0 0 1-14 0 5 5 0 0 1 1-3 1 1 0 0 0 5 0c0-2-1.5-3-1.5-5q0-2 2.5-4";
使用 SVG 变换进行组合

使用 <g transform="..."> 来定位、缩放和旋转图标:

<svg viewBox="0 0 48 32" fill="none">
	
	<g
		transform="translate(2, 4) scale(0.85)"
		stroke={color}
		stroke-width="2"
		stroke-linecap="round"
		stroke-linejoin="round"
	>
		<path d={treePine.canopy} />
		<path d={treePine.trunk} />
	</g>

	
	<g
		transform="translate(20, 8) scale(0.65) rotate(-5, 12, 12)"
		stroke={color}
		stroke-width="2"
		stroke-linecap="round"
		stroke-linejoin="round"
		opacity="0.7"
	>
		<path d={treePine.canopy} />
		<path d={treePine.trunk} />
	</g>

	
	<circle cx="30" cy="10" r="1.5" fill={glowColor} opacity="0.8" />
	
	<path d="M2 28h44" stroke={color} stroke-width="1.5" opacity="0.3" />
	
</svg>
变换速查表
变换效果示例
translate(x, y)移动原点translate(20, 8) 将图标向右移动 20,向下移动 8
scale(s)等比缩放scale(0.65) 将图标缩小至原尺寸的 65%
rotate(deg, cx, cy)绕指定点旋转rotate(-5, 12, 12) 绕中心旋转 5°
组合链式应用变换translate(20, 8) scale(0.65) rotate(-5, 12, 12)
示例:Grove 徽标组合

查看 /landing/src/lib/components/logo-concepts/ 中的实际实现:

徽标组合
LogoFireflyForestTreePine + TreeDeciduous + 发光圆圈
LogoGatheringHearth两棵朝向中心 Flame 倾斜的树
LogoStarlightPines两棵 TreePine + Moon + 星形圆圈
LogoShelter两棵 TreePine 组成拱门 + Moon
LogoWinterGroveTreePine + 雪地线条装饰
指南
  1. 以 Lucide 路径作为主要结构 — 树、月亮、火焰等
  2. 自定义 SVG 仅用于简单图形 — 圆形(萤火虫)、线条(地面、雪地)
  3. 保持 Lucide 的样式 — 2px 描边、圆形端点和连接处、统一的不透明度
  4. 用不透明度和缩放营造层次感 — 较大 = 前景(不透明度 0.9),较小 = 背景(0.5-0.7)
  5. 保持合理的 viewBox 宽高比 — 水平组合使用 40×32 或 48×32
适用场景
  • 徽标与品牌形象 — 将图标组合成独特的标志
  • 插图 — 构建场景(森林、天空等)
  • 自定义图标 — Lucide 中没有完全符合需求的图标时
  • 季节变化 — 沿用同一组合,替换不同元素(雪、花朵)

移动端注意事项

溢出菜单模式

无法放入桌面导航的项目应放入移动端抽屉菜单:


<button onclick={() => (mobileMenuOpen = true)} class="md:hidden p-2">
	<Menu class="w-5 h-5" />
</button>


<MobileMenu bind:open={mobileMenuOpen} onClose={() => (mobileMenuOpen = false)} />
移动端装饰元素
元素移动端处理方式
树木减少数量并简化(密度乘数 = 1)
粒子减少数量(雪花从 40 减至 20)
云朵隐藏部分,保留 2-3 朵
复杂动画减少或禁用
触控目标至少为 44x44px
性能指南

<SnowfallLayer count={isLargeScreen ? 100 : 40} ... />


{#if !prefersReducedMotion}
	<FallingLeavesLayer ... />
{/if}

适用场景

样式适用场景
玻璃拟态背景上的文字、导航栏、卡片、模态框
随机森林故事页面、关于页面、视觉展示区
季节主题路线图、时间线、情感叙事
午夜绽放未来功能、梦想、神秘内容
天气粒子Hero 区域、季节间的过渡
鸟类为森林场景增添生机、作为季节指示

不适用场景

样式避免使用的场景
繁复装饰数据密集型页面、管理界面、表单
粒子效果对性能要求极高的页面、存在无障碍方面的顾虑
季节性色彩需要保持色彩一致性的品牌关键场景
多层玻璃效果可能导致模糊效果影响性能
随机化内容需要在不同会话间保持一致
复杂森林场景移动优先页面、简单的信息展示内容

参考页面

参考以下页面,了解实现模式:

  • /forest — 包含所有季节的完整随机森林
  • /roadmap — 季节性分区、渐进式装饰、午夜绽放
  • /vision — 带玻璃拟态提示框的叙事页面

OG 图片(社交媒体预览)

Grove 使用动态 OG 图片作为社交媒体预览(Discord、Twitter、iMessage 等)。

架构

由于 SvelteKit + Cloudflare Pages 在打包 WASM 方面存在限制,OG 图片由 og.grove.place 上的独立 Cloudflare Worker 生成。

grove.place/api/og?title=X
       ↓ 302 redirect
og.grove.place/?title=X
       ↓ workers-og
PNG image (1200×630)
API
GET https://og.grove.place/?title=X&subtitle=Y&accent=HEX
参数默认值说明
title"Grove"主标题(最多 100 个字符)
subtitle"A place to Be."副标题(最多 200 个字符)
accent"16a34a"不带 # 的十六进制颜色(森林绿)
为新页面添加 OG

使用 SEO 组件处理 OG 元标签:

<script>
	import SEO from "$lib/components/SEO.svelte";
</script>

<SEO
	title="Page Title"
	description="Page description for search engines"
	ogImage="/api/og?title=Page%20Title&subtitle=Custom%20subtitle"
/>
文件
  • services/og-worker/ — 独立 Worker(使用 workers-og)
  • landing/src/routes/api/og/+server.ts — 指向 og.grove.place 的代理
  • landing/src/lib/components/SEO.svelte — 元标签管理

与其他技能集成

为 Grove UI 编写文本(工具提示、按钮、引导流程、错误消息)时,请先调用 grove-documentation 技能。文案风格应与视觉效果相匹配。

典型流程:

  1. 设计 UI 组件/页面
  2. 对任何面向用户的文本启用 grove-documentation
  3. 遵循 Grove 的语气原则编写内容
  4. 返回视觉实现

使用 Showroom 审核组件

在验证完整页面之前,先审核单个组件。 Showroom 会在隔离环境中渲染单个 .svelte 组件,运行设计规范检查(颜色令牌、间距网格、排版、焦点样式、标题层级),并与视觉基线进行差异比较。它能捕获完整页面 Glimpse 检查遗漏的问题。

# Audit a component in isolation
uv run --project tools/glimpse glimpse showroom \
  libs/engine/src/lib/ui/components/primitives/button/button.svelte

# Scaffold a fixture for a new component (generates .showroom.ts with scenarios)
uv run --project tools/glimpse glimpse showroom \
  libs/engine/src/lib/ui/components/ui/MyComponent.svelte --scaffold

# Audit with specific scenario and theme
uv run --project tools/glimpse glimpse showroom \
  libs/engine/src/lib/ui/components/ui/MyComponent.svelte \
  --scenario error --theme dark

# Update visual baselines after intentional design changes
uv run --project tools/glimpse glimpse showroom \
  libs/engine/src/lib/ui/components/ui/MyComponent.svelte --update-baselines

组件关卡: 每个新建或修改的组件都必须通过 glimpse showroom,之后才能进行页面级 Glimpse 验证。请先修复所有规范违规。


使用 Glimpse 进行视觉验证

发布任何 Grove 页面之前,都要亲自查看。 CI 通过不代表页面看起来正确。使用 Glimpse 捕获渲染后的页面并自行检查:

# Capture the page with Grove theme injection
uv run --project tools/glimpse glimpse capture http://localhost:5173/[page] \
  --season autumn --theme dark --logs

# Verify all season × theme combos
uv run --project tools/glimpse glimpse matrix http://localhost:5173/[page]

# Interactive browse — click around, verify navigation and flows
uv run --project tools/glimpse glimpse browse http://localhost:5173/[page] \
  --do "click links, scroll down, interact with elements" --screenshot-each --logs

迭代流程: 捕获 → 检查 → 修复 → 再次捕获。重复此流程,直到页面符合 Grove 的美学风格。不要发布自己没有检查过的内容。


快速检查清单

发布 Grove 页面前:

  • Showroom:每个新建或修改的组件都通过 glimpse showroom 检查,且无合规性违规
  • Glimpse:已捕获页面并完成视觉检查
  • Glimpse:所有目标季节的渲染均正确(使用 matrix)
  • Glimpse:--logs 输出中没有控制台错误
  • 在繁杂背景上使用玻璃效果来提升文本可读性了吗?
  • 使用 Lucide 图标,没有使用表情符号吗?
  • 导航项是否有适用于移动端的溢出菜单?
  • 装饰元素是否遵循 prefers-reduced-motion?
  • 触控目标尺寸是否至少为 44x44px?
  • 季节配色是否符合页面的情感基调?
  • 树木是否随机排列,并保持适当间距(至少留出 8% 的间隔)?
  • 是否支持深色模式,并使用了合适的玻璃效果变体?
  • 面向用户的文本是否符合 Grove 的语气(参见 grove-documentation)?
  • Grove 术语是否使用 GroveTerm 组件(而非硬编码)?
  • 数据驱动的内容是否使用 [[term]] 语法和 GroveText?

评论

支持 Markdown