@ifi/oh-pi-skills 0.2.1
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/package.json +18 -0
- package/skills/claymorphism/SKILL.md +127 -0
- package/skills/claymorphism/references/tokens.css +52 -0
- package/skills/context7/SKILL.md +38 -0
- package/skills/context7/docs.js +13 -0
- package/skills/context7/search.js +13 -0
- package/skills/debug-helper/SKILL.md +45 -0
- package/skills/git-workflow/SKILL.md +57 -0
- package/skills/glassmorphism/SKILL.md +147 -0
- package/skills/glassmorphism/references/tokens.css +32 -0
- package/skills/liquid-glass/SKILL.md +148 -0
- package/skills/liquid-glass/references/tokens.css +81 -0
- package/skills/neubrutalism/SKILL.md +154 -0
- package/skills/neubrutalism/references/tokens.css +44 -0
- package/skills/quick-setup/SKILL.md +46 -0
- package/skills/web-fetch/SKILL.md +26 -0
- package/skills/web-fetch/fetch.js +28 -0
- package/skills/web-search/SKILL.md +19 -0
- package/skills/web-search/search.js +29 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ifiok Jr.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ifi/oh-pi-skills",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "On-demand skill packs for pi: web-search, debug-helper, git-workflow, and more.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pi-package"
|
|
7
|
+
],
|
|
8
|
+
"pi": {
|
|
9
|
+
"skills": [
|
|
10
|
+
"./skills"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"skills",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"license": "MIT"
|
|
18
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: claymorphism
|
|
3
|
+
description:
|
|
4
|
+
Claymorphism design system skill. Use when building soft, puffy, clay-like UI components with
|
|
5
|
+
large radii, dual inner shadows, and offset outer shadows.
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
tags: [design, css, ui, claymorphism]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Claymorphism Design Spec
|
|
11
|
+
|
|
12
|
+
## 3 Core Elements
|
|
13
|
+
|
|
14
|
+
1. **Large Radius** — Generous `border-radius` (20–50px) for a puffy, inflated look
|
|
15
|
+
2. **Dual Inner Shadows** — Light inset from top-left + dark inset from bottom-right to simulate 3D
|
|
16
|
+
clay surface
|
|
17
|
+
3. **Offset Outer Shadow** — Directional `box-shadow` offset (not centered) to ground the element
|
|
18
|
+
|
|
19
|
+
## CSS Tokens
|
|
20
|
+
|
|
21
|
+
Reference: [references/tokens.css](references/tokens.css)
|
|
22
|
+
|
|
23
|
+
```css
|
|
24
|
+
@import "references/tokens.css";
|
|
25
|
+
|
|
26
|
+
.clay-card {
|
|
27
|
+
background: var(--clay-bg-card);
|
|
28
|
+
border-radius: var(--clay-radius-lg);
|
|
29
|
+
box-shadow: var(--clay-shadow);
|
|
30
|
+
color: var(--clay-text);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Component Examples
|
|
35
|
+
|
|
36
|
+
### Card
|
|
37
|
+
|
|
38
|
+
```css
|
|
39
|
+
.clay-card {
|
|
40
|
+
background: var(--clay-bg-card);
|
|
41
|
+
border-radius: var(--clay-radius-lg);
|
|
42
|
+
box-shadow: var(--clay-shadow);
|
|
43
|
+
padding: 1.5rem;
|
|
44
|
+
color: var(--clay-text);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Button
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
.clay-btn {
|
|
52
|
+
background: var(--clay-bg-button);
|
|
53
|
+
border: none;
|
|
54
|
+
border-radius: var(--clay-radius-pill);
|
|
55
|
+
box-shadow: var(--clay-shadow);
|
|
56
|
+
padding: 0.75rem 1.5rem;
|
|
57
|
+
color: var(--clay-text);
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
transition: box-shadow 0.2s;
|
|
60
|
+
}
|
|
61
|
+
.clay-btn:hover {
|
|
62
|
+
box-shadow: var(--clay-shadow-elevated);
|
|
63
|
+
}
|
|
64
|
+
.clay-btn:active {
|
|
65
|
+
box-shadow: var(--clay-shadow-pressed);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Input
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
.clay-input {
|
|
73
|
+
background: var(--clay-bg);
|
|
74
|
+
border: none;
|
|
75
|
+
border-radius: var(--clay-radius);
|
|
76
|
+
box-shadow: var(--clay-shadow-pressed);
|
|
77
|
+
padding: 0.75rem 1rem;
|
|
78
|
+
color: var(--clay-text);
|
|
79
|
+
}
|
|
80
|
+
.clay-input:focus {
|
|
81
|
+
outline: 2px solid var(--clay-accent);
|
|
82
|
+
outline-offset: 2px;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Toggle
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
.clay-toggle {
|
|
90
|
+
width: 56px;
|
|
91
|
+
height: 30px;
|
|
92
|
+
background: var(--clay-bg-card);
|
|
93
|
+
border-radius: var(--clay-radius-pill);
|
|
94
|
+
box-shadow: var(--clay-shadow-pressed);
|
|
95
|
+
}
|
|
96
|
+
.clay-toggle-knob {
|
|
97
|
+
width: 24px;
|
|
98
|
+
height: 24px;
|
|
99
|
+
background: var(--clay-bg);
|
|
100
|
+
border-radius: 50%;
|
|
101
|
+
box-shadow: var(--clay-shadow);
|
|
102
|
+
transition: transform 0.2s;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Dark Mode Notes
|
|
107
|
+
|
|
108
|
+
- Dark mode reduces inner highlight intensity (`rgba(255,255,255,0.05)` vs `0.6`) to avoid glowing
|
|
109
|
+
artifacts
|
|
110
|
+
- Outer shadow opacity increases to maintain depth on dark backgrounds
|
|
111
|
+
- Background colors shift to warm dark tones — avoid pure black to preserve the clay feel
|
|
112
|
+
- All dark tokens are defined in `[data-theme="dark"]` in `tokens.css`
|
|
113
|
+
|
|
114
|
+
## Accessibility Notes
|
|
115
|
+
|
|
116
|
+
- Ensure **contrast ratio ≥ 4.5:1** for text — clay backgrounds are muted, verify against
|
|
117
|
+
`--clay-text`
|
|
118
|
+
- Provide visible `:focus` outlines since clay shadows alone don't indicate focus
|
|
119
|
+
- Use `prefers-contrast: more` to flatten shadows and increase text contrast
|
|
120
|
+
|
|
121
|
+
```css
|
|
122
|
+
@media (prefers-contrast: more) {
|
|
123
|
+
.clay-card {
|
|
124
|
+
box-shadow: 0 0 0 2px var(--clay-text);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
/* Backgrounds — soft, muted pastels */
|
|
3
|
+
--clay-bg: #f0e6db;
|
|
4
|
+
--clay-bg-card: #e8ddd4;
|
|
5
|
+
--clay-bg-button: #d4c4b0;
|
|
6
|
+
--clay-accent: #c4a882;
|
|
7
|
+
|
|
8
|
+
/* Radius — large, rounded, puffy */
|
|
9
|
+
--clay-radius: 20px;
|
|
10
|
+
--clay-radius-lg: 32px;
|
|
11
|
+
--clay-radius-pill: 50px;
|
|
12
|
+
|
|
13
|
+
/* Shadows — dual inner + offset outer */
|
|
14
|
+
--clay-shadow:
|
|
15
|
+
8px 8px 16px rgba(0, 0, 0, 0.12),
|
|
16
|
+
inset -4px -4px 8px rgba(0, 0, 0, 0.08),
|
|
17
|
+
inset 4px 4px 8px rgba(255, 255, 255, 0.6);
|
|
18
|
+
--clay-shadow-elevated:
|
|
19
|
+
12px 12px 24px rgba(0, 0, 0, 0.15),
|
|
20
|
+
inset -6px -6px 12px rgba(0, 0, 0, 0.1),
|
|
21
|
+
inset 6px 6px 12px rgba(255, 255, 255, 0.7);
|
|
22
|
+
--clay-shadow-pressed:
|
|
23
|
+
2px 2px 6px rgba(0, 0, 0, 0.1),
|
|
24
|
+
inset -6px -6px 12px rgba(0, 0, 0, 0.12),
|
|
25
|
+
inset 6px 6px 12px rgba(255, 255, 255, 0.5);
|
|
26
|
+
|
|
27
|
+
/* Text */
|
|
28
|
+
--clay-text: #4a3f35;
|
|
29
|
+
--clay-text-muted: #8a7e72;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Dark mode */
|
|
33
|
+
[data-theme="dark"] {
|
|
34
|
+
--clay-bg: #2a2520;
|
|
35
|
+
--clay-bg-card: #352f28;
|
|
36
|
+
--clay-bg-button: #443c33;
|
|
37
|
+
--clay-accent: #6b5d4f;
|
|
38
|
+
--clay-shadow:
|
|
39
|
+
8px 8px 16px rgba(0, 0, 0, 0.35),
|
|
40
|
+
inset -4px -4px 8px rgba(0, 0, 0, 0.25),
|
|
41
|
+
inset 4px 4px 8px rgba(255, 255, 255, 0.05);
|
|
42
|
+
--clay-shadow-elevated:
|
|
43
|
+
12px 12px 24px rgba(0, 0, 0, 0.4),
|
|
44
|
+
inset -6px -6px 12px rgba(0, 0, 0, 0.3),
|
|
45
|
+
inset 6px 6px 12px rgba(255, 255, 255, 0.06);
|
|
46
|
+
--clay-shadow-pressed:
|
|
47
|
+
2px 2px 6px rgba(0, 0, 0, 0.3),
|
|
48
|
+
inset -6px -6px 12px rgba(0, 0, 0, 0.35),
|
|
49
|
+
inset 6px 6px 12px rgba(255, 255, 255, 0.04);
|
|
50
|
+
--clay-text: #d4c8bc;
|
|
51
|
+
--clay-text-muted: #8a7e72;
|
|
52
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: context7
|
|
3
|
+
description:
|
|
4
|
+
Search and query up-to-date documentation for any programming library via Context7 API. Use when
|
|
5
|
+
you need current docs, code examples, or API references for libraries and frameworks.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Context7
|
|
9
|
+
|
|
10
|
+
Search for libraries and query their documentation via the Context7 API.
|
|
11
|
+
|
|
12
|
+
## Search Libraries
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
{baseDir}/search.js "library name" "what you need help with"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
{baseDir}/search.js "react" "hooks for state management"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Returns matching libraries with Context7-compatible IDs for use with the docs tool.
|
|
25
|
+
|
|
26
|
+
## Query Documentation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
{baseDir}/docs.js "/org/project" "your question"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
{baseDir}/docs.js "/websites/react_dev" "useEffect cleanup"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Use the library ID from search results. Returns relevant documentation and code examples.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const [libraryId, query] = process.argv.slice(2);
|
|
4
|
+
if (!libraryId || !query) { console.error("Usage: docs.js <libraryId> <query>"); process.exit(1); }
|
|
5
|
+
|
|
6
|
+
const res = await fetch("https://mcp.context7.com/mcp", {
|
|
7
|
+
method: "POST",
|
|
8
|
+
headers: { "Content-Type": "application/json", "Accept": "application/json, text/event-stream" },
|
|
9
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call", params: { name: "query-docs", arguments: { libraryId, query } } })
|
|
10
|
+
});
|
|
11
|
+
const data = await res.json();
|
|
12
|
+
if (data.error) { console.error("Error:", data.error.message); process.exit(1); }
|
|
13
|
+
console.log(data.result.content[0].text);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const [libraryName, query = libraryName] = process.argv.slice(2);
|
|
4
|
+
if (!libraryName) { console.error("Usage: search.js <libraryName> [query]"); process.exit(1); }
|
|
5
|
+
|
|
6
|
+
const res = await fetch("https://mcp.context7.com/mcp", {
|
|
7
|
+
method: "POST",
|
|
8
|
+
headers: { "Content-Type": "application/json", "Accept": "application/json, text/event-stream" },
|
|
9
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call", params: { name: "resolve-library-id", arguments: { query, libraryName } } })
|
|
10
|
+
});
|
|
11
|
+
const data = await res.json();
|
|
12
|
+
if (data.error) { console.error("Error:", data.error.message); process.exit(1); }
|
|
13
|
+
console.log(data.result.content[0].text);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debug-helper
|
|
3
|
+
description:
|
|
4
|
+
Debug assistant for error analysis, log interpretation, and performance profiling. Use when user
|
|
5
|
+
encounters errors, crashes, or performance issues.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Debug Helper
|
|
9
|
+
|
|
10
|
+
Systematic debugging workflow.
|
|
11
|
+
|
|
12
|
+
## Error Analysis
|
|
13
|
+
|
|
14
|
+
1. **Read the error** — Full stack trace and error message
|
|
15
|
+
2. **Locate** — Find the source file and line
|
|
16
|
+
```bash
|
|
17
|
+
# Search for the error origin
|
|
18
|
+
grep -rn "ErrorClass\|error_function" src/
|
|
19
|
+
```
|
|
20
|
+
3. **Context** — Read surrounding code (±30 lines)
|
|
21
|
+
4. **Reproduce** — Identify minimal reproduction steps
|
|
22
|
+
5. **Root cause** — Trace the data flow to find where it goes wrong
|
|
23
|
+
6. **Fix** — Minimal change that addresses the root cause
|
|
24
|
+
7. **Verify** — Run the failing case to confirm the fix
|
|
25
|
+
|
|
26
|
+
## Log Analysis
|
|
27
|
+
|
|
28
|
+
1. Read the log file or output
|
|
29
|
+
2. Identify patterns: timestamps, error levels, request IDs
|
|
30
|
+
3. Correlate events across log lines
|
|
31
|
+
4. Summarize: what happened, when, and why
|
|
32
|
+
|
|
33
|
+
## Performance Profiling
|
|
34
|
+
|
|
35
|
+
1. **Measure** — Get baseline numbers first
|
|
36
|
+
```bash
|
|
37
|
+
time <command>
|
|
38
|
+
```
|
|
39
|
+
2. **Profile** — Use language-appropriate tools:
|
|
40
|
+
- Node.js: `--prof`, `clinic.js`
|
|
41
|
+
- Python: `cProfile`, `py-spy`
|
|
42
|
+
- Go: `pprof`
|
|
43
|
+
3. **Identify** — Find the hotspot (usually 1-2 functions)
|
|
44
|
+
4. **Optimize** — Fix the bottleneck
|
|
45
|
+
5. **Verify** — Measure again, compare with baseline
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-workflow
|
|
3
|
+
description:
|
|
4
|
+
Git workflow assistant for branching, commits, PRs, and conflict resolution. Use when user asks
|
|
5
|
+
about git strategy, branch management, or PR workflow.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Git Workflow
|
|
9
|
+
|
|
10
|
+
Help with Git operations and workflow best practices.
|
|
11
|
+
|
|
12
|
+
## Capabilities
|
|
13
|
+
|
|
14
|
+
### Branch Strategy
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Check current state
|
|
18
|
+
git branch -a
|
|
19
|
+
git log --oneline -20
|
|
20
|
+
git status
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Recommend branching strategy based on project:
|
|
24
|
+
|
|
25
|
+
- **Solo**: main + feature branches
|
|
26
|
+
- **Team**: main + develop + feature/fix branches
|
|
27
|
+
- **Release**: GitFlow (main/develop/release/hotfix)
|
|
28
|
+
|
|
29
|
+
### Commit Messages
|
|
30
|
+
|
|
31
|
+
Follow Conventional Commits:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
feat(scope): add new feature
|
|
35
|
+
fix(scope): fix bug description
|
|
36
|
+
refactor(scope): restructure code
|
|
37
|
+
docs(scope): update documentation
|
|
38
|
+
test(scope): add/update tests
|
|
39
|
+
chore(scope): maintenance tasks
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### PR Workflow
|
|
43
|
+
|
|
44
|
+
1. `git diff main --stat` — Review changes
|
|
45
|
+
2. Generate PR title and description
|
|
46
|
+
3. Suggest reviewers based on changed files (`git log --format='%an' -- <files>`)
|
|
47
|
+
|
|
48
|
+
### Conflict Resolution
|
|
49
|
+
|
|
50
|
+
1. `git diff --name-only --diff-filter=U` — Find conflicted files
|
|
51
|
+
2. Read each conflicted file
|
|
52
|
+
3. Understand both sides of the conflict
|
|
53
|
+
4. Resolve with minimal changes preserving intent from both sides
|
|
54
|
+
|
|
55
|
+
### Interactive Rebase
|
|
56
|
+
|
|
57
|
+
Guide through `git rebase -i` for cleaning up history before PR.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: glassmorphism
|
|
3
|
+
description:
|
|
4
|
+
Glassmorphism design system skill. Use when building frosted-glass UI components with blur,
|
|
5
|
+
transparency, and layered depth effects.
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
tags: [design, css, ui, glassmorphism]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Glassmorphism Design Spec
|
|
11
|
+
|
|
12
|
+
## 4 Core Elements
|
|
13
|
+
|
|
14
|
+
1. **Transparency** — Semi-transparent backgrounds using `rgba()` or `hsla()` with alpha `0.05–0.4`
|
|
15
|
+
2. **Blur** — `backdrop-filter: blur()` ranging 8–40px for frosted-glass effect
|
|
16
|
+
3. **Border** — Subtle semi-transparent borders (`1px solid rgba(255,255,255,0.18)`) to define edges
|
|
17
|
+
4. **Shadow** — Soft layered `box-shadow` for depth separation from background
|
|
18
|
+
|
|
19
|
+
## CSS Tokens
|
|
20
|
+
|
|
21
|
+
Reference: [references/tokens.css](references/tokens.css)
|
|
22
|
+
|
|
23
|
+
Use CSS custom properties from `tokens.css` for consistent theming:
|
|
24
|
+
|
|
25
|
+
```css
|
|
26
|
+
@import "references/tokens.css";
|
|
27
|
+
|
|
28
|
+
.glass-card {
|
|
29
|
+
background: var(--glass-bg);
|
|
30
|
+
backdrop-filter: var(--glass-blur);
|
|
31
|
+
-webkit-backdrop-filter: var(--glass-blur);
|
|
32
|
+
border: var(--glass-border);
|
|
33
|
+
border-radius: var(--glass-radius);
|
|
34
|
+
box-shadow: var(--glass-shadow);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Component Examples
|
|
39
|
+
|
|
40
|
+
### Card
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
.glass-card {
|
|
44
|
+
background: var(--glass-bg);
|
|
45
|
+
backdrop-filter: var(--glass-blur);
|
|
46
|
+
-webkit-backdrop-filter: var(--glass-blur);
|
|
47
|
+
border: var(--glass-border);
|
|
48
|
+
border-radius: var(--glass-radius);
|
|
49
|
+
box-shadow: var(--glass-shadow);
|
|
50
|
+
padding: 1.5rem;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Navbar
|
|
55
|
+
|
|
56
|
+
```css
|
|
57
|
+
.glass-nav {
|
|
58
|
+
background: var(--glass-bg-heavy);
|
|
59
|
+
backdrop-filter: var(--glass-blur-strong);
|
|
60
|
+
-webkit-backdrop-filter: var(--glass-blur-strong);
|
|
61
|
+
border-bottom: var(--glass-border);
|
|
62
|
+
box-shadow: var(--glass-shadow);
|
|
63
|
+
position: sticky;
|
|
64
|
+
top: 0;
|
|
65
|
+
z-index: 100;
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Modal Overlay
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
.glass-modal-backdrop {
|
|
73
|
+
background: rgba(0, 0, 0, 0.4);
|
|
74
|
+
backdrop-filter: blur(4px);
|
|
75
|
+
}
|
|
76
|
+
.glass-modal {
|
|
77
|
+
background: var(--glass-bg-heavy);
|
|
78
|
+
backdrop-filter: var(--glass-blur-strong);
|
|
79
|
+
-webkit-backdrop-filter: var(--glass-blur-strong);
|
|
80
|
+
border: var(--glass-border);
|
|
81
|
+
border-radius: var(--glass-radius-lg);
|
|
82
|
+
box-shadow: var(--glass-shadow-elevated);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Button
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
.glass-btn {
|
|
90
|
+
background: var(--glass-bg-light);
|
|
91
|
+
backdrop-filter: var(--glass-blur-light);
|
|
92
|
+
-webkit-backdrop-filter: var(--glass-blur-light);
|
|
93
|
+
border: var(--glass-border);
|
|
94
|
+
border-radius: var(--glass-radius);
|
|
95
|
+
transition: background 0.2s;
|
|
96
|
+
}
|
|
97
|
+
.glass-btn:hover {
|
|
98
|
+
background: var(--glass-bg);
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Browser Compatibility
|
|
103
|
+
|
|
104
|
+
| Feature | Chrome | Firefox | Safari | Edge |
|
|
105
|
+
| -------------------- | ------ | ------- | --------------- | ---- |
|
|
106
|
+
| `backdrop-filter` | 76+ | 103+ | 9+ (`-webkit-`) | 79+ |
|
|
107
|
+
| `rgba()` backgrounds | All | All | All | All |
|
|
108
|
+
|
|
109
|
+
- Always include `-webkit-backdrop-filter` for Safari support
|
|
110
|
+
- Firefox <103: use `@supports` fallback with solid semi-transparent bg
|
|
111
|
+
- Fallback pattern:
|
|
112
|
+
|
|
113
|
+
```css
|
|
114
|
+
.glass-card {
|
|
115
|
+
background: rgba(255, 255, 255, 0.85); /* fallback */
|
|
116
|
+
}
|
|
117
|
+
@supports (backdrop-filter: blur(1px)) {
|
|
118
|
+
.glass-card {
|
|
119
|
+
background: var(--glass-bg);
|
|
120
|
+
backdrop-filter: var(--glass-blur);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Accessibility Notes
|
|
126
|
+
|
|
127
|
+
- Ensure **contrast ratio ≥ 4.5:1** for text over glass surfaces — test against all possible
|
|
128
|
+
backgrounds
|
|
129
|
+
- Provide `prefers-reduced-transparency` media query to disable blur/transparency for users who need
|
|
130
|
+
it
|
|
131
|
+
- Avoid placing critical text on highly transparent surfaces without a fallback
|
|
132
|
+
- Use `prefers-contrast: more` to increase border opacity and reduce transparency
|
|
133
|
+
|
|
134
|
+
```css
|
|
135
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
136
|
+
.glass-card {
|
|
137
|
+
background: rgba(255, 255, 255, 0.92);
|
|
138
|
+
backdrop-filter: none;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
@media (prefers-contrast: more) {
|
|
142
|
+
.glass-card {
|
|
143
|
+
background: rgba(255, 255, 255, 0.85);
|
|
144
|
+
border: 1px solid rgba(0, 0, 0, 0.3);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
@@ -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,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: liquid-glass
|
|
3
|
+
description:
|
|
4
|
+
Apple Liquid Glass design system. Use when building UI with translucent, depth-aware glass
|
|
5
|
+
morphism following Apple's design language. Provides CSS tokens, component patterns, dark/light
|
|
6
|
+
mode, and animation specs.
|
|
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
|
|
110
|
+
dark-tinted glass with higher blur to maintain readability.
|
|
111
|
+
|
|
112
|
+
```css
|
|
113
|
+
/* Force a mode on a subtree */
|
|
114
|
+
.light-glass {
|
|
115
|
+
color-scheme: light;
|
|
116
|
+
}
|
|
117
|
+
.dark-glass {
|
|
118
|
+
color-scheme: dark;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Animations
|
|
123
|
+
|
|
124
|
+
Use spring-based easing for physical feel:
|
|
125
|
+
|
|
126
|
+
```css
|
|
127
|
+
/* Entry */
|
|
128
|
+
@keyframes glass-enter {
|
|
129
|
+
from {
|
|
130
|
+
opacity: 0;
|
|
131
|
+
transform: scale(0.95) translateY(8px);
|
|
132
|
+
}
|
|
133
|
+
to {
|
|
134
|
+
opacity: 1;
|
|
135
|
+
transform: scale(1) translateY(0);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.glass-animate-in {
|
|
140
|
+
animation: glass-enter var(--lg-duration-normal) var(--lg-easing-spring) both;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Accessibility
|
|
145
|
+
|
|
146
|
+
- Ensure `contrast-ratio ≥ 4.5:1` for text over glass surfaces
|
|
147
|
+
- Respect `prefers-reduced-motion` — disable blur animations, use opacity-only transitions
|
|
148
|
+
- 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
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: neubrutalism
|
|
3
|
+
description:
|
|
4
|
+
Neubrutalism design system skill. Use when building bold UI with thick borders, offset solid
|
|
5
|
+
shadows, high saturation colors, and minimal border radius.
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
tags: [design, css, ui, neubrutalism, brutalism]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Neubrutalism Design Spec
|
|
11
|
+
|
|
12
|
+
## Core Principles
|
|
13
|
+
|
|
14
|
+
1. **Thick Borders** — Bold `3–5px solid` black outlines on all elements
|
|
15
|
+
2. **Offset Solid Shadows** — Hard-edge `box-shadow` with zero blur (e.g. `5px 5px 0 #000`)
|
|
16
|
+
3. **High Saturation Colors** — Vivid, punchy fills: pinks, yellows, blues, greens
|
|
17
|
+
4. **Minimal Radius** — `0–8px` border-radius; sharp or barely rounded corners
|
|
18
|
+
5. **Flat Aesthetic** — No gradients, no blur, no transparency
|
|
19
|
+
|
|
20
|
+
## CSS Tokens
|
|
21
|
+
|
|
22
|
+
Reference: [references/tokens.css](references/tokens.css)
|
|
23
|
+
|
|
24
|
+
```css
|
|
25
|
+
@import "references/tokens.css";
|
|
26
|
+
|
|
27
|
+
.nb-card {
|
|
28
|
+
background: var(--nb-yellow);
|
|
29
|
+
border: var(--nb-border-thick);
|
|
30
|
+
border-radius: var(--nb-radius);
|
|
31
|
+
box-shadow: var(--nb-shadow);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Component Examples
|
|
36
|
+
|
|
37
|
+
### Card
|
|
38
|
+
|
|
39
|
+
```css
|
|
40
|
+
.nb-card {
|
|
41
|
+
background: var(--nb-white);
|
|
42
|
+
border: var(--nb-border-thick);
|
|
43
|
+
border-radius: var(--nb-radius);
|
|
44
|
+
box-shadow: var(--nb-shadow);
|
|
45
|
+
padding: 1.5rem;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Button
|
|
50
|
+
|
|
51
|
+
```css
|
|
52
|
+
.nb-btn {
|
|
53
|
+
background: var(--nb-yellow);
|
|
54
|
+
border: var(--nb-border);
|
|
55
|
+
border-radius: var(--nb-radius);
|
|
56
|
+
box-shadow: var(--nb-shadow-sm);
|
|
57
|
+
padding: 0.6rem 1.4rem;
|
|
58
|
+
font-family: var(--nb-font);
|
|
59
|
+
font-weight: var(--nb-font-weight);
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
transition:
|
|
62
|
+
transform 0.1s,
|
|
63
|
+
box-shadow 0.1s;
|
|
64
|
+
}
|
|
65
|
+
.nb-btn:hover {
|
|
66
|
+
transform: translate(-2px, -2px);
|
|
67
|
+
box-shadow: var(--nb-shadow);
|
|
68
|
+
}
|
|
69
|
+
.nb-btn:active {
|
|
70
|
+
transform: translate(3px, 3px);
|
|
71
|
+
box-shadow: none;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Navbar
|
|
76
|
+
|
|
77
|
+
```css
|
|
78
|
+
.nb-nav {
|
|
79
|
+
background: var(--nb-bg);
|
|
80
|
+
border-bottom: var(--nb-border-thick);
|
|
81
|
+
padding: 1rem 2rem;
|
|
82
|
+
position: sticky;
|
|
83
|
+
top: 0;
|
|
84
|
+
z-index: 100;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Input
|
|
89
|
+
|
|
90
|
+
```css
|
|
91
|
+
.nb-input {
|
|
92
|
+
background: var(--nb-white);
|
|
93
|
+
border: var(--nb-border);
|
|
94
|
+
border-radius: var(--nb-radius);
|
|
95
|
+
box-shadow: var(--nb-shadow-sm);
|
|
96
|
+
padding: 0.6rem 1rem;
|
|
97
|
+
font-family: var(--nb-font);
|
|
98
|
+
font-weight: var(--nb-font-weight-body);
|
|
99
|
+
}
|
|
100
|
+
.nb-input:focus {
|
|
101
|
+
outline: none;
|
|
102
|
+
box-shadow: var(--nb-shadow);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Badge
|
|
107
|
+
|
|
108
|
+
```css
|
|
109
|
+
.nb-badge {
|
|
110
|
+
background: var(--nb-pink);
|
|
111
|
+
border: var(--nb-border);
|
|
112
|
+
border-radius: var(--nb-radius);
|
|
113
|
+
padding: 0.2rem 0.8rem;
|
|
114
|
+
font-family: var(--nb-font);
|
|
115
|
+
font-weight: var(--nb-font-weight);
|
|
116
|
+
font-size: 0.85rem;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Typography
|
|
121
|
+
|
|
122
|
+
- Use bold, geometric sans-serif fonts (Space Grotesk, Inter, etc.)
|
|
123
|
+
- Headings: `font-weight: 700`, `letter-spacing: -0.02em`
|
|
124
|
+
- Body: `font-weight: 500`
|
|
125
|
+
- Uppercase sparingly for labels/badges
|
|
126
|
+
|
|
127
|
+
```css
|
|
128
|
+
h1,
|
|
129
|
+
h2,
|
|
130
|
+
h3 {
|
|
131
|
+
font-family: var(--nb-font-heading);
|
|
132
|
+
font-weight: var(--nb-font-weight);
|
|
133
|
+
letter-spacing: var(--nb-letter-spacing);
|
|
134
|
+
}
|
|
135
|
+
body {
|
|
136
|
+
font-family: var(--nb-font);
|
|
137
|
+
font-weight: var(--nb-font-weight-body);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Accessibility Notes
|
|
142
|
+
|
|
143
|
+
- Thick borders provide strong visual boundaries — good for low-vision users
|
|
144
|
+
- Ensure color contrast ≥ 4.5:1 for text on colored backgrounds
|
|
145
|
+
- Active/hover states use `transform` shifts — provide `prefers-reduced-motion` fallback
|
|
146
|
+
|
|
147
|
+
```css
|
|
148
|
+
@media (prefers-reduced-motion: reduce) {
|
|
149
|
+
.nb-btn:hover,
|
|
150
|
+
.nb-btn:active {
|
|
151
|
+
transform: none;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
/* Borders */
|
|
3
|
+
--nb-border: 3px solid #000;
|
|
4
|
+
--nb-border-thick: 5px solid #000;
|
|
5
|
+
|
|
6
|
+
/* Shadows (offset solid, no blur) */
|
|
7
|
+
--nb-shadow-sm: 3px 3px 0 #000;
|
|
8
|
+
--nb-shadow: 5px 5px 0 #000;
|
|
9
|
+
--nb-shadow-lg: 8px 8px 0 #000;
|
|
10
|
+
|
|
11
|
+
/* Radius */
|
|
12
|
+
--nb-radius: 4px;
|
|
13
|
+
--nb-radius-lg: 8px;
|
|
14
|
+
|
|
15
|
+
/* Colors — high saturation */
|
|
16
|
+
--nb-pink: #ff6b9d;
|
|
17
|
+
--nb-yellow: #ffd43b;
|
|
18
|
+
--nb-blue: #4dabf7;
|
|
19
|
+
--nb-green: #51cf66;
|
|
20
|
+
--nb-orange: #ff922b;
|
|
21
|
+
--nb-purple: #cc5de8;
|
|
22
|
+
--nb-red: #ff6b6b;
|
|
23
|
+
--nb-white: #fff;
|
|
24
|
+
--nb-black: #000;
|
|
25
|
+
--nb-bg: #f5f0e8;
|
|
26
|
+
|
|
27
|
+
/* Typography */
|
|
28
|
+
--nb-font: 'Space Grotesk', 'Inter', system-ui, sans-serif;
|
|
29
|
+
--nb-font-heading: 'Space Grotesk', 'Inter', system-ui, sans-serif;
|
|
30
|
+
--nb-font-weight: 700;
|
|
31
|
+
--nb-font-weight-body: 500;
|
|
32
|
+
--nb-letter-spacing: -0.02em;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
[data-theme="dark"] {
|
|
36
|
+
--nb-border: 3px solid #fff;
|
|
37
|
+
--nb-border-thick: 5px solid #fff;
|
|
38
|
+
--nb-shadow-sm: 3px 3px 0 #fff;
|
|
39
|
+
--nb-shadow: 5px 5px 0 #fff;
|
|
40
|
+
--nb-shadow-lg: 8px 8px 0 #fff;
|
|
41
|
+
--nb-bg: #1a1a2e;
|
|
42
|
+
--nb-black: #fff;
|
|
43
|
+
--nb-white: #1a1a2e;
|
|
44
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: quick-setup
|
|
3
|
+
description:
|
|
4
|
+
Detect project type and generate .pi/ configuration. Use when setting up pi for a new project or
|
|
5
|
+
when user asks to initialize pi config.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Quick Setup
|
|
9
|
+
|
|
10
|
+
Analyze the current project and generate appropriate `.pi/` configuration.
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
1. **Detect project type** by examining files:
|
|
15
|
+
- `package.json` → Node.js/TypeScript
|
|
16
|
+
- `requirements.txt` / `pyproject.toml` → Python
|
|
17
|
+
- `go.mod` → Go
|
|
18
|
+
- `Cargo.toml` → Rust
|
|
19
|
+
- `pom.xml` / `build.gradle` → Java
|
|
20
|
+
- `Makefile` / `CMakeLists.txt` → C/C++
|
|
21
|
+
|
|
22
|
+
2. **Detect frameworks** (React, Vue, Next.js, Django, FastAPI, Gin, etc.)
|
|
23
|
+
|
|
24
|
+
3. **Detect existing tooling** (ESLint, Prettier, pytest, etc.)
|
|
25
|
+
|
|
26
|
+
4. **Generate `.pi/` directory**:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
.pi/
|
|
30
|
+
├── settings.json # Project-specific settings
|
|
31
|
+
└── AGENTS.md # Project context for the agent
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
5. **Generate AGENTS.md** with:
|
|
35
|
+
- Project stack description
|
|
36
|
+
- Build/test/lint commands (from package.json scripts, Makefile, etc.)
|
|
37
|
+
- Code conventions detected from config files
|
|
38
|
+
- Directory structure overview
|
|
39
|
+
|
|
40
|
+
6. **Generate settings.json** with:
|
|
41
|
+
- Appropriate thinking level for project complexity
|
|
42
|
+
- Relevant skills enabled
|
|
43
|
+
|
|
44
|
+
## Output
|
|
45
|
+
|
|
46
|
+
Show the generated files and ask user to confirm before writing.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: web-fetch
|
|
3
|
+
description:
|
|
4
|
+
Fetch a web page and extract readable text content. Use when user needs to retrieve or read a web
|
|
5
|
+
page.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# web-fetch
|
|
9
|
+
|
|
10
|
+
Fetch a web page and extract readable text content.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
{baseDir}/fetch.js <url> [--raw]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- `<url>` — URL to fetch
|
|
19
|
+
- `--raw` — Output raw HTML instead of extracted text
|
|
20
|
+
|
|
21
|
+
## Examples
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
{baseDir}/fetch.js https://example.com
|
|
25
|
+
{baseDir}/fetch.js https://example.com --raw
|
|
26
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
4
|
+
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
const raw = args.includes('--raw');
|
|
7
|
+
const url = args.find(a => !a.startsWith('--'));
|
|
8
|
+
|
|
9
|
+
if (!url) { console.error('Usage: fetch.js <url> [--raw]'); process.exit(1); }
|
|
10
|
+
|
|
11
|
+
const res = await fetch(url);
|
|
12
|
+
const html = await res.text();
|
|
13
|
+
|
|
14
|
+
if (raw) { console.log(html); } else {
|
|
15
|
+
const text = html
|
|
16
|
+
.replace(/<script[\s\S]*?<\/script>/gi, '')
|
|
17
|
+
.replace(/<style[\s\S]*?<\/style>/gi, '')
|
|
18
|
+
.replace(/<[^>]+>/g, ' ')
|
|
19
|
+
.replace(/ /g, ' ')
|
|
20
|
+
.replace(/&/g, '&')
|
|
21
|
+
.replace(/</g, '<')
|
|
22
|
+
.replace(/>/g, '>')
|
|
23
|
+
.replace(/&#(\d+);/g, (_, n) => String.fromCharCode(n))
|
|
24
|
+
.replace(/[ \t]+/g, ' ')
|
|
25
|
+
.replace(/\n\s*\n/g, '\n')
|
|
26
|
+
.trim();
|
|
27
|
+
console.log(text);
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: web-search
|
|
3
|
+
description:
|
|
4
|
+
Web search via DuckDuckGo. Use when the user needs to look up current information online.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# web-search
|
|
8
|
+
|
|
9
|
+
Web search via DuckDuckGo. Use when the user needs to look up current information online.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
{baseDir}/search.js "query terms"
|
|
15
|
+
{baseDir}/search.js -n 10 "query terms"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- `-n <count>` — number of results to return (default: 5)
|
|
19
|
+
- Returns title, URL, and snippet for each result.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const args = process.argv.slice(2);
|
|
4
|
+
let n = 5, query;
|
|
5
|
+
|
|
6
|
+
for (let i = 0; i < args.length; i++) {
|
|
7
|
+
if (args[i] === '-n' && args[i + 1]) { n = parseInt(args[++i], 10); }
|
|
8
|
+
else { query = args[i]; }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (!query) { console.error('Usage: search.js [-n count] "query"'); process.exit(1); }
|
|
12
|
+
|
|
13
|
+
const res = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`, {
|
|
14
|
+
headers: { 'User-Agent': 'Mozilla/5.0' }
|
|
15
|
+
});
|
|
16
|
+
const html = await res.text();
|
|
17
|
+
|
|
18
|
+
const results = [];
|
|
19
|
+
const blockRe = /<a rel="nofollow" class="result__a" href="([^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<a class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g;
|
|
20
|
+
let m;
|
|
21
|
+
while ((m = blockRe.exec(html)) && results.length < n) {
|
|
22
|
+
const url = decodeURIComponent(m[1].replace(/^\/\/duckduckgo\.com\/l\/\?uddg=/, '').replace(/&rut=.*$/, '').replace(/&rut=.*$/, ''));
|
|
23
|
+
const title = m[2].replace(/<[^>]*>/g, '').trim();
|
|
24
|
+
const snippet = m[3].replace(/<[^>]*>/g, '').trim();
|
|
25
|
+
results.push({ title, url, snippet });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!results.length) { console.log('No results found.'); }
|
|
29
|
+
else { results.forEach((r, i) => console.log(`${i + 1}. ${r.title}\n ${r.url}\n ${r.snippet}\n`)); }
|