ccbot-cli 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/bin/adapters/claude.js +150 -0
- package/bin/adapters/codex.js +439 -0
- package/bin/install.js +509 -349
- package/bin/lib/ccline.js +82 -0
- package/bin/lib/utils.js +87 -34
- package/bin/uninstall.js +48 -0
- package/config/AGENTS.md +630 -0
- package/config/CLAUDE.md +229 -20
- package/config/ccline/config.toml +161 -0
- package/config/codex-config.example.toml +22 -0
- package/config/settings.example.json +32 -0
- package/output-styles/abyss-cultivator.md +399 -0
- package/package.json +14 -5
- package/skills/SKILL.md +159 -0
- package/skills/domains/ai/SKILL.md +34 -0
- package/skills/domains/ai/agent-dev.md +242 -0
- package/skills/domains/ai/llm-security.md +288 -0
- package/skills/domains/ai/prompt-and-eval.md +279 -0
- package/skills/domains/ai/rag-system.md +542 -0
- package/skills/domains/architecture/SKILL.md +42 -0
- package/skills/domains/architecture/api-design.md +225 -0
- package/skills/domains/architecture/caching.md +299 -0
- package/skills/domains/architecture/cloud-native.md +285 -0
- package/skills/domains/architecture/message-queue.md +329 -0
- package/skills/domains/architecture/security-arch.md +297 -0
- package/skills/domains/data-engineering/SKILL.md +207 -0
- package/skills/domains/development/SKILL.md +46 -0
- package/skills/domains/development/cpp.md +246 -0
- package/skills/domains/development/go.md +323 -0
- package/skills/domains/development/java.md +277 -0
- package/skills/domains/development/python.md +288 -0
- package/skills/domains/development/rust.md +313 -0
- package/skills/domains/development/shell.md +313 -0
- package/skills/domains/development/typescript.md +277 -0
- package/skills/domains/devops/SKILL.md +39 -0
- package/skills/domains/devops/cost-optimization.md +272 -0
- package/skills/domains/devops/database.md +217 -0
- package/skills/domains/devops/devsecops.md +198 -0
- package/skills/domains/devops/git-workflow.md +181 -0
- package/skills/domains/devops/observability.md +280 -0
- package/skills/domains/devops/performance.md +336 -0
- package/skills/domains/devops/testing.md +283 -0
- package/skills/domains/frontend-design/SKILL.md +38 -0
- package/skills/domains/frontend-design/claymorphism/SKILL.md +119 -0
- package/skills/domains/frontend-design/claymorphism/references/tokens.css +52 -0
- package/skills/domains/frontend-design/component-patterns.md +202 -0
- package/skills/domains/frontend-design/engineering.md +287 -0
- package/skills/domains/frontend-design/glassmorphism/SKILL.md +140 -0
- package/skills/domains/frontend-design/glassmorphism/references/tokens.css +32 -0
- package/skills/domains/frontend-design/liquid-glass/SKILL.md +137 -0
- package/skills/domains/frontend-design/liquid-glass/references/tokens.css +81 -0
- package/skills/domains/frontend-design/neubrutalism/SKILL.md +143 -0
- package/skills/domains/frontend-design/neubrutalism/references/tokens.css +44 -0
- package/skills/domains/frontend-design/state-management.md +680 -0
- package/skills/domains/frontend-design/ui-aesthetics.md +110 -0
- package/skills/domains/frontend-design/ux-principles.md +156 -0
- package/skills/domains/infrastructure/SKILL.md +200 -0
- package/skills/domains/mobile/SKILL.md +224 -0
- package/skills/domains/orchestration/SKILL.md +29 -0
- package/skills/domains/orchestration/multi-agent.md +263 -0
- package/skills/domains/security/SKILL.md +54 -0
- package/skills/domains/security/blue-team.md +436 -0
- package/skills/domains/security/code-audit.md +265 -0
- package/skills/domains/security/pentest.md +226 -0
- package/skills/domains/security/red-team.md +375 -0
- package/skills/domains/security/threat-intel.md +372 -0
- package/skills/domains/security/vuln-research.md +369 -0
- package/skills/orchestration/multi-agent/SKILL.md +493 -0
- package/skills/run_skill.js +129 -0
- package/skills/tools/gen-docs/SKILL.md +116 -0
- package/skills/tools/gen-docs/scripts/doc_generator.js +435 -0
- package/skills/tools/lib/shared.js +98 -0
- package/skills/tools/verify-change/SKILL.md +140 -0
- package/skills/tools/verify-change/scripts/change_analyzer.js +289 -0
- package/skills/tools/verify-module/SKILL.md +127 -0
- package/skills/tools/verify-module/scripts/module_scanner.js +171 -0
- package/skills/tools/verify-quality/SKILL.md +160 -0
- package/skills/tools/verify-quality/scripts/quality_checker.js +337 -0
- package/skills/tools/verify-security/SKILL.md +143 -0
- package/skills/tools/verify-security/scripts/security_scanner.js +283 -0
- package/bin/lib/registry.js +0 -61
- package/config/.claudeignore +0 -11
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-engineering
|
|
3
|
+
description: 前端工程化。性能优化(Web Vitals、懒加载、虚拟滚动)、测试(Vitest、Playwright、MSW)、构建工具(Vite、Webpack、esbuild)。当用户提到性能优化、前端测试、构建工具、代码分割时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 前端工程化 · Frontend Engineering
|
|
7
|
+
|
|
8
|
+
## 一、性能优化
|
|
9
|
+
|
|
10
|
+
### Core Web Vitals
|
|
11
|
+
|
|
12
|
+
| 指标 | 含义 | 目标值 |
|
|
13
|
+
|------|------|--------|
|
|
14
|
+
| LCP | Largest Contentful Paint | < 2.5s |
|
|
15
|
+
| FID | First Input Delay | < 100ms |
|
|
16
|
+
| CLS | Cumulative Layout Shift | < 0.1 |
|
|
17
|
+
| FCP | First Contentful Paint | < 1.8s |
|
|
18
|
+
| TTI | Time to Interactive | < 3.8s |
|
|
19
|
+
|
|
20
|
+
### 性能决策树
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
加载慢 → Bundle 大?代码分割 + Tree Shaking | 资源多?懒加载 + 预加载 | 网络慢?CDN + 压缩
|
|
24
|
+
渲染慢 → 列表长?虚拟滚动 | 重渲染?React.memo + useMemo | 布局抖动?固定尺寸
|
|
25
|
+
交互慢 → JS 阻塞?Web Worker + startTransition | 动画卡顿?CSS 动画 + rAF
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 代码分割
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// 路由级别 — React.lazy + Suspense
|
|
32
|
+
const Dashboard = lazy(() => import('./pages/Dashboard'))
|
|
33
|
+
|
|
34
|
+
// 组件级别 — 按需加载重量级组件
|
|
35
|
+
const HeavyChart = lazy(() => import('./components/HeavyChart'))
|
|
36
|
+
|
|
37
|
+
// Vite manualChunks
|
|
38
|
+
export default defineConfig({
|
|
39
|
+
build: {
|
|
40
|
+
rollupOptions: {
|
|
41
|
+
output: {
|
|
42
|
+
manualChunks: {
|
|
43
|
+
'react-vendor': ['react', 'react-dom'],
|
|
44
|
+
'ui': ['@mui/material'],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 虚拟滚动
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { FixedSizeList } from 'react-window'
|
|
56
|
+
|
|
57
|
+
function VirtualList({ items }: { items: Item[] }) {
|
|
58
|
+
return (
|
|
59
|
+
<FixedSizeList height={600} itemCount={items.length} itemSize={50} width="100%">
|
|
60
|
+
{({ index, style }) => <div style={style}>{items[index].name}</div>}
|
|
61
|
+
</FixedSizeList>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### React 性能要点
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// memo 避免重渲染
|
|
70
|
+
const Row = memo(function Row({ item, onClick }: Props) {
|
|
71
|
+
return <div onClick={() => onClick(item.id)}>{item.name}</div>
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// useMemo 缓存计算 + useCallback 缓存回调
|
|
75
|
+
const filtered = useMemo(() => data.filter(x => x.name.includes(q)), [data, q])
|
|
76
|
+
const handleClick = useCallback((id: string) => select(id), [])
|
|
77
|
+
|
|
78
|
+
// startTransition 低优先级更新
|
|
79
|
+
startTransition(() => setResults(heavySearch(query)))
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 资源优化 Checklist
|
|
83
|
+
|
|
84
|
+
- 图片:WebP 格式 + `loading="lazy"` + 响应式 `<picture>`
|
|
85
|
+
- 字体:`font-display: swap` + `preload` woff2
|
|
86
|
+
- 预加载:`dns-prefetch` → `preconnect` → `preload` → `prefetch`
|
|
87
|
+
- 压缩:Gzip/Brotli + HTTP/2
|
|
88
|
+
|
|
89
|
+
### 性能监控
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { onCLS, onFID, onLCP } from 'web-vitals'
|
|
93
|
+
onCLS(sendToAnalytics)
|
|
94
|
+
onFID(sendToAnalytics)
|
|
95
|
+
onLCP(sendToAnalytics)
|
|
96
|
+
|
|
97
|
+
// 自定义指标
|
|
98
|
+
performance.mark('start')
|
|
99
|
+
doWork()
|
|
100
|
+
performance.mark('end')
|
|
101
|
+
performance.measure('work', 'start', 'end')
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 二、测试
|
|
105
|
+
|
|
106
|
+
### 测试金字塔
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
/\ E2E (10%) — Playwright
|
|
110
|
+
/--\ 集成 (20%) — Testing Library + MSW
|
|
111
|
+
/----\ 单元 (70%) — Vitest
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Vitest 配置
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// vitest.config.ts
|
|
118
|
+
export default defineConfig({
|
|
119
|
+
test: {
|
|
120
|
+
globals: true,
|
|
121
|
+
environment: 'jsdom',
|
|
122
|
+
setupFiles: './src/test/setup.ts',
|
|
123
|
+
coverage: {
|
|
124
|
+
provider: 'v8',
|
|
125
|
+
thresholds: { lines: 80, functions: 80, branches: 75 },
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
})
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 单元测试
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
describe('formatCurrency', () => {
|
|
135
|
+
it('formats number', () => expect(formatCurrency(1234.56)).toBe('$1,234.56'))
|
|
136
|
+
it('handles zero', () => expect(formatCurrency(0)).toBe('$0.00'))
|
|
137
|
+
})
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 组件测试
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import { render, screen, fireEvent } from '@testing-library/react'
|
|
144
|
+
|
|
145
|
+
it('calls onClick', () => {
|
|
146
|
+
const fn = vi.fn()
|
|
147
|
+
render(<Button onClick={fn}>Click</Button>)
|
|
148
|
+
fireEvent.click(screen.getByText('Click'))
|
|
149
|
+
expect(fn).toHaveBeenCalledTimes(1)
|
|
150
|
+
})
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### MSW Mock
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { http, HttpResponse } from 'msw'
|
|
157
|
+
import { setupServer } from 'msw/node'
|
|
158
|
+
|
|
159
|
+
const server = setupServer(
|
|
160
|
+
http.get('/api/users/:id', ({ params }) =>
|
|
161
|
+
HttpResponse.json({ id: params.id, name: 'John' })
|
|
162
|
+
),
|
|
163
|
+
)
|
|
164
|
+
beforeAll(() => server.listen())
|
|
165
|
+
afterEach(() => server.resetHandlers())
|
|
166
|
+
afterAll(() => server.close())
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Playwright E2E
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// playwright.config.ts 核心
|
|
173
|
+
export default defineConfig({
|
|
174
|
+
testDir: './e2e',
|
|
175
|
+
use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry' },
|
|
176
|
+
webServer: { command: 'npm run dev', url: 'http://localhost:3000' },
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
// Page Object 模式
|
|
180
|
+
class LoginPage {
|
|
181
|
+
constructor(private page: Page) {}
|
|
182
|
+
async login(email: string, password: string) {
|
|
183
|
+
await this.page.fill('[name="email"]', email)
|
|
184
|
+
await this.page.fill('[name="password"]', password)
|
|
185
|
+
await this.page.click('[type="submit"]')
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 测试 Checklist
|
|
191
|
+
|
|
192
|
+
- 遵循 AAA 模式(Arrange / Act / Assert)
|
|
193
|
+
- 测试行为而非实现
|
|
194
|
+
- Mock 外部依赖(API、时间)
|
|
195
|
+
- 测试边界条件和错误路径
|
|
196
|
+
- CI 中自动运行 + 覆盖率门禁 80%+
|
|
197
|
+
|
|
198
|
+
## 三、构建工具
|
|
199
|
+
|
|
200
|
+
### 选型决策
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
新项目 React/Vue → Vite | Next.js → Turbopack | 零配置 → Parcel
|
|
204
|
+
库开发 → Rollup / esbuild
|
|
205
|
+
老项目复杂配置 → 保持 Webpack | 可迁移 → Vite
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 工具对比
|
|
209
|
+
|
|
210
|
+
| 工具 | 冷启动 | HMR | 生产构建 | 生态 |
|
|
211
|
+
|------|--------|-----|----------|------|
|
|
212
|
+
| Vite | < 1s | < 100ms | 10-30s | 成熟 |
|
|
213
|
+
| Webpack | 10-30s | 1-3s | 30-60s | 最丰富 |
|
|
214
|
+
| Turbopack | < 1s | < 100ms | 10-20s | 新兴 |
|
|
215
|
+
| esbuild | < 1s | N/A | 5-10s | 基础 |
|
|
216
|
+
|
|
217
|
+
### Vite 核心配置
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
export default defineConfig({
|
|
221
|
+
plugins: [react()],
|
|
222
|
+
resolve: { alias: { '@': path.resolve(__dirname, './src') } },
|
|
223
|
+
server: {
|
|
224
|
+
port: 3000,
|
|
225
|
+
proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } },
|
|
226
|
+
},
|
|
227
|
+
build: {
|
|
228
|
+
minify: 'terser',
|
|
229
|
+
terserOptions: { compress: { drop_console: true } },
|
|
230
|
+
rollupOptions: {
|
|
231
|
+
output: {
|
|
232
|
+
manualChunks: { 'react-vendor': ['react', 'react-dom'] },
|
|
233
|
+
entryFileNames: 'assets/[name].[hash].js',
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
optimizeDeps: { include: ['react', 'react-dom'] },
|
|
238
|
+
})
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Webpack 生产优化要点
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
optimization: {
|
|
245
|
+
minimize: true,
|
|
246
|
+
minimizer: [new TerserPlugin(), new CssMinimizerPlugin()],
|
|
247
|
+
splitChunks: {
|
|
248
|
+
chunks: 'all',
|
|
249
|
+
cacheGroups: {
|
|
250
|
+
react: { test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/, priority: 20 },
|
|
251
|
+
vendor: { test: /[\\/]node_modules[\\/]/, priority: 10 },
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
runtimeChunk: 'single',
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Webpack → Vite 迁移要点
|
|
259
|
+
|
|
260
|
+
1. `npm install -D vite @vitejs/plugin-react`
|
|
261
|
+
2. `index.html` 移到根目录,加 `<script type="module" src="/src/main.tsx">`
|
|
262
|
+
3. `REACT_APP_*` → `VITE_*`,`process.env` → `import.meta.env`
|
|
263
|
+
4. `require()` → `import`
|
|
264
|
+
|
|
265
|
+
### 构建 Checklist
|
|
266
|
+
|
|
267
|
+
- 合理代码分割(路由级 + 第三方库分组)
|
|
268
|
+
- Tree Shaking + 压缩(terser / esbuild)
|
|
269
|
+
- 文件名哈希实现长期缓存
|
|
270
|
+
- Source map 仅 dev 或 hidden
|
|
271
|
+
- 定期 `webpack-bundle-analyzer` / `rollup-plugin-visualizer` 审计
|
|
272
|
+
- CI 缓存 `node_modules` + 构建产物
|
|
273
|
+
|
|
274
|
+
## 工具速查
|
|
275
|
+
|
|
276
|
+
| 类别 | 推荐工具 |
|
|
277
|
+
|------|----------|
|
|
278
|
+
| 构建 | Vite (新项目) / Webpack (复杂项目) |
|
|
279
|
+
| 单元测试 | Vitest |
|
|
280
|
+
| 组件测试 | Testing Library |
|
|
281
|
+
| E2E | Playwright |
|
|
282
|
+
| API Mock | MSW |
|
|
283
|
+
| 性能监控 | web-vitals + Lighthouse |
|
|
284
|
+
| Bundle 分析 | webpack-bundle-analyzer / rollup-plugin-visualizer |
|
|
285
|
+
| 视觉回归 | Playwright screenshots / Chromatic |
|
|
286
|
+
|
|
287
|
+
---
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: glassmorphism
|
|
3
|
+
description: Glassmorphism design system skill. Use when building frosted-glass UI components with blur, transparency, and layered depth effects.
|
|
4
|
+
license: MIT
|
|
5
|
+
user-invocable: false
|
|
6
|
+
disable-model-invocation: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Glassmorphism Design Spec
|
|
10
|
+
|
|
11
|
+
## 4 Core Elements
|
|
12
|
+
|
|
13
|
+
1. **Transparency** — Semi-transparent backgrounds using `rgba()` or `hsla()` with alpha `0.05–0.4`
|
|
14
|
+
2. **Blur** — `backdrop-filter: blur()` ranging 8–40px for frosted-glass effect
|
|
15
|
+
3. **Border** — Subtle semi-transparent borders (`1px solid rgba(255,255,255,0.18)`) to define edges
|
|
16
|
+
4. **Shadow** — Soft layered `box-shadow` for depth separation from background
|
|
17
|
+
|
|
18
|
+
## CSS Tokens
|
|
19
|
+
|
|
20
|
+
Reference: [references/tokens.css](references/tokens.css)
|
|
21
|
+
|
|
22
|
+
Use CSS custom properties from `tokens.css` for consistent theming:
|
|
23
|
+
|
|
24
|
+
```css
|
|
25
|
+
@import 'references/tokens.css';
|
|
26
|
+
|
|
27
|
+
.glass-card {
|
|
28
|
+
background: var(--glass-bg);
|
|
29
|
+
backdrop-filter: var(--glass-blur);
|
|
30
|
+
-webkit-backdrop-filter: var(--glass-blur);
|
|
31
|
+
border: var(--glass-border);
|
|
32
|
+
border-radius: var(--glass-radius);
|
|
33
|
+
box-shadow: var(--glass-shadow);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Component Examples
|
|
38
|
+
|
|
39
|
+
### Card
|
|
40
|
+
```css
|
|
41
|
+
.glass-card {
|
|
42
|
+
background: var(--glass-bg);
|
|
43
|
+
backdrop-filter: var(--glass-blur);
|
|
44
|
+
-webkit-backdrop-filter: var(--glass-blur);
|
|
45
|
+
border: var(--glass-border);
|
|
46
|
+
border-radius: var(--glass-radius);
|
|
47
|
+
box-shadow: var(--glass-shadow);
|
|
48
|
+
padding: 1.5rem;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Navbar
|
|
53
|
+
```css
|
|
54
|
+
.glass-nav {
|
|
55
|
+
background: var(--glass-bg-heavy);
|
|
56
|
+
backdrop-filter: var(--glass-blur-strong);
|
|
57
|
+
-webkit-backdrop-filter: var(--glass-blur-strong);
|
|
58
|
+
border-bottom: var(--glass-border);
|
|
59
|
+
box-shadow: var(--glass-shadow);
|
|
60
|
+
position: sticky;
|
|
61
|
+
top: 0;
|
|
62
|
+
z-index: 100;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Modal Overlay
|
|
67
|
+
```css
|
|
68
|
+
.glass-modal-backdrop {
|
|
69
|
+
background: rgba(0, 0, 0, 0.4);
|
|
70
|
+
backdrop-filter: blur(4px);
|
|
71
|
+
}
|
|
72
|
+
.glass-modal {
|
|
73
|
+
background: var(--glass-bg-heavy);
|
|
74
|
+
backdrop-filter: var(--glass-blur-strong);
|
|
75
|
+
-webkit-backdrop-filter: var(--glass-blur-strong);
|
|
76
|
+
border: var(--glass-border);
|
|
77
|
+
border-radius: var(--glass-radius-lg);
|
|
78
|
+
box-shadow: var(--glass-shadow-elevated);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Button
|
|
83
|
+
```css
|
|
84
|
+
.glass-btn {
|
|
85
|
+
background: var(--glass-bg-light);
|
|
86
|
+
backdrop-filter: var(--glass-blur-light);
|
|
87
|
+
-webkit-backdrop-filter: var(--glass-blur-light);
|
|
88
|
+
border: var(--glass-border);
|
|
89
|
+
border-radius: var(--glass-radius);
|
|
90
|
+
transition: background 0.2s;
|
|
91
|
+
}
|
|
92
|
+
.glass-btn:hover {
|
|
93
|
+
background: var(--glass-bg);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Browser Compatibility
|
|
98
|
+
|
|
99
|
+
| Feature | Chrome | Firefox | Safari | Edge |
|
|
100
|
+
|---------|--------|---------|--------|------|
|
|
101
|
+
| `backdrop-filter` | 76+ | 103+ | 9+ (`-webkit-`) | 79+ |
|
|
102
|
+
| `rgba()` backgrounds | All | All | All | All |
|
|
103
|
+
|
|
104
|
+
- Always include `-webkit-backdrop-filter` for Safari support
|
|
105
|
+
- Firefox <103: use `@supports` fallback with solid semi-transparent bg
|
|
106
|
+
- Fallback pattern:
|
|
107
|
+
|
|
108
|
+
```css
|
|
109
|
+
.glass-card {
|
|
110
|
+
background: rgba(255, 255, 255, 0.85); /* fallback */
|
|
111
|
+
}
|
|
112
|
+
@supports (backdrop-filter: blur(1px)) {
|
|
113
|
+
.glass-card {
|
|
114
|
+
background: var(--glass-bg);
|
|
115
|
+
backdrop-filter: var(--glass-blur);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Accessibility Notes
|
|
121
|
+
|
|
122
|
+
- Ensure **contrast ratio ≥ 4.5:1** for text over glass surfaces — test against all possible backgrounds
|
|
123
|
+
- Provide `prefers-reduced-transparency` media query to disable blur/transparency for users who need it
|
|
124
|
+
- Avoid placing critical text on highly transparent surfaces without a fallback
|
|
125
|
+
- Use `prefers-contrast: more` to increase border opacity and reduce transparency
|
|
126
|
+
|
|
127
|
+
```css
|
|
128
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
129
|
+
.glass-card {
|
|
130
|
+
background: rgba(255, 255, 255, 0.92);
|
|
131
|
+
backdrop-filter: none;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
@media (prefers-contrast: more) {
|
|
135
|
+
.glass-card {
|
|
136
|
+
background: rgba(255, 255, 255, 0.85);
|
|
137
|
+
border: 1px solid rgba(0, 0, 0, 0.3);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
/* Backgrounds */
|
|
3
|
+
--glass-bg-light: rgba(255, 255, 255, 0.08);
|
|
4
|
+
--glass-bg: rgba(255, 255, 255, 0.15);
|
|
5
|
+
--glass-bg-heavy: rgba(255, 255, 255, 0.25);
|
|
6
|
+
|
|
7
|
+
/* Blur */
|
|
8
|
+
--glass-blur-light: blur(8px);
|
|
9
|
+
--glass-blur: blur(16px);
|
|
10
|
+
--glass-blur-strong: blur(32px);
|
|
11
|
+
|
|
12
|
+
/* Border */
|
|
13
|
+
--glass-border: 1px solid rgba(255, 255, 255, 0.18);
|
|
14
|
+
|
|
15
|
+
/* Radius */
|
|
16
|
+
--glass-radius: 12px;
|
|
17
|
+
--glass-radius-lg: 20px;
|
|
18
|
+
|
|
19
|
+
/* Shadow */
|
|
20
|
+
--glass-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
|
21
|
+
--glass-shadow-elevated: 0 8px 40px rgba(0, 0, 0, 0.15);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Dark theme overrides */
|
|
25
|
+
[data-theme="dark"] {
|
|
26
|
+
--glass-bg-light: rgba(255, 255, 255, 0.04);
|
|
27
|
+
--glass-bg: rgba(255, 255, 255, 0.08);
|
|
28
|
+
--glass-bg-heavy: rgba(255, 255, 255, 0.14);
|
|
29
|
+
--glass-border: 1px solid rgba(255, 255, 255, 0.12);
|
|
30
|
+
--glass-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
|
|
31
|
+
--glass-shadow-elevated: 0 8px 40px rgba(0, 0, 0, 0.4);
|
|
32
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: liquid-glass
|
|
3
|
+
description: Apple Liquid Glass design system. Use when building UI with translucent, depth-aware glass morphism following Apple's design language. Provides CSS tokens, component patterns, dark/light mode, and animation specs.
|
|
4
|
+
license: MIT
|
|
5
|
+
user-invocable: false
|
|
6
|
+
disable-model-invocation: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Liquid Glass Design System
|
|
10
|
+
|
|
11
|
+
Apple-inspired translucent glass UI with depth, refraction, and ambient light response.
|
|
12
|
+
|
|
13
|
+
## Core Principles
|
|
14
|
+
|
|
15
|
+
1. **Translucency** — Surfaces reveal layered content beneath via backdrop blur
|
|
16
|
+
2. **Depth** — Elements float on distinct z-layers with realistic shadows
|
|
17
|
+
3. **Ambient Response** — Glass tints shift based on underlying content color
|
|
18
|
+
4. **Minimal Chrome** — Borders are subtle; shape and blur define boundaries
|
|
19
|
+
5. **Motion** — Transitions feel physical: spring-based, with inertia
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
Import the token file in your CSS:
|
|
24
|
+
|
|
25
|
+
```css
|
|
26
|
+
@import 'references/tokens.css';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## CSS Tokens Reference
|
|
30
|
+
|
|
31
|
+
All tokens are defined in `references/tokens.css`. Key categories:
|
|
32
|
+
|
|
33
|
+
| Category | Prefix | Example |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| Glass backgrounds | `--lg-bg-*` | `--lg-bg-primary` |
|
|
36
|
+
| Blur | `--lg-blur-*` | `--lg-blur-md` |
|
|
37
|
+
| Borders | `--lg-border-*` | `--lg-border-color` |
|
|
38
|
+
| Shadows | `--lg-shadow-*` | `--lg-shadow-elevated` |
|
|
39
|
+
| Radius | `--lg-radius-*` | `--lg-radius-lg` |
|
|
40
|
+
| Animation | `--lg-duration-*` | `--lg-duration-normal` |
|
|
41
|
+
|
|
42
|
+
## Component Patterns
|
|
43
|
+
|
|
44
|
+
### Glass Card
|
|
45
|
+
|
|
46
|
+
```css
|
|
47
|
+
.glass-card {
|
|
48
|
+
background: var(--lg-bg-primary);
|
|
49
|
+
backdrop-filter: blur(var(--lg-blur-md));
|
|
50
|
+
-webkit-backdrop-filter: blur(var(--lg-blur-md));
|
|
51
|
+
border: 1px solid var(--lg-border-color);
|
|
52
|
+
border-radius: var(--lg-radius-lg);
|
|
53
|
+
box-shadow: var(--lg-shadow-elevated);
|
|
54
|
+
transition: transform var(--lg-duration-normal) var(--lg-easing-spring);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.glass-card:hover {
|
|
58
|
+
transform: translateY(-2px);
|
|
59
|
+
box-shadow: var(--lg-shadow-high);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Glass Toolbar
|
|
64
|
+
|
|
65
|
+
```css
|
|
66
|
+
.glass-toolbar {
|
|
67
|
+
background: var(--lg-bg-toolbar);
|
|
68
|
+
backdrop-filter: blur(var(--lg-blur-lg)) saturate(var(--lg-saturate));
|
|
69
|
+
-webkit-backdrop-filter: blur(var(--lg-blur-lg)) saturate(var(--lg-saturate));
|
|
70
|
+
border-bottom: 1px solid var(--lg-border-subtle);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Glass Button
|
|
75
|
+
|
|
76
|
+
```css
|
|
77
|
+
.glass-btn {
|
|
78
|
+
background: var(--lg-bg-interactive);
|
|
79
|
+
backdrop-filter: blur(var(--lg-blur-sm));
|
|
80
|
+
border: 1px solid var(--lg-border-color);
|
|
81
|
+
border-radius: var(--lg-radius-md);
|
|
82
|
+
transition: all var(--lg-duration-fast) var(--lg-easing-spring);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.glass-btn:active {
|
|
86
|
+
transform: scale(0.97);
|
|
87
|
+
background: var(--lg-bg-pressed);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Glass Modal Overlay
|
|
92
|
+
|
|
93
|
+
```css
|
|
94
|
+
.glass-overlay {
|
|
95
|
+
background: var(--lg-bg-scrim);
|
|
96
|
+
backdrop-filter: blur(var(--lg-blur-xl));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.glass-modal {
|
|
100
|
+
background: var(--lg-bg-elevated);
|
|
101
|
+
border: 1px solid var(--lg-border-color);
|
|
102
|
+
border-radius: var(--lg-radius-xl);
|
|
103
|
+
box-shadow: var(--lg-shadow-high);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Dark / Light Mode
|
|
108
|
+
|
|
109
|
+
Tokens auto-switch via `prefers-color-scheme`. Light mode uses white-tinted glass; dark mode uses dark-tinted glass with higher blur to maintain readability.
|
|
110
|
+
|
|
111
|
+
```css
|
|
112
|
+
/* Force a mode on a subtree */
|
|
113
|
+
.light-glass { color-scheme: light; }
|
|
114
|
+
.dark-glass { color-scheme: dark; }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Animations
|
|
118
|
+
|
|
119
|
+
Use spring-based easing for physical feel:
|
|
120
|
+
|
|
121
|
+
```css
|
|
122
|
+
/* Entry */
|
|
123
|
+
@keyframes glass-enter {
|
|
124
|
+
from { opacity: 0; transform: scale(0.95) translateY(8px); }
|
|
125
|
+
to { opacity: 1; transform: scale(1) translateY(0); }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.glass-animate-in {
|
|
129
|
+
animation: glass-enter var(--lg-duration-normal) var(--lg-easing-spring) both;
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Accessibility
|
|
134
|
+
|
|
135
|
+
- Ensure `contrast-ratio ≥ 4.5:1` for text over glass surfaces
|
|
136
|
+
- Respect `prefers-reduced-motion` — disable blur animations, use opacity-only transitions
|
|
137
|
+
- Provide `prefers-contrast: high` overrides that replace translucent backgrounds with solid ones
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/* Liquid Glass Design Tokens */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
color-scheme: light dark;
|
|
5
|
+
|
|
6
|
+
/* Blur */
|
|
7
|
+
--lg-blur-sm: 8px;
|
|
8
|
+
--lg-blur-md: 16px;
|
|
9
|
+
--lg-blur-lg: 32px;
|
|
10
|
+
--lg-blur-xl: 48px;
|
|
11
|
+
|
|
12
|
+
/* Saturation */
|
|
13
|
+
--lg-saturate: 1.8;
|
|
14
|
+
|
|
15
|
+
/* Radius */
|
|
16
|
+
--lg-radius-sm: 8px;
|
|
17
|
+
--lg-radius-md: 12px;
|
|
18
|
+
--lg-radius-lg: 16px;
|
|
19
|
+
--lg-radius-xl: 24px;
|
|
20
|
+
|
|
21
|
+
/* Shadows */
|
|
22
|
+
--lg-shadow-subtle: 0 1px 3px rgba(0,0,0,0.08);
|
|
23
|
+
--lg-shadow-elevated: 0 4px 16px rgba(0,0,0,0.1);
|
|
24
|
+
--lg-shadow-high: 0 8px 32px rgba(0,0,0,0.15);
|
|
25
|
+
|
|
26
|
+
/* Animation */
|
|
27
|
+
--lg-duration-fast: 150ms;
|
|
28
|
+
--lg-duration-normal: 300ms;
|
|
29
|
+
--lg-duration-slow: 500ms;
|
|
30
|
+
--lg-easing-spring: cubic-bezier(0.22, 1, 0.36, 1);
|
|
31
|
+
|
|
32
|
+
/* Light mode (default) */
|
|
33
|
+
--lg-bg-primary: rgba(255,255,255,0.72);
|
|
34
|
+
--lg-bg-elevated: rgba(255,255,255,0.82);
|
|
35
|
+
--lg-bg-toolbar: rgba(255,255,255,0.65);
|
|
36
|
+
--lg-bg-interactive: rgba(255,255,255,0.5);
|
|
37
|
+
--lg-bg-pressed: rgba(255,255,255,0.35);
|
|
38
|
+
--lg-bg-scrim: rgba(0,0,0,0.25);
|
|
39
|
+
--lg-border-color: rgba(255,255,255,0.45);
|
|
40
|
+
--lg-border-subtle: rgba(0,0,0,0.06);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@media (prefers-color-scheme: dark) {
|
|
44
|
+
:root {
|
|
45
|
+
--lg-bg-primary: rgba(30,30,30,0.65);
|
|
46
|
+
--lg-bg-elevated: rgba(40,40,40,0.75);
|
|
47
|
+
--lg-bg-toolbar: rgba(25,25,25,0.6);
|
|
48
|
+
--lg-bg-interactive: rgba(255,255,255,0.1);
|
|
49
|
+
--lg-bg-pressed: rgba(255,255,255,0.06);
|
|
50
|
+
--lg-bg-scrim: rgba(0,0,0,0.5);
|
|
51
|
+
--lg-border-color: rgba(255,255,255,0.12);
|
|
52
|
+
--lg-border-subtle: rgba(255,255,255,0.06);
|
|
53
|
+
--lg-shadow-subtle: 0 1px 3px rgba(0,0,0,0.3);
|
|
54
|
+
--lg-shadow-elevated: 0 4px 16px rgba(0,0,0,0.4);
|
|
55
|
+
--lg-shadow-high: 0 8px 32px rgba(0,0,0,0.5);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@media (prefers-contrast: high) {
|
|
60
|
+
:root {
|
|
61
|
+
--lg-bg-primary: rgba(255,255,255,0.95);
|
|
62
|
+
--lg-bg-elevated: rgba(255,255,255,0.98);
|
|
63
|
+
--lg-border-color: rgba(0,0,0,0.3);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@media (prefers-contrast: high) and (prefers-color-scheme: dark) {
|
|
68
|
+
:root {
|
|
69
|
+
--lg-bg-primary: rgba(20,20,20,0.95);
|
|
70
|
+
--lg-bg-elevated: rgba(25,25,25,0.98);
|
|
71
|
+
--lg-border-color: rgba(255,255,255,0.3);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@media (prefers-reduced-motion: reduce) {
|
|
76
|
+
:root {
|
|
77
|
+
--lg-duration-fast: 0ms;
|
|
78
|
+
--lg-duration-normal: 0ms;
|
|
79
|
+
--lg-duration-slow: 0ms;
|
|
80
|
+
}
|
|
81
|
+
}
|