ebade 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,86 @@
1
+ # ebade: Green AI Development ๐ŸŒฑ
2
+
3
+ > **Less tokens. Less compute. Less carbon. The Essence of Code.**
4
+
5
+ ---
6
+
7
+ ## ๐ŸŒŽ The Hidden Cost of AI Coding
8
+
9
+ Every token an AI generates requires:
10
+ - โšก **GPU Compute Cycles**: High-intensity processing in data centers.
11
+ - ๐Ÿ”ฅ **Energy Consumption**: Massive amounts of electricity.
12
+ - ๐ŸŒซ๏ธ **Carbon Emissions**: The direct environmental footprint of digital growth.
13
+
14
+ **When an AI writes 1,000 tokens of boilerplate code, it's not free for the planet.** ๐ŸŒ
15
+
16
+ ---
17
+
18
+ ## ๐Ÿ“Š The Numbers
19
+
20
+ ### Token Reduction = Carbon Reduction (1,000,000 sessions)
21
+
22
+ | Framework | Tokens (Estimated) | Relative Compute | CO2 Footprint |
23
+ |-----------|------------------|------------------|---------------|
24
+ | Next.js | 539,000,000 | 100% | ~26.9 kg |
25
+ | Vue.js | 420,000,000 | ~78% | ~21.0 kg |
26
+ | **ebade** | **185,000,000** | **34%** | **~9.2 kg** |
27
+
28
+ **ebade uses 66% less compute for the same output.** ๐ŸŒฑ
29
+
30
+ ---
31
+
32
+ ## ๐ŸŒณ Environmental Impact Guide
33
+
34
+ Based on our benchmarks, switching to **ebade** for AI agent workflows saves:
35
+
36
+ - **17.7 kg CO2** per million sessions.
37
+ - Equivalent to the carbon sequestered by **~1 young tree** every 5 million sessions.
38
+ - Equivalent to driving **~70 km** in a gasoline car.
39
+
40
+ ---
41
+
42
+ ## ๐Ÿง  The Efficiency Philosophy
43
+
44
+ Traditional frameworks are human-centric. They require the AI to write huge amounts of "how" code (boilerplate, imports, setup). **ebade** is agent-centric. It only needs the "what" (intent).
45
+
46
+ ```text
47
+ Human-Centric (Next.js): AI writes IMPLEMENTATION โ†’ Bloated Context โ†’ High Carbon
48
+ Agent-Centric (ebade): AI writes ESSENCE (ebade) โ†’ Lean Context โ†’ Low Carbon
49
+ ```
50
+
51
+ **Same result. Fraction of the energy.**
52
+
53
+ ---
54
+
55
+ ## ๐Ÿš€ Slogan for the Planet
56
+
57
+ > **"Code = f(ebade). Planet = f(efficiency)."**
58
+
59
+ > **"ebade: AI-first coding that doesn't cost the Earth."** ๐ŸŒฑ
60
+
61
+ > **"The greenest code is the code you never have to generate."**
62
+
63
+ ---
64
+
65
+ ## ๐Ÿ›ก๏ธ Green AI Badge
66
+
67
+ Add this to your repository to show your commitment to sustainable AI development:
68
+
69
+ ```markdown
70
+ [![Green AI](https://img.shields.io/badge/Green_AI-ebade-brightgreen)](https://github.com/ebade)
71
+ ```
72
+
73
+ > ๐ŸŒฑ **Built with ebade โ€” saving 66% of AI compute.**
74
+
75
+ ---
76
+
77
+ ## ๐ŸŒ Call to Action
78
+
79
+ Every framework choice is an environmental choice.
80
+ If you build for AI, build with **ebade**.
81
+
82
+ **ebade: The essence of code. Kind to Earth.** ๐ŸŒฑ
83
+
84
+ ---
85
+
86
+ *"The most sustainable code is the code that expresses intent, not implementation."*
@@ -0,0 +1,192 @@
1
+ # ebade Project Definition File
2
+ # Bu dosya AI Agent tarafฤฑndan okunur ve projeyi scaffold eder.
3
+ # -----------------------------------------------------------
4
+
5
+ name: "modern-store"
6
+ type: "e-commerce"
7
+ description: "Minimal ve modern bir e-ticaret sitesi"
8
+
9
+ # Aktif รถzellikler
10
+ features:
11
+ - product-catalog
12
+ - shopping-cart
13
+ - checkout
14
+ - user-auth
15
+ - reviews
16
+ - search
17
+ - dark-mode
18
+ - seo
19
+
20
+ # Sayfa tanฤฑmlarฤฑ
21
+ pages:
22
+ - path: "/"
23
+ intent: "landing-page"
24
+ components:
25
+ - hero-section
26
+ - featured-products
27
+ - testimonials
28
+ - newsletter-signup
29
+
30
+ - path: "/products"
31
+ intent: "product-listing"
32
+ components:
33
+ - search-bar
34
+ - filter-sidebar
35
+ - product-grid
36
+ - pagination
37
+
38
+ - path: "/products/[slug]"
39
+ intent: "product-detail"
40
+ components:
41
+ - product-gallery
42
+ - product-info
43
+ - add-to-cart
44
+ - reviews-section
45
+ - related-products
46
+
47
+ - path: "/cart"
48
+ intent: "shopping-cart"
49
+ auth: optional
50
+ components:
51
+ - cart-items
52
+ - cart-summary
53
+ - checkout-cta
54
+
55
+ - path: "/checkout"
56
+ intent: "checkout-flow"
57
+ auth: required
58
+ components:
59
+ - checkout-form
60
+ - order-summary
61
+ - payment-section
62
+
63
+ - path: "/account"
64
+ intent: "user-dashboard"
65
+ auth: required
66
+ components:
67
+ - profile-card
68
+ - order-history
69
+ - saved-addresses
70
+
71
+ # Tasarฤฑm sistemi
72
+ design:
73
+ style: "minimal-modern"
74
+ colors:
75
+ primary: "#6366f1" # Indigo
76
+ secondary: "#f59e0b" # Amber
77
+ accent: "#10b981" # Emerald
78
+ font: "Inter"
79
+ borderRadius: "lg"
80
+
81
+ # Entegrasyonlar
82
+ integrations:
83
+ database: "supabase"
84
+ auth: "clerk"
85
+ payments: "stripe"
86
+ analytics: "vercel"
87
+ email: "resend"
88
+
89
+ # API Endpoints
90
+ api:
91
+ - path: "/api/products"
92
+ methods: ["GET"]
93
+ auth: none
94
+ description: "รœrรผn listesi getir"
95
+
96
+ - path: "/api/products/[id]"
97
+ methods: ["GET"]
98
+ auth: none
99
+ description: "Tekil รผrรผn detayฤฑ"
100
+
101
+ - path: "/api/cart"
102
+ methods: ["GET", "POST", "PUT", "DELETE"]
103
+ auth: optional
104
+ description: "Sepet iลŸlemleri"
105
+
106
+ - path: "/api/checkout"
107
+ methods: ["POST"]
108
+ auth: required
109
+ description: "ร–deme iลŸlemi baลŸlat"
110
+
111
+ - path: "/api/orders"
112
+ methods: ["GET", "POST"]
113
+ auth: required
114
+ description: "SipariลŸ geรงmiลŸi ve yeni sipariลŸ"
115
+
116
+ - path: "/api/reviews"
117
+ methods: ["GET", "POST"]
118
+ auth: optional
119
+ description: "รœrรผn yorumlarฤฑ"
120
+
121
+ # Veri modelleri
122
+ data:
123
+ Product:
124
+ fields:
125
+ id: { type: "uuid", required: true, unique: true }
126
+ name: { type: "string", required: true }
127
+ slug: { type: "string", required: true, unique: true }
128
+ description: { type: "text", required: false }
129
+ price: { type: "decimal", required: true }
130
+ images: { type: "array", required: false }
131
+ category: { type: "string", required: true }
132
+ stock: { type: "integer", required: true }
133
+ createdAt: { type: "timestamp", required: true }
134
+ relations:
135
+ - "has_many: Review"
136
+ - "has_many: CartItem"
137
+
138
+ User:
139
+ fields:
140
+ id: { type: "uuid", required: true, unique: true }
141
+ email: { type: "string", required: true, unique: true }
142
+ name: { type: "string", required: true }
143
+ avatar: { type: "string", required: false }
144
+ createdAt: { type: "timestamp", required: true }
145
+ relations:
146
+ - "has_many: Order"
147
+ - "has_many: Review"
148
+ - "has_one: Cart"
149
+
150
+ Cart:
151
+ fields:
152
+ id: { type: "uuid", required: true, unique: true }
153
+ userId: { type: "uuid", required: false }
154
+ sessionId: { type: "string", required: false }
155
+ updatedAt: { type: "timestamp", required: true }
156
+ relations:
157
+ - "belongs_to: User"
158
+ - "has_many: CartItem"
159
+
160
+ CartItem:
161
+ fields:
162
+ id: { type: "uuid", required: true, unique: true }
163
+ cartId: { type: "uuid", required: true }
164
+ productId: { type: "uuid", required: true }
165
+ quantity: { type: "integer", required: true }
166
+ relations:
167
+ - "belongs_to: Cart"
168
+ - "belongs_to: Product"
169
+
170
+ Order:
171
+ fields:
172
+ id: { type: "uuid", required: true, unique: true }
173
+ userId: { type: "uuid", required: true }
174
+ status: { type: "enum", required: true } # pending, paid, shipped, delivered
175
+ total: { type: "decimal", required: true }
176
+ shippingAddress: { type: "json", required: true }
177
+ createdAt: { type: "timestamp", required: true }
178
+ relations:
179
+ - "belongs_to: User"
180
+ - "has_many: OrderItem"
181
+
182
+ Review:
183
+ fields:
184
+ id: { type: "uuid", required: true, unique: true }
185
+ productId: { type: "uuid", required: true }
186
+ userId: { type: "uuid", required: true }
187
+ rating: { type: "integer", required: true } # 1-5
188
+ comment: { type: "text", required: false }
189
+ createdAt: { type: "timestamp", required: true }
190
+ relations:
191
+ - "belongs_to: Product"
192
+ - "belongs_to: User"
@@ -0,0 +1,6 @@
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>
@@ -0,0 +1,227 @@
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 66% 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 66% 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 66%." />
26
+ <meta name="twitter:image" content="https://ebade.dev/og-image.png" />
27
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
28
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
29
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;600;800;900&family=JetBrains+Mono&display=swap"
30
+ rel="stylesheet" />
31
+ <link rel="stylesheet" href="style.css" />
32
+ <script src="https://unpkg.com/lucide@latest"></script>
33
+ </head>
34
+
35
+ <body>
36
+ <div id="canvas-container"></div>
37
+ <div class="bg-glow"></div>
38
+
39
+ <nav class="full-nav">
40
+ <div class="logo">ebade<span>.dev</span></div>
41
+ <div class="nav-links">
42
+ <a href="#technology">Technology</a>
43
+ <a href="#benchmarks">Benchmarks</a>
44
+ <a href="https://github.com/hasankemaldemirci/ebade" target="_blank" class="nav-github">
45
+ <i data-lucide="github"></i>
46
+ <span>GitHub</span>
47
+ </a>
48
+ <a href="https://github.com/hasankemaldemirci/ebade#quick-start" target="_blank" class="nav-cta">Get Started</a>
49
+ </div>
50
+ </nav>
51
+
52
+ <main>
53
+ <section class="hero-full">
54
+ <div class="hero-content">
55
+ <div class="badge-modern">
56
+ <i data-lucide="cpu" class="icon-small"></i> Protocol 0.1.0 // Alpha
57
+ </div>
58
+ <h1 class="glitch-text">The Essence of <span>Code</span></h1>
59
+ <p class="hero-description">
60
+ <span class="ebade-brand">ebade</span> is an evolution in abstract
61
+ engineering. We don't build components; we model intent. Designed
62
+ for the era where <strong>Agents</strong> are the primary
63
+ developers.
64
+ </p>
65
+ <div class="hero-actions">
66
+ <a href="#technology" class="btn-glow">Explore Protocol</a>
67
+ <a href="https://www.npmjs.com/package/ebade" class="btn-minimal">npm install ebade</a>
68
+ </div>
69
+ </div>
70
+
71
+ <div class="scroll-indicator">
72
+ <div class="line"></div>
73
+ <span>INTENT_STREAM</span>
74
+ </div>
75
+ </section>
76
+
77
+ <section id="technology" class="section-dark">
78
+ <div class="section-container">
79
+ <header class="section-header">
80
+ <div class="badge-accent">Philosophy</div>
81
+ <h2>Agentic <span>Intent</span></h2>
82
+ <p>
83
+ Why write 100 lines of boilerplate when an agent can infer
84
+ implementation from 8 lines of pure intent?
85
+ </p>
86
+ </header>
87
+
88
+ <div class="comparison-modern">
89
+ <div class="code-card legacy">
90
+ <div class="card-header">
91
+ <div class="window-controls">
92
+ <span class="control close"></span>
93
+ <span class="control minimize"></span>
94
+ <span class="control maximize"></span>
95
+ </div>
96
+ <div class="card-tag">React + Next.js</div>
97
+ </div>
98
+ <pre><code>export default function ProductList() {
99
+ const [items, setItems] = useState([]);
100
+ const [loading, setLoading] = useState(true);
101
+
102
+ useEffect(() => {
103
+ async function load() {
104
+ const res = await fetch('/api/products');
105
+ const json = await res.json();
106
+ setItems(json);
107
+ setLoading(false);
108
+ }
109
+ load();
110
+ }, []);
111
+
112
+ if (loading) return &lt;Spinner /&gt;;
113
+
114
+ return (
115
+ &lt;section className="grid"&gt;
116
+ {items.map(p =&gt; &lt;Card key={p.id} {...p} /&gt;)}
117
+ &lt;/section&gt;
118
+ );
119
+ }</code></pre>
120
+ </div>
121
+
122
+ <div class="transform-arrow">
123
+ <i data-lucide="zap"></i>
124
+ </div>
125
+
126
+ <div class="code-card ebade">
127
+ <div class="card-header">
128
+ <div class="window-controls">
129
+ <span class="control close"></span>
130
+ <span class="control minimize"></span>
131
+ <span class="control maximize"></span>
132
+ </div>
133
+ <div class="card-tag">ebade Protocol</div>
134
+ </div>
135
+ <pre><code><span class="keyword">@page</span>(<span class="string">'/products'</span>)
136
+ <span class="keyword">@intent</span>(<span class="string">'product-catalog'</span>)
137
+ <span class="keyword">@requires</span>([<span class="string">'products'</span>])
138
+ <span class="keyword">@compose</span>([<span class="string">'grid'</span>, <span class="string">'loader'</span>])
139
+ <span class="keyword">export function</span> <span class="function">Catalog</span>() {}</code></pre>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </section>
144
+
145
+ <section id="benchmarks" class="benchmark-minimal">
146
+ <div class="section-container">
147
+ <header class="section-header" style="margin-bottom: 4rem">
148
+ <div class="badge-accent">Efficiency</div>
149
+ <h2>Proven <span>Performance</span></h2>
150
+ <p style="margin: 0 auto; color: var(--text-dim); max-width: 600px">
151
+ Real-world benchmarks demonstrating how ebade slashes operational
152
+ costs and cognitive load for AI agents.
153
+ </p>
154
+ </header>
155
+ <div class="stats-box">
156
+ <div class="stat">
157
+ <div class="stat-icon"><i data-lucide="zap"></i></div>
158
+ <span class="val">66%</span>
159
+ <span class="label">Token Reduction</span>
160
+ </div>
161
+ <div class="stat-divider"></div>
162
+ <div class="stat">
163
+ <div class="stat-icon"><i data-lucide="brain"></i></div>
164
+ <span class="val">2.9x</span>
165
+ <span class="label">Agent Context Efficiency</span>
166
+ </div>
167
+ <div class="stat-divider"></div>
168
+ <div class="stat">
169
+ <div class="stat-icon" style="color: var(--accent-emerald)">
170
+ <i data-lucide="leaf"></i>
171
+ </div>
172
+ <span class="val">Zero</span>
173
+ <span class="label">Sustainable AI Core</span>
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </section>
178
+
179
+ <section class="features-grid-section">
180
+ <div class="section-container">
181
+ <header class="section-header">
182
+ <div class="badge-accent">Standard</div>
183
+ <h2 style="color: var(--text)">The ebade <span>Ecosystem</span></h2>
184
+ <p style="margin: 0 auto; color: var(--text-dim)">
185
+ Engineered for high-autonomy agents and complex product
186
+ lifecycles.
187
+ </p>
188
+ </header>
189
+ <div class="grid-3">
190
+ <div class="feature-item">
191
+ <i data-lucide="code-2"></i>
192
+ <h3>Agent-Native</h3>
193
+ <p>
194
+ Designed as a first-class citizen for LLMs. Structured intent
195
+ that models understand instantly.
196
+ </p>
197
+ </div>
198
+ <div class="feature-item">
199
+ <i data-lucide="layers"></i>
200
+ <h3>Meta-Abstraction</h3>
201
+ <p>
202
+ Platform-agnostic intent layer. Currently optimized for Next.js.
203
+ The same intent will power mobile, backend, and beyond.
204
+ </p>
205
+ </div>
206
+ <div class="feature-item">
207
+ <i data-lucide="terminal"></i>
208
+ <h3>Binary Scaffold</h3>
209
+ <p>
210
+ Generate full, production-ready project structures from a single
211
+ schema definition.
212
+ </p>
213
+ </div>
214
+ </div>
215
+ </div>
216
+ </section>
217
+ </main>
218
+
219
+
220
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
221
+ <script src="main.js"></script>
222
+ <script>
223
+ lucide.createIcons();
224
+ </script>
225
+ </body>
226
+
227
+ </html>
@@ -0,0 +1,147 @@
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
+ });
Binary file