aura-security 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/LICENSE +21 -0
- package/README.md +446 -0
- package/deploy/AWS-DEPLOYMENT.md +358 -0
- package/deploy/terraform/main.tf +362 -0
- package/deploy/terraform/terraform.tfvars.example +6 -0
- package/dist/agents/base.d.ts +44 -0
- package/dist/agents/base.js +96 -0
- package/dist/agents/index.d.ts +14 -0
- package/dist/agents/index.js +17 -0
- package/dist/agents/policy/evaluator.d.ts +15 -0
- package/dist/agents/policy/evaluator.js +183 -0
- package/dist/agents/policy/index.d.ts +12 -0
- package/dist/agents/policy/index.js +15 -0
- package/dist/agents/policy/validator.d.ts +15 -0
- package/dist/agents/policy/validator.js +182 -0
- package/dist/agents/scanners/gitleaks.d.ts +14 -0
- package/dist/agents/scanners/gitleaks.js +155 -0
- package/dist/agents/scanners/grype.d.ts +14 -0
- package/dist/agents/scanners/grype.js +109 -0
- package/dist/agents/scanners/index.d.ts +15 -0
- package/dist/agents/scanners/index.js +27 -0
- package/dist/agents/scanners/npm-audit.d.ts +13 -0
- package/dist/agents/scanners/npm-audit.js +129 -0
- package/dist/agents/scanners/semgrep.d.ts +14 -0
- package/dist/agents/scanners/semgrep.js +131 -0
- package/dist/agents/scanners/trivy.d.ts +14 -0
- package/dist/agents/scanners/trivy.js +122 -0
- package/dist/agents/types.d.ts +137 -0
- package/dist/agents/types.js +91 -0
- package/dist/auditor/index.d.ts +3 -0
- package/dist/auditor/index.js +2 -0
- package/dist/auditor/pipeline.d.ts +19 -0
- package/dist/auditor/pipeline.js +240 -0
- package/dist/auditor/validator.d.ts +17 -0
- package/dist/auditor/validator.js +58 -0
- package/dist/aura/client.d.ts +29 -0
- package/dist/aura/client.js +125 -0
- package/dist/aura/index.d.ts +4 -0
- package/dist/aura/index.js +2 -0
- package/dist/aura/server.d.ts +45 -0
- package/dist/aura/server.js +343 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.js +1433 -0
- package/dist/client/index.d.ts +41 -0
- package/dist/client/index.js +170 -0
- package/dist/compliance/index.d.ts +40 -0
- package/dist/compliance/index.js +292 -0
- package/dist/database/index.d.ts +77 -0
- package/dist/database/index.js +395 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +762 -0
- package/dist/integrations/aura-scanner.d.ts +69 -0
- package/dist/integrations/aura-scanner.js +155 -0
- package/dist/integrations/aws-scanner.d.ts +63 -0
- package/dist/integrations/aws-scanner.js +624 -0
- package/dist/integrations/config.d.ts +69 -0
- package/dist/integrations/config.js +212 -0
- package/dist/integrations/github.d.ts +45 -0
- package/dist/integrations/github.js +201 -0
- package/dist/integrations/gitlab.d.ts +36 -0
- package/dist/integrations/gitlab.js +110 -0
- package/dist/integrations/index.d.ts +11 -0
- package/dist/integrations/index.js +11 -0
- package/dist/integrations/local-scanner.d.ts +146 -0
- package/dist/integrations/local-scanner.js +1654 -0
- package/dist/integrations/notifications.d.ts +99 -0
- package/dist/integrations/notifications.js +305 -0
- package/dist/integrations/scanners.d.ts +57 -0
- package/dist/integrations/scanners.js +217 -0
- package/dist/integrations/slop-scanner.d.ts +69 -0
- package/dist/integrations/slop-scanner.js +155 -0
- package/dist/integrations/webhook.d.ts +37 -0
- package/dist/integrations/webhook.js +256 -0
- package/dist/orchestrator/index.d.ts +72 -0
- package/dist/orchestrator/index.js +187 -0
- package/dist/output/index.d.ts +152 -0
- package/dist/output/index.js +399 -0
- package/dist/pipeline/index.d.ts +72 -0
- package/dist/pipeline/index.js +313 -0
- package/dist/sbom/index.d.ts +94 -0
- package/dist/sbom/index.js +298 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.js +2 -0
- package/dist/schemas/input.schema.d.ts +87 -0
- package/dist/schemas/input.schema.js +44 -0
- package/dist/schemas/output.schema.d.ts +115 -0
- package/dist/schemas/output.schema.js +64 -0
- package/dist/serve-visualizer.d.ts +2 -0
- package/dist/serve-visualizer.js +78 -0
- package/dist/slop/client.d.ts +29 -0
- package/dist/slop/client.js +125 -0
- package/dist/slop/index.d.ts +4 -0
- package/dist/slop/index.js +2 -0
- package/dist/slop/server.d.ts +45 -0
- package/dist/slop/server.js +343 -0
- package/dist/types/events.d.ts +62 -0
- package/dist/types/events.js +2 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/visualizer/index.d.ts +4 -0
- package/dist/visualizer/index.js +181 -0
- package/dist/websocket/index.d.ts +88 -0
- package/dist/websocket/index.js +195 -0
- package/dist/zones/index.d.ts +7 -0
- package/dist/zones/index.js +7 -0
- package/dist/zones/manager.d.ts +101 -0
- package/dist/zones/manager.js +304 -0
- package/dist/zones/types.d.ts +78 -0
- package/dist/zones/types.js +33 -0
- package/package.json +84 -0
- package/visualizer/app.js +0 -0
- package/visualizer/index-minimal.html +1771 -0
- package/visualizer/index.html +2933 -0
- package/visualizer/landing.html +1328 -0
- package/visualizer/styles.css +0 -0
|
@@ -0,0 +1,1328 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>aurasecurity - Security Scanning Visualized</title>
|
|
7
|
+
<meta name="description" content="Unified security scanning with 3D visualization. One command, all your scanners, complete clarity.">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
|
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
|
|
11
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
|
12
|
+
<style>
|
|
13
|
+
* {
|
|
14
|
+
margin: 0;
|
|
15
|
+
padding: 0;
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
:root {
|
|
20
|
+
--bg: #030712;
|
|
21
|
+
--bg-elevated: #0f172a;
|
|
22
|
+
--bg-card: rgba(15, 23, 42, 0.6);
|
|
23
|
+
--border: rgba(148, 163, 184, 0.1);
|
|
24
|
+
--text: #f8fafc;
|
|
25
|
+
--text-secondary: #94a3b8;
|
|
26
|
+
--text-muted: #64748b;
|
|
27
|
+
--primary: #06b6d4;
|
|
28
|
+
--primary-glow: rgba(6, 182, 212, 0.4);
|
|
29
|
+
--secondary: #8b5cf6;
|
|
30
|
+
--danger: #ef4444;
|
|
31
|
+
--warning: #f59e0b;
|
|
32
|
+
--success: #10b981;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
body {
|
|
36
|
+
font-family: 'Inter', sans-serif;
|
|
37
|
+
background: var(--bg);
|
|
38
|
+
color: var(--text);
|
|
39
|
+
line-height: 1.6;
|
|
40
|
+
overflow-x: hidden;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
h1, h2, h3, h4 {
|
|
44
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Animated gradient mesh background */
|
|
48
|
+
.mesh-gradient {
|
|
49
|
+
position: fixed;
|
|
50
|
+
top: 0;
|
|
51
|
+
left: 0;
|
|
52
|
+
right: 0;
|
|
53
|
+
bottom: 0;
|
|
54
|
+
z-index: -2;
|
|
55
|
+
background:
|
|
56
|
+
radial-gradient(at 0% 0%, rgba(6, 182, 212, 0.15) 0%, transparent 50%),
|
|
57
|
+
radial-gradient(at 100% 0%, rgba(139, 92, 246, 0.1) 0%, transparent 50%),
|
|
58
|
+
radial-gradient(at 100% 100%, rgba(6, 182, 212, 0.1) 0%, transparent 50%),
|
|
59
|
+
radial-gradient(at 0% 100%, rgba(139, 92, 246, 0.15) 0%, transparent 50%);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Grid pattern overlay */
|
|
63
|
+
.grid-pattern {
|
|
64
|
+
position: fixed;
|
|
65
|
+
top: 0;
|
|
66
|
+
left: 0;
|
|
67
|
+
right: 0;
|
|
68
|
+
bottom: 0;
|
|
69
|
+
z-index: -1;
|
|
70
|
+
background-image:
|
|
71
|
+
linear-gradient(rgba(148, 163, 184, 0.03) 1px, transparent 1px),
|
|
72
|
+
linear-gradient(90deg, rgba(148, 163, 184, 0.03) 1px, transparent 1px);
|
|
73
|
+
background-size: 60px 60px;
|
|
74
|
+
mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Navigation */
|
|
78
|
+
nav {
|
|
79
|
+
position: fixed;
|
|
80
|
+
top: 0;
|
|
81
|
+
left: 0;
|
|
82
|
+
right: 0;
|
|
83
|
+
z-index: 100;
|
|
84
|
+
padding: 1rem 2rem;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.nav-inner {
|
|
88
|
+
max-width: 1280px;
|
|
89
|
+
margin: 0 auto;
|
|
90
|
+
display: flex;
|
|
91
|
+
justify-content: space-between;
|
|
92
|
+
align-items: center;
|
|
93
|
+
padding: 0.75rem 1.5rem;
|
|
94
|
+
background: rgba(3, 7, 18, 0.8);
|
|
95
|
+
backdrop-filter: blur(20px);
|
|
96
|
+
border: 1px solid var(--border);
|
|
97
|
+
border-radius: 16px;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.logo {
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: 0.75rem;
|
|
104
|
+
text-decoration: none;
|
|
105
|
+
color: var(--text);
|
|
106
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
107
|
+
font-weight: 700;
|
|
108
|
+
font-size: 1.25rem;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.logo-mark {
|
|
112
|
+
width: 36px;
|
|
113
|
+
height: 36px;
|
|
114
|
+
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
|
115
|
+
border-radius: 10px;
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
font-size: 1.25rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.nav-links {
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
gap: 0.5rem;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.nav-link {
|
|
129
|
+
color: var(--text-secondary);
|
|
130
|
+
text-decoration: none;
|
|
131
|
+
padding: 0.5rem 1rem;
|
|
132
|
+
border-radius: 8px;
|
|
133
|
+
font-size: 0.875rem;
|
|
134
|
+
font-weight: 500;
|
|
135
|
+
transition: all 0.2s;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.nav-link:hover {
|
|
139
|
+
color: var(--text);
|
|
140
|
+
background: rgba(148, 163, 184, 0.1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.btn {
|
|
144
|
+
display: inline-flex;
|
|
145
|
+
align-items: center;
|
|
146
|
+
gap: 0.5rem;
|
|
147
|
+
padding: 0.625rem 1.25rem;
|
|
148
|
+
border-radius: 10px;
|
|
149
|
+
font-size: 0.875rem;
|
|
150
|
+
font-weight: 600;
|
|
151
|
+
text-decoration: none;
|
|
152
|
+
transition: all 0.2s;
|
|
153
|
+
border: none;
|
|
154
|
+
cursor: pointer;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.btn-primary {
|
|
158
|
+
background: linear-gradient(135deg, var(--primary), #0891b2);
|
|
159
|
+
color: white;
|
|
160
|
+
box-shadow: 0 0 20px var(--primary-glow);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.btn-primary:hover {
|
|
164
|
+
transform: translateY(-2px);
|
|
165
|
+
box-shadow: 0 0 30px var(--primary-glow);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.btn-ghost {
|
|
169
|
+
background: transparent;
|
|
170
|
+
color: var(--text);
|
|
171
|
+
border: 1px solid var(--border);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.btn-ghost:hover {
|
|
175
|
+
background: rgba(148, 163, 184, 0.1);
|
|
176
|
+
border-color: rgba(148, 163, 184, 0.2);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* Hero Section */
|
|
180
|
+
.hero {
|
|
181
|
+
min-height: 100vh;
|
|
182
|
+
display: flex;
|
|
183
|
+
align-items: center;
|
|
184
|
+
padding: 8rem 2rem 4rem;
|
|
185
|
+
position: relative;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.hero-container {
|
|
189
|
+
max-width: 1280px;
|
|
190
|
+
margin: 0 auto;
|
|
191
|
+
display: grid;
|
|
192
|
+
grid-template-columns: 1fr 1fr;
|
|
193
|
+
gap: 4rem;
|
|
194
|
+
align-items: center;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.hero-content {
|
|
198
|
+
position: relative;
|
|
199
|
+
z-index: 2;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.hero-badge {
|
|
203
|
+
display: inline-flex;
|
|
204
|
+
align-items: center;
|
|
205
|
+
gap: 0.5rem;
|
|
206
|
+
padding: 0.5rem 1rem;
|
|
207
|
+
background: rgba(6, 182, 212, 0.1);
|
|
208
|
+
border: 1px solid rgba(6, 182, 212, 0.2);
|
|
209
|
+
border-radius: 100px;
|
|
210
|
+
font-size: 0.8125rem;
|
|
211
|
+
color: var(--primary);
|
|
212
|
+
margin-bottom: 1.5rem;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.hero-badge::before {
|
|
216
|
+
content: '';
|
|
217
|
+
width: 6px;
|
|
218
|
+
height: 6px;
|
|
219
|
+
background: var(--primary);
|
|
220
|
+
border-radius: 50%;
|
|
221
|
+
animation: pulse 2s infinite;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
@keyframes pulse {
|
|
225
|
+
0%, 100% { opacity: 1; transform: scale(1); }
|
|
226
|
+
50% { opacity: 0.5; transform: scale(1.2); }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.hero h1 {
|
|
230
|
+
font-size: clamp(2.5rem, 5vw, 3.75rem);
|
|
231
|
+
font-weight: 700;
|
|
232
|
+
line-height: 1.1;
|
|
233
|
+
margin-bottom: 1.5rem;
|
|
234
|
+
letter-spacing: -0.02em;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.hero h1 .gradient-text {
|
|
238
|
+
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
|
239
|
+
-webkit-background-clip: text;
|
|
240
|
+
-webkit-text-fill-color: transparent;
|
|
241
|
+
background-clip: text;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.hero-description {
|
|
245
|
+
font-size: 1.125rem;
|
|
246
|
+
color: var(--text-secondary);
|
|
247
|
+
margin-bottom: 2rem;
|
|
248
|
+
max-width: 480px;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.hero-actions {
|
|
252
|
+
display: flex;
|
|
253
|
+
gap: 1rem;
|
|
254
|
+
flex-wrap: wrap;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.hero-actions .btn {
|
|
258
|
+
padding: 0.875rem 1.75rem;
|
|
259
|
+
font-size: 0.9375rem;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.hero-stats {
|
|
263
|
+
display: flex;
|
|
264
|
+
gap: 2.5rem;
|
|
265
|
+
margin-top: 3rem;
|
|
266
|
+
padding-top: 2rem;
|
|
267
|
+
border-top: 1px solid var(--border);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.stat {
|
|
271
|
+
text-align: left;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.stat-value {
|
|
275
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
276
|
+
font-size: 1.75rem;
|
|
277
|
+
font-weight: 700;
|
|
278
|
+
color: var(--text);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.stat-label {
|
|
282
|
+
font-size: 0.8125rem;
|
|
283
|
+
color: var(--text-muted);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* 3D Scene */
|
|
287
|
+
.hero-3d {
|
|
288
|
+
position: relative;
|
|
289
|
+
height: 500px;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
#hero-canvas {
|
|
293
|
+
width: 100%;
|
|
294
|
+
height: 100%;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* Bento Grid Features */
|
|
298
|
+
.features-section {
|
|
299
|
+
padding: 6rem 2rem;
|
|
300
|
+
position: relative;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.features-container {
|
|
304
|
+
max-width: 1280px;
|
|
305
|
+
margin: 0 auto;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.section-header {
|
|
309
|
+
text-align: center;
|
|
310
|
+
margin-bottom: 4rem;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.section-header h2 {
|
|
314
|
+
font-size: 2.5rem;
|
|
315
|
+
font-weight: 700;
|
|
316
|
+
margin-bottom: 1rem;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.section-header p {
|
|
320
|
+
color: var(--text-secondary);
|
|
321
|
+
font-size: 1.125rem;
|
|
322
|
+
max-width: 600px;
|
|
323
|
+
margin: 0 auto;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.bento-grid {
|
|
327
|
+
display: grid;
|
|
328
|
+
grid-template-columns: repeat(3, 1fr);
|
|
329
|
+
grid-template-rows: auto auto;
|
|
330
|
+
gap: 1.5rem;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.bento-card {
|
|
334
|
+
background: var(--bg-card);
|
|
335
|
+
backdrop-filter: blur(10px);
|
|
336
|
+
border: 1px solid var(--border);
|
|
337
|
+
border-radius: 20px;
|
|
338
|
+
padding: 2rem;
|
|
339
|
+
transition: all 0.3s;
|
|
340
|
+
position: relative;
|
|
341
|
+
overflow: hidden;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.bento-card::before {
|
|
345
|
+
content: '';
|
|
346
|
+
position: absolute;
|
|
347
|
+
top: 0;
|
|
348
|
+
left: 0;
|
|
349
|
+
right: 0;
|
|
350
|
+
height: 1px;
|
|
351
|
+
background: linear-gradient(90deg, transparent, rgba(6, 182, 212, 0.5), transparent);
|
|
352
|
+
opacity: 0;
|
|
353
|
+
transition: opacity 0.3s;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.bento-card:hover {
|
|
357
|
+
border-color: rgba(6, 182, 212, 0.3);
|
|
358
|
+
transform: translateY(-4px);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.bento-card:hover::before {
|
|
362
|
+
opacity: 1;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.bento-card.featured {
|
|
366
|
+
grid-column: span 2;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.bento-icon {
|
|
370
|
+
width: 48px;
|
|
371
|
+
height: 48px;
|
|
372
|
+
background: linear-gradient(135deg, rgba(6, 182, 212, 0.2), rgba(139, 92, 246, 0.2));
|
|
373
|
+
border-radius: 12px;
|
|
374
|
+
display: flex;
|
|
375
|
+
align-items: center;
|
|
376
|
+
justify-content: center;
|
|
377
|
+
font-size: 1.5rem;
|
|
378
|
+
margin-bottom: 1.25rem;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.bento-card h3 {
|
|
382
|
+
font-size: 1.25rem;
|
|
383
|
+
font-weight: 600;
|
|
384
|
+
margin-bottom: 0.75rem;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.bento-card p {
|
|
388
|
+
color: var(--text-secondary);
|
|
389
|
+
font-size: 0.9375rem;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* Code Preview */
|
|
393
|
+
.code-preview {
|
|
394
|
+
margin-top: 1.5rem;
|
|
395
|
+
background: rgba(0, 0, 0, 0.4);
|
|
396
|
+
border-radius: 12px;
|
|
397
|
+
padding: 1rem 1.25rem;
|
|
398
|
+
font-family: 'SF Mono', 'Fira Code', monospace;
|
|
399
|
+
font-size: 0.8125rem;
|
|
400
|
+
overflow-x: auto;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.code-line {
|
|
404
|
+
display: flex;
|
|
405
|
+
gap: 0.75rem;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.code-prompt {
|
|
409
|
+
color: var(--primary);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.code-command {
|
|
413
|
+
color: var(--text);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* SLOP Protocol Section */
|
|
417
|
+
.slop-section {
|
|
418
|
+
padding: 6rem 2rem;
|
|
419
|
+
background: linear-gradient(180deg, rgba(139, 92, 246, 0.02), transparent, rgba(6, 182, 212, 0.02));
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.slop-container {
|
|
423
|
+
max-width: 1280px;
|
|
424
|
+
margin: 0 auto;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.slop-grid {
|
|
428
|
+
display: grid;
|
|
429
|
+
grid-template-columns: repeat(4, 1fr);
|
|
430
|
+
gap: 1.5rem;
|
|
431
|
+
margin-top: 3rem;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.slop-card {
|
|
435
|
+
background: var(--bg-card);
|
|
436
|
+
border: 1px solid var(--border);
|
|
437
|
+
border-radius: 16px;
|
|
438
|
+
padding: 1.75rem;
|
|
439
|
+
text-align: center;
|
|
440
|
+
transition: all 0.3s;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.slop-card:hover {
|
|
444
|
+
border-color: rgba(6, 182, 212, 0.3);
|
|
445
|
+
transform: translateY(-4px);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.slop-letter {
|
|
449
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
450
|
+
font-size: 3rem;
|
|
451
|
+
font-weight: 700;
|
|
452
|
+
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
|
453
|
+
-webkit-background-clip: text;
|
|
454
|
+
-webkit-text-fill-color: transparent;
|
|
455
|
+
background-clip: text;
|
|
456
|
+
margin-bottom: 0.5rem;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.slop-word {
|
|
460
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
461
|
+
font-size: 1.125rem;
|
|
462
|
+
font-weight: 600;
|
|
463
|
+
color: var(--text);
|
|
464
|
+
margin-bottom: 0.75rem;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.slop-desc {
|
|
468
|
+
font-size: 0.875rem;
|
|
469
|
+
color: var(--text-secondary);
|
|
470
|
+
line-height: 1.5;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/* Team Section */
|
|
474
|
+
.team-section {
|
|
475
|
+
padding: 6rem 2rem;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.team-container {
|
|
479
|
+
max-width: 1280px;
|
|
480
|
+
margin: 0 auto;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.team-grid {
|
|
484
|
+
display: grid;
|
|
485
|
+
grid-template-columns: repeat(3, 1fr);
|
|
486
|
+
gap: 2rem;
|
|
487
|
+
margin-top: 3rem;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.team-card {
|
|
491
|
+
background: var(--bg-card);
|
|
492
|
+
border: 1px solid var(--border);
|
|
493
|
+
border-radius: 16px;
|
|
494
|
+
padding: 2rem;
|
|
495
|
+
text-align: center;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.team-icon {
|
|
499
|
+
width: 64px;
|
|
500
|
+
height: 64px;
|
|
501
|
+
margin: 0 auto 1rem;
|
|
502
|
+
background: linear-gradient(135deg, rgba(6, 182, 212, 0.2), rgba(139, 92, 246, 0.2));
|
|
503
|
+
border-radius: 16px;
|
|
504
|
+
display: flex;
|
|
505
|
+
align-items: center;
|
|
506
|
+
justify-content: center;
|
|
507
|
+
font-size: 1.75rem;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.team-card h3 {
|
|
511
|
+
font-size: 1.125rem;
|
|
512
|
+
font-weight: 600;
|
|
513
|
+
margin-bottom: 0.5rem;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
.team-card p {
|
|
517
|
+
font-size: 0.9375rem;
|
|
518
|
+
color: var(--text-secondary);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/* Deterministic Section */
|
|
522
|
+
.deterministic-section {
|
|
523
|
+
padding: 6rem 2rem;
|
|
524
|
+
background: linear-gradient(180deg, transparent, rgba(16, 185, 129, 0.03), transparent);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.deterministic-container {
|
|
528
|
+
max-width: 900px;
|
|
529
|
+
margin: 0 auto;
|
|
530
|
+
text-align: center;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.comparison-grid {
|
|
534
|
+
display: grid;
|
|
535
|
+
grid-template-columns: 1fr 1fr;
|
|
536
|
+
gap: 2rem;
|
|
537
|
+
margin-top: 3rem;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
.comparison-card {
|
|
541
|
+
background: var(--bg-card);
|
|
542
|
+
border: 1px solid var(--border);
|
|
543
|
+
border-radius: 16px;
|
|
544
|
+
padding: 2rem;
|
|
545
|
+
text-align: left;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.comparison-card.bad {
|
|
549
|
+
border-color: rgba(239, 68, 68, 0.3);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.comparison-card.good {
|
|
553
|
+
border-color: rgba(16, 185, 129, 0.3);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.comparison-header {
|
|
557
|
+
display: flex;
|
|
558
|
+
align-items: center;
|
|
559
|
+
gap: 0.75rem;
|
|
560
|
+
margin-bottom: 1.25rem;
|
|
561
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
562
|
+
font-weight: 600;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.comparison-card.bad .comparison-header {
|
|
566
|
+
color: #ef4444;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.comparison-card.good .comparison-header {
|
|
570
|
+
color: #10b981;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.comparison-list {
|
|
574
|
+
list-style: none;
|
|
575
|
+
font-size: 0.9375rem;
|
|
576
|
+
color: var(--text-secondary);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.comparison-list li {
|
|
580
|
+
padding: 0.5rem 0;
|
|
581
|
+
padding-left: 1.5rem;
|
|
582
|
+
position: relative;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.comparison-list li::before {
|
|
586
|
+
content: '';
|
|
587
|
+
position: absolute;
|
|
588
|
+
left: 0;
|
|
589
|
+
top: 50%;
|
|
590
|
+
transform: translateY(-50%);
|
|
591
|
+
width: 8px;
|
|
592
|
+
height: 8px;
|
|
593
|
+
border-radius: 50%;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
.comparison-card.bad .comparison-list li::before {
|
|
597
|
+
background: #ef4444;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.comparison-card.good .comparison-list li::before {
|
|
601
|
+
background: #10b981;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
@media (max-width: 1024px) {
|
|
605
|
+
.slop-grid {
|
|
606
|
+
grid-template-columns: repeat(2, 1fr);
|
|
607
|
+
}
|
|
608
|
+
.team-grid {
|
|
609
|
+
grid-template-columns: 1fr;
|
|
610
|
+
}
|
|
611
|
+
.comparison-grid {
|
|
612
|
+
grid-template-columns: 1fr;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
@media (max-width: 640px) {
|
|
617
|
+
.slop-grid {
|
|
618
|
+
grid-template-columns: 1fr;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/* Tools Section */
|
|
623
|
+
.tools-section {
|
|
624
|
+
padding: 6rem 2rem;
|
|
625
|
+
background: linear-gradient(180deg, transparent, rgba(6, 182, 212, 0.02), transparent);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.tools-container {
|
|
629
|
+
max-width: 1280px;
|
|
630
|
+
margin: 0 auto;
|
|
631
|
+
text-align: center;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.tools-grid {
|
|
635
|
+
display: flex;
|
|
636
|
+
flex-wrap: wrap;
|
|
637
|
+
gap: 1rem;
|
|
638
|
+
justify-content: center;
|
|
639
|
+
margin-top: 3rem;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.tool-chip {
|
|
643
|
+
display: flex;
|
|
644
|
+
align-items: center;
|
|
645
|
+
gap: 0.625rem;
|
|
646
|
+
padding: 0.75rem 1.25rem;
|
|
647
|
+
background: var(--bg-card);
|
|
648
|
+
border: 1px solid var(--border);
|
|
649
|
+
border-radius: 100px;
|
|
650
|
+
font-size: 0.9375rem;
|
|
651
|
+
font-weight: 500;
|
|
652
|
+
transition: all 0.2s;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.tool-chip:hover {
|
|
656
|
+
border-color: var(--primary);
|
|
657
|
+
box-shadow: 0 0 20px rgba(6, 182, 212, 0.1);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
.tool-chip .icon {
|
|
661
|
+
font-size: 1.125rem;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/* CTA Section */
|
|
665
|
+
.cta-section {
|
|
666
|
+
padding: 8rem 2rem;
|
|
667
|
+
text-align: center;
|
|
668
|
+
position: relative;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.cta-section::before {
|
|
672
|
+
content: '';
|
|
673
|
+
position: absolute;
|
|
674
|
+
top: 50%;
|
|
675
|
+
left: 50%;
|
|
676
|
+
transform: translate(-50%, -50%);
|
|
677
|
+
width: 600px;
|
|
678
|
+
height: 600px;
|
|
679
|
+
background: radial-gradient(circle, rgba(6, 182, 212, 0.1) 0%, transparent 70%);
|
|
680
|
+
pointer-events: none;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.cta-content {
|
|
684
|
+
position: relative;
|
|
685
|
+
z-index: 2;
|
|
686
|
+
max-width: 600px;
|
|
687
|
+
margin: 0 auto;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.cta-content h2 {
|
|
691
|
+
font-size: 2.5rem;
|
|
692
|
+
font-weight: 700;
|
|
693
|
+
margin-bottom: 1rem;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.cta-content p {
|
|
697
|
+
color: var(--text-secondary);
|
|
698
|
+
font-size: 1.125rem;
|
|
699
|
+
margin-bottom: 2rem;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
.cta-buttons {
|
|
703
|
+
display: flex;
|
|
704
|
+
gap: 1rem;
|
|
705
|
+
justify-content: center;
|
|
706
|
+
flex-wrap: wrap;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/* Footer */
|
|
710
|
+
footer {
|
|
711
|
+
padding: 4rem 2rem 2rem;
|
|
712
|
+
border-top: 1px solid var(--border);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
.footer-container {
|
|
716
|
+
max-width: 1280px;
|
|
717
|
+
margin: 0 auto;
|
|
718
|
+
display: flex;
|
|
719
|
+
justify-content: space-between;
|
|
720
|
+
align-items: center;
|
|
721
|
+
flex-wrap: wrap;
|
|
722
|
+
gap: 2rem;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
.footer-left {
|
|
726
|
+
display: flex;
|
|
727
|
+
align-items: center;
|
|
728
|
+
gap: 2rem;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.footer-links {
|
|
732
|
+
display: flex;
|
|
733
|
+
gap: 1.5rem;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.footer-links a {
|
|
737
|
+
color: var(--text-muted);
|
|
738
|
+
text-decoration: none;
|
|
739
|
+
font-size: 0.875rem;
|
|
740
|
+
transition: color 0.2s;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.footer-links a:hover {
|
|
744
|
+
color: var(--text);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
.footer-right {
|
|
748
|
+
color: var(--text-muted);
|
|
749
|
+
font-size: 0.8125rem;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/* Responsive */
|
|
753
|
+
@media (max-width: 1024px) {
|
|
754
|
+
.hero-container {
|
|
755
|
+
grid-template-columns: 1fr;
|
|
756
|
+
text-align: center;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
.hero-content {
|
|
760
|
+
order: 2;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
.hero-3d {
|
|
764
|
+
order: 1;
|
|
765
|
+
height: 350px;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.hero-description {
|
|
769
|
+
margin: 0 auto 2rem;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.hero-actions {
|
|
773
|
+
justify-content: center;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
.hero-stats {
|
|
777
|
+
justify-content: center;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
.bento-grid {
|
|
781
|
+
grid-template-columns: 1fr;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.bento-card.featured {
|
|
785
|
+
grid-column: span 1;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
@media (max-width: 640px) {
|
|
790
|
+
.nav-links {
|
|
791
|
+
display: none;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.hero h1 {
|
|
795
|
+
font-size: 2rem;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
.hero-stats {
|
|
799
|
+
flex-direction: column;
|
|
800
|
+
gap: 1.5rem;
|
|
801
|
+
align-items: center;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.footer-container {
|
|
805
|
+
flex-direction: column;
|
|
806
|
+
text-align: center;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.footer-left {
|
|
810
|
+
flex-direction: column;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
</style>
|
|
814
|
+
</head>
|
|
815
|
+
<body>
|
|
816
|
+
<div class="mesh-gradient"></div>
|
|
817
|
+
<div class="grid-pattern"></div>
|
|
818
|
+
|
|
819
|
+
<!-- Navigation -->
|
|
820
|
+
<nav>
|
|
821
|
+
<div class="nav-inner">
|
|
822
|
+
<a href="/" class="logo">
|
|
823
|
+
<div class="logo-mark">🛡️</div>
|
|
824
|
+
aurasecurity
|
|
825
|
+
</a>
|
|
826
|
+
<div class="nav-links">
|
|
827
|
+
<a href="#slop" class="nav-link">SLOP Protocol</a>
|
|
828
|
+
<a href="#features" class="nav-link">Features</a>
|
|
829
|
+
<a href="#team" class="nav-link">Team</a>
|
|
830
|
+
<a href="https://github.com/aurasecurity/aura-security" target="_blank" class="nav-link">GitHub</a>
|
|
831
|
+
<a href="/app" class="btn btn-primary">Open Dashboard</a>
|
|
832
|
+
</div>
|
|
833
|
+
</div>
|
|
834
|
+
</nav>
|
|
835
|
+
|
|
836
|
+
<!-- Hero Section -->
|
|
837
|
+
<section class="hero">
|
|
838
|
+
<div class="hero-container">
|
|
839
|
+
<div class="hero-content">
|
|
840
|
+
<div class="hero-badge">Built by Security Engineers · 100% Deterministic</div>
|
|
841
|
+
<h1>Real security tools.<br><span class="gradient-text">Zero AI hallucinations.</span></h1>
|
|
842
|
+
<p class="hero-description">
|
|
843
|
+
We run Gitleaks, Trivy, Semgrep, and Grype in parallel. Same input = same output, every time.
|
|
844
|
+
No LLM guessing. No false confidence. Just real CVEs and real secrets, with line numbers.
|
|
845
|
+
</p>
|
|
846
|
+
<div class="hero-actions">
|
|
847
|
+
<a href="/app" class="btn btn-primary">
|
|
848
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
849
|
+
<path d="M5 12h14M12 5l7 7-7 7"/>
|
|
850
|
+
</svg>
|
|
851
|
+
Try Dashboard
|
|
852
|
+
</a>
|
|
853
|
+
<a href="https://github.com/aurasecurity/aura-security" target="_blank" class="btn btn-ghost">
|
|
854
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
|
|
855
|
+
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
|
856
|
+
</svg>
|
|
857
|
+
View Source
|
|
858
|
+
</a>
|
|
859
|
+
</div>
|
|
860
|
+
<div class="hero-stats">
|
|
861
|
+
<div class="stat">
|
|
862
|
+
<div class="stat-value">0%</div>
|
|
863
|
+
<div class="stat-label">AI Hallucinations</div>
|
|
864
|
+
</div>
|
|
865
|
+
<div class="stat">
|
|
866
|
+
<div class="stat-value">8+</div>
|
|
867
|
+
<div class="stat-label">Real Scanners</div>
|
|
868
|
+
</div>
|
|
869
|
+
<div class="stat">
|
|
870
|
+
<div class="stat-value">SLOP</div>
|
|
871
|
+
<div class="stat-label">Multi-Agent Protocol</div>
|
|
872
|
+
</div>
|
|
873
|
+
</div>
|
|
874
|
+
</div>
|
|
875
|
+
|
|
876
|
+
<div class="hero-3d">
|
|
877
|
+
<div id="hero-canvas"></div>
|
|
878
|
+
</div>
|
|
879
|
+
</div>
|
|
880
|
+
</section>
|
|
881
|
+
|
|
882
|
+
<!-- Features Section -->
|
|
883
|
+
<section class="features-section" id="features">
|
|
884
|
+
<div class="features-container">
|
|
885
|
+
<div class="section-header">
|
|
886
|
+
<h2>No fluff. Just works.</h2>
|
|
887
|
+
<p>One command. Eight scanners. Real vulnerabilities with real line numbers.</p>
|
|
888
|
+
</div>
|
|
889
|
+
|
|
890
|
+
<div class="bento-grid">
|
|
891
|
+
<div class="bento-card featured">
|
|
892
|
+
<div class="bento-icon">⚡</div>
|
|
893
|
+
<h3>Unified Command Interface</h3>
|
|
894
|
+
<p>Run multiple security scanners with a single command. No more juggling terminals and output formats. Results aggregated and normalized automatically.</p>
|
|
895
|
+
<div class="code-preview">
|
|
896
|
+
<div class="code-line">
|
|
897
|
+
<span class="code-prompt">$</span>
|
|
898
|
+
<span class="code-command">aura-security scan ./my-project</span>
|
|
899
|
+
</div>
|
|
900
|
+
</div>
|
|
901
|
+
</div>
|
|
902
|
+
|
|
903
|
+
<div class="bento-card">
|
|
904
|
+
<div class="bento-icon">🎯</div>
|
|
905
|
+
<h3>3D Dashboard</h3>
|
|
906
|
+
<p>Interactive Three.js visualization shows your security posture spatially. Click nodes, filter findings, see the big picture.</p>
|
|
907
|
+
</div>
|
|
908
|
+
|
|
909
|
+
<div class="bento-card">
|
|
910
|
+
<div class="bento-icon">☁️</div>
|
|
911
|
+
<h3>AWS Scanning</h3>
|
|
912
|
+
<p>Audit IAM, S3, EC2, Lambda, and RDS for misconfigurations. Cloud security in the same unified view.</p>
|
|
913
|
+
</div>
|
|
914
|
+
|
|
915
|
+
<div class="bento-card">
|
|
916
|
+
<div class="bento-icon">📡</div>
|
|
917
|
+
<h3>Real-time WebSocket</h3>
|
|
918
|
+
<p>Live updates as scanners run. No polling, no refresh. Findings appear instantly in the dashboard.</p>
|
|
919
|
+
</div>
|
|
920
|
+
|
|
921
|
+
<div class="bento-card featured">
|
|
922
|
+
<div class="bento-icon">🔔</div>
|
|
923
|
+
<h3>Notifications & Integrations</h3>
|
|
924
|
+
<p>Slack, Discord, and custom webhooks. Get alerted on critical findings. Integrates with your existing workflow seamlessly.</p>
|
|
925
|
+
<div class="code-preview">
|
|
926
|
+
<div class="code-line">
|
|
927
|
+
<span class="code-prompt">$</span>
|
|
928
|
+
<span class="code-command">aura-security scan . --notify slack</span>
|
|
929
|
+
</div>
|
|
930
|
+
</div>
|
|
931
|
+
</div>
|
|
932
|
+
</div>
|
|
933
|
+
</div>
|
|
934
|
+
</section>
|
|
935
|
+
|
|
936
|
+
<!-- SLOP Protocol Section -->
|
|
937
|
+
<section class="slop-section" id="slop">
|
|
938
|
+
<div class="slop-container">
|
|
939
|
+
<div class="section-header">
|
|
940
|
+
<h2>The SLOP Protocol</h2>
|
|
941
|
+
<p>Multi-agent architecture that makes AI security scanning actually reliable. Each component is isolated, labeled, and verifiable.</p>
|
|
942
|
+
</div>
|
|
943
|
+
|
|
944
|
+
<div class="slop-grid">
|
|
945
|
+
<div class="slop-card">
|
|
946
|
+
<div class="slop-letter">S</div>
|
|
947
|
+
<div class="slop-word">Segmentation</div>
|
|
948
|
+
<p class="slop-desc">Each scanner runs in its own isolated zone. Gitleaks can't corrupt Trivy's output. One tool failing doesn't break the pipeline.</p>
|
|
949
|
+
</div>
|
|
950
|
+
<div class="slop-card">
|
|
951
|
+
<div class="slop-letter">L</div>
|
|
952
|
+
<div class="slop-word">Labeling</div>
|
|
953
|
+
<p class="slop-desc">Every finding is tagged with its source tool, file path, and line number. You know exactly where each result came from. No black boxes.</p>
|
|
954
|
+
</div>
|
|
955
|
+
<div class="slop-card">
|
|
956
|
+
<div class="slop-letter">O</div>
|
|
957
|
+
<div class="slop-word">Organization</div>
|
|
958
|
+
<p class="slop-desc">Policy agents validate findings before reporting. Duplicate CVEs are merged. False positives are filtered. Clean, actionable output.</p>
|
|
959
|
+
</div>
|
|
960
|
+
<div class="slop-card">
|
|
961
|
+
<div class="slop-letter">P</div>
|
|
962
|
+
<div class="slop-word">Parallelism</div>
|
|
963
|
+
<p class="slop-desc">All scanners run simultaneously. 8 tools don't mean 8x the wait time. Results stream in real-time via WebSocket.</p>
|
|
964
|
+
</div>
|
|
965
|
+
</div>
|
|
966
|
+
</div>
|
|
967
|
+
</section>
|
|
968
|
+
|
|
969
|
+
<!-- Deterministic Section -->
|
|
970
|
+
<section class="deterministic-section">
|
|
971
|
+
<div class="deterministic-container">
|
|
972
|
+
<div class="section-header">
|
|
973
|
+
<h2>Why "Deterministic" Matters</h2>
|
|
974
|
+
<p>LLM-based security tools hallucinate vulnerabilities. We don't.</p>
|
|
975
|
+
</div>
|
|
976
|
+
|
|
977
|
+
<div class="comparison-grid">
|
|
978
|
+
<div class="comparison-card bad">
|
|
979
|
+
<div class="comparison-header">
|
|
980
|
+
<span>✗</span> AI Security Tools
|
|
981
|
+
</div>
|
|
982
|
+
<ul class="comparison-list">
|
|
983
|
+
<li>Different results each run</li>
|
|
984
|
+
<li>Invents CVEs that don't exist</li>
|
|
985
|
+
<li>"Might be vulnerable" confidence theater</li>
|
|
986
|
+
<li>Can't reproduce findings for audits</li>
|
|
987
|
+
<li>Black box reasoning</li>
|
|
988
|
+
</ul>
|
|
989
|
+
</div>
|
|
990
|
+
<div class="comparison-card good">
|
|
991
|
+
<div class="comparison-header">
|
|
992
|
+
<span>✓</span> aurasecurity
|
|
993
|
+
</div>
|
|
994
|
+
<ul class="comparison-list">
|
|
995
|
+
<li>Same input = same output, always</li>
|
|
996
|
+
<li>Only real CVEs from NVD/OSV databases</li>
|
|
997
|
+
<li>Exact file:line for every finding</li>
|
|
998
|
+
<li>Reproducible for compliance audits</li>
|
|
999
|
+
<li>Full transparency on tool sources</li>
|
|
1000
|
+
</ul>
|
|
1001
|
+
</div>
|
|
1002
|
+
</div>
|
|
1003
|
+
</div>
|
|
1004
|
+
</section>
|
|
1005
|
+
|
|
1006
|
+
<!-- Team Section -->
|
|
1007
|
+
<section class="team-section" id="team">
|
|
1008
|
+
<div class="team-container">
|
|
1009
|
+
<div class="section-header">
|
|
1010
|
+
<h2>Built by Security Engineers</h2>
|
|
1011
|
+
<p>Not a wrapper around ChatGPT. Built by people who've actually found bugs.</p>
|
|
1012
|
+
</div>
|
|
1013
|
+
|
|
1014
|
+
<div class="team-grid">
|
|
1015
|
+
<div class="team-card">
|
|
1016
|
+
<div class="team-icon">🔓</div>
|
|
1017
|
+
<h3>Pentest Background</h3>
|
|
1018
|
+
<p>Years of offensive security experience. We know what real vulnerabilities look like because we've exploited them.</p>
|
|
1019
|
+
</div>
|
|
1020
|
+
<div class="team-card">
|
|
1021
|
+
<div class="team-icon">🐛</div>
|
|
1022
|
+
<h3>Bug Bounty Hunters</h3>
|
|
1023
|
+
<p>Found and reported vulnerabilities in production systems. We built this tool because we needed it ourselves.</p>
|
|
1024
|
+
</div>
|
|
1025
|
+
<div class="team-card">
|
|
1026
|
+
<div class="team-icon">📖</div>
|
|
1027
|
+
<h3>Open Source</h3>
|
|
1028
|
+
<p>MIT licensed. Read every line of code. No telemetry, no tracking, no BS. Fork it, audit it, run it air-gapped.</p>
|
|
1029
|
+
</div>
|
|
1030
|
+
</div>
|
|
1031
|
+
</div>
|
|
1032
|
+
</section>
|
|
1033
|
+
|
|
1034
|
+
<!-- Tools Section -->
|
|
1035
|
+
<section class="tools-section" id="tools">
|
|
1036
|
+
<div class="tools-container">
|
|
1037
|
+
<div class="section-header">
|
|
1038
|
+
<h2>Real tools. Not GPT wrappers.</h2>
|
|
1039
|
+
<p>Battle-tested scanners used by actual security teams. We just orchestrate them intelligently.</p>
|
|
1040
|
+
</div>
|
|
1041
|
+
|
|
1042
|
+
<div class="tools-grid">
|
|
1043
|
+
<div class="tool-chip"><span class="icon">🔐</span> Gitleaks</div>
|
|
1044
|
+
<div class="tool-chip"><span class="icon">🛡️</span> Trivy</div>
|
|
1045
|
+
<div class="tool-chip"><span class="icon">🔬</span> Semgrep</div>
|
|
1046
|
+
<div class="tool-chip"><span class="icon">📦</span> npm audit</div>
|
|
1047
|
+
<div class="tool-chip"><span class="icon">🐍</span> pip-audit</div>
|
|
1048
|
+
<div class="tool-chip"><span class="icon">🦀</span> cargo-audit</div>
|
|
1049
|
+
<div class="tool-chip"><span class="icon">🐹</span> govulncheck</div>
|
|
1050
|
+
<div class="tool-chip"><span class="icon">🔎</span> Grype</div>
|
|
1051
|
+
</div>
|
|
1052
|
+
</div>
|
|
1053
|
+
</section>
|
|
1054
|
+
|
|
1055
|
+
<!-- CTA Section -->
|
|
1056
|
+
<section class="cta-section">
|
|
1057
|
+
<div class="cta-content">
|
|
1058
|
+
<h2>Stop guessing. Start scanning.</h2>
|
|
1059
|
+
<p>No signup. No API keys. No cloud dependency. Just clone and run.</p>
|
|
1060
|
+
<div class="cta-buttons">
|
|
1061
|
+
<a href="/app" class="btn btn-primary">Try the Dashboard</a>
|
|
1062
|
+
<a href="https://github.com/aurasecurity/aura-security" target="_blank" class="btn btn-ghost">Read the Code</a>
|
|
1063
|
+
</div>
|
|
1064
|
+
</div>
|
|
1065
|
+
</section>
|
|
1066
|
+
|
|
1067
|
+
<!-- Footer -->
|
|
1068
|
+
<footer>
|
|
1069
|
+
<div class="footer-container">
|
|
1070
|
+
<div class="footer-left">
|
|
1071
|
+
<a href="/" class="logo">
|
|
1072
|
+
<div class="logo-mark">🛡️</div>
|
|
1073
|
+
aurasecurity
|
|
1074
|
+
</a>
|
|
1075
|
+
<div class="footer-links">
|
|
1076
|
+
<a href="https://github.com/aurasecurity/aura-security" target="_blank">GitHub</a>
|
|
1077
|
+
<a href="https://www.npmjs.com/package/aura-security" target="_blank">npm</a>
|
|
1078
|
+
<a href="https://pypi.org/project/aura-security/" target="_blank">PyPI</a>
|
|
1079
|
+
<a href="/app">Dashboard</a>
|
|
1080
|
+
</div>
|
|
1081
|
+
</div>
|
|
1082
|
+
<div class="footer-right">
|
|
1083
|
+
© 2026 aurasecurity · MIT License
|
|
1084
|
+
</div>
|
|
1085
|
+
</div>
|
|
1086
|
+
</footer>
|
|
1087
|
+
|
|
1088
|
+
<script>
|
|
1089
|
+
// Three.js Security Scene
|
|
1090
|
+
const container = document.getElementById('hero-canvas');
|
|
1091
|
+
const scene = new THREE.Scene();
|
|
1092
|
+
const camera = new THREE.PerspectiveCamera(45, container.clientWidth / container.clientHeight, 0.1, 1000);
|
|
1093
|
+
const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
|
|
1094
|
+
|
|
1095
|
+
renderer.setSize(container.clientWidth, container.clientHeight);
|
|
1096
|
+
renderer.setClearColor(0x000000, 0);
|
|
1097
|
+
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
1098
|
+
container.appendChild(renderer.domElement);
|
|
1099
|
+
|
|
1100
|
+
// Lighting
|
|
1101
|
+
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
|
|
1102
|
+
scene.add(ambientLight);
|
|
1103
|
+
|
|
1104
|
+
const mainLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
|
1105
|
+
mainLight.position.set(10, 20, 10);
|
|
1106
|
+
scene.add(mainLight);
|
|
1107
|
+
|
|
1108
|
+
const cyanLight = new THREE.PointLight(0x06b6d4, 1, 20);
|
|
1109
|
+
cyanLight.position.set(-5, 5, 5);
|
|
1110
|
+
scene.add(cyanLight);
|
|
1111
|
+
|
|
1112
|
+
const purpleLight = new THREE.PointLight(0x8b5cf6, 0.8, 20);
|
|
1113
|
+
purpleLight.position.set(5, -3, 5);
|
|
1114
|
+
scene.add(purpleLight);
|
|
1115
|
+
|
|
1116
|
+
// Main group for all objects
|
|
1117
|
+
const mainGroup = new THREE.Group();
|
|
1118
|
+
|
|
1119
|
+
// Central Shield/Core
|
|
1120
|
+
const shieldGroup = new THREE.Group();
|
|
1121
|
+
|
|
1122
|
+
// Outer hexagonal shield
|
|
1123
|
+
const shieldShape = new THREE.Shape();
|
|
1124
|
+
const shieldRadius = 1.5;
|
|
1125
|
+
for (let i = 0; i < 6; i++) {
|
|
1126
|
+
const angle = (i / 6) * Math.PI * 2 - Math.PI / 2;
|
|
1127
|
+
const x = Math.cos(angle) * shieldRadius;
|
|
1128
|
+
const y = Math.sin(angle) * shieldRadius;
|
|
1129
|
+
if (i === 0) shieldShape.moveTo(x, y);
|
|
1130
|
+
else shieldShape.lineTo(x, y);
|
|
1131
|
+
}
|
|
1132
|
+
shieldShape.closePath();
|
|
1133
|
+
|
|
1134
|
+
const shieldExtrudeSettings = { depth: 0.3, bevelEnabled: true, bevelThickness: 0.05, bevelSize: 0.05, bevelSegments: 3 };
|
|
1135
|
+
const shieldGeo = new THREE.ExtrudeGeometry(shieldShape, shieldExtrudeSettings);
|
|
1136
|
+
const shieldMat = new THREE.MeshStandardMaterial({
|
|
1137
|
+
color: 0x06b6d4,
|
|
1138
|
+
metalness: 0.8,
|
|
1139
|
+
roughness: 0.2,
|
|
1140
|
+
emissive: 0x06b6d4,
|
|
1141
|
+
emissiveIntensity: 0.1
|
|
1142
|
+
});
|
|
1143
|
+
const shield = new THREE.Mesh(shieldGeo, shieldMat);
|
|
1144
|
+
shield.rotation.x = Math.PI / 2;
|
|
1145
|
+
shieldGroup.add(shield);
|
|
1146
|
+
|
|
1147
|
+
// Inner shield detail
|
|
1148
|
+
const innerShieldGeo = new THREE.ExtrudeGeometry(shieldShape, { depth: 0.1, bevelEnabled: false });
|
|
1149
|
+
const innerShieldMat = new THREE.MeshStandardMaterial({
|
|
1150
|
+
color: 0x0f172a,
|
|
1151
|
+
metalness: 0.9,
|
|
1152
|
+
roughness: 0.1
|
|
1153
|
+
});
|
|
1154
|
+
const innerShield = new THREE.Mesh(innerShieldGeo, innerShieldMat);
|
|
1155
|
+
innerShield.scale.set(0.7, 0.7, 1);
|
|
1156
|
+
innerShield.rotation.x = Math.PI / 2;
|
|
1157
|
+
innerShield.position.z = 0.2;
|
|
1158
|
+
shieldGroup.add(innerShield);
|
|
1159
|
+
|
|
1160
|
+
// Lock icon in center
|
|
1161
|
+
const lockBodyGeo = new THREE.BoxGeometry(0.4, 0.5, 0.15);
|
|
1162
|
+
const lockMat = new THREE.MeshStandardMaterial({ color: 0x06b6d4, metalness: 0.7, roughness: 0.3 });
|
|
1163
|
+
const lockBody = new THREE.Mesh(lockBodyGeo, lockMat);
|
|
1164
|
+
lockBody.position.z = 0.3;
|
|
1165
|
+
shieldGroup.add(lockBody);
|
|
1166
|
+
|
|
1167
|
+
const lockArcGeo = new THREE.TorusGeometry(0.2, 0.05, 8, 16, Math.PI);
|
|
1168
|
+
const lockArc = new THREE.Mesh(lockArcGeo, lockMat);
|
|
1169
|
+
lockArc.position.set(0, 0.25, 0.3);
|
|
1170
|
+
lockArc.rotation.z = Math.PI;
|
|
1171
|
+
shieldGroup.add(lockArc);
|
|
1172
|
+
|
|
1173
|
+
mainGroup.add(shieldGroup);
|
|
1174
|
+
|
|
1175
|
+
// Orbiting security nodes
|
|
1176
|
+
const nodePositions = [
|
|
1177
|
+
{ radius: 3, speed: 0.5, offset: 0, color: 0x10b981, icon: 'check' },
|
|
1178
|
+
{ radius: 3, speed: 0.5, offset: Math.PI * 0.66, color: 0xf59e0b, icon: 'warning' },
|
|
1179
|
+
{ radius: 3, speed: 0.5, offset: Math.PI * 1.33, color: 0xef4444, icon: 'alert' },
|
|
1180
|
+
{ radius: 4.2, speed: 0.3, offset: Math.PI * 0.25, color: 0x8b5cf6, icon: 'scan' },
|
|
1181
|
+
{ radius: 4.2, speed: 0.3, offset: Math.PI * 0.75, color: 0x06b6d4, icon: 'scan' },
|
|
1182
|
+
{ radius: 4.2, speed: 0.3, offset: Math.PI * 1.25, color: 0x10b981, icon: 'scan' },
|
|
1183
|
+
{ radius: 4.2, speed: 0.3, offset: Math.PI * 1.75, color: 0x8b5cf6, icon: 'scan' },
|
|
1184
|
+
];
|
|
1185
|
+
|
|
1186
|
+
const nodes = [];
|
|
1187
|
+
nodePositions.forEach((config, index) => {
|
|
1188
|
+
const nodeGroup = new THREE.Group();
|
|
1189
|
+
|
|
1190
|
+
// Node body - rounded cube style
|
|
1191
|
+
const nodeGeo = new THREE.BoxGeometry(0.5, 0.5, 0.5);
|
|
1192
|
+
const nodeMat = new THREE.MeshStandardMaterial({
|
|
1193
|
+
color: config.color,
|
|
1194
|
+
metalness: 0.6,
|
|
1195
|
+
roughness: 0.3,
|
|
1196
|
+
emissive: config.color,
|
|
1197
|
+
emissiveIntensity: 0.2
|
|
1198
|
+
});
|
|
1199
|
+
const node = new THREE.Mesh(nodeGeo, nodeMat);
|
|
1200
|
+
node.rotation.set(Math.PI / 4, Math.PI / 4, 0);
|
|
1201
|
+
nodeGroup.add(node);
|
|
1202
|
+
|
|
1203
|
+
// Glow ring
|
|
1204
|
+
const ringGeo = new THREE.RingGeometry(0.35, 0.4, 32);
|
|
1205
|
+
const ringMat = new THREE.MeshBasicMaterial({
|
|
1206
|
+
color: config.color,
|
|
1207
|
+
transparent: true,
|
|
1208
|
+
opacity: 0.3,
|
|
1209
|
+
side: THREE.DoubleSide
|
|
1210
|
+
});
|
|
1211
|
+
const ring = new THREE.Mesh(ringGeo, ringMat);
|
|
1212
|
+
nodeGroup.add(ring);
|
|
1213
|
+
|
|
1214
|
+
nodeGroup.userData = config;
|
|
1215
|
+
nodes.push(nodeGroup);
|
|
1216
|
+
mainGroup.add(nodeGroup);
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
// Orbital rings
|
|
1220
|
+
const createOrbitRing = (radius, opacity) => {
|
|
1221
|
+
const ringGeo = new THREE.RingGeometry(radius - 0.02, radius + 0.02, 64);
|
|
1222
|
+
const ringMat = new THREE.MeshBasicMaterial({
|
|
1223
|
+
color: 0x06b6d4,
|
|
1224
|
+
transparent: true,
|
|
1225
|
+
opacity: opacity,
|
|
1226
|
+
side: THREE.DoubleSide
|
|
1227
|
+
});
|
|
1228
|
+
const ring = new THREE.Mesh(ringGeo, ringMat);
|
|
1229
|
+
ring.rotation.x = Math.PI / 2;
|
|
1230
|
+
return ring;
|
|
1231
|
+
};
|
|
1232
|
+
|
|
1233
|
+
mainGroup.add(createOrbitRing(3, 0.15));
|
|
1234
|
+
mainGroup.add(createOrbitRing(4.2, 0.1));
|
|
1235
|
+
|
|
1236
|
+
// Data stream particles
|
|
1237
|
+
const particleCount = 100;
|
|
1238
|
+
const particleGeo = new THREE.BufferGeometry();
|
|
1239
|
+
const particlePositions = new Float32Array(particleCount * 3);
|
|
1240
|
+
const particleSpeeds = [];
|
|
1241
|
+
|
|
1242
|
+
for (let i = 0; i < particleCount; i++) {
|
|
1243
|
+
const angle = Math.random() * Math.PI * 2;
|
|
1244
|
+
const radius = 2 + Math.random() * 3;
|
|
1245
|
+
particlePositions[i * 3] = Math.cos(angle) * radius;
|
|
1246
|
+
particlePositions[i * 3 + 1] = (Math.random() - 0.5) * 2;
|
|
1247
|
+
particlePositions[i * 3 + 2] = Math.sin(angle) * radius;
|
|
1248
|
+
particleSpeeds.push(0.01 + Math.random() * 0.02);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
particleGeo.setAttribute('position', new THREE.BufferAttribute(particlePositions, 3));
|
|
1252
|
+
const particleMat = new THREE.PointsMaterial({
|
|
1253
|
+
color: 0x06b6d4,
|
|
1254
|
+
size: 0.05,
|
|
1255
|
+
transparent: true,
|
|
1256
|
+
opacity: 0.6
|
|
1257
|
+
});
|
|
1258
|
+
const particles = new THREE.Points(particleGeo, particleMat);
|
|
1259
|
+
mainGroup.add(particles);
|
|
1260
|
+
|
|
1261
|
+
// Tilt the whole scene
|
|
1262
|
+
mainGroup.rotation.x = 0.3;
|
|
1263
|
+
scene.add(mainGroup);
|
|
1264
|
+
|
|
1265
|
+
camera.position.set(0, 2, 8);
|
|
1266
|
+
camera.lookAt(0, 0, 0);
|
|
1267
|
+
|
|
1268
|
+
// Animation
|
|
1269
|
+
let time = 0;
|
|
1270
|
+
function animate() {
|
|
1271
|
+
requestAnimationFrame(animate);
|
|
1272
|
+
time += 0.01;
|
|
1273
|
+
|
|
1274
|
+
// Rotate shield slowly
|
|
1275
|
+
shieldGroup.rotation.z = Math.sin(time * 0.5) * 0.1;
|
|
1276
|
+
|
|
1277
|
+
// Animate orbiting nodes
|
|
1278
|
+
nodes.forEach((node, i) => {
|
|
1279
|
+
const config = node.userData;
|
|
1280
|
+
const angle = time * config.speed + config.offset;
|
|
1281
|
+
node.position.x = Math.cos(angle) * config.radius;
|
|
1282
|
+
node.position.z = Math.sin(angle) * config.radius;
|
|
1283
|
+
node.position.y = Math.sin(time * 2 + i) * 0.2;
|
|
1284
|
+
node.rotation.y = time;
|
|
1285
|
+
});
|
|
1286
|
+
|
|
1287
|
+
// Animate particles
|
|
1288
|
+
const positions = particles.geometry.attributes.position.array;
|
|
1289
|
+
for (let i = 0; i < particleCount; i++) {
|
|
1290
|
+
const idx = i * 3;
|
|
1291
|
+
const x = positions[idx];
|
|
1292
|
+
const z = positions[idx + 2];
|
|
1293
|
+
const angle = Math.atan2(z, x) + particleSpeeds[i];
|
|
1294
|
+
const radius = Math.sqrt(x * x + z * z);
|
|
1295
|
+
positions[idx] = Math.cos(angle) * radius;
|
|
1296
|
+
positions[idx + 2] = Math.sin(angle) * radius;
|
|
1297
|
+
positions[idx + 1] += 0.01;
|
|
1298
|
+
if (positions[idx + 1] > 1) positions[idx + 1] = -1;
|
|
1299
|
+
}
|
|
1300
|
+
particles.geometry.attributes.position.needsUpdate = true;
|
|
1301
|
+
|
|
1302
|
+
// Gentle scene rotation
|
|
1303
|
+
mainGroup.rotation.y = time * 0.1;
|
|
1304
|
+
|
|
1305
|
+
renderer.render(scene, camera);
|
|
1306
|
+
}
|
|
1307
|
+
animate();
|
|
1308
|
+
|
|
1309
|
+
// Handle resize
|
|
1310
|
+
window.addEventListener('resize', () => {
|
|
1311
|
+
camera.aspect = container.clientWidth / container.clientHeight;
|
|
1312
|
+
camera.updateProjectionMatrix();
|
|
1313
|
+
renderer.setSize(container.clientWidth, container.clientHeight);
|
|
1314
|
+
});
|
|
1315
|
+
|
|
1316
|
+
// Smooth scroll
|
|
1317
|
+
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
1318
|
+
anchor.addEventListener('click', function(e) {
|
|
1319
|
+
e.preventDefault();
|
|
1320
|
+
const target = document.querySelector(this.getAttribute('href'));
|
|
1321
|
+
if (target) {
|
|
1322
|
+
target.scrollIntoView({ behavior: 'smooth' });
|
|
1323
|
+
}
|
|
1324
|
+
});
|
|
1325
|
+
});
|
|
1326
|
+
</script>
|
|
1327
|
+
</body>
|
|
1328
|
+
</html>
|