zelune 0.0.0-stage → 1.4.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/CHANGELOG.md +57 -0
- package/DESIGN.md +90 -0
- package/PRODUCT.md +31 -0
- package/README.md +63 -2
- package/assets/logo.svg +8 -0
- package/bin/cli.mjs +243 -0
- package/index.html +18 -0
- package/mcp/server.ts +140 -0
- package/mcp_config.json +8 -0
- package/package.json +77 -4
- package/plugin.json +12 -0
- package/plugins/viteRnSourceInject.ts +117 -0
- package/plugins/viteVirtualScreensPlugin.ts +85 -0
- package/rules/AGENTS.md +21 -0
- package/skills/rn-canvas/SKILL.md +33 -0
- package/src/canvas/CanvasApp.tsx +1203 -0
- package/src/canvas/FlowArrowsLayer.tsx +197 -0
- package/src/canvas/InspectorPanel.tsx +979 -0
- package/src/canvas/ScreenArtboard.tsx +451 -0
- package/src/canvas/types.ts +23 -0
- package/src/main.tsx +10 -0
- package/src/runtime/MockNavigationContext.tsx +199 -0
- package/src/runtime/ScreenErrorBoundary.tsx +86 -0
- package/src/screens/CheckoutScreen.tsx +229 -0
- package/src/screens/HomeScreen.tsx +288 -0
- package/src/screens/LoginScreen.tsx +176 -0
- package/src/screens/ProductDetailScreen.tsx +234 -0
- package/src/screens/ProfileScreen.tsx +172 -0
- package/src/screens/index.ts +1 -0
- package/src/server/apiMiddleware.ts +154 -0
- package/src/server/astEngine.ts +877 -0
- package/src/styles.css +298 -0
- package/src/vite-env.d.ts +7 -0
- package/tsconfig.json +23 -0
- package/vite.config.ts +81 -0
package/src/styles.css
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
/* Opt-in to intrinsic keyword size animations (modern-web-guidance: animate-to-intrinsic-sizes) */
|
|
3
|
+
interpolate-size: allow-keywords;
|
|
4
|
+
|
|
5
|
+
/* Typography Tokens (pbakaus/impeccable + leonxlnx/taste-skill) */
|
|
6
|
+
--font-sans: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
7
|
+
--font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
8
|
+
|
|
9
|
+
/* Tinted Obsidian Surface Palette (No pure black/untinted gray slop) */
|
|
10
|
+
--studio-canvas-bg: #08090c;
|
|
11
|
+
--studio-surface-1: #0d0f14;
|
|
12
|
+
--studio-surface-2: #13161e;
|
|
13
|
+
--studio-surface-3: #191d28;
|
|
14
|
+
--studio-border-hairline: rgba(255, 255, 255, 0.07);
|
|
15
|
+
--studio-border-subtle: #1e2330;
|
|
16
|
+
--studio-border-strong: #2a3142;
|
|
17
|
+
|
|
18
|
+
/* Text Hierarchy */
|
|
19
|
+
--studio-text-primary: #f1f5f9;
|
|
20
|
+
--studio-text-secondary: #94a3b8;
|
|
21
|
+
--studio-text-muted: #64748b;
|
|
22
|
+
|
|
23
|
+
/* Intentional Signal Accents */
|
|
24
|
+
--studio-accent-cyan: #38bdf8;
|
|
25
|
+
--studio-accent-indigo: #6366f1;
|
|
26
|
+
--studio-accent-emerald: #10b981;
|
|
27
|
+
--studio-accent-amber: #f59e0b;
|
|
28
|
+
|
|
29
|
+
/* Emil Kowalski Motion & Easing Tokens (emilkowalski/skills) */
|
|
30
|
+
--ease-out: cubic-bezier(0.23, 1, 0.32, 1);
|
|
31
|
+
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
|
|
32
|
+
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
|
33
|
+
--duration-press: 120ms;
|
|
34
|
+
--duration-micro: 160ms;
|
|
35
|
+
--duration-panel: 220ms;
|
|
36
|
+
--duration-camera: 380ms;
|
|
37
|
+
|
|
38
|
+
/* Parametric Taste Density Defaults (leonxlnx/taste-skill) */
|
|
39
|
+
--inspector-pad-compact: 12px;
|
|
40
|
+
--inspector-pad-spacious: 20px;
|
|
41
|
+
--inspector-gap-compact: 14px;
|
|
42
|
+
--inspector-gap-spacious: 22px;
|
|
43
|
+
--control-py-compact: 5px;
|
|
44
|
+
--control-py-spacious: 8px;
|
|
45
|
+
--rail-item-py-compact: 7px;
|
|
46
|
+
--rail-item-py-spacious: 10px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
*,
|
|
50
|
+
*::before,
|
|
51
|
+
*::after {
|
|
52
|
+
box-sizing: border-box;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
html,
|
|
56
|
+
body,
|
|
57
|
+
#root {
|
|
58
|
+
margin: 0;
|
|
59
|
+
padding: 0;
|
|
60
|
+
width: 100%;
|
|
61
|
+
height: 100%;
|
|
62
|
+
font-family: var(--font-sans);
|
|
63
|
+
background-color: var(--studio-canvas-bg);
|
|
64
|
+
color: var(--studio-text-primary);
|
|
65
|
+
-webkit-font-smoothing: antialiased;
|
|
66
|
+
overscroll-behavior: none;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Prevent numeric jitter on coordinates, zoom readouts, line numbers, and prices */
|
|
70
|
+
.tabular-nums {
|
|
71
|
+
font-variant-numeric: tabular-nums;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Targeted heading balance (modern-web-guidance: improve-text-layout-and-legibility) */
|
|
75
|
+
.balance-heading {
|
|
76
|
+
text-wrap: balance;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Precision architectural dot matrix on the infinite canvas */
|
|
80
|
+
.infinite-canvas-surface {
|
|
81
|
+
background-color: var(--studio-canvas-bg);
|
|
82
|
+
background-image: radial-gradient(rgba(148, 163, 184, 0.14) 1px, transparent 1px);
|
|
83
|
+
background-size: 24px 24px;
|
|
84
|
+
touch-action: none;
|
|
85
|
+
overscroll-behavior: none;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Smooth Collapsible Studio Side Panels (emilkowalski/skills --ease-out-expo) */
|
|
89
|
+
.zelune-collapsible-panel {
|
|
90
|
+
overflow: hidden;
|
|
91
|
+
flex-shrink: 0;
|
|
92
|
+
transition:
|
|
93
|
+
width var(--duration-panel) var(--ease-out-expo),
|
|
94
|
+
opacity var(--duration-micro) var(--ease-out),
|
|
95
|
+
border-color var(--duration-micro) var(--ease-out);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Icon-Only Toolbar Buttons that Expand to Reveal Text on Hover (animate-to-intrinsic-sizes) */
|
|
99
|
+
.zelune-icon-reveal-btn {
|
|
100
|
+
display: inline-flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
justify-content: center;
|
|
103
|
+
gap: 0px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.zelune-reveal-label {
|
|
107
|
+
display: inline-block;
|
|
108
|
+
inline-size: 0px;
|
|
109
|
+
max-inline-size: 0px;
|
|
110
|
+
opacity: 0;
|
|
111
|
+
overflow: hidden;
|
|
112
|
+
white-space: nowrap;
|
|
113
|
+
margin-inline-start: 0px;
|
|
114
|
+
transition:
|
|
115
|
+
inline-size var(--duration-panel) var(--ease-out-expo),
|
|
116
|
+
max-inline-size var(--duration-panel) var(--ease-out-expo),
|
|
117
|
+
opacity var(--duration-micro) var(--ease-out),
|
|
118
|
+
margin-inline-start var(--duration-panel) var(--ease-out-expo);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.zelune-icon-reveal-btn:hover .zelune-reveal-label,
|
|
122
|
+
.zelune-icon-reveal-btn:focus-visible .zelune-reveal-label {
|
|
123
|
+
inline-size: auto; /* Fallback for browsers without calc-size() */
|
|
124
|
+
inline-size: calc-size(max-content, size);
|
|
125
|
+
max-inline-size: 190px;
|
|
126
|
+
opacity: 1;
|
|
127
|
+
margin-inline-start: 6px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Tactile Studio Controls (emilkowalski/skills + individual-transform-properties) */
|
|
131
|
+
.zelune-interactive {
|
|
132
|
+
/* Identity transforms prevent stacking-context or z-index shifts on hover/active */
|
|
133
|
+
translate: 0px 0px;
|
|
134
|
+
rotate: 0deg;
|
|
135
|
+
scale: 1;
|
|
136
|
+
transition:
|
|
137
|
+
scale var(--duration-press) var(--ease-out),
|
|
138
|
+
background-color var(--duration-micro) var(--ease-out),
|
|
139
|
+
border-color var(--duration-micro) var(--ease-out),
|
|
140
|
+
color var(--duration-micro) var(--ease-out),
|
|
141
|
+
box-shadow var(--duration-micro) var(--ease-out);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.zelune-interactive:hover:not(:disabled) {
|
|
145
|
+
border-color: var(--studio-border-strong);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.zelune-interactive:active:not(:disabled) {
|
|
149
|
+
scale: 0.97;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.zelune-interactive:focus-visible {
|
|
153
|
+
outline: 1.5px solid var(--studio-accent-cyan);
|
|
154
|
+
outline-offset: 1px;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* Parametric Density Reactivity (modern-web-guidance: design-token-reactivity) */
|
|
158
|
+
.zelune-studio-root[data-density="compact"] {
|
|
159
|
+
--density: compact;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.zelune-studio-root[data-density="spacious"] {
|
|
163
|
+
--density: spacious;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
:where([data-density="compact"]) .zelune-inspector-body {
|
|
167
|
+
padding: var(--inspector-pad-compact);
|
|
168
|
+
gap: var(--inspector-gap-compact);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
:where([data-density="spacious"]) .zelune-inspector-body {
|
|
172
|
+
padding: var(--inspector-pad-spacious);
|
|
173
|
+
gap: var(--inspector-gap-spacious);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
:where([data-density="compact"]) .zelune-rail-item {
|
|
177
|
+
padding-top: var(--rail-item-py-compact);
|
|
178
|
+
padding-bottom: var(--rail-item-py-compact);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
:where([data-density="spacious"]) .zelune-rail-item {
|
|
182
|
+
padding-top: var(--rail-item-py-spacious);
|
|
183
|
+
padding-bottom: var(--rail-item-py-spacious);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
:where([data-density="compact"]) .zelune-input {
|
|
187
|
+
padding-top: var(--control-py-compact);
|
|
188
|
+
padding-bottom: var(--control-py-compact);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
:where([data-density="spacious"]) .zelune-input {
|
|
192
|
+
padding-top: var(--control-py-spacious);
|
|
193
|
+
padding-bottom: var(--control-py-spacious);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@container style(--density: compact) {
|
|
197
|
+
.zelune-inspector-body {
|
|
198
|
+
padding: var(--inspector-pad-compact);
|
|
199
|
+
gap: var(--inspector-gap-compact);
|
|
200
|
+
}
|
|
201
|
+
.zelune-rail-item {
|
|
202
|
+
padding-top: var(--rail-item-py-compact);
|
|
203
|
+
padding-bottom: var(--rail-item-py-compact);
|
|
204
|
+
}
|
|
205
|
+
.zelune-input {
|
|
206
|
+
padding-top: var(--control-py-compact);
|
|
207
|
+
padding-bottom: var(--control-py-compact);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@container style(--density: spacious) {
|
|
212
|
+
.zelune-inspector-body {
|
|
213
|
+
padding: var(--inspector-pad-spacious);
|
|
214
|
+
gap: var(--inspector-gap-spacious);
|
|
215
|
+
}
|
|
216
|
+
.zelune-rail-item {
|
|
217
|
+
padding-top: var(--rail-item-py-spacious);
|
|
218
|
+
padding-bottom: var(--rail-item-py-spacious);
|
|
219
|
+
}
|
|
220
|
+
.zelune-input {
|
|
221
|
+
padding-top: var(--control-py-spacious);
|
|
222
|
+
padding-bottom: var(--control-py-spacious);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/* Custom Scrollbar Styling (modern-web-guidance: customize-scrollbar-color-and-thickness) */
|
|
227
|
+
.zelune-scroller {
|
|
228
|
+
--scrollbar-thumb: #262d3d;
|
|
229
|
+
--scrollbar-track: #0d0f14;
|
|
230
|
+
scrollbar-width: thin;
|
|
231
|
+
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
@supports not (scrollbar-color: auto) {
|
|
235
|
+
.zelune-scroller::-webkit-scrollbar {
|
|
236
|
+
width: 8px;
|
|
237
|
+
height: 8px;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.zelune-scroller::-webkit-scrollbar-thumb {
|
|
241
|
+
background: var(--scrollbar-thumb);
|
|
242
|
+
border-radius: 4px;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.zelune-scroller::-webkit-scrollbar-track {
|
|
246
|
+
background: var(--scrollbar-track);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* Inspect Overlay Micro-Transitions */
|
|
251
|
+
.zelune-box-overlay {
|
|
252
|
+
translate: 0px 0px;
|
|
253
|
+
scale: 1;
|
|
254
|
+
transition:
|
|
255
|
+
top 90ms var(--ease-out),
|
|
256
|
+
left 90ms var(--ease-out),
|
|
257
|
+
width 90ms var(--ease-out),
|
|
258
|
+
height 90ms var(--ease-out),
|
|
259
|
+
opacity var(--duration-micro) var(--ease-out);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* Modal <dialog> Choreography & Scroll Containment */
|
|
263
|
+
@keyframes zeluneDialogEntry {
|
|
264
|
+
from {
|
|
265
|
+
opacity: 0;
|
|
266
|
+
scale: 0.96;
|
|
267
|
+
translate: 0 6px;
|
|
268
|
+
}
|
|
269
|
+
to {
|
|
270
|
+
opacity: 1;
|
|
271
|
+
scale: 1;
|
|
272
|
+
translate: 0 0;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
dialog:modal {
|
|
277
|
+
overscroll-behavior: contain;
|
|
278
|
+
border: none;
|
|
279
|
+
padding: 0;
|
|
280
|
+
background: transparent;
|
|
281
|
+
animation: zeluneDialogEntry var(--duration-panel) var(--ease-out-expo) forwards;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
dialog::backdrop {
|
|
285
|
+
overflow: hidden;
|
|
286
|
+
overscroll-behavior: contain;
|
|
287
|
+
background-color: rgba(5, 7, 11, 0.76);
|
|
288
|
+
backdrop-filter: blur(6px);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
@media (prefers-reduced-motion: reduce) {
|
|
292
|
+
*,
|
|
293
|
+
*::before,
|
|
294
|
+
*::after {
|
|
295
|
+
animation-duration: 0.01ms !important;
|
|
296
|
+
transition-duration: 0.01ms !important;
|
|
297
|
+
}
|
|
298
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"jsx": "react-jsx",
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noUnusedLocals": false,
|
|
16
|
+
"noUnusedParameters": false,
|
|
17
|
+
"noFallthroughCasesInSwitch": true,
|
|
18
|
+
"paths": {
|
|
19
|
+
"react-native": ["./node_modules/react-native-web"]
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"include": ["src", "plugins", "mcp", "tests", "vite.config.ts"]
|
|
23
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { viteRnSourceInject } from './plugins/viteRnSourceInject';
|
|
7
|
+
import { viteVirtualScreensPlugin } from './plugins/viteVirtualScreensPlugin';
|
|
8
|
+
import { viteCanvasApiMiddleware } from './src/server/apiMiddleware';
|
|
9
|
+
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const targetProjectRoot = process.env.ANTIGRAVITY_TARGET_PROJECT
|
|
12
|
+
? path.resolve(process.env.ANTIGRAVITY_TARGET_PROJECT)
|
|
13
|
+
: __dirname;
|
|
14
|
+
|
|
15
|
+
const mockNavShimPath = path.resolve(__dirname, 'src/runtime/MockNavigationContext.tsx');
|
|
16
|
+
|
|
17
|
+
function resolveTargetProjectPathAliases(projectRoot: string): Record<string, string> {
|
|
18
|
+
const aliases: Record<string, string> = {};
|
|
19
|
+
try {
|
|
20
|
+
const tsconfigPath = path.join(projectRoot, 'tsconfig.json');
|
|
21
|
+
if (!fs.existsSync(tsconfigPath)) return aliases;
|
|
22
|
+
const raw = fs.readFileSync(tsconfigPath, 'utf-8');
|
|
23
|
+
// Strip single-line and multi-line comments before JSON.parse
|
|
24
|
+
const cleaned = raw.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
|
|
25
|
+
const parsed = JSON.parse(cleaned) as {
|
|
26
|
+
compilerOptions?: {
|
|
27
|
+
baseUrl?: string;
|
|
28
|
+
paths?: Record<string, string[]>;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
const baseUrl = parsed.compilerOptions?.baseUrl ?? '.';
|
|
32
|
+
const paths = parsed.compilerOptions?.paths ?? {};
|
|
33
|
+
for (const [pattern, targets] of Object.entries(paths)) {
|
|
34
|
+
if (!targets || targets.length === 0) continue;
|
|
35
|
+
const cleanKey = pattern.replace(/\/\*$/, '');
|
|
36
|
+
const cleanTarget = targets[0].replace(/\/\*$/, '');
|
|
37
|
+
aliases[cleanKey] = path.resolve(projectRoot, baseUrl, cleanTarget);
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
// Fallback to standard @ alias if tsconfig parsing fails
|
|
41
|
+
const srcDir = path.join(projectRoot, 'src');
|
|
42
|
+
aliases['@'] = fs.existsSync(srcDir) ? srcDir : projectRoot;
|
|
43
|
+
}
|
|
44
|
+
return aliases;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default defineConfig({
|
|
48
|
+
plugins: [
|
|
49
|
+
viteVirtualScreensPlugin(targetProjectRoot),
|
|
50
|
+
viteRnSourceInject(targetProjectRoot),
|
|
51
|
+
react(),
|
|
52
|
+
viteCanvasApiMiddleware(targetProjectRoot),
|
|
53
|
+
],
|
|
54
|
+
resolve: {
|
|
55
|
+
alias: {
|
|
56
|
+
...resolveTargetProjectPathAliases(targetProjectRoot),
|
|
57
|
+
'react-native': 'react-native-web',
|
|
58
|
+
'@react-navigation/native': mockNavShimPath,
|
|
59
|
+
'expo-router': mockNavShimPath,
|
|
60
|
+
'react-native-safe-area-context': mockNavShimPath,
|
|
61
|
+
'expo-status-bar': mockNavShimPath,
|
|
62
|
+
'lucide-react-native': 'lucide-react',
|
|
63
|
+
},
|
|
64
|
+
extensions: ['.web.tsx', '.web.ts', '.web.js', '.tsx', '.ts', '.jsx', '.js'],
|
|
65
|
+
},
|
|
66
|
+
define: {
|
|
67
|
+
__DEV__: JSON.stringify(true),
|
|
68
|
+
global: 'window',
|
|
69
|
+
},
|
|
70
|
+
css: {
|
|
71
|
+
postcss: {},
|
|
72
|
+
},
|
|
73
|
+
server: {
|
|
74
|
+
host: '127.0.0.1',
|
|
75
|
+
port: 5173,
|
|
76
|
+
strictPort: false,
|
|
77
|
+
fs: {
|
|
78
|
+
allow: [__dirname, targetProjectRoot],
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
});
|