@aexol/spectral 0.9.229 → 0.9.231
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/CHANGELOG.md +2 -0
- package/dist/auth-helper.d.ts.map +1 -1
- package/dist/auth-helper.js +14 -8
- package/dist/commands/login.d.ts +12 -4
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +36 -15
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +3 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -1
- package/dist/designer/data/skills/blog-post.d.ts +3 -0
- package/dist/designer/data/skills/blog-post.d.ts.map +1 -0
- package/dist/designer/data/skills/blog-post.js +84 -0
- package/dist/designer/data/skills/blog-post.ts +87 -0
- package/dist/designer/data/skills/critique.d.ts +3 -0
- package/dist/designer/data/skills/critique.d.ts.map +1 -0
- package/dist/designer/data/skills/critique.js +109 -0
- package/dist/designer/data/skills/critique.ts +112 -0
- package/dist/designer/data/skills/dashboard.d.ts +3 -0
- package/dist/designer/data/skills/dashboard.d.ts.map +1 -0
- package/dist/designer/data/skills/dashboard.js +165 -0
- package/dist/designer/data/skills/dashboard.ts +168 -0
- package/dist/designer/data/skills/design-brief.d.ts +3 -0
- package/dist/designer/data/skills/design-brief.d.ts.map +1 -0
- package/dist/designer/data/skills/design-brief.js +141 -0
- package/dist/designer/data/skills/design-brief.ts +144 -0
- package/dist/designer/data/skills/design-skill.d.ts +10 -0
- package/dist/designer/data/skills/design-skill.d.ts.map +1 -0
- package/dist/designer/data/skills/design-skill.js +1 -0
- package/dist/designer/data/skills/design-skill.ts +9 -0
- package/dist/designer/data/skills/docs-page.d.ts +3 -0
- package/dist/designer/data/skills/docs-page.d.ts.map +1 -0
- package/dist/designer/data/skills/docs-page.js +68 -0
- package/dist/designer/data/skills/docs-page.ts +71 -0
- package/dist/designer/data/skills/index.d.ts +3 -0
- package/dist/designer/data/skills/index.d.ts.map +1 -0
- package/dist/designer/data/skills/index.js +28 -0
- package/dist/designer/data/skills/index.ts +30 -0
- package/dist/designer/data/skills/magazine-poster.d.ts +3 -0
- package/dist/designer/data/skills/magazine-poster.d.ts.map +1 -0
- package/dist/designer/data/skills/magazine-poster.js +70 -0
- package/dist/designer/data/skills/magazine-poster.ts +73 -0
- package/dist/designer/data/skills/mobile-app.d.ts +3 -0
- package/dist/designer/data/skills/mobile-app.d.ts.map +1 -0
- package/dist/designer/data/skills/mobile-app.js +229 -0
- package/dist/designer/data/skills/mobile-app.ts +232 -0
- package/dist/designer/data/skills/motion-frames.d.ts +3 -0
- package/dist/designer/data/skills/motion-frames.d.ts.map +1 -0
- package/dist/designer/data/skills/motion-frames.js +121 -0
- package/dist/designer/data/skills/motion-frames.ts +124 -0
- package/dist/designer/data/skills/pricing-page.d.ts +3 -0
- package/dist/designer/data/skills/pricing-page.d.ts.map +1 -0
- package/dist/designer/data/skills/pricing-page.js +76 -0
- package/dist/designer/data/skills/pricing-page.ts +79 -0
- package/dist/designer/data/skills/saas-landing.d.ts +3 -0
- package/dist/designer/data/skills/saas-landing.d.ts.map +1 -0
- package/dist/designer/data/skills/saas-landing.js +71 -0
- package/dist/designer/data/skills/saas-landing.ts +74 -0
- package/dist/designer/data/skills/slide-deck.d.ts +3 -0
- package/dist/designer/data/skills/slide-deck.d.ts.map +1 -0
- package/dist/designer/data/skills/slide-deck.js +213 -0
- package/dist/designer/data/skills/slide-deck.ts +216 -0
- package/dist/designer/data/skills/social-carousel.d.ts +3 -0
- package/dist/designer/data/skills/social-carousel.d.ts.map +1 -0
- package/dist/designer/data/skills/social-carousel.js +135 -0
- package/dist/designer/data/skills/social-carousel.ts +138 -0
- package/dist/designer/data/skills/web-prototype.d.ts +3 -0
- package/dist/designer/data/skills/web-prototype.d.ts.map +1 -0
- package/dist/designer/data/skills/web-prototype.js +159 -0
- package/dist/designer/data/skills/web-prototype.ts +162 -0
- package/dist/designer/skills.d.ts +4 -10
- package/dist/designer/skills.d.ts.map +1 -1
- package/dist/designer/skills.js +2 -1643
- package/dist/extensions/wizard/index.js +9 -1
- package/dist/generated/parser/ast/nodes.d.ts +115 -0
- package/dist/generated/parser/ast/nodes.d.ts.map +1 -0
- package/dist/generated/parser/ast/nodes.js +8 -0
- package/dist/generated/parser/lexer/lexer.d.ts +28 -0
- package/dist/generated/parser/lexer/lexer.d.ts.map +1 -0
- package/dist/generated/parser/{lexer.js → lexer/lexer.js} +1 -180
- package/dist/generated/parser/{lexer.d.ts → lexer/tokens.d.ts} +5 -24
- package/dist/generated/parser/lexer/tokens.d.ts.map +1 -0
- package/dist/generated/parser/lexer/tokens.js +187 -0
- package/dist/generated/parser/mod.d.ts +5 -7
- package/dist/generated/parser/mod.d.ts.map +1 -1
- package/dist/generated/parser/mod.js +2 -1
- package/dist/generated/parser/parser/cursor.d.ts +47 -0
- package/dist/generated/parser/parser/cursor.d.ts.map +1 -0
- package/dist/generated/parser/parser/cursor.js +12 -0
- package/dist/generated/parser/parser/definitions.d.ts +16 -0
- package/dist/generated/parser/parser/definitions.d.ts.map +1 -0
- package/dist/generated/parser/parser/definitions.js +353 -0
- package/dist/generated/parser/parser/expressions.d.ts +17 -0
- package/dist/generated/parser/parser/expressions.d.ts.map +1 -0
- package/dist/generated/parser/parser/expressions.js +165 -0
- package/dist/generated/parser/parser.d.ts +18 -133
- package/dist/generated/parser/parser.d.ts.map +1 -1
- package/dist/generated/parser/parser.js +9 -505
- package/dist/generated/parser/tokenizer.d.ts +1 -2
- package/dist/generated/parser/tokenizer.d.ts.map +1 -1
- package/dist/generated/parser/tokenizer.js +2 -1
- package/dist/generated/parser/validator.d.ts +1 -1
- package/dist/generated/parser/validator.d.ts.map +1 -1
- package/dist/generated/zeus/const.d.ts.map +1 -1
- package/dist/generated/zeus/const.js +21 -0
- package/dist/generated/zeus/index.d.ts +98 -0
- package/dist/generated/zeus/index.d.ts.map +1 -1
- package/dist/mcp/glimpse-ui.js +9 -1
- package/dist/relay/dispatcher.d.ts +11 -104
- package/dist/relay/dispatcher.d.ts.map +1 -1
- package/dist/relay/dispatcher.js +10 -1130
- package/dist/relay/registration.d.ts +10 -2
- package/dist/relay/registration.d.ts.map +1 -1
- package/dist/relay/registration.js +32 -3
- package/dist/relay/rest.d.ts +31 -0
- package/dist/relay/rest.d.ts.map +1 -0
- package/dist/relay/rest.js +85 -0
- package/dist/relay/routing.d.ts +109 -0
- package/dist/relay/routing.d.ts.map +1 -0
- package/dist/relay/routing.js +669 -0
- package/dist/relay/wizard-login.d.ts +17 -0
- package/dist/relay/wizard-login.d.ts.map +1 -0
- package/dist/relay/wizard-login.js +419 -0
- package/dist/sdk/agent-core/agent-loop.d.ts +2 -9
- package/dist/sdk/agent-core/agent-loop.d.ts.map +1 -1
- package/dist/sdk/agent-core/agent-loop.js +4 -288
- package/dist/sdk/agent-core/tool-execution.d.ts +33 -0
- package/dist/sdk/agent-core/tool-execution.d.ts.map +1 -0
- package/dist/sdk/agent-core/tool-execution.js +300 -0
- package/dist/sdk/ai/env-api-keys.js +9 -1
- package/dist/sdk/ai/providers/openai/reasoning-replay.d.ts +48 -0
- package/dist/sdk/ai/providers/openai/reasoning-replay.d.ts.map +1 -0
- package/dist/sdk/ai/providers/openai/reasoning-replay.js +209 -0
- package/dist/sdk/ai/providers/openai-completions.d.ts.map +1 -1
- package/dist/sdk/ai/providers/openai-completions.js +1 -203
- package/dist/sdk/coding-agent/core/compaction/compaction.d.ts +6 -118
- package/dist/sdk/coding-agent/core/compaction/compaction.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/compaction/compaction.js +11 -733
- package/dist/sdk/coding-agent/core/compaction/cut-points.d.ts +58 -0
- package/dist/sdk/coding-agent/core/compaction/cut-points.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/compaction/cut-points.js +191 -0
- package/dist/sdk/coding-agent/core/compaction/dedupe.d.ts +28 -0
- package/dist/sdk/coding-agent/core/compaction/dedupe.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/compaction/dedupe.js +156 -0
- package/dist/sdk/coding-agent/core/compaction/summarize.d.ts +21 -0
- package/dist/sdk/coding-agent/core/compaction/summarize.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/compaction/summarize.js +181 -0
- package/dist/sdk/coding-agent/core/compaction/tokens.d.ts +47 -0
- package/dist/sdk/coding-agent/core/compaction/tokens.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/compaction/tokens.js +224 -0
- package/dist/sdk/coding-agent/core/extensions/session-events.d.ts +157 -0
- package/dist/sdk/coding-agent/core/extensions/session-events.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/extensions/session-events.js +13 -0
- package/dist/sdk/coding-agent/core/extensions/types.d.ts +6 -365
- package/dist/sdk/coding-agent/core/extensions/types.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/extensions/types.js +2 -10
- package/dist/sdk/coding-agent/core/extensions/ui-types.d.ts +219 -0
- package/dist/sdk/coding-agent/core/extensions/ui-types.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/extensions/ui-types.js +4 -0
- package/dist/sdk/coding-agent/core/package/default-package-manager.d.ts +115 -0
- package/dist/sdk/coding-agent/core/package/default-package-manager.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/package/default-package-manager.js +1184 -0
- package/dist/sdk/coding-agent/core/package/discovery.d.ts +20 -0
- package/dist/sdk/coding-agent/core/package/discovery.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/package/discovery.js +283 -0
- package/dist/sdk/coding-agent/core/package/ignore.d.ts +29 -0
- package/dist/sdk/coding-agent/core/package/ignore.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/package/ignore.js +235 -0
- package/dist/sdk/coding-agent/core/package/types.d.ts +128 -0
- package/dist/sdk/coding-agent/core/package/types.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/package/types.js +18 -0
- package/dist/sdk/coding-agent/core/package/update-check.d.ts +43 -0
- package/dist/sdk/coding-agent/core/package/update-check.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/package/update-check.js +253 -0
- package/dist/sdk/coding-agent/core/package-manager.d.ts +2 -188
- package/dist/sdk/coding-agent/core/package-manager.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/package-manager.js +1 -1940
- package/dist/sdk/coding-agent/core/session/migrate.d.ts +18 -0
- package/dist/sdk/coding-agent/core/session/migrate.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/session/migrate.js +78 -0
- package/dist/sdk/coding-agent/core/session/types.d.ts +165 -0
- package/dist/sdk/coding-agent/core/session/types.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/session/types.js +4 -0
- package/dist/sdk/coding-agent/core/session-manager.d.ts +3 -161
- package/dist/sdk/coding-agent/core/session-manager.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/session-manager.js +4 -72
- package/package.json +2 -2
- package/dist/generated/parser/lexer.d.ts.map +0 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
export const mobileApp = {
|
|
2
|
+
name: "mobile-app",
|
|
3
|
+
scenario: "design",
|
|
4
|
+
description: "Mobile app prototype. Phone-frame-contained HTML with iOS/Android patterns, touch targets, and native-feel interactions.",
|
|
5
|
+
outputKind: "html",
|
|
6
|
+
workflow: `# Mobile App Prototype Skill
|
|
7
|
+
|
|
8
|
+
Produce a mobile app prototype as a single HTML file. Phone-frame contained, touch-friendly, native-feel interactions.
|
|
9
|
+
|
|
10
|
+
## Phase 0 — Pre-flight
|
|
11
|
+
|
|
12
|
+
1. Read the design system for color tokens.
|
|
13
|
+
2. Determine: app name, screens needed (2-5), platform style (iOS or Material).
|
|
14
|
+
3. Vocalize: "I'll build [app name] with [N] screens: [screen names]. [iOS/Material] patterns."
|
|
15
|
+
|
|
16
|
+
## Phase 1 — Shell with Phone Frame
|
|
17
|
+
|
|
18
|
+
Create \`app.html\` with a phone frame wrapper:
|
|
19
|
+
|
|
20
|
+
\`\`\`html
|
|
21
|
+
<!doctype html>
|
|
22
|
+
<html lang="en">
|
|
23
|
+
<head>
|
|
24
|
+
<meta charset="utf-8">
|
|
25
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
26
|
+
<title>App Name</title>
|
|
27
|
+
<style>
|
|
28
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; }
|
|
29
|
+
|
|
30
|
+
:root {
|
|
31
|
+
--phone-w: 390px;
|
|
32
|
+
--phone-h: 844px;
|
|
33
|
+
--phone-radius: 44px;
|
|
34
|
+
--safe-top: 54px;
|
|
35
|
+
--safe-bottom: 34px;
|
|
36
|
+
/* Design system tokens */
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
body {
|
|
40
|
+
display: flex;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
align-items: center;
|
|
43
|
+
min-height: 100vh;
|
|
44
|
+
background: #f0f0f0;
|
|
45
|
+
font-family: -apple-system, "SF Pro Text", "Inter", sans-serif;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.phone-frame {
|
|
49
|
+
width: var(--phone-w);
|
|
50
|
+
height: var(--phone-h);
|
|
51
|
+
background: var(--color-bg-primary);
|
|
52
|
+
border-radius: var(--phone-radius);
|
|
53
|
+
overflow: hidden;
|
|
54
|
+
position: relative;
|
|
55
|
+
box-shadow: 0 0 0 8px #1a1a1a, 0 0 0 10px #333, 0 20px 60px rgba(0,0,0,0.3);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.status-bar {
|
|
59
|
+
height: var(--safe-top);
|
|
60
|
+
display: flex;
|
|
61
|
+
justify-content: space-between;
|
|
62
|
+
align-items: center;
|
|
63
|
+
padding: 0 24px;
|
|
64
|
+
font-size: 14px;
|
|
65
|
+
font-weight: 600;
|
|
66
|
+
background: var(--color-bg-primary);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.screen {
|
|
70
|
+
position: absolute;
|
|
71
|
+
top: var(--safe-top);
|
|
72
|
+
left: 0;
|
|
73
|
+
right: 0;
|
|
74
|
+
bottom: var(--safe-bottom);
|
|
75
|
+
display: none;
|
|
76
|
+
flex-direction: column;
|
|
77
|
+
overflow-y: auto;
|
|
78
|
+
-webkit-overflow-scrolling: touch;
|
|
79
|
+
}
|
|
80
|
+
.screen.active { display: flex; }
|
|
81
|
+
|
|
82
|
+
.bottom-nav {
|
|
83
|
+
position: absolute;
|
|
84
|
+
bottom: 0;
|
|
85
|
+
left: 0;
|
|
86
|
+
right: 0;
|
|
87
|
+
height: var(--safe-bottom);
|
|
88
|
+
display: flex;
|
|
89
|
+
border-top: 1px solid var(--color-border);
|
|
90
|
+
background: var(--color-bg-surface, var(--color-bg-primary));
|
|
91
|
+
}
|
|
92
|
+
.nav-item {
|
|
93
|
+
flex: 1;
|
|
94
|
+
display: flex;
|
|
95
|
+
flex-direction: column;
|
|
96
|
+
align-items: center;
|
|
97
|
+
justify-content: center;
|
|
98
|
+
gap: 2px;
|
|
99
|
+
font-size: 10px;
|
|
100
|
+
color: var(--color-text-secondary);
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
user-select: none;
|
|
103
|
+
}
|
|
104
|
+
.nav-item.active { color: var(--color-accent); }
|
|
105
|
+
.nav-icon { font-size: 22px; line-height: 1; }
|
|
106
|
+
</style>
|
|
107
|
+
</head>
|
|
108
|
+
<body>
|
|
109
|
+
<div class="phone-frame">
|
|
110
|
+
<div class="status-bar">
|
|
111
|
+
<span>9:41</span>
|
|
112
|
+
<span>●●●○ WiFi ▮▮▮</span>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div class="screen active" id="screen-home"><!-- Home content --></div>
|
|
116
|
+
<div class="screen" id="screen-detail"><!-- Detail content --></div>
|
|
117
|
+
<div class="screen" id="screen-settings"><!-- Settings content --></div>
|
|
118
|
+
|
|
119
|
+
<div class="bottom-nav">
|
|
120
|
+
<div class="nav-item active" onclick="showScreen('home')">
|
|
121
|
+
<span class="nav-icon">🏠</span>Home
|
|
122
|
+
</div>
|
|
123
|
+
<div class="nav-item" onclick="showScreen('detail')">
|
|
124
|
+
<span class="nav-icon">🔍</span>Search
|
|
125
|
+
</div>
|
|
126
|
+
<div class="nav-item" onclick="showScreen('settings')">
|
|
127
|
+
<span class="nav-icon">👤</span>Profile
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<script>
|
|
133
|
+
function showScreen(id) {
|
|
134
|
+
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
|
|
135
|
+
document.getElementById('screen-' + id).classList.add('active');
|
|
136
|
+
document.querySelectorAll('.nav-item').forEach((n, i) => {
|
|
137
|
+
n.classList.toggle('active', n.textContent.trim().toLowerCase().includes(id));
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
</script>
|
|
141
|
+
</body>
|
|
142
|
+
</html>
|
|
143
|
+
\`\`\`
|
|
144
|
+
|
|
145
|
+
## Phase 2 — Component Patterns
|
|
146
|
+
|
|
147
|
+
### List Item (44px minimum tap target)
|
|
148
|
+
\`\`\`css
|
|
149
|
+
.list-item {
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
padding: 12px 16px;
|
|
153
|
+
min-height: 44px;
|
|
154
|
+
gap: 12px;
|
|
155
|
+
border-bottom: 0.5px solid var(--color-border);
|
|
156
|
+
cursor: pointer;
|
|
157
|
+
}
|
|
158
|
+
.list-item:active { background: var(--color-bg-hover, rgba(0,0,0,0.04)); }
|
|
159
|
+
.list-item-icon { width: 40px; height: 40px; border-radius: 10px; background: var(--color-accent); display: flex; align-items: center; justify-content: center; color: white; font-size: 18px; }
|
|
160
|
+
.list-item-content { flex: 1; }
|
|
161
|
+
.list-item-title { font-size: 16px; font-weight: 500; }
|
|
162
|
+
.list-item-subtitle { font-size: 14px; color: var(--color-text-secondary); margin-top: 2px; }
|
|
163
|
+
.list-item-trailing { color: var(--color-text-secondary); font-size: 14px; }
|
|
164
|
+
\`\`\`
|
|
165
|
+
|
|
166
|
+
### Card
|
|
167
|
+
\`\`\`css
|
|
168
|
+
.card {
|
|
169
|
+
background: var(--color-bg-surface, #fff);
|
|
170
|
+
border-radius: 16px;
|
|
171
|
+
padding: 16px;
|
|
172
|
+
margin: 8px 16px;
|
|
173
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
|
|
174
|
+
}
|
|
175
|
+
.card-image { width: 100%; height: 180px; border-radius: 12px; object-fit: cover; background: var(--color-bg-secondary); }
|
|
176
|
+
.card-title { font-size: 17px; font-weight: 600; margin: 12px 0 4px; }
|
|
177
|
+
.card-subtitle { font-size: 14px; color: var(--color-text-secondary); }
|
|
178
|
+
\`\`\`
|
|
179
|
+
|
|
180
|
+
### Input Field
|
|
181
|
+
\`\`\`css
|
|
182
|
+
.input-group { padding: 8px 16px; }
|
|
183
|
+
.input-label { font-size: 13px; color: var(--color-text-secondary); margin-bottom: 4px; display: block; }
|
|
184
|
+
.input-field {
|
|
185
|
+
width: 100%;
|
|
186
|
+
height: 44px;
|
|
187
|
+
padding: 0 12px;
|
|
188
|
+
border: 1px solid var(--color-border);
|
|
189
|
+
border-radius: 10px;
|
|
190
|
+
font-size: 16px;
|
|
191
|
+
background: var(--color-bg-secondary, #f5f5f5);
|
|
192
|
+
outline: none;
|
|
193
|
+
}
|
|
194
|
+
.input-field:focus { border-color: var(--color-accent); }
|
|
195
|
+
\`\`\`
|
|
196
|
+
|
|
197
|
+
### Button
|
|
198
|
+
\`\`\`css
|
|
199
|
+
.btn {
|
|
200
|
+
display: flex;
|
|
201
|
+
align-items: center;
|
|
202
|
+
justify-content: center;
|
|
203
|
+
height: 50px;
|
|
204
|
+
padding: 0 24px;
|
|
205
|
+
border-radius: 14px;
|
|
206
|
+
font-size: 17px;
|
|
207
|
+
font-weight: 600;
|
|
208
|
+
border: none;
|
|
209
|
+
cursor: pointer;
|
|
210
|
+
margin: 8px 16px;
|
|
211
|
+
user-select: none;
|
|
212
|
+
}
|
|
213
|
+
.btn-primary { background: var(--color-accent); color: #fff; }
|
|
214
|
+
.btn-secondary { background: var(--color-bg-secondary, #f0f0f0); color: var(--color-text-primary); }
|
|
215
|
+
.btn:active { opacity: 0.8; transform: scale(0.98); }
|
|
216
|
+
\`\`\`
|
|
217
|
+
|
|
218
|
+
## Phase 3 — Mobile-Specific Rules
|
|
219
|
+
|
|
220
|
+
- Minimum touch target: 44×44px
|
|
221
|
+
- Font sizes: 13px (captions), 15px (body), 17px (headlines), 22px (titles), 28px (hero)
|
|
222
|
+
- Padding: 16px horizontal standard, 8-16px card margins
|
|
223
|
+
- Never use hover effects — use :active for tap feedback
|
|
224
|
+
- Scrollable content uses \`overflow-y: auto; -webkit-overflow-scrolling: touch;\`
|
|
225
|
+
- Status bar: 54px height standard, dark or light based on design system
|
|
226
|
+
- Bottom safe area: 34px for home indicator
|
|
227
|
+
- Images: use \`object-fit: cover\` with fixed aspect ratios, gradient placeholders
|
|
228
|
+
- No hamburger menus — use tab bar navigation (3-5 items)`,
|
|
229
|
+
};
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import type { DesignSkill } from "./design-skill.js";
|
|
2
|
+
|
|
3
|
+
export const mobileApp: DesignSkill = {
|
|
4
|
+
name: "mobile-app",
|
|
5
|
+
scenario: "design",
|
|
6
|
+
description:
|
|
7
|
+
"Mobile app prototype. Phone-frame-contained HTML with iOS/Android patterns, touch targets, and native-feel interactions.",
|
|
8
|
+
outputKind: "html",
|
|
9
|
+
workflow: `# Mobile App Prototype Skill
|
|
10
|
+
|
|
11
|
+
Produce a mobile app prototype as a single HTML file. Phone-frame contained, touch-friendly, native-feel interactions.
|
|
12
|
+
|
|
13
|
+
## Phase 0 — Pre-flight
|
|
14
|
+
|
|
15
|
+
1. Read the design system for color tokens.
|
|
16
|
+
2. Determine: app name, screens needed (2-5), platform style (iOS or Material).
|
|
17
|
+
3. Vocalize: "I'll build [app name] with [N] screens: [screen names]. [iOS/Material] patterns."
|
|
18
|
+
|
|
19
|
+
## Phase 1 — Shell with Phone Frame
|
|
20
|
+
|
|
21
|
+
Create \`app.html\` with a phone frame wrapper:
|
|
22
|
+
|
|
23
|
+
\`\`\`html
|
|
24
|
+
<!doctype html>
|
|
25
|
+
<html lang="en">
|
|
26
|
+
<head>
|
|
27
|
+
<meta charset="utf-8">
|
|
28
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
29
|
+
<title>App Name</title>
|
|
30
|
+
<style>
|
|
31
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; }
|
|
32
|
+
|
|
33
|
+
:root {
|
|
34
|
+
--phone-w: 390px;
|
|
35
|
+
--phone-h: 844px;
|
|
36
|
+
--phone-radius: 44px;
|
|
37
|
+
--safe-top: 54px;
|
|
38
|
+
--safe-bottom: 34px;
|
|
39
|
+
/* Design system tokens */
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
body {
|
|
43
|
+
display: flex;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
align-items: center;
|
|
46
|
+
min-height: 100vh;
|
|
47
|
+
background: #f0f0f0;
|
|
48
|
+
font-family: -apple-system, "SF Pro Text", "Inter", sans-serif;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.phone-frame {
|
|
52
|
+
width: var(--phone-w);
|
|
53
|
+
height: var(--phone-h);
|
|
54
|
+
background: var(--color-bg-primary);
|
|
55
|
+
border-radius: var(--phone-radius);
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
position: relative;
|
|
58
|
+
box-shadow: 0 0 0 8px #1a1a1a, 0 0 0 10px #333, 0 20px 60px rgba(0,0,0,0.3);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.status-bar {
|
|
62
|
+
height: var(--safe-top);
|
|
63
|
+
display: flex;
|
|
64
|
+
justify-content: space-between;
|
|
65
|
+
align-items: center;
|
|
66
|
+
padding: 0 24px;
|
|
67
|
+
font-size: 14px;
|
|
68
|
+
font-weight: 600;
|
|
69
|
+
background: var(--color-bg-primary);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.screen {
|
|
73
|
+
position: absolute;
|
|
74
|
+
top: var(--safe-top);
|
|
75
|
+
left: 0;
|
|
76
|
+
right: 0;
|
|
77
|
+
bottom: var(--safe-bottom);
|
|
78
|
+
display: none;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
overflow-y: auto;
|
|
81
|
+
-webkit-overflow-scrolling: touch;
|
|
82
|
+
}
|
|
83
|
+
.screen.active { display: flex; }
|
|
84
|
+
|
|
85
|
+
.bottom-nav {
|
|
86
|
+
position: absolute;
|
|
87
|
+
bottom: 0;
|
|
88
|
+
left: 0;
|
|
89
|
+
right: 0;
|
|
90
|
+
height: var(--safe-bottom);
|
|
91
|
+
display: flex;
|
|
92
|
+
border-top: 1px solid var(--color-border);
|
|
93
|
+
background: var(--color-bg-surface, var(--color-bg-primary));
|
|
94
|
+
}
|
|
95
|
+
.nav-item {
|
|
96
|
+
flex: 1;
|
|
97
|
+
display: flex;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
align-items: center;
|
|
100
|
+
justify-content: center;
|
|
101
|
+
gap: 2px;
|
|
102
|
+
font-size: 10px;
|
|
103
|
+
color: var(--color-text-secondary);
|
|
104
|
+
cursor: pointer;
|
|
105
|
+
user-select: none;
|
|
106
|
+
}
|
|
107
|
+
.nav-item.active { color: var(--color-accent); }
|
|
108
|
+
.nav-icon { font-size: 22px; line-height: 1; }
|
|
109
|
+
</style>
|
|
110
|
+
</head>
|
|
111
|
+
<body>
|
|
112
|
+
<div class="phone-frame">
|
|
113
|
+
<div class="status-bar">
|
|
114
|
+
<span>9:41</span>
|
|
115
|
+
<span>●●●○ WiFi ▮▮▮</span>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div class="screen active" id="screen-home"><!-- Home content --></div>
|
|
119
|
+
<div class="screen" id="screen-detail"><!-- Detail content --></div>
|
|
120
|
+
<div class="screen" id="screen-settings"><!-- Settings content --></div>
|
|
121
|
+
|
|
122
|
+
<div class="bottom-nav">
|
|
123
|
+
<div class="nav-item active" onclick="showScreen('home')">
|
|
124
|
+
<span class="nav-icon">🏠</span>Home
|
|
125
|
+
</div>
|
|
126
|
+
<div class="nav-item" onclick="showScreen('detail')">
|
|
127
|
+
<span class="nav-icon">🔍</span>Search
|
|
128
|
+
</div>
|
|
129
|
+
<div class="nav-item" onclick="showScreen('settings')">
|
|
130
|
+
<span class="nav-icon">👤</span>Profile
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<script>
|
|
136
|
+
function showScreen(id) {
|
|
137
|
+
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
|
|
138
|
+
document.getElementById('screen-' + id).classList.add('active');
|
|
139
|
+
document.querySelectorAll('.nav-item').forEach((n, i) => {
|
|
140
|
+
n.classList.toggle('active', n.textContent.trim().toLowerCase().includes(id));
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
</script>
|
|
144
|
+
</body>
|
|
145
|
+
</html>
|
|
146
|
+
\`\`\`
|
|
147
|
+
|
|
148
|
+
## Phase 2 — Component Patterns
|
|
149
|
+
|
|
150
|
+
### List Item (44px minimum tap target)
|
|
151
|
+
\`\`\`css
|
|
152
|
+
.list-item {
|
|
153
|
+
display: flex;
|
|
154
|
+
align-items: center;
|
|
155
|
+
padding: 12px 16px;
|
|
156
|
+
min-height: 44px;
|
|
157
|
+
gap: 12px;
|
|
158
|
+
border-bottom: 0.5px solid var(--color-border);
|
|
159
|
+
cursor: pointer;
|
|
160
|
+
}
|
|
161
|
+
.list-item:active { background: var(--color-bg-hover, rgba(0,0,0,0.04)); }
|
|
162
|
+
.list-item-icon { width: 40px; height: 40px; border-radius: 10px; background: var(--color-accent); display: flex; align-items: center; justify-content: center; color: white; font-size: 18px; }
|
|
163
|
+
.list-item-content { flex: 1; }
|
|
164
|
+
.list-item-title { font-size: 16px; font-weight: 500; }
|
|
165
|
+
.list-item-subtitle { font-size: 14px; color: var(--color-text-secondary); margin-top: 2px; }
|
|
166
|
+
.list-item-trailing { color: var(--color-text-secondary); font-size: 14px; }
|
|
167
|
+
\`\`\`
|
|
168
|
+
|
|
169
|
+
### Card
|
|
170
|
+
\`\`\`css
|
|
171
|
+
.card {
|
|
172
|
+
background: var(--color-bg-surface, #fff);
|
|
173
|
+
border-radius: 16px;
|
|
174
|
+
padding: 16px;
|
|
175
|
+
margin: 8px 16px;
|
|
176
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
|
|
177
|
+
}
|
|
178
|
+
.card-image { width: 100%; height: 180px; border-radius: 12px; object-fit: cover; background: var(--color-bg-secondary); }
|
|
179
|
+
.card-title { font-size: 17px; font-weight: 600; margin: 12px 0 4px; }
|
|
180
|
+
.card-subtitle { font-size: 14px; color: var(--color-text-secondary); }
|
|
181
|
+
\`\`\`
|
|
182
|
+
|
|
183
|
+
### Input Field
|
|
184
|
+
\`\`\`css
|
|
185
|
+
.input-group { padding: 8px 16px; }
|
|
186
|
+
.input-label { font-size: 13px; color: var(--color-text-secondary); margin-bottom: 4px; display: block; }
|
|
187
|
+
.input-field {
|
|
188
|
+
width: 100%;
|
|
189
|
+
height: 44px;
|
|
190
|
+
padding: 0 12px;
|
|
191
|
+
border: 1px solid var(--color-border);
|
|
192
|
+
border-radius: 10px;
|
|
193
|
+
font-size: 16px;
|
|
194
|
+
background: var(--color-bg-secondary, #f5f5f5);
|
|
195
|
+
outline: none;
|
|
196
|
+
}
|
|
197
|
+
.input-field:focus { border-color: var(--color-accent); }
|
|
198
|
+
\`\`\`
|
|
199
|
+
|
|
200
|
+
### Button
|
|
201
|
+
\`\`\`css
|
|
202
|
+
.btn {
|
|
203
|
+
display: flex;
|
|
204
|
+
align-items: center;
|
|
205
|
+
justify-content: center;
|
|
206
|
+
height: 50px;
|
|
207
|
+
padding: 0 24px;
|
|
208
|
+
border-radius: 14px;
|
|
209
|
+
font-size: 17px;
|
|
210
|
+
font-weight: 600;
|
|
211
|
+
border: none;
|
|
212
|
+
cursor: pointer;
|
|
213
|
+
margin: 8px 16px;
|
|
214
|
+
user-select: none;
|
|
215
|
+
}
|
|
216
|
+
.btn-primary { background: var(--color-accent); color: #fff; }
|
|
217
|
+
.btn-secondary { background: var(--color-bg-secondary, #f0f0f0); color: var(--color-text-primary); }
|
|
218
|
+
.btn:active { opacity: 0.8; transform: scale(0.98); }
|
|
219
|
+
\`\`\`
|
|
220
|
+
|
|
221
|
+
## Phase 3 — Mobile-Specific Rules
|
|
222
|
+
|
|
223
|
+
- Minimum touch target: 44×44px
|
|
224
|
+
- Font sizes: 13px (captions), 15px (body), 17px (headlines), 22px (titles), 28px (hero)
|
|
225
|
+
- Padding: 16px horizontal standard, 8-16px card margins
|
|
226
|
+
- Never use hover effects — use :active for tap feedback
|
|
227
|
+
- Scrollable content uses \`overflow-y: auto; -webkit-overflow-scrolling: touch;\`
|
|
228
|
+
- Status bar: 54px height standard, dark or light based on design system
|
|
229
|
+
- Bottom safe area: 34px for home indicator
|
|
230
|
+
- Images: use \`object-fit: cover\` with fixed aspect ratios, gradient placeholders
|
|
231
|
+
- No hamburger menus — use tab bar navigation (3-5 items)`,
|
|
232
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"motion-frames.d.ts","sourceRoot":"","sources":["../../../../src/designer/data/skills/motion-frames.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,YAAY,EAAE,WAyHxB,CAAC"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export const motionFrames = {
|
|
2
|
+
name: "motion-frames",
|
|
3
|
+
scenario: "creative",
|
|
4
|
+
description: "CSS animation and motion design frames. Keyframe-driven animations, scroll-triggered reveals, staggered lists, loading states, and page transitions — all CSS-only where possible.",
|
|
5
|
+
outputKind: "html",
|
|
6
|
+
workflow: `# Motion Frames Skill
|
|
7
|
+
|
|
8
|
+
Produce a motion design showcase as a single HTML file. CSS keyframe animations, scroll-triggered effects, and subtle micro-interactions — no JavaScript libraries.
|
|
9
|
+
|
|
10
|
+
## Phase 1 — Animation Vocabulary
|
|
11
|
+
|
|
12
|
+
### Entrance Animations
|
|
13
|
+
\`\`\`css
|
|
14
|
+
/* Fade up */
|
|
15
|
+
@keyframes fadeUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
|
|
16
|
+
|
|
17
|
+
/* Scale in */
|
|
18
|
+
@keyframes scaleIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }
|
|
19
|
+
|
|
20
|
+
/* Slide from left */
|
|
21
|
+
@keyframes slideLeft { from { opacity: 0; transform: translateX(-30px); } to { opacity: 1; transform: translateX(0); } }
|
|
22
|
+
|
|
23
|
+
/* Reveal by clip-path */
|
|
24
|
+
@keyframes clipReveal { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
|
|
25
|
+
\`\`\`
|
|
26
|
+
|
|
27
|
+
### Scroll-Triggered Reveals
|
|
28
|
+
\`\`\`css
|
|
29
|
+
/* Use scroll-driven animations (modern browsers) */
|
|
30
|
+
.reveal {
|
|
31
|
+
animation: fadeUp 0.6s ease-out;
|
|
32
|
+
animation-timeline: view();
|
|
33
|
+
animation-range: entry 20% cover 40%;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Fallback: use Intersection Observer pattern in a small script */
|
|
37
|
+
.reveal-on-scroll { opacity: 0; transform: translateY(24px); transition: opacity 0.6s ease-out, transform 0.6s ease-out; }
|
|
38
|
+
.reveal-on-scroll.visible { opacity: 1; transform: translateY(0); }
|
|
39
|
+
\`\`\`
|
|
40
|
+
|
|
41
|
+
### Staggered Lists
|
|
42
|
+
\`\`\`css
|
|
43
|
+
.stagger-list > * { opacity: 0; animation: fadeUp 0.4s ease-out forwards; }
|
|
44
|
+
.stagger-list > *:nth-child(1) { animation-delay: 0ms; }
|
|
45
|
+
.stagger-list > *:nth-child(2) { animation-delay: 80ms; }
|
|
46
|
+
.stagger-list > *:nth-child(3) { animation-delay: 160ms; }
|
|
47
|
+
.stagger-list > *:nth-child(4) { animation-delay: 240ms; }
|
|
48
|
+
.stagger-list > *:nth-child(5) { animation-delay: 320ms; }
|
|
49
|
+
.stagger-list > *:nth-child(6) { animation-delay: 400ms; }
|
|
50
|
+
/* Continue pattern: delay = (n-1) * 80ms up to n=20 */
|
|
51
|
+
\`\`\`
|
|
52
|
+
|
|
53
|
+
### Loading States
|
|
54
|
+
\`\`\`css
|
|
55
|
+
/* Spinner */
|
|
56
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
57
|
+
.spinner { width: 24px; height: 24px; border: 3px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.6s linear infinite; }
|
|
58
|
+
|
|
59
|
+
/* Skeleton pulse */
|
|
60
|
+
@keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } }
|
|
61
|
+
.skeleton { background: linear-gradient(90deg, var(--surface) 25%, color-mix(in oklab, var(--surface) 50%, var(--bg)) 50%, var(--surface) 75%); background-size: 200% 100%; animation: shimmer 1.5s ease-in-out infinite; border-radius: 4px; }
|
|
62
|
+
|
|
63
|
+
/* Progress bar */
|
|
64
|
+
@keyframes progress { from { width: 0%; } to { width: 100%; } }
|
|
65
|
+
.progress-bar { height: 4px; background: var(--surface); border-radius: 2px; overflow: hidden; }
|
|
66
|
+
.progress-bar-fill { height: 100%; background: var(--accent); border-radius: 2px; animation: progress 2s ease-out forwards; }
|
|
67
|
+
\`\`\`
|
|
68
|
+
|
|
69
|
+
### Hover Micro-Interactions
|
|
70
|
+
\`\`\`css
|
|
71
|
+
/* Subtle card lift */
|
|
72
|
+
.card-hover { transition: transform 0.2s ease, box-shadow 0.2s ease; }
|
|
73
|
+
.card-hover:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.1); }
|
|
74
|
+
|
|
75
|
+
/* Button press */
|
|
76
|
+
.btn-press { transition: transform 0.1s ease; }
|
|
77
|
+
.btn-press:active { transform: scale(0.97); }
|
|
78
|
+
|
|
79
|
+
/* Link underline slide */
|
|
80
|
+
.link-slide { position: relative; text-decoration: none; }
|
|
81
|
+
.link-slide::after { content: ""; position: absolute; bottom: -1px; left: 0; width: 0; height: 1.5px; background: var(--accent); transition: width 0.3s ease; }
|
|
82
|
+
.link-slide:hover::after { width: 100%; }
|
|
83
|
+
|
|
84
|
+
/* Image zoom */
|
|
85
|
+
.img-zoom { overflow: hidden; border-radius: 8px; }
|
|
86
|
+
.img-zoom img { transition: transform 0.3s ease; }
|
|
87
|
+
.img-zoom:hover img { transform: scale(1.05); }
|
|
88
|
+
\`\`\`
|
|
89
|
+
|
|
90
|
+
### Page Transitions (View Transitions API)
|
|
91
|
+
\`\`\`css
|
|
92
|
+
/* Add to :root for cross-fade transitions */
|
|
93
|
+
::view-transition-old(root),
|
|
94
|
+
::view-transition-new(root) {
|
|
95
|
+
animation-duration: 0.4s;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Named transitions for specific elements */
|
|
99
|
+
.hero-title { view-transition-name: hero-title; }
|
|
100
|
+
.hero-image { view-transition-name: hero-image; }
|
|
101
|
+
\`\`\`
|
|
102
|
+
|
|
103
|
+
## Phase 2 — Showcase Layout
|
|
104
|
+
|
|
105
|
+
Build a single HTML page demonstrating each animation category:
|
|
106
|
+
1. **Entrance section** — cards/stats that animate in on load
|
|
107
|
+
2. **Scroll reveal section** — content that appears as you scroll
|
|
108
|
+
3. **Staggered list** — feature list with cascading reveal
|
|
109
|
+
4. **Loading section** — skeleton screens next to real content
|
|
110
|
+
5. **Hover gallery** — cards with different hover treatments
|
|
111
|
+
6. **Interactive section** — buttons and links with micro-interactions
|
|
112
|
+
|
|
113
|
+
## Phase 3 — Motion Design Rules
|
|
114
|
+
- **Duration**: 150-400ms for micro-interactions; 400-800ms for entrances; DON'T use values above 1s
|
|
115
|
+
- **Easing**: ease-out for entrances (fast start, settle gracefully); ease-in-out for continuous animations
|
|
116
|
+
- **Stagger**: 60-100ms between children; maximum 20 items in a stagger
|
|
117
|
+
- **Performance**: animate transform and opacity only (no width/height/margin animations)
|
|
118
|
+
- **Respect reduced motion**: wrap animations in @media (prefers-reduced-motion: no-preference)
|
|
119
|
+
- **No animation on every element** — pick 2-3 key moments per page
|
|
120
|
+
- **Animation should communicate** — loading state, new content arriving, affordance — not just decoration`,
|
|
121
|
+
};
|