-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
801 lines (747 loc) · 60.5 KB
/
Copy pathindex.html
File metadata and controls
801 lines (747 loc) · 60.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EGG — Event Git Graph</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 240'%3E%3Cpath d='M36 88 Q48 66 72 60 Q100 54 124 66 Q142 76 150 96' stroke='%231a5fa8' stroke-width='1.4' opacity='0.45' fill='none'/%3E%3Cpath d='M26 112 Q40 86 70 80 Q106 73 136 90 Q156 102 162 124' stroke='%231a5fa8' stroke-width='1.2' opacity='0.38' fill='none'/%3E%3Cpath d='M36 88 L50 108 L72 100' stroke='%231a5fa8' stroke-width='1.8' stroke-linecap='round' fill='none'/%3E%3Cpath d='M50 108 L60 130 L88 124' stroke='%231a5fa8' stroke-width='1.8' stroke-linecap='round' fill='none'/%3E%3Cpath d='M88 124 L108 112 L124 66' stroke='%231a5fa8' stroke-width='1.6' stroke-linecap='round' fill='none'/%3E%3Cpath d='M108 112 L136 120 L150 96' stroke='%231a5fa8' stroke-width='1.6' stroke-linecap='round' fill='none'/%3E%3Ccircle cx='36' cy='88' r='4.5' fill='%231a5fa8'/%3E%3Ccircle cx='50' cy='108' r='5' fill='%231a5fa8'/%3E%3Ccircle cx='72' cy='100' r='4' fill='%231a5fa8'/%3E%3Ccircle cx='108' cy='112' r='5.5' fill='%231a5fa8'/%3E%3Ccircle cx='136' cy='120' r='4.5' fill='%231a5fa8'/%3E%3Ccircle cx='88' cy='124' r='4.5' fill='%231a5fa8'/%3E%3Cellipse cx='100' cy='128' rx='88' ry='108' stroke='%231a5fa8' stroke-width='3.5' fill='none'/%3E%3C/svg%3E">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Outfit:wght@200;300;400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--blue: #1a5fa8;
--blue-mid: #2272c3;
--blue-light: #2b7fe0;
--blue-pale: #e8f1fb;
--blue-pale2: #f0f6ff;
--text: #0d1b2e;
--text-mid: #2d4a6e;
--text-muted: #5a7a9e;
--text-dim: #94aec8;
--border: rgba(26,95,168,0.13);
--border-mid: rgba(26,95,168,0.28);
--bg: #ffffff;
--bg3: #f0f6ff;
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
background: var(--bg);
color: var(--text);
font-family: 'Outfit', sans-serif;
font-weight: 300;
line-height: 1.7;
overflow-x: hidden;
}
body::before {
content: '';
position: fixed; inset: 0;
background-image:
linear-gradient(rgba(26,95,168,0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(26,95,168,0.035) 1px, transparent 1px);
background-size: 52px 52px;
pointer-events: none; z-index: 0;
}
/* ── TOPBAR ── */
.topbar {
position: fixed; top: 0; left: 0; right: 0; z-index: 200;
background: rgba(255,255,255,0.94);
backdrop-filter: blur(14px);
border-bottom: 1px solid var(--border);
display: flex; align-items: center; justify-content: space-between;
padding: 0 36px; height: 58px; gap: 16px;
}
.topbar-brand { display: flex; align-items: center; gap: 9px; text-decoration: none; flex-shrink: 0; }
.topbar-logo { width: 24px; height: 29px; }
.topbar-name { font-family: 'DM Mono', monospace; font-size: 14px; font-weight: 500; letter-spacing: 0.18em; color: var(--blue); }
.topbar-tagline { font-family: 'DM Mono', monospace; font-size: 10px; color: var(--text-dim); letter-spacing: 0.1em; border-left: 1px solid var(--border); padding-left: 12px; margin-left: 4px; }
.topbar-links { display: flex; align-items: center; gap: 5px; flex: 1; justify-content: center; }
.topbar-link {
display: inline-flex; align-items: center; gap: 5px;
padding: 5px 12px; border-radius: 6px;
font-family: 'DM Mono', monospace; font-size: 11px; letter-spacing: 0.05em;
text-decoration: none; color: var(--text-mid);
border: 1px solid var(--border); transition: all 0.18s; white-space: nowrap;
}
.topbar-link:hover { background: var(--blue-pale); border-color: var(--blue-mid); color: var(--blue); }
.topbar-link.primary { background: var(--blue); color: #fff; border-color: var(--blue); }
.topbar-link.primary:hover { background: var(--blue-mid); }
.lang-toggle { display: flex; background: var(--bg3); border: 1px solid var(--border); border-radius: 6px; overflow: hidden; font-family: 'DM Mono', monospace; font-size: 11px; letter-spacing: 0.1em; flex-shrink: 0; }
.lang-btn { padding: 6px 13px; cursor: pointer; color: var(--text-muted); background: none; border: none; font-family: inherit; font-size: inherit; letter-spacing: inherit; transition: all 0.15s; }
.lang-btn.active { background: var(--blue); color: #fff; }
.lang-btn:hover:not(.active) { color: var(--blue); }
/* ── HERO ── */
.hero {
position: relative; z-index: 1;
min-height: 100vh;
display: flex; flex-direction: column;
align-items: center; justify-content: center;
text-align: center; padding: 110px 40px 80px;
}
.egg-wrap { width: 150px; height: 180px; margin: 0 auto 36px; animation: eggFloat 5s ease-in-out infinite; filter: drop-shadow(0 6px 28px rgba(26,95,168,0.14)); }
@keyframes eggFloat { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-9px)} }
.hero-badge { font-family:'DM Mono',monospace; font-size:10px; letter-spacing:0.2em; color:var(--blue-light); text-transform:uppercase; background:var(--blue-pale); border:1px solid var(--border-mid); border-radius:100px; padding:4px 14px; margin-bottom:20px; display:inline-block; opacity:0; animation:fadeUp 0.7s ease 0.3s forwards; }
.hero-title { font-size:clamp(56px,10vw,108px); font-weight:700; letter-spacing:-0.04em; line-height:1; margin-bottom:10px; color:var(--blue); opacity:0; animation:fadeUp 0.8s ease 0.45s forwards; }
.hero-expand { font-family:'DM Mono',monospace; font-size:clamp(11px,1.3vw,14px); color:var(--text-muted); letter-spacing:0.16em; margin-bottom:28px; opacity:0; animation:fadeUp 0.8s ease 0.6s forwards; }
.hero-expand b { color:var(--blue); font-weight:500; }
.hero-desc { max-width:620px; font-size:18px; font-weight:300; color:var(--text-mid); line-height:1.85; margin:0 auto 44px; opacity:0; animation:fadeUp 0.8s ease 0.8s forwards; }
.hero-desc strong { font-weight:500; color:var(--blue); }
.hero-cta { display:flex; gap:12px; justify-content:center; flex-wrap:wrap; opacity:0; animation:fadeUp 0.8s ease 1s forwards; }
.btn-primary { display:inline-flex; align-items:center; gap:8px; padding:13px 28px; background:var(--blue); color:#fff; border-radius:8px; text-decoration:none; font-weight:500; font-size:15px; transition:all 0.2s; border:1px solid var(--blue); }
.btn-primary:hover { background:var(--blue-mid); transform:translateY(-1px); box-shadow:0 6px 18px rgba(26,95,168,0.22); }
.btn-ghost { display:inline-flex; align-items:center; gap:8px; padding:13px 28px; background:transparent; color:var(--text-mid); border-radius:8px; text-decoration:none; font-weight:400; font-size:15px; border:1px solid var(--border-mid); transition:all 0.2s; }
.btn-ghost:hover { border-color:var(--blue); color:var(--blue); background:var(--blue-pale); }
/* architecture diagram in hero */
.arch-diagram { margin-top:52px; width:100%; max-width:700px; opacity:0; animation:fadeUp 0.9s ease 1.2s forwards; }
.scroll-hint { position:absolute; bottom:32px; left:50%; transform:translateX(-50%); display:flex; flex-direction:column; align-items:center; gap:5px; opacity:0; animation:fadeUp 1s ease 1.6s forwards; }
.scroll-line { width:1px; height:34px; background:linear-gradient(to bottom,var(--blue),transparent); animation:scrollPulse 2s ease-in-out infinite; }
.scroll-label { font-family:'DM Mono',monospace; font-size:9px; letter-spacing:0.22em; color:var(--text-dim); }
@keyframes scrollPulse { 0%,100%{opacity:.3} 50%{opacity:.9} }
@keyframes fadeUp { from{opacity:0;transform:translateY(18px)} to{opacity:1;transform:translateY(0)} }
/* ── SHARED ── */
hr.divider { border:none; border-top:1px solid var(--border); margin:0 40px; position:relative; z-index:1; }
section { position:relative; z-index:1; padding:84px 40px; max-width:1100px; margin:0 auto; }
.section-label { font-family:'DM Mono',monospace; font-size:10px; letter-spacing:0.26em; color:var(--blue-light); text-transform:uppercase; margin-bottom:12px; display:flex; align-items:center; gap:10px; }
.section-label::before { content:''; width:26px; height:1px; background:var(--blue); }
.section-title { font-size:clamp(26px,3.5vw,42px); font-weight:600; letter-spacing:-0.02em; line-height:1.15; margin-bottom:14px; color:var(--text); }
.section-title em { font-style:normal; color:var(--blue); }
.section-sub { font-size:17px; color:var(--text-muted); max-width:640px; line-height:1.75; }
/* ── ACRONYM ── */
.acronym-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:16px; margin-top:44px; }
.acro-card { padding:32px 26px; border:1px solid var(--border); border-radius:14px; background:var(--bg); transition:all 0.22s; position:relative; overflow:hidden; }
.acro-card::before { content:''; position:absolute; top:0; left:0; right:0; height:2px; background:var(--blue); opacity:0; transition:opacity 0.22s; }
.acro-card:hover { border-color:var(--blue-mid); background:var(--blue-pale2); transform:translateY(-2px); }
.acro-card:hover::before { opacity:1; }
.acro-letter { font-family:'DM Mono',monospace; font-size:40px; font-weight:500; color:var(--blue); opacity:0.16; line-height:1; margin-bottom:12px; display:block; }
.acro-word { font-weight:700; font-size:18px; color:var(--blue); margin-bottom:8px; }
.acro-desc { font-size:14px; color:var(--text-muted); line-height:1.72; }
/* ── HOW IT WORKS — two-layer ── */
.two-layer { display:grid; grid-template-columns:1fr 1fr; gap:20px; margin-top:44px; }
.layer-block { border:1px solid var(--border); border-radius:16px; overflow:hidden; }
.layer-header { padding:20px 24px; border-bottom:1px solid var(--border); display:flex; align-items:center; gap:12px; }
.layer-icon { width:36px; height:36px; border-radius:8px; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.layer-icon.server { background:var(--blue-pale); }
.layer-icon.nostr { background:#f0eaff; }
.layer-heading { font-weight:600; font-size:16px; color:var(--text); }
.layer-sub { font-family:'DM Mono',monospace; font-size:10px; color:var(--text-dim); letter-spacing:0.08em; margin-top:2px; }
.layer-items { padding:8px 0; }
.layer-item { display:flex; align-items:flex-start; gap:12px; padding:14px 24px; border-bottom:1px solid var(--border); transition:background 0.15s; }
.layer-item:last-child { border-bottom:none; }
.layer-item:hover { background:var(--blue-pale2); }
.layer-dot { width:6px; height:6px; border-radius:50%; background:var(--blue); flex-shrink:0; margin-top:8px; }
.layer-dot.purple { background:#7c5fa8; }
.item-title { font-weight:500; font-size:14px; color:var(--text); margin-bottom:2px; }
.item-desc { font-size:13px; color:var(--text-muted); line-height:1.6; }
/* ── SETUP FLOW ── */
.setup-steps { display:flex; flex-direction:column; gap:2px; margin-top:44px; }
.setup-step { display:grid; grid-template-columns:56px auto 1fr; gap:18px; align-items:start; padding:22px 24px; border:1px solid var(--border); border-radius:10px; background:var(--bg); transition:all 0.22s; }
.setup-step:hover { border-color:var(--blue-mid); background:var(--blue-pale2); transform:translateX(4px); }
.step-num { font-family:'DM Mono',monospace; font-size:24px; font-weight:500; color:var(--blue); opacity:0.2; line-height:1; padding-top:2px; }
.step-badge { font-family:'DM Mono',monospace; font-size:10px; letter-spacing:0.08em; color:#fff; background:var(--blue); padding:3px 9px; border-radius:4px; white-space:nowrap; align-self:start; margin-top:4px; }
.step-badge.nostr-badge { background:#7c5fa8; }
.step-title { font-weight:500; font-size:16px; margin-bottom:4px; color:var(--text); }
.step-desc { font-size:14px; color:var(--text-muted); line-height:1.7; }
.step-code { font-family:'DM Mono',monospace; font-size:12px; color:var(--blue-light); background:var(--blue-pale); border:1px solid var(--border); border-radius:6px; padding:8px 12px; margin-top:10px; letter-spacing:0.04em; display:inline-block; }
/* ── ACCESS MODEL ── */
.access-grid { display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-top:44px; }
.access-card { padding:30px; border:1px solid var(--border); border-radius:14px; background:var(--bg); transition:all 0.2s; position:relative; overflow:hidden; }
.access-card::after { content:''; position:absolute; top:0; left:0; bottom:0; width:3px; }
.access-card.public::after { background:var(--blue); }
.access-card.private::after { background:#7c5fa8; }
.access-card:hover { border-color:var(--blue-mid); background:var(--blue-pale2); }
.access-type { font-family:'DM Mono',monospace; font-size:10px; letter-spacing:0.18em; text-transform:uppercase; margin-bottom:14px; padding-left:4px; }
.access-type.pub { color:var(--blue); }
.access-type.priv { color:#7c5fa8; }
.access-title { font-weight:600; font-size:18px; color:var(--text); margin-bottom:10px; padding-left:4px; }
.access-list { list-style:none; display:flex; flex-direction:column; gap:6px; padding-left:4px; }
.access-list li { font-size:14px; color:var(--text-muted); display:flex; align-items:flex-start; gap:8px; }
.access-list li::before { content:'→'; color:var(--blue); flex-shrink:0; font-size:13px; }
.access-card.private .access-list li::before { color:#7c5fa8; }
/* ── COMPARISON ── */
.compare-wrap { margin-top:44px; border:1px solid var(--border); border-radius:14px; overflow:hidden; }
table { width:100%; border-collapse:collapse; font-size:14px; }
thead tr { background:var(--bg3); }
thead th { padding:14px 22px; text-align:left; font-weight:500; font-size:13px; color:var(--text); border-bottom:1px solid var(--border); }
thead th:nth-child(2) { color:var(--text-muted); font-weight:400; }
thead th:nth-child(3) { color:var(--blue); }
tbody tr { border-bottom:1px solid var(--border); }
tbody tr:last-child { border-bottom:none; }
tbody tr:hover td { background:var(--blue-pale2); }
tbody td { padding:13px 22px; color:var(--text-muted); transition:background .15s; }
tbody td:first-child { font-weight:500; color:var(--text); }
.check { color:var(--blue); font-weight:600; }
.cross { color:var(--text-dim); }
/* ── ROADMAP ── */
.roadmap { display:grid; grid-template-columns:repeat(4,1fr); gap:13px; margin-top:44px; }
.phase { padding:24px 20px; border:1px solid var(--border); border-radius:12px; background:var(--bg); transition:all .2s; }
.phase:hover { border-color:var(--blue-mid); background:var(--blue-pale2); }
.phase-label { font-family:'DM Mono',monospace; font-size:10px; color:var(--blue-light); letter-spacing:.18em; margin-bottom:8px; }
.phase-title { font-weight:600; font-size:15px; margin-bottom:10px; color:var(--text); }
.phase-items { list-style:none; display:flex; flex-direction:column; gap:5px; }
.phase-items li { font-size:13px; color:var(--text-muted); display:flex; align-items:flex-start; gap:6px; }
.phase-items li::before { content:'→'; color:var(--blue); flex-shrink:0; }
/* ── DEV SECTION ── */
.dev-section { position:relative; z-index:1; max-width:1100px; margin:0 auto; padding:0 40px 84px; }
.dev-label { font-family:'DM Mono',monospace; font-size:10px; letter-spacing:.26em; color:var(--blue-light); text-transform:uppercase; margin-bottom:12px; display:flex; align-items:center; gap:10px; }
.dev-label::before { content:''; width:26px; height:1px; background:var(--blue); }
.dev-title { font-size:clamp(26px,3.5vw,40px); font-weight:600; letter-spacing:-.02em; line-height:1.15; margin-bottom:8px; color:var(--text); }
.dev-title em { font-style:normal; color:var(--blue); }
.dev-sub { font-size:16px; color:var(--text-muted); }
.dev-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:16px; margin-top:44px; }
.dev-card { display:flex; align-items:flex-start; gap:16px; padding:26px; border:1px solid var(--border); border-radius:14px; background:var(--bg); text-decoration:none; color:inherit; transition:all .22s; }
.dev-card:hover { border-color:var(--blue-mid); background:var(--blue-pale2); transform:translateY(-2px); }
.dev-card-icon { width:42px; height:42px; border-radius:10px; background:var(--blue-pale); border:1px solid var(--border-mid); display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.dev-card-title { font-weight:600; font-size:15px; margin-bottom:3px; color:var(--text); }
.dev-card-url { font-family:'DM Mono',monospace; font-size:11px; color:var(--blue-light); letter-spacing:.04em; margin-bottom:7px; }
.dev-card-desc { font-size:13px; color:var(--text-muted); line-height:1.6; }
/* ── FOOTER ── */
footer { position:relative; z-index:1; background:var(--bg3); border-top:1px solid var(--border); padding:48px 40px; }
.footer-inner { max-width:1100px; margin:0 auto; display:grid; grid-template-columns:1fr 1fr; gap:48px; align-items:start; }
.footer-col-title { font-family:'DM Mono',monospace; font-size:10px; letter-spacing:.22em; color:var(--text-dim); text-transform:uppercase; margin-bottom:14px; }
.footer-links { display:flex; flex-direction:column; gap:8px; }
.footer-link { display:inline-flex; align-items:center; gap:8px; font-size:14px; color:var(--text-mid); text-decoration:none; transition:color .15s; }
.footer-link:hover { color:var(--blue); }
.footer-dot { width:5px; height:5px; border-radius:50%; background:var(--blue); opacity:.4; flex-shrink:0; }
.footer-link:hover .footer-dot { opacity:1; }
.footer-author-col { border-left:1px solid var(--border); padding-left:48px; }
.author-name-big { font-size:22px; font-weight:600; color:var(--text); letter-spacing:-.01em; margin-bottom:3px; }
.author-site { font-family:'DM Mono',monospace; font-size:12px; color:var(--blue-light); text-decoration:none; letter-spacing:.04em; transition:color .15s; display:block; margin-bottom:14px; }
.author-site:hover { color:var(--blue); }
.footer-bottom { max-width:1100px; margin:36px auto 0; padding-top:22px; border-top:1px solid var(--border); text-align:center; font-family:'DM Mono',monospace; font-size:11px; color:var(--text-dim); letter-spacing:.06em; }
.footer-bottom a { color:var(--text-dim); text-decoration:none; }
.footer-bottom a:hover { color:var(--blue); }
@media(max-width:768px){
.topbar { padding:0 16px; height:auto; flex-wrap:wrap; padding-top:10px; padding-bottom:10px; }
.topbar-links,.topbar-tagline { display:none; }
.acronym-grid,.two-layer,.access-grid,.dev-grid,.footer-inner { grid-template-columns:1fr; }
.roadmap { grid-template-columns:repeat(2,1fr); }
.setup-step { grid-template-columns:40px 1fr; }
.step-badge { display:none; }
.footer-author-col { border-left:none; border-top:1px solid var(--border); padding-left:0; padding-top:28px; }
section { padding:56px 20px; }
.hero { padding:96px 20px 60px; }
hr.divider { margin:0 20px; }
.dev-section { padding:0 20px 56px; }
footer { padding:36px 20px; }
}
/* GH icon inline */
.gh-icon { width:11px; height:11px; }
.nostr-icon { width:11px; height:11px; }
</style>
</head>
<body>
<!-- TOPBAR -->
<header class="topbar">
<a href="https://egg.edgarpaula.org" class="topbar-brand" target="_blank">
<svg class="topbar-logo" viewBox="0 0 200 240" fill="none">
<path d="M36 88 Q48 66 72 60 Q100 54 124 66 Q142 76 150 96" stroke="#1a5fa8" stroke-width="1.4" opacity="0.45" fill="none"/>
<path d="M26 112 Q40 86 70 80 Q106 73 136 90 Q156 102 162 124" stroke="#1a5fa8" stroke-width="1.2" opacity="0.38" fill="none"/>
<path d="M36 88 L50 108 L72 100" stroke="#1a5fa8" stroke-width="1.8" stroke-linecap="round" fill="none"/>
<path d="M50 108 L60 130 L88 124" stroke="#1a5fa8" stroke-width="1.8" stroke-linecap="round" fill="none"/>
<path d="M88 124 L108 112 L124 66" stroke="#1a5fa8" stroke-width="1.6" stroke-linecap="round" fill="none"/>
<path d="M108 112 L136 120 L150 96" stroke="#1a5fa8" stroke-width="1.6" stroke-linecap="round" fill="none"/>
<circle cx="36" cy="88" r="4.5" fill="#1a5fa8"/><circle cx="50" cy="108" r="5" fill="#1a5fa8"/>
<circle cx="72" cy="100" r="4" fill="#1a5fa8"/><circle cx="108" cy="112" r="5.5" fill="#1a5fa8"/>
<circle cx="136" cy="120" r="4.5" fill="#1a5fa8"/><circle cx="88" cy="124" r="4.5" fill="#1a5fa8"/>
<ellipse cx="100" cy="128" rx="88" ry="108" stroke="#1a5fa8" stroke-width="3.5" fill="none"/>
</svg>
<span class="topbar-name">EGG</span>
<span class="topbar-tagline">Event Git Graph</span>
</a>
<div class="topbar-links">
<a href="https://egg.edgarpaula.org" class="topbar-link primary" target="_blank">
<svg class="gh-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15 15 0 0 1 0 20M12 2a15 15 0 0 0 0 20"/></svg>
egg.edgarpaula.org
</a>
<a href="https://nosta.me/npub1xux7a76ad990n594q6kxn68gefh4zvyjmpa68wc2t7sml7ks7j7qxrhpc5" class="topbar-link" target="_blank">
<svg class="nostr-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>
<span data-en="EGG on Nostr" data-pt="EGG no Nostr">EGG on Nostr</span>
</a>
<a href="https://github.com/getegg" class="topbar-link" target="_blank">
<svg class="gh-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.3 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61-.546-1.387-1.333-1.756-1.333-1.756-1.09-.745.083-.73.083-.73 1.205.085 1.84 1.237 1.84 1.237 1.07 1.835 2.807 1.305 3.492.997.108-.775.418-1.305.762-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.605-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 21.795 24 17.295 24 12c0-6.63-5.37-12-12-12z"/></svg>
github.com/getegg
</a>
<a href="https://github.com/getegg/egg" class="topbar-link" target="_blank">
<svg class="gh-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.3 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61-.546-1.387-1.333-1.756-1.333-1.756-1.09-.745.083-.73.083-.73 1.205.085 1.84 1.237 1.84 1.237 1.07 1.835 2.807 1.305 3.492.997.108-.775.418-1.305.762-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.605-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 21.795 24 17.295 24 12c0-6.63-5.37-12-12-12z"/></svg>
getegg/egg
</a>
</div>
<div class="lang-toggle">
<button class="lang-btn active" onclick="setLang('en')" id="btn-en">EN</button>
<button class="lang-btn" onclick="setLang('pt')" id="btn-pt">PT</button>
</div>
</header>
<!-- HERO -->
<div class="hero">
<div class="egg-wrap">
<svg viewBox="0 0 200 240" fill="none" style="width:100%;height:100%">
<path d="M36 88 Q48 66 72 60 Q100 54 124 66 Q142 76 150 96" stroke="#1a5fa8" stroke-width="1.4" opacity="0.45" fill="none"/>
<path d="M26 112 Q40 86 70 80 Q106 73 136 90 Q156 102 162 124" stroke="#1a5fa8" stroke-width="1.2" opacity="0.38" fill="none"/>
<path d="M24 138 Q40 112 70 106 Q108 99 140 118 Q160 130 164 154" stroke="#1a5fa8" stroke-width="1.1" opacity="0.32" fill="none"/>
<path d="M32 164 Q52 144 78 140 Q110 135 138 150" stroke="#1a5fa8" stroke-width="1" opacity="0.24" fill="none"/>
<path d="M17 104 Q20 92 28 84" stroke="#1a5fa8" stroke-width="1" opacity="0.28" fill="none"/>
<path d="M14 128 Q17 114 24 102" stroke="#1a5fa8" stroke-width="0.9" opacity="0.22" fill="none"/>
<path d="M36 88 L50 108 L72 100" stroke="#1a5fa8" stroke-width="1.8" stroke-linecap="round" fill="none"/>
<path d="M50 108 L60 130 L88 124" stroke="#1a5fa8" stroke-width="1.8" stroke-linecap="round" fill="none"/>
<path d="M88 124 L108 112 L124 66" stroke="#1a5fa8" stroke-width="1.6" stroke-linecap="round" fill="none"/>
<path d="M108 112 L136 120 L150 96" stroke="#1a5fa8" stroke-width="1.6" stroke-linecap="round" fill="none"/>
<path d="M60 130 L72 158 L88 124" stroke="#1a5fa8" stroke-width="1.5" stroke-linecap="round" fill="none"/>
<path d="M72 158 L108 162 L136 120" stroke="#1a5fa8" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<path d="M30 140 L50 108" stroke="#1a5fa8" stroke-width="1.2" stroke-linecap="round" opacity="0.5" fill="none"/>
<path d="M72 100 L90 76 L124 66" stroke="#1a5fa8" stroke-width="1.3" stroke-linecap="round" opacity="0.6" fill="none"/>
<path d="M150 96 L164 96 L164 114" stroke="#1a5fa8" stroke-width="1" stroke-linecap="round" opacity="0.36" fill="none"/>
<path d="M36 88 L24 88 L24 108" stroke="#1a5fa8" stroke-width="1" stroke-linecap="round" opacity="0.34" fill="none"/>
<circle cx="36" cy="88" r="4.5" fill="#1a5fa8"/><circle cx="50" cy="108" r="5" fill="#1a5fa8"/>
<circle cx="72" cy="100" r="4" fill="#1a5fa8"/><circle cx="124" cy="66" r="4" fill="#1a5fa8"/>
<circle cx="150" cy="96" r="4.5" fill="#1a5fa8"/><circle cx="108" cy="112" r="5.5" fill="#1a5fa8"/>
<circle cx="136" cy="120" r="4.5" fill="#1a5fa8"/><circle cx="60" cy="130" r="4" fill="#1a5fa8"/>
<circle cx="88" cy="124" r="4.5" fill="#1a5fa8"/><circle cx="72" cy="158" r="4" fill="#1a5fa8"/>
<circle cx="108" cy="162" r="4" fill="#1a5fa8"/><circle cx="30" cy="140" r="3.5" fill="#1a5fa8"/>
<circle cx="90" cy="76" r="3.5" fill="#1a5fa8"/><circle cx="164" cy="114" r="3" fill="#1a5fa8"/>
<circle cx="24" cy="108" r="3" fill="#1a5fa8"/>
<ellipse cx="100" cy="128" rx="88" ry="108" stroke="#1a5fa8" stroke-width="3.5" fill="none"/>
</svg>
</div>
<div class="hero-badge" data-en="Decentralized Git · Native Nostr" data-pt="Git Descentralizado · Nostr Nativo">Decentralized Git · Native Nostr</div>
<h1 class="hero-title">EGG</h1>
<div class="hero-expand">
<b data-en="E" data-pt="E">E</b>vent
<b data-en="G" data-pt="G">G</b>it
<b data-en="G" data-pt="G">G</b>raph
</div>
<p class="hero-desc"
data-en="Your server, your code. <strong>Deploy EGG on your own domain</strong> — egg.yourdomain.com — and get a full Git forge with client, relay and access control. Social interactions — issues, pull requests, reviews — happen <strong>entirely through Nostr events</strong>, connecting every EGG instance in an open network."
data-pt="Seu servidor, seu código. <strong>Instale o EGG no seu próprio domínio</strong> — egg.seudominio.com — e tenha uma forge Git completa com client, relay e controle de acesso. Interações sociais — issues, pull requests, reviews — acontecem <strong>inteiramente por eventos Nostr</strong>, conectando cada instância EGG em uma rede aberta.">
Your server, your code. <strong>Deploy EGG on your own domain</strong> — egg.yourdomain.com — and get a full Git forge with client, relay and access control. Social interactions — issues, pull requests, reviews — happen <strong>entirely through Nostr events</strong>, connecting every EGG instance in an open network.
</p>
<div class="hero-cta">
<a href="https://egg.edgarpaula.org" class="btn-primary" target="_blank">
<span data-en="See a live instance" data-pt="Ver uma instância ao vivo">See a live instance</span> ↗
</a>
<a href="https://github.com/getegg/egg" class="btn-ghost" target="_blank">
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.3 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61-.546-1.387-1.333-1.756-1.333-1.756-1.09-.745.083-.73.083-.73 1.205.085 1.84 1.237 1.84 1.237 1.07 1.835 2.807 1.305 3.492.997.108-.775.418-1.305.762-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.605-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 21.795 24 17.295 24 12c0-6.63-5.37-12-12-12z"/></svg>
<span data-en="Deploy your instance" data-pt="Instalar sua instância">Deploy your instance</span>
</a>
</div>
<!-- Architecture mini-diagram -->
<svg class="arch-diagram" viewBox="0 0 700 96" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- boxes -->
<rect x="0" y="24" width="148" height="48" rx="10" fill="white" stroke="rgba(26,95,168,0.2)" stroke-width="1.5"/>
<text x="74" y="43" text-anchor="middle" font-family="DM Mono, monospace" font-size="9" fill="#1a5fa8" letter-spacing="0.08em">egg.alice.com</text>
<text x="74" y="59" text-anchor="middle" font-family="Outfit, sans-serif" font-size="11" fill="#5a7a9e" font-weight="400">Git + Client + Relay</text>
<rect x="276" y="24" width="148" height="48" rx="10" fill="white" stroke="rgba(26,95,168,0.2)" stroke-width="1.5"/>
<text x="350" y="43" text-anchor="middle" font-family="DM Mono, monospace" font-size="9" fill="#1a5fa8" letter-spacing="0.08em">egg.bob.com</text>
<text x="350" y="59" text-anchor="middle" font-family="Outfit, sans-serif" font-size="11" fill="#5a7a9e" font-weight="400">Git + Client + Relay</text>
<rect x="552" y="24" width="148" height="48" rx="10" fill="white" stroke="rgba(26,95,168,0.2)" stroke-width="1.5"/>
<text x="626" y="43" text-anchor="middle" font-family="DM Mono, monospace" font-size="9" fill="#1a5fa8" letter-spacing="0.08em">egg.corp.io</text>
<text x="626" y="59" text-anchor="middle" font-family="Outfit, sans-serif" font-size="11" fill="#5a7a9e" font-weight="400">Git + Client + Relay</text>
<!-- Nostr event connections -->
<path d="M148 48 L276 48" stroke="rgba(26,95,168,0.25)" stroke-width="1.5" stroke-dasharray="4 3"/>
<path d="M424 48 L552 48" stroke="rgba(26,95,168,0.25)" stroke-width="1.5" stroke-dasharray="4 3"/>
<!-- nostr label on arrows -->
<rect x="186" y="36" width="72" height="22" rx="5" fill="rgba(240,246,255,0.9)" stroke="rgba(26,95,168,0.2)"/>
<text x="222" y="51" text-anchor="middle" font-family="DM Mono, monospace" font-size="9" fill="#7c5fa8" letter-spacing="0.06em">nostr events</text>
<rect x="462" y="36" width="72" height="22" rx="5" fill="rgba(240,246,255,0.9)" stroke="rgba(26,95,168,0.2)"/>
<text x="498" y="51" text-anchor="middle" font-family="DM Mono, monospace" font-size="9" fill="#7c5fa8" letter-spacing="0.06em">nostr events</text>
<!-- dots on connections -->
<circle cx="148" cy="48" r="3.5" fill="#1a5fa8"/>
<circle cx="276" cy="48" r="3.5" fill="#1a5fa8"/>
<circle cx="424" cy="48" r="3.5" fill="#1a5fa8"/>
<circle cx="552" cy="48" r="3.5" fill="#1a5fa8"/>
<!-- labels below -->
<text x="74" y="90" text-anchor="middle" font-family="DM Mono, monospace" font-size="8" fill="rgba(26,95,168,0.4)" letter-spacing="0.04em">instance A</text>
<text x="350" y="90" text-anchor="middle" font-family="DM Mono, monospace" font-size="8" fill="rgba(26,95,168,0.4)" letter-spacing="0.04em">instance B</text>
<text x="626" y="90" text-anchor="middle" font-family="DM Mono, monospace" font-size="8" fill="rgba(26,95,168,0.4)" letter-spacing="0.04em">instance C</text>
</svg>
<div class="scroll-hint">
<div class="scroll-line"></div>
<span class="scroll-label" data-en="scroll" data-pt="rolar">scroll</span>
</div>
</div>
<hr class="divider">
<!-- ACRONYM -->
<section>
<div class="section-label" data-en="What is EGG" data-pt="O que é o EGG">What is EGG</div>
<h2 class="section-title" data-en="Three words. One <em>architecture</em>." data-pt="Três palavras. Uma <em>arquitetura</em>.">Three words. One <em>architecture</em>.</h2>
<div class="acronym-grid">
<div class="acro-card">
<span class="acro-letter">E</span>
<div class="acro-word">Event</div>
<p class="acro-desc" data-en="Every social interaction — issues, pull requests, comments, follows, access grants — is a cryptographically signed Nostr event. Tamper-proof. Verifiable by anyone. Not stored on any central server." data-pt="Toda interação social — issues, pull requests, comentários, follows, concessões de acesso — é um evento Nostr assinado criptograficamente. Inviolável. Verificável por qualquer pessoa. Não armazenado em nenhum servidor central.">Every social interaction — issues, pull requests, comments, follows, access grants — is a cryptographically signed Nostr event. Tamper-proof. Verifiable by anyone. Not stored on any central server.</p>
</div>
<div class="acro-card">
<span class="acro-letter">G</span>
<div class="acro-word">Git</div>
<p class="acro-desc" data-en="Standard Git — the same tool developers already use. The code itself lives on your own server (egg.yourdomain.com), not in someone else's cloud. Push, pull, branch, merge — all native git operations." data-pt="Git padrão — a mesma ferramenta que desenvolvedores já usam. O código em si vive no seu próprio servidor (egg.seudominio.com), não na nuvem de outra pessoa. Push, pull, branch, merge — todas as operações git nativas.">Standard Git — the same tool developers already use. The code itself lives on your own server (egg.yourdomain.com), not in someone else's cloud. Push, pull, branch, merge — all native git operations.</p>
</div>
<div class="acro-card">
<span class="acro-letter">G</span>
<div class="acro-word">Graph</div>
<p class="acro-desc" data-en="A commit graph that is also a social graph. Every EGG instance connects to every other through Nostr. Developers on alice.com can open issues on repos hosted at bob.com — no federation setup required." data-pt="Um grafo de commits que também é um grafo social. Cada instância EGG conecta-se a todas as outras pelo Nostr. Desenvolvedores em alice.com podem abrir issues em repos hospedados em bob.com — sem configuração de federação.">A commit graph that is also a social graph. Every EGG instance connects to every other through Nostr. Developers on alice.com can open issues on repos hosted at bob.com — no federation setup required.</p>
</div>
</div>
</section>
<hr class="divider">
<!-- TWO LAYERS -->
<section>
<div class="section-label" data-en="Architecture" data-pt="Arquitetura">Architecture</div>
<h2 class="section-title" data-en="Two layers. <em>Zero compromise</em>." data-pt="Duas camadas. <em>Zero compromisso</em>.">Two layers. <em>Zero compromise</em>.</h2>
<p class="section-sub" data-en="EGG separates storage from communication. Your server owns the code. Nostr owns the conversation." data-pt="O EGG separa armazenamento de comunicação. Seu servidor é dono do código. O Nostr é dono da conversa.">EGG separates storage from communication. Your server owns the code. Nostr owns the conversation.</p>
<div class="two-layer">
<!-- Server layer -->
<div class="layer-block">
<div class="layer-header">
<div class="layer-icon server">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#1a5fa8" stroke-width="2" stroke-linecap="round"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/><circle cx="6" cy="6" r="1" fill="#1a5fa8" stroke="none"/><circle cx="6" cy="18" r="1" fill="#1a5fa8" stroke="none"/></svg>
</div>
<div>
<div class="layer-heading" data-en="Your EGG Server" data-pt="Seu Servidor EGG">Your EGG Server</div>
<div class="layer-sub">egg.yourdomain.com</div>
</div>
</div>
<div class="layer-items">
<div class="layer-item">
<div class="layer-dot"></div>
<div>
<div class="item-title" data-en="Git repositories" data-pt="Repositórios Git">Git repositories</div>
<p class="item-desc" data-en="Bare git repos stored on your disk. You own every byte." data-pt="Repos git bare armazenados no seu disco. Você é dono de cada byte.">Bare git repos stored on your disk. You own every byte.</p>
</div>
</div>
<div class="layer-item">
<div class="layer-dot"></div>
<div>
<div class="item-title" data-en="Web client (EGG UI)" data-pt="Client web (EGG UI)">Web client (EGG UI)</div>
<p class="item-desc" data-en="Browse repos, view diffs, explore history — served from your own domain." data-pt="Navegue pelos repos, veja diffs, explore o histórico — servido do seu próprio domínio.">Browse repos, view diffs, explore history — served from your own domain.</p>
</div>
</div>
<div class="layer-item">
<div class="layer-dot"></div>
<div>
<div class="item-title" data-en="Nostr relay (built-in)" data-pt="Relay Nostr (embutido)">Nostr relay (built-in)</div>
<p class="item-desc" data-en="Your instance runs its own relay. Social events arrive here and broadcast to the network." data-pt="Sua instância roda seu próprio relay. Eventos sociais chegam aqui e propagam pela rede.">Your instance runs its own relay. Social events arrive here and broadcast to the network.</p>
</div>
</div>
<div class="layer-item">
<div class="layer-dot"></div>
<div>
<div class="item-title" data-en="Access control" data-pt="Controle de acesso">Access control</div>
<p class="item-desc" data-en="Define which npubs can push, pull, or view each repository." data-pt="Defina quais npubs podem fazer push, pull ou ver cada repositório.">Define which npubs can push, pull, or view each repository.</p>
</div>
</div>
</div>
</div>
<!-- Nostr layer -->
<div class="layer-block">
<div class="layer-header">
<div class="layer-icon nostr">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#7c5fa8" stroke-width="2" stroke-linecap="round"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>
</div>
<div>
<div class="layer-heading" data-en="Nostr Network" data-pt="Rede Nostr">Nostr Network</div>
<div class="layer-sub" data-en="social layer · open protocol" data-pt="camada social · protocolo aberto">social layer · open protocol</div>
</div>
</div>
<div class="layer-items">
<div class="layer-item">
<div class="layer-dot purple"></div>
<div>
<div class="item-title" data-en="Issues & pull requests" data-pt="Issues & pull requests">Issues & pull requests</div>
<p class="item-desc" data-en="Opened as signed Nostr events. Anyone with a keypair can participate, across any instance." data-pt="Abertos como eventos Nostr assinados. Qualquer pessoa com um par de chaves pode participar, em qualquer instância.">Opened as signed Nostr events. Anyone with a keypair can participate, across any instance.</p>
</div>
</div>
<div class="layer-item">
<div class="layer-dot purple"></div>
<div>
<div class="item-title" data-en="Code reviews & comments" data-pt="Code reviews & comentários">Code reviews & comments</div>
<p class="item-desc" data-en="Threaded conversations linked to commits and PR events. Verifiable authorship." data-pt="Conversas encadeadas vinculadas a commits e eventos de PR. Autoria verificável.">Threaded conversations linked to commits and PR events. Verifiable authorship.</p>
</div>
</div>
<div class="layer-item">
<div class="layer-dot purple"></div>
<div>
<div class="item-title" data-en="Developer identity" data-pt="Identidade do desenvolvedor">Developer identity</div>
<p class="item-desc" data-en="Your npub is your universal username. No account on each platform. Works across all EGG instances." data-pt="Seu npub é seu username universal. Sem conta em cada plataforma. Funciona em todas as instâncias EGG.">Your npub is your universal username. No account on each platform. Works across all EGG instances.</p>
</div>
</div>
<div class="layer-item">
<div class="layer-dot purple"></div>
<div>
<div class="item-title" data-en="User management" data-pt="Gerenciamento de usuários">User management</div>
<p class="item-desc" data-en="Grant or revoke access via Nostr events. No user database to maintain — Nostr keypairs are the accounts." data-pt="Conceda ou revogue acesso via eventos Nostr. Sem banco de usuários para manter — pares de chaves Nostr são as contas.">Grant or revoke access via Nostr events. No user database to maintain — Nostr keypairs are the accounts.</p>
</div>
</div>
</div>
</div>
</div>
</section>
<hr class="divider">
<!-- HOW TO DEPLOY -->
<section>
<div class="section-label" data-en="How to get started" data-pt="Como começar">How to get started</div>
<h2 class="section-title" data-en="Your instance in <em>four steps</em>." data-pt="Sua instância em <em>quatro passos</em>.">Your instance in <em>four steps</em>.</h2>
<div class="setup-steps">
<div class="setup-step">
<div class="step-num">01</div>
<div class="step-badge" data-en="server" data-pt="servidor">server</div>
<div>
<div class="step-title" data-en="Deploy EGG on your server" data-pt="Instale o EGG no seu servidor">Deploy EGG on your server</div>
<p class="step-desc" data-en="Clone the EGG repo and run the installer. Works on any Linux VPS. Points your subdomain — egg.yourdomain.com — to your instance." data-pt="Clone o repo EGG e rode o instalador. Funciona em qualquer VPS Linux. Aponte seu subdomínio — egg.seudominio.com — para sua instância.">Clone the EGG repo and run the installer. Works on any Linux VPS. Points your subdomain — egg.yourdomain.com — to your instance.</p>
<div class="step-code">git clone https://github.com/getegg/egg && cd egg && ./install.sh</div>
</div>
</div>
<div class="setup-step">
<div class="step-num">02</div>
<div class="step-badge nostr-badge">nostr</div>
<div>
<div class="step-title" data-en="Connect your Nostr identity" data-pt="Conecte sua identidade Nostr">Connect your Nostr identity</div>
<p class="step-desc" data-en="Sign in with your Nostr keypair (npub). Your existing identity works — no new account needed. You are automatically the admin of your instance." data-pt="Faça login com seu par de chaves Nostr (npub). Sua identidade existente funciona — nenhuma nova conta necessária. Você é automaticamente o admin da sua instância.">Sign in with your Nostr keypair (npub). Your existing identity works — no new account needed. You are automatically the admin of your instance.</p>
</div>
</div>
<div class="setup-step">
<div class="step-num">03</div>
<div class="step-badge" data-en="repositories" data-pt="repositórios">repositories</div>
<div>
<div class="step-title" data-en="Push your repositories" data-pt="Suba seus repositórios">Push your repositories</div>
<p class="step-desc" data-en="Use standard git commands to push code to your EGG instance. Set each repo as public or private. Manage collaborators by authorizing npubs via Nostr events." data-pt="Use comandos git padrão para enviar código para sua instância EGG. Defina cada repo como público ou privado. Gerencie colaboradores autorizando npubs via eventos Nostr.">Use standard git commands to push code to your EGG instance. Set each repo as public or private. Manage collaborators by authorizing npubs via Nostr events.</p>
<div class="step-code">git remote add egg git@egg.yourdomain.com:myproject.git</div>
</div>
</div>
<div class="setup-step">
<div class="step-num">04</div>
<div class="step-badge nostr-badge">network</div>
<div>
<div class="step-title" data-en="Join the EGG network" data-pt="Entre na rede EGG">Join the EGG network</div>
<p class="step-desc" data-en="Your instance is now part of the decentralized EGG network. Developers on any other EGG instance can discover your public repos, open issues and submit pull requests — all through Nostr events." data-pt="Sua instância agora faz parte da rede EGG descentralizada. Desenvolvedores em qualquer outra instância EGG podem descobrir seus repos públicos, abrir issues e submeter pull requests — tudo por eventos Nostr.">Your instance is now part of the decentralized EGG network. Developers on any other EGG instance can discover your public repos, open issues and submit pull requests — all through Nostr events.</p>
</div>
</div>
</div>
</section>
<hr class="divider">
<!-- ACCESS MODEL -->
<section>
<div class="section-label" data-en="Access control" data-pt="Controle de acesso">Access control</div>
<h2 class="section-title" data-en="Public or private — <em>you decide</em>." data-pt="Público ou privado — <em>você decide</em>.">Public or private — <em>you decide</em>.</h2>
<p class="section-sub" data-en="Access is enforced jointly — by your server (who can clone) and by Nostr (who can interact). Both layers always work together." data-pt="O acesso é controlado em conjunto — pelo seu servidor (quem pode clonar) e pelo Nostr (quem pode interagir). As duas camadas trabalham juntas sempre.">Access is enforced jointly — by your server (who can clone) and by Nostr (who can interact). Both layers always work together.</p>
<div class="access-grid">
<div class="access-card public">
<div class="access-type pub" data-en="◉ PUBLIC REPOSITORY" data-pt="◉ REPOSITÓRIO PÚBLICO">◉ PUBLIC REPOSITORY</div>
<div class="access-title" data-en="Open to the world" data-pt="Aberto para o mundo">Open to the world</div>
<ul class="access-list">
<li><span data-en="Anyone can clone and browse the code" data-pt="Qualquer pessoa pode clonar e navegar pelo código">Anyone can clone and browse the code</span></li>
<li><span data-en="Any npub can open issues via Nostr events" data-pt="Qualquer npub pode abrir issues via eventos Nostr">Any npub can open issues via Nostr events</span></li>
<li><span data-en="Pull requests submitted as signed events from any instance" data-pt="Pull requests submetidos como eventos assinados de qualquer instância">Pull requests submitted as signed events from any instance</span></li>
<li><span data-en="You control who can merge — via authorized npubs" data-pt="Você controla quem pode fazer merge — via npubs autorizados">You control who can merge — via authorized npubs</span></li>
</ul>
</div>
<div class="access-card private">
<div class="access-type priv" data-en="◉ PRIVATE REPOSITORY" data-pt="◉ REPOSITÓRIO PRIVADO">◉ PRIVATE REPOSITORY</div>
<div class="access-title" data-en="Invite-only collaboration" data-pt="Colaboração por convite">Invite-only collaboration</div>
<ul class="access-list">
<li><span data-en="Server enforces: only authorized npubs can clone" data-pt="Servidor impõe: somente npubs autorizados podem clonar">Server enforces: only authorized npubs can clone</span></li>
<li><span data-en="Issues and PRs visible only to invited npubs via Nostr" data-pt="Issues e PRs visíveis somente para npubs convidados via Nostr">Issues and PRs visible only to invited npubs via Nostr</span></li>
<li><span data-en="Grant access with a Nostr event — revoke the same way" data-pt="Conceda acesso com um evento Nostr — revogue da mesma forma">Grant access with a Nostr event — revoke the same way</span></li>
<li><span data-en="No user database — npubs are the accounts" data-pt="Sem banco de usuários — npubs são as contas">No user database — npubs are the accounts</span></li>
</ul>
</div>
</div>
</section>
<hr class="divider">
<!-- COMPARISON -->
<section>
<div class="section-label" data-en="Comparison" data-pt="Comparação">Comparison</div>
<h2 class="section-title" data-en="GitHub vs Gitea vs <em>EGG</em>" data-pt="GitHub vs Gitea vs <em>EGG</em>">GitHub vs Gitea vs <em>EGG</em></h2>
<div class="compare-wrap">
<table>
<thead><tr>
<th data-en="Feature" data-pt="Característica">Feature</th>
<th>GitHub / GitLab</th>
<th>Gitea / Forgejo</th>
<th>EGG</th>
</tr></thead>
<tbody>
<tr>
<td data-en="Self-hostable" data-pt="Auto-hospedável">Self-hostable</td>
<td><span class="cross">✕</span> GitHub / <span class="check">✓</span> GitLab</td>
<td><span class="check">✓</span> <span data-en="Yes" data-pt="Sim">Yes</span></td>
<td><span class="check">✓</span> <span data-en="Yes — core model" data-pt="Sim — modelo central">Yes — core model</span></td>
</tr>
<tr>
<td data-en="User accounts" data-pt="Contas de usuário">User accounts</td>
<td><span class="cross">✕</span> <span data-en="Email + password" data-pt="Email + senha">Email + password</span></td>
<td><span class="cross">✕</span> <span data-en="Local database" data-pt="Banco local">Local database</span></td>
<td><span class="check">✓</span> <span data-en="Nostr keypairs only" data-pt="Somente pares de chaves Nostr">Nostr keypairs only</span></td>
</tr>
<tr>
<td data-en="Cross-instance interaction" data-pt="Interação entre instâncias">Cross-instance interaction</td>
<td><span class="cross">✕</span> <span data-en="Same platform only" data-pt="Somente mesma plataforma">Same platform only</span></td>
<td><span class="cross">✕</span> <span data-en="No federation" data-pt="Sem federação">No federation</span></td>
<td><span class="check">✓</span> <span data-en="Native via Nostr" data-pt="Nativo via Nostr">Native via Nostr</span></td>
</tr>
<tr>
<td data-en="Social layer" data-pt="Camada social">Social layer</td>
<td><span class="cross">✕</span> <span data-en="Proprietary" data-pt="Proprietária">Proprietary</span></td>
<td><span class="cross">✕</span> <span data-en="Per-instance only" data-pt="Por instância somente">Per-instance only</span></td>
<td><span class="check">✓</span> <span data-en="Open Nostr protocol" data-pt="Protocolo Nostr aberto">Open Nostr protocol</span></td>
</tr>
<tr>
<td data-en="Code ownership" data-pt="Propriedade do código">Code ownership</td>
<td><span class="cross">✕</span> <span data-en="Platform's servers" data-pt="Servidores da plataforma">Platform's servers</span></td>
<td><span class="check">✓</span> <span data-en="Your server" data-pt="Seu servidor">Your server</span></td>
<td><span class="check">✓</span> <span data-en="Your server" data-pt="Seu servidor">Your server</span></td>
</tr>
<tr>
<td data-en="Censorship resistance" data-pt="Resistência à censura">Censorship resistance</td>
<td><span class="cross">✕</span> <span data-en="Platform ToS" data-pt="ToS da plataforma">Platform ToS</span></td>
<td><span class="cross">✕</span> <span data-en="Isolated — no network" data-pt="Isolado — sem rede">Isolated — no network</span></td>
<td><span class="check">✓</span> <span data-en="Distributed network" data-pt="Rede distribuída">Distributed network</span></td>
</tr>
<tr>
<td data-en="Protocol" data-pt="Protocolo">Protocol</td>
<td><span class="cross">✕</span> <span data-en="Proprietary API" data-pt="API proprietária">Proprietary API</span></td>
<td><span class="cross">✕</span> <span data-en="HTTP API only" data-pt="Somente HTTP API">HTTP API only</span></td>
<td><span class="check">✓</span> <span data-en="Open Nostr + Git" data-pt="Nostr aberto + Git">Open Nostr + Git</span></td>
</tr>
</tbody>
</table>
</div>
</section>
<hr class="divider">
<!-- ROADMAP -->
<section>
<div class="section-label" data-en="Roadmap" data-pt="Roadmap">Roadmap</div>
<h2 class="section-title" data-en="Building the <em>open forge</em>." data-pt="Construindo a <em>forge aberta</em>.">Building the <em>open forge</em>.</h2>
<div class="roadmap">
<div class="phase">
<div class="phase-label" data-en="PHASE 01" data-pt="FASE 01">PHASE 01</div>
<div class="phase-title" data-en="Core Server" data-pt="Servidor Core">Core Server</div>
<ul class="phase-items">
<li><span data-en="Git hosting + web UI" data-pt="Hospedagem Git + UI web">Git hosting + web UI</span></li>
<li><span data-en="Built-in Nostr relay" data-pt="Relay Nostr embutido">Built-in Nostr relay</span></li>
<li><span data-en="npub-based auth" data-pt="Auth baseada em npub">npub-based auth</span></li>
<li><span data-en="Public / private repos" data-pt="Repos públicos / privados">Public / private repos</span></li>
</ul>
</div>
<div class="phase">
<div class="phase-label" data-en="PHASE 02" data-pt="FASE 02">PHASE 02</div>
<div class="phase-title" data-en="Collaboration" data-pt="Colaboração">Collaboration</div>
<ul class="phase-items">
<li><span data-en="Issues as Nostr events" data-pt="Issues como eventos Nostr">Issues as Nostr events</span></li>
<li><span data-en="Pull request events" data-pt="Eventos de pull request">Pull request events</span></li>
<li><span data-en="Cross-instance PRs" data-pt="PRs entre instâncias">Cross-instance PRs</span></li>
<li><span data-en="Code review threads" data-pt="Threads de code review">Code review threads</span></li>
</ul>
</div>
<div class="phase">
<div class="phase-label" data-en="PHASE 03" data-pt="FASE 03">PHASE 03</div>
<div class="phase-title" data-en="Network" data-pt="Rede">Network</div>
<ul class="phase-items">
<li><span data-en="Instance discovery" data-pt="Descoberta de instâncias">Instance discovery</span></li>
<li><span data-en="Repo federation" data-pt="Federação de repos">Repo federation</span></li>
<li><span data-en="Releases & tags" data-pt="Releases & tags">Releases & tags</span></li>
<li><span data-en="Git CLI plugin" data-pt="Plugin de CLI Git">Git CLI plugin</span></li>
</ul>
</div>
<div class="phase">
<div class="phase-label" data-en="PHASE 04" data-pt="FASE 04">PHASE 04</div>
<div class="phase-title" data-en="Ecosystem" data-pt="Ecossistema">Ecosystem</div>
<ul class="phase-items">
<li><span data-en="CI/CD event hooks" data-pt="Hooks de CI/CD">CI/CD event hooks</span></li>
<li><span data-en="IDE integrations" data-pt="Integrações com IDEs">IDE integrations</span></li>
<li><span data-en="SDK for developers" data-pt="SDK para desenvolvedores">SDK for developers</span></li>
<li><span data-en="Instance marketplace" data-pt="Marketplace de instâncias">Instance marketplace</span></li>
</ul>
</div>
</div>
</section>
<hr class="divider">
<!-- DEVELOPERS -->
<div class="dev-section">
<div class="dev-label" data-en="For Developers" data-pt="Para Desenvolvedores">For Developers</div>
<h2 class="dev-title" data-en="<em>Contribute</em> or deploy your instance." data-pt="<em>Contribua</em> ou instale sua instância."><em>Contribute</em> or deploy your instance.</h2>
<p class="dev-sub" style="margin-top:8px; font-size:16px; color:var(--text-muted);"
data-en="EGG is built in the open. Every line of code is public."
data-pt="O EGG é construído abertamente. Cada linha de código é pública.">
EGG is built in the open. Every line of code is public.
</p>
<div class="dev-grid">
<a href="https://github.com/getegg" class="dev-card" target="_blank">
<div class="dev-card-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="#1a5fa8"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.3 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61-.546-1.387-1.333-1.756-1.333-1.756-1.09-.745.083-.73.083-.73 1.205.085 1.84 1.237 1.84 1.237 1.07 1.835 2.807 1.305 3.492.997.108-.775.418-1.305.762-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.605-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 21.795 24 17.295 24 12c0-6.63-5.37-12-12-12z"/></svg>
</div>
<div>
<div class="dev-card-title" data-en="GitHub Organization" data-pt="Organização no GitHub">GitHub Organization</div>
<div class="dev-card-url">github.com/getegg</div>
<p class="dev-card-desc" data-en="All EGG repositories, issue tracker, protocol discussions and contribution guidelines." data-pt="Todos os repositórios EGG, rastreador de issues, discussões de protocolo e guias de contribuição.">All EGG repositories, issue tracker, protocol discussions and contribution guidelines.</p>
</div>
</a>
<a href="https://github.com/getegg/egg" class="dev-card" target="_blank">
<div class="dev-card-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#1a5fa8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/><polyline points="7 8 10 11 7 14"/><line x1="13" y1="14" x2="17" y2="14"/></svg>
</div>
<div>
<div class="dev-card-title" data-en="Deploy your EGG instance" data-pt="Instalar sua instância EGG">Deploy your EGG instance</div>
<div class="dev-card-url">github.com/getegg/egg</div>
<p class="dev-card-desc" data-en="Complete installation guide — from VPS setup to your first repository push. Self-host in minutes." data-pt="Guia de instalação completo — do setup do VPS ao primeiro push de repositório. Auto-hospede em minutos.">Complete installation guide — from VPS setup to your first repository push. Self-host in minutes.</p>
</div>
</a>
</div>
</div>
<!-- FOOTER -->
<footer>
<div class="footer-inner">
<div>
<div class="footer-col-title" data-en="Project" data-pt="Projeto">Project</div>
<div class="footer-links">
<a href="https://egg.edgarpaula.org" class="footer-link" target="_blank"><span class="footer-dot"></span>egg.edgarpaula.org</a>
<a href="https://nosta.me/npub1xux7a76ad990n594q6kxn68gefh4zvyjmpa68wc2t7sml7ks7j7qxrhpc5" class="footer-link" target="_blank">
<span class="footer-dot"></span><span data-en="EGG on Nostr" data-pt="EGG no Nostr">EGG on Nostr</span>
</a>
<a href="https://github.com/getegg" class="footer-link" target="_blank"><span class="footer-dot"></span>github.com/getegg</a>
<a href="https://github.com/getegg/egg" class="footer-link" target="_blank"><span class="footer-dot"></span>github.com/getegg/egg</a>
</div>
</div>
<div class="footer-author-col">
<div class="footer-col-title" data-en="Author" data-pt="Autor">Author</div>
<div class="author-name-big">Edgar Paula</div>
<a href="https://edgarpaula.org" class="author-site" target="_blank">edgarpaula.org</a>
<div class="footer-links">
<a href="https://nosta.me/npub1gx95nc7f4yslxwqg8u84jt9zqcsg80lsecl0ld2zyesx4qpevf9sd2ph6j" class="footer-link" target="_blank">
<span class="footer-dot"></span><span data-en="Edgar Paula on Nostr" data-pt="Edgar Paula no Nostr">Edgar Paula on Nostr</span>
</a>
</div>
</div>
</div>
<div class="footer-bottom">
EGG — Event Git Graph ·
<a href="https://edgarpaula.org" target="_blank">Edgar Paula</a> ·
<span data-en="built on" data-pt="construído sobre">built on</span> <a href="https://nostr.com" target="_blank">Nostr</a>
</div>
</footer>
<script>
function setLang(lang) {
document.getElementById('btn-en').classList.toggle('active', lang === 'en');
document.getElementById('btn-pt').classList.toggle('active', lang === 'pt');
document.documentElement.lang = lang;
document.querySelectorAll('[data-' + lang + ']').forEach(el => {
const val = el.getAttribute('data-' + lang);
if (val !== null) el.innerHTML = val;
});
}
const io = new IntersectionObserver(entries => {
entries.forEach(e => {
if (e.isIntersecting) {
e.target.style.opacity = '1';
e.target.style.transform = 'translateY(0)';
}
});
}, { threshold: 0.06 });
document.querySelectorAll('section, .dev-section, .footer-inner').forEach(el => {
el.style.opacity = '0';
el.style.transform = 'translateY(18px)';
el.style.transition = 'opacity 0.65s ease, transform 0.65s ease';
io.observe(el);
});
</script>
</body>
</html>