ebade 0.3.0 → 0.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 +5 -0
- package/README.md +30 -30
- package/ROADMAP.md +17 -12
- package/cli/scaffold.js +315 -183
- package/cli/simulate.js +102 -0
- package/cli/templates/feature-grid.tsx +80 -0
- package/cli/templates/footer.tsx +121 -0
- package/cli/templates/hero-section.tsx +34 -0
- package/cli/templates/login-form.tsx +124 -0
- package/cli/templates/navbar.tsx +53 -0
- package/cli/templates/pricing-table.tsx +140 -0
- package/cli/templates/signup-form.tsx +111 -0
- package/demo.tape +2 -2
- package/examples/saas-dashboard.ebade.yaml +2 -0
- package/netlify.toml +7 -0
- package/package.json +1 -1
- package/packages/mcp-server/README.md +3 -3
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/index.ts +12 -16
- package/packages/mcp-server/src/tools/scaffold.ts +153 -404
- package/packages/vscode-extension/README.md +11 -8
- package/packages/vscode-extension/ebade-0.3.0.vsix +0 -0
- package/packages/vscode-extension/ebade-0.3.1.vsix +0 -0
- package/packages/vscode-extension/ebade-0.3.2.vsix +0 -0
- package/packages/vscode-extension/images/icon.png +0 -0
- package/packages/vscode-extension/package.json +2 -1
- package/packages/vscode-extension/snippets/ebade.json +86 -0
- package/www/README.md +36 -0
- package/www/app/favicon.ico +0 -0
- package/{landing/style.css → www/app/globals.css} +390 -19
- package/www/app/layout.tsx +66 -0
- package/www/app/page.tsx +374 -0
- package/www/app/playground/page.tsx +627 -0
- package/www/components/ThreeCanvas.tsx +156 -0
- package/www/next.config.ts +19 -0
- package/www/package-lock.json +1779 -0
- package/www/package.json +27 -0
- package/www/postcss.config.mjs +7 -0
- package/www/public/logo.png +0 -0
- package/www/tsconfig.json +42 -0
- package/landing/index.html +0 -268
- package/landing/main.js +0 -147
- package/packages/vscode-extension/images/icon.svg +0 -6
- /package/{demo.gif → assets/demo.gif} +0 -0
- /package/{demo.mp4 → assets/demo.mp4} +0 -0
- /package/{landing → www/public}/_headers +0 -0
- /package/{landing → www/public}/favicon.svg +0 -0
- /package/{landing → www/public}/og-image.png +0 -0
- /package/{landing → www/public}/og-readme.png +0 -0
package/www/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "www",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"lucide-react": "^0.562.0",
|
|
12
|
+
"next": "^15.1.4",
|
|
13
|
+
"react": "^19.0.0",
|
|
14
|
+
"react-dom": "^19.0.0",
|
|
15
|
+
"three": "^0.182.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@tailwindcss/postcss": "^4",
|
|
19
|
+
"@types/node": "^20",
|
|
20
|
+
"@types/react": "^19",
|
|
21
|
+
"@types/react-dom": "^19",
|
|
22
|
+
"@types/three": "^0.182.0",
|
|
23
|
+
"babel-plugin-react-compiler": "1.0.0",
|
|
24
|
+
"tailwindcss": "^4",
|
|
25
|
+
"typescript": "^5"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"lib": [
|
|
5
|
+
"dom",
|
|
6
|
+
"dom.iterable",
|
|
7
|
+
"esnext"
|
|
8
|
+
],
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"module": "esnext",
|
|
15
|
+
"moduleResolution": "bundler",
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"isolatedModules": true,
|
|
18
|
+
"jsx": "preserve",
|
|
19
|
+
"incremental": true,
|
|
20
|
+
"plugins": [
|
|
21
|
+
{
|
|
22
|
+
"name": "next"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"paths": {
|
|
26
|
+
"@/*": [
|
|
27
|
+
"./*"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"include": [
|
|
32
|
+
"next-env.d.ts",
|
|
33
|
+
"**/*.ts",
|
|
34
|
+
"**/*.tsx",
|
|
35
|
+
".next/types/**/*.ts",
|
|
36
|
+
".next/dev/types/**/*.ts",
|
|
37
|
+
"**/*.mts"
|
|
38
|
+
],
|
|
39
|
+
"exclude": [
|
|
40
|
+
"node_modules"
|
|
41
|
+
]
|
|
42
|
+
}
|
package/landing/index.html
DELETED
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>ebade | The First Agent-First Framework</title>
|
|
8
|
-
<meta name="description"
|
|
9
|
-
content="ebade is The first framework designed for AI agents, readable by humans. Reduce token usage by 70% with intent-driven development." />
|
|
10
|
-
|
|
11
|
-
<!-- Favicon -->
|
|
12
|
-
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
|
13
|
-
|
|
14
|
-
<!-- Open Graph / Social -->
|
|
15
|
-
<meta property="og:type" content="website" />
|
|
16
|
-
<meta property="og:url" content="https://ebade.dev/" />
|
|
17
|
-
<meta property="og:title" content="ebade | The First Agent-First Framework" />
|
|
18
|
-
<meta property="og:description"
|
|
19
|
-
content="The first framework designed FOR AI agents. Reduce token usage by 70% with intent-driven development." />
|
|
20
|
-
<meta property="og:image" content="https://ebade.dev/og-image.png" />
|
|
21
|
-
|
|
22
|
-
<!-- Twitter -->
|
|
23
|
-
<meta name="twitter:card" content="summary_large_image" />
|
|
24
|
-
<meta name="twitter:title" content="ebade | The First Agent-First Framework" />
|
|
25
|
-
<meta name="twitter:description" content="The first framework designed FOR AI agents. Reduce token usage by 70%." />
|
|
26
|
-
<meta name="twitter:image" content="https://ebade.dev/og-image.png" />
|
|
27
|
-
|
|
28
|
-
<!-- Google tag (gtag.js) -->
|
|
29
|
-
<script async src="https://www.googletagmanager.com/gtag/js?id=G-RMQ7E747ZH"></script>
|
|
30
|
-
<script>
|
|
31
|
-
window.dataLayer = window.dataLayer || [];
|
|
32
|
-
function gtag() { dataLayer.push(arguments); }
|
|
33
|
-
gtag('js', new Date());
|
|
34
|
-
|
|
35
|
-
gtag('config', 'G-RMQ7E747ZH');
|
|
36
|
-
</script>
|
|
37
|
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
38
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
39
|
-
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;600;800;900&family=JetBrains+Mono&display=swap"
|
|
40
|
-
rel="stylesheet" />
|
|
41
|
-
<link rel="stylesheet" href="style.css" />
|
|
42
|
-
<script src="https://unpkg.com/lucide@latest"></script>
|
|
43
|
-
</head>
|
|
44
|
-
|
|
45
|
-
<body>
|
|
46
|
-
<div id="canvas-container"></div>
|
|
47
|
-
<div class="bg-glow"></div>
|
|
48
|
-
|
|
49
|
-
<nav class="full-nav">
|
|
50
|
-
<div class="logo">ebade<span>.dev</span></div>
|
|
51
|
-
<div class="nav-links">
|
|
52
|
-
<a href="#technology">Technology</a>
|
|
53
|
-
<a href="#benchmarks">Benchmarks</a>
|
|
54
|
-
<a href="https://github.com/hasankemaldemirci/ebade" target="_blank" class="nav-github">
|
|
55
|
-
<i data-lucide="github"></i>
|
|
56
|
-
<span>GitHub</span>
|
|
57
|
-
</a>
|
|
58
|
-
<a href="https://github.com/hasankemaldemirci/ebade#-quick-start" target="_blank" class="nav-cta">Get Started</a>
|
|
59
|
-
</div>
|
|
60
|
-
</nav>
|
|
61
|
-
|
|
62
|
-
<main>
|
|
63
|
-
<section class="hero-full">
|
|
64
|
-
<div class="hero-content">
|
|
65
|
-
<div class="badge-modern">
|
|
66
|
-
<i data-lucide="cpu" class="icon-small"></i> Protocol 0.1.0 // Alpha
|
|
67
|
-
</div>
|
|
68
|
-
<h1 class="glitch-text">Code = f(<span>Intent</span>)</h1>
|
|
69
|
-
<p class="hero-description">
|
|
70
|
-
<span class="ebade-brand">ebade</span> is an evolution in abstract
|
|
71
|
-
engineering. We don't build components; we model intent. Designed
|
|
72
|
-
for the era where <strong>Agents</strong> are the primary
|
|
73
|
-
developers.
|
|
74
|
-
</p>
|
|
75
|
-
<div class="hero-actions">
|
|
76
|
-
<a href="#technology" class="btn-glow">Explore Protocol</a>
|
|
77
|
-
<a href="https://www.npmjs.com/package/ebade" class="btn-minimal">npm install ebade</a>
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
80
|
-
|
|
81
|
-
<div class="scroll-indicator">
|
|
82
|
-
<div class="line"></div>
|
|
83
|
-
<span>INTENT_STREAM</span>
|
|
84
|
-
</div>
|
|
85
|
-
</section>
|
|
86
|
-
|
|
87
|
-
<section id="technology" class="section-dark">
|
|
88
|
-
<div class="section-container">
|
|
89
|
-
<header class="section-header">
|
|
90
|
-
<div class="badge-accent">Philosophy</div>
|
|
91
|
-
<h2>Agentic <span>Intent</span></h2>
|
|
92
|
-
<p>
|
|
93
|
-
Why write 100 lines of boilerplate when an agent can infer
|
|
94
|
-
implementation from 8 lines of pure intent?
|
|
95
|
-
</p>
|
|
96
|
-
</header>
|
|
97
|
-
|
|
98
|
-
<div class="comparison-modern">
|
|
99
|
-
<div class="code-card legacy">
|
|
100
|
-
<div class="card-header">
|
|
101
|
-
<div class="window-controls">
|
|
102
|
-
<span class="control close"></span>
|
|
103
|
-
<span class="control minimize"></span>
|
|
104
|
-
<span class="control maximize"></span>
|
|
105
|
-
</div>
|
|
106
|
-
<div class="card-tag">React + Next.js</div>
|
|
107
|
-
</div>
|
|
108
|
-
<pre><code>export default function ProductList() {
|
|
109
|
-
const [items, setItems] = useState([]);
|
|
110
|
-
const [loading, setLoading] = useState(true);
|
|
111
|
-
|
|
112
|
-
useEffect(() => {
|
|
113
|
-
async function load() {
|
|
114
|
-
const res = await fetch('/api/products');
|
|
115
|
-
const json = await res.json();
|
|
116
|
-
setItems(json);
|
|
117
|
-
setLoading(false);
|
|
118
|
-
}
|
|
119
|
-
load();
|
|
120
|
-
}, []);
|
|
121
|
-
|
|
122
|
-
if (loading) return <Spinner />;
|
|
123
|
-
|
|
124
|
-
return (
|
|
125
|
-
<section className="grid">
|
|
126
|
-
{items.map(p => <Card key={p.id} {...p} />)}
|
|
127
|
-
</section>
|
|
128
|
-
);
|
|
129
|
-
}</code></pre>
|
|
130
|
-
</div>
|
|
131
|
-
|
|
132
|
-
<div class="transform-arrow">
|
|
133
|
-
<i data-lucide="zap"></i>
|
|
134
|
-
</div>
|
|
135
|
-
|
|
136
|
-
<div class="code-card ebade">
|
|
137
|
-
<div class="card-header">
|
|
138
|
-
<div class="window-controls">
|
|
139
|
-
<span class="control close"></span>
|
|
140
|
-
<span class="control minimize"></span>
|
|
141
|
-
<span class="control maximize"></span>
|
|
142
|
-
</div>
|
|
143
|
-
<div class="card-tag">ebade Protocol</div>
|
|
144
|
-
</div>
|
|
145
|
-
<pre><code><span class="keyword">@page</span>(<span class="string">'/products'</span>)
|
|
146
|
-
<span class="keyword">@intent</span>(<span class="string">'product-catalog'</span>)
|
|
147
|
-
<span class="keyword">@requires</span>([<span class="string">'products'</span>])
|
|
148
|
-
<span class="keyword">@compose</span>([<span class="string">'grid'</span>, <span class="string">'loader'</span>])
|
|
149
|
-
<span class="keyword">export function</span> <span class="function">Catalog</span>() {}</code></pre>
|
|
150
|
-
</div>
|
|
151
|
-
</div>
|
|
152
|
-
</div>
|
|
153
|
-
</section>
|
|
154
|
-
|
|
155
|
-
<section id="benchmarks" class="benchmark-minimal">
|
|
156
|
-
<div class="section-container">
|
|
157
|
-
<header class="section-header" style="margin-bottom: 4rem">
|
|
158
|
-
<div class="badge-accent">Efficiency</div>
|
|
159
|
-
<h2>Proven <span>Performance</span></h2>
|
|
160
|
-
<p style="margin: 0 auto; color: var(--text-dim); max-width: 600px">
|
|
161
|
-
Real-world benchmarks demonstrating how ebade slashes operational
|
|
162
|
-
costs and cognitive load for AI agents.
|
|
163
|
-
</p>
|
|
164
|
-
</header>
|
|
165
|
-
<div class="stats-box">
|
|
166
|
-
<div class="stat">
|
|
167
|
-
<div class="stat-icon"><i data-lucide="zap"></i></div>
|
|
168
|
-
<span class="val">70%</span>
|
|
169
|
-
<span class="label">Token Reduction</span>
|
|
170
|
-
</div>
|
|
171
|
-
<div class="stat-divider"></div>
|
|
172
|
-
<div class="stat">
|
|
173
|
-
<div class="stat-icon"><i data-lucide="brain"></i></div>
|
|
174
|
-
<span class="val">4.1x</span>
|
|
175
|
-
<span class="label">Agent Context Efficiency</span>
|
|
176
|
-
</div>
|
|
177
|
-
<div class="stat-divider"></div>
|
|
178
|
-
<div class="stat">
|
|
179
|
-
<div class="stat-icon" style="color: var(--accent-emerald)">
|
|
180
|
-
<i data-lucide="leaf"></i>
|
|
181
|
-
</div>
|
|
182
|
-
<span class="val">Zero</span>
|
|
183
|
-
<span class="label">Sustainable AI Core</span>
|
|
184
|
-
</div>
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
187
|
-
</section>
|
|
188
|
-
|
|
189
|
-
<section class="features-grid-section">
|
|
190
|
-
<div class="section-container">
|
|
191
|
-
<header class="section-header">
|
|
192
|
-
<div class="badge-accent">Standard</div>
|
|
193
|
-
<h2 style="color: var(--text)">The ebade <span>Ecosystem</span></h2>
|
|
194
|
-
<p style="margin: 0 auto; color: var(--text-dim)">
|
|
195
|
-
Engineered for high-autonomy agents and complex product
|
|
196
|
-
lifecycles.
|
|
197
|
-
</p>
|
|
198
|
-
</header>
|
|
199
|
-
<div class="grid-3">
|
|
200
|
-
<div class="feature-item">
|
|
201
|
-
<i data-lucide="code-2"></i>
|
|
202
|
-
<h3>Agent-Native</h3>
|
|
203
|
-
<p>
|
|
204
|
-
Designed as a first-class citizen for LLMs. Structured intent
|
|
205
|
-
that models understand instantly.
|
|
206
|
-
</p>
|
|
207
|
-
</div>
|
|
208
|
-
<div class="feature-item">
|
|
209
|
-
<i data-lucide="layers"></i>
|
|
210
|
-
<h3>Meta-Abstraction</h3>
|
|
211
|
-
<p>
|
|
212
|
-
Platform-agnostic intent layer. Currently optimized for Next.js.
|
|
213
|
-
The same intent will power mobile, backend, and beyond.
|
|
214
|
-
</p>
|
|
215
|
-
</div>
|
|
216
|
-
<div class="feature-item">
|
|
217
|
-
<i data-lucide="terminal"></i>
|
|
218
|
-
<h3>Binary Scaffold</h3>
|
|
219
|
-
<p>
|
|
220
|
-
Generate full, production-ready project structures from a single
|
|
221
|
-
schema definition.
|
|
222
|
-
</p>
|
|
223
|
-
</div>
|
|
224
|
-
</div>
|
|
225
|
-
</div>
|
|
226
|
-
</section>
|
|
227
|
-
</main>
|
|
228
|
-
|
|
229
|
-
<footer class="site-footer">
|
|
230
|
-
<div class="footer-container">
|
|
231
|
-
<div class="footer-brand">
|
|
232
|
-
<div class="footer-logo">🧠 ebade</div>
|
|
233
|
-
<p class="footer-slogan">Capture the essence of code.<br>Less tokens. Less carbon. Same result. 🌱</p>
|
|
234
|
-
</div>
|
|
235
|
-
<div class="footer-links">
|
|
236
|
-
<div class="footer-column">
|
|
237
|
-
<h4>Product</h4>
|
|
238
|
-
<a href="#technology">Technology</a>
|
|
239
|
-
<a href="#benchmarks">Benchmarks</a>
|
|
240
|
-
<a href="https://github.com/hasankemaldemirci/ebade/tree/main/examples" target="_blank">Examples</a>
|
|
241
|
-
</div>
|
|
242
|
-
<div class="footer-column">
|
|
243
|
-
<h4>Resources</h4>
|
|
244
|
-
<a href="https://github.com/hasankemaldemirci/ebade" target="_blank">GitHub</a>
|
|
245
|
-
<a href="https://www.npmjs.com/package/ebade" target="_blank">npm</a>
|
|
246
|
-
<a href="https://github.com/hasankemaldemirci/ebade/blob/main/ROADMAP.md" target="_blank">Roadmap</a>
|
|
247
|
-
</div>
|
|
248
|
-
<div class="footer-column">
|
|
249
|
-
<h4>Contact</h4>
|
|
250
|
-
<a href="mailto:hello@ebade.dev">hello@ebade.dev</a>
|
|
251
|
-
<a href="https://github.com/sponsors/hasankemaldemirci" target="_blank">Sponsor 💜</a>
|
|
252
|
-
</div>
|
|
253
|
-
</div>
|
|
254
|
-
</div>
|
|
255
|
-
<div class="footer-bottom">
|
|
256
|
-
<p>© 2026 ebade. The Agent-First Framework.</p>
|
|
257
|
-
<p class="footer-tagline">Code = f(Intent) // Kind to Earth 🌍</p>
|
|
258
|
-
</div>
|
|
259
|
-
</footer>
|
|
260
|
-
|
|
261
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
|
262
|
-
<script src="main.js"></script>
|
|
263
|
-
<script>
|
|
264
|
-
lucide.createIcons();
|
|
265
|
-
</script>
|
|
266
|
-
</body>
|
|
267
|
-
|
|
268
|
-
</html>
|
package/landing/main.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
let scene, camera, renderer, cloud;
|
|
2
|
-
const PARTICLE_COUNT = 1500;
|
|
3
|
-
const CONNECT_DISTANCE = 2.5;
|
|
4
|
-
|
|
5
|
-
function init() {
|
|
6
|
-
scene = new THREE.Scene();
|
|
7
|
-
camera = new THREE.PerspectiveCamera(
|
|
8
|
-
75,
|
|
9
|
-
window.innerWidth / window.innerHeight,
|
|
10
|
-
0.1,
|
|
11
|
-
1000
|
|
12
|
-
);
|
|
13
|
-
camera.position.z = 10;
|
|
14
|
-
|
|
15
|
-
renderer = new THREE.WebGLRenderer({
|
|
16
|
-
antialias: true,
|
|
17
|
-
alpha: true,
|
|
18
|
-
});
|
|
19
|
-
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
20
|
-
renderer.setPixelRatio(window.devicePixelRatio);
|
|
21
|
-
document.getElementById("canvas-container").appendChild(renderer.domElement);
|
|
22
|
-
|
|
23
|
-
// Create Plus Sign Texture (+)
|
|
24
|
-
const canvas = document.createElement("canvas");
|
|
25
|
-
canvas.width = 64;
|
|
26
|
-
canvas.height = 64;
|
|
27
|
-
const ctx = canvas.getContext("2d");
|
|
28
|
-
ctx.strokeStyle = "#4f46e5";
|
|
29
|
-
ctx.lineWidth = 10;
|
|
30
|
-
ctx.beginPath();
|
|
31
|
-
ctx.moveTo(32, 10);
|
|
32
|
-
ctx.lineTo(32, 54);
|
|
33
|
-
ctx.moveTo(10, 32);
|
|
34
|
-
ctx.lineTo(54, 32);
|
|
35
|
-
ctx.stroke();
|
|
36
|
-
|
|
37
|
-
const texture = new THREE.CanvasTexture(canvas);
|
|
38
|
-
|
|
39
|
-
// Stabilized Particle Data
|
|
40
|
-
const geometry = new THREE.BufferGeometry();
|
|
41
|
-
const positions = new Float32Array(PARTICLE_COUNT * 3);
|
|
42
|
-
const originalPositions = new Float32Array(PARTICLE_COUNT * 3);
|
|
43
|
-
|
|
44
|
-
for (let i = 0; i < PARTICLE_COUNT * 3; i++) {
|
|
45
|
-
const val = (Math.random() - 0.5) * 40;
|
|
46
|
-
positions[i] = val;
|
|
47
|
-
originalPositions[i] = val;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
|
|
51
|
-
|
|
52
|
-
const material = new THREE.PointsMaterial({
|
|
53
|
-
map: texture,
|
|
54
|
-
size: 0.2, // Slightly larger for visibility
|
|
55
|
-
transparent: true,
|
|
56
|
-
opacity: 0.6,
|
|
57
|
-
sizeAttenuation: true,
|
|
58
|
-
alphaTest: 0.05,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
cloud = new THREE.Points(geometry, material);
|
|
62
|
-
cloud.userData.originalPositions = originalPositions;
|
|
63
|
-
scene.add(cloud);
|
|
64
|
-
|
|
65
|
-
animate();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
let mouseX = 0,
|
|
69
|
-
mouseY = 0;
|
|
70
|
-
document.addEventListener("mousemove", (e) => {
|
|
71
|
-
mouseX = (e.clientX / window.innerWidth - 0.5) * 2;
|
|
72
|
-
mouseY = (e.clientY / window.innerHeight - 0.5) * 2;
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
function animate() {
|
|
76
|
-
requestAnimationFrame(animate);
|
|
77
|
-
|
|
78
|
-
const posAttr = cloud.geometry.attributes.position;
|
|
79
|
-
const positions = posAttr.array;
|
|
80
|
-
const originals = cloud.userData.originalPositions;
|
|
81
|
-
const time = Date.now() * 0.0005;
|
|
82
|
-
|
|
83
|
-
for (let i = 0; i < PARTICLE_COUNT; i++) {
|
|
84
|
-
const i3 = i * 3;
|
|
85
|
-
|
|
86
|
-
// Fluid, non-shaking drift
|
|
87
|
-
// We calculate offset FROM original position to avoid feedback jitters
|
|
88
|
-
const driftX = Math.sin(time + originals[i3 + 1] * 0.5) * 0.5;
|
|
89
|
-
const driftY = Math.cos(time + originals[i3] * 0.5) * 0.5;
|
|
90
|
-
|
|
91
|
-
// Mouse Interaction (Smoother Repulsion)
|
|
92
|
-
const worldMouseX = mouseX * 15;
|
|
93
|
-
const worldMouseY = -mouseY * 15;
|
|
94
|
-
|
|
95
|
-
const dx = originals[i3] - worldMouseX;
|
|
96
|
-
const dy = originals[i3 + 1] - worldMouseY;
|
|
97
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
98
|
-
|
|
99
|
-
let forceX = 0,
|
|
100
|
-
forceY = 0;
|
|
101
|
-
if (dist < 5) {
|
|
102
|
-
const power = (5 - dist) / 5;
|
|
103
|
-
forceX = dx * power * 0.5;
|
|
104
|
-
forceY = dy * power * 0.5;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
positions[i3] = originals[i3] + driftX + forceX;
|
|
108
|
-
positions[i3 + 1] = originals[i3 + 1] + driftY + forceY;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
posAttr.needsUpdate = true;
|
|
112
|
-
cloud.rotation.y += 0.0005;
|
|
113
|
-
|
|
114
|
-
// Cinematic Camera
|
|
115
|
-
camera.position.x += (mouseX * 3 - camera.position.x) * 0.02;
|
|
116
|
-
camera.position.y += (-mouseY * 3 - camera.position.y) * 0.02;
|
|
117
|
-
camera.lookAt(0, 0, 0);
|
|
118
|
-
|
|
119
|
-
renderer.render(scene, camera);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
window.addEventListener("resize", () => {
|
|
123
|
-
camera.aspect = window.innerWidth / window.innerHeight;
|
|
124
|
-
camera.updateProjectionMatrix();
|
|
125
|
-
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Scroll Reveal Logic
|
|
129
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
130
|
-
init();
|
|
131
|
-
|
|
132
|
-
const observer = new IntersectionObserver(
|
|
133
|
-
(entries) => {
|
|
134
|
-
entries.forEach((entry) => {
|
|
135
|
-
if (entry.isIntersecting) {
|
|
136
|
-
entry.target.classList.add("visible");
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
},
|
|
140
|
-
{ threshold: 0.1 }
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
document.querySelectorAll("section, .code-card, .stat").forEach((el) => {
|
|
144
|
-
el.classList.add("reveal-on-scroll");
|
|
145
|
-
observer.observe(el);
|
|
146
|
-
});
|
|
147
|
-
});
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
|
2
|
-
<rect width="32" height="32" rx="6" fill="#4F46E5"/>
|
|
3
|
-
<text x="50%" y="52%" dominant-baseline="middle" text-anchor="middle"
|
|
4
|
-
font-family="system-ui, -apple-system, sans-serif"
|
|
5
|
-
font-size="22" font-weight="900" fill="white">e</text>
|
|
6
|
-
</svg>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|