@h-rig/product-ad-website 0.0.6-alpha.283
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/README.md +3 -0
- package/package.json +52 -0
- package/site/assets/favicon.svg +1 -0
- package/site/assets/og-card.png +0 -0
- package/site/assets/rig.css +199 -0
- package/site/assets/rig.js +66 -0
- package/site/assets/search-index.json +1 -0
- package/site/assets/site.css +46 -0
- package/site/assets/site.js +510 -0
- package/site/cli/index.html +88 -0
- package/site/config/index.html +256 -0
- package/site/docs/agent-tools/index.html +129 -0
- package/site/docs/architecture/index.html +42 -0
- package/site/docs/capabilities/index.html +84 -0
- package/site/docs/entities/index.html +68 -0
- package/site/docs/environment/index.html +62 -0
- package/site/docs/faq/index.html +17 -0
- package/site/docs/fleet-irc/index.html +44 -0
- package/site/docs/gate/index.html +128 -0
- package/site/docs/getting-started/index.html +50 -0
- package/site/docs/glossary/index.html +31 -0
- package/site/docs/index.html +68 -0
- package/site/docs/operator/index.html +49 -0
- package/site/docs/packages/index.html +36 -0
- package/site/docs/pi-extensions/index.html +15 -0
- package/site/docs/recipes/index.html +28 -0
- package/site/docs/runs/index.html +35 -0
- package/site/docs/security/index.html +29 -0
- package/site/docs/server/index.html +27 -0
- package/site/docs/swarm-commander/index.html +41 -0
- package/site/docs/task-sources/index.html +129 -0
- package/site/docs/troubleshooting/index.html +23 -0
- package/site/docs/validators/index.html +177 -0
- package/site/index.html +1653 -0
- package/site/plugins/examples/index.html +419 -0
- package/site/plugins/index.html +193 -0
- package/site/skills/index.html +140 -0
- package/site/variants/deck/index.html +1 -0
package/site/index.html
ADDED
|
@@ -0,0 +1,1653 @@
|
|
|
1
|
+
<!doctype html><html lang="en"><head>
|
|
2
|
+
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
3
|
+
<title>Rig — air superiority as a binary</title><meta property="og:image" content="https://how.rig-does.work/assets/og-card.png"><meta property="og:title" content="Rig — air superiority as a binary"><meta name="twitter:card" content="summary_large_image">
|
|
4
|
+
<meta name="build" content="omp-v1"><meta name="description" content="Ground control for coding drones: launch the swarm from one terminal session, watch the fleet in the cnet, message any drone mid-flight, and land only SHA-pinned, review-cleared merges."><meta property="og:description" content="Ground control for coding drones: launch the swarm from one terminal session, watch the fleet in the cnet, message any drone mid-flight, and land only SHA-pinned, review-cleared merges.">
|
|
5
|
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
6
|
+
<style>
|
|
7
|
+
:root{
|
|
8
|
+
--bg:#070809;--bg-2:#0b0c0e;--panel:rgba(16,17,21,.72);--glass:rgba(20,22,27,.5);
|
|
9
|
+
--line:rgba(255,255,255,.07);--line-2:rgba(255,255,255,.13);
|
|
10
|
+
--ink:#f2f3f6;--ink-2:#aeb0ba;--ink-3:#6c6e79;--ink-4:#44464f;
|
|
11
|
+
--ac:#ccff4d;--ac-dim:#a9d63f;--ac-2:#56d8ff;
|
|
12
|
+
--mono:'JetBrains Mono',ui-monospace,monospace;--disp:'Space Grotesk',system-ui,sans-serif;
|
|
13
|
+
--gut:clamp(24px,5vw,90px);
|
|
14
|
+
}
|
|
15
|
+
*{box-sizing:border-box}html{scroll-behavior:smooth}
|
|
16
|
+
body{margin:0;background:var(--bg);color:var(--ink-2);font-family:var(--disp);font-size:17px;line-height:1.6;-webkit-font-smoothing:antialiased;overflow-x:hidden}
|
|
17
|
+
a{color:var(--ink);text-decoration:none;transition:color .18s}a:hover{color:var(--ac)}
|
|
18
|
+
code,pre,kbd{font-family:var(--mono)}::selection{background:var(--ac);color:#070809}
|
|
19
|
+
.bleed{width:100%;padding-left:var(--gut);padding-right:var(--gut)}
|
|
20
|
+
|
|
21
|
+
/* per-section dedicated scene canvas — absolute INSIDE each section, not a global fixed bg */
|
|
22
|
+
.stage-wrap{position:relative;overflow:hidden}
|
|
23
|
+
.scene{position:absolute;inset:0;width:100%;height:100%;z-index:0;display:block;pointer-events:none}
|
|
24
|
+
.scene-veil{position:absolute;inset:0;z-index:1;pointer-events:none}
|
|
25
|
+
|
|
26
|
+
.nav{position:fixed;top:0;left:0;right:0;z-index:40;backdrop-filter:blur(14px);background:linear-gradient(180deg,rgba(7,8,9,.72),rgba(7,8,9,0))}
|
|
27
|
+
.nav-in{display:flex;align-items:center;gap:34px;padding:22px var(--gut)}
|
|
28
|
+
.brand{font-family:var(--disp);font-weight:600;font-size:16px;color:var(--ink);display:flex;align-items:center;gap:9px}
|
|
29
|
+
.brand .mark{width:9px;height:9px;background:var(--ac);border-radius:2px;box-shadow:0 0 12px var(--ac);animation:pulse 2.4s ease-in-out infinite}
|
|
30
|
+
@keyframes pulse{50%{opacity:.45;transform:scale(.82)}}
|
|
31
|
+
.nav-links{display:flex;gap:26px;margin-left:auto;align-items:center}
|
|
32
|
+
.nav-links a{font-size:13.5px;color:var(--ink-3);position:relative}.nav-links a:hover{color:var(--ink)}
|
|
33
|
+
.nav-links a.active{color:var(--ink)}.nav-links a.active::after{content:"";position:absolute;left:0;right:0;bottom:-7px;height:1px;background:var(--ac)}
|
|
34
|
+
.nav-links a.ext{color:var(--ink-4)}
|
|
35
|
+
|
|
36
|
+
/* HERO */
|
|
37
|
+
.hero{position:relative;z-index:2;min-height:100vh;display:flex;flex-direction:column;justify-content:center;padding:120px var(--gut) 60px}
|
|
38
|
+
.hero .scene{z-index:0}
|
|
39
|
+
.hero>*:not(.scene):not(.scene-veil){position:relative;z-index:2}
|
|
40
|
+
.kick{font-family:var(--mono);font-size:13px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-3);display:flex;align-items:center;gap:14px;margin-bottom:26px}
|
|
41
|
+
.kick::before{content:"";width:44px;height:1px;background:var(--ac)}
|
|
42
|
+
.hl{font-family:var(--disp);font-weight:700;font-size:clamp(60px,13vw,220px);line-height:.86;letter-spacing:-.05em;color:var(--ink);margin:0;max-width:none}
|
|
43
|
+
.hl .ac{color:var(--ac)}
|
|
44
|
+
.herorow{display:flex;align-items:flex-end;justify-content:space-between;gap:48px;flex-wrap:wrap;margin-top:36px}
|
|
45
|
+
.lede{font-size:clamp(18px,1.6vw,22px);color:var(--ink-2);max-width:440px;line-height:1.5;margin:0}.lede b{color:var(--ink);font-weight:500}
|
|
46
|
+
.cta{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
|
|
47
|
+
.btn{font-size:14px;padding:14px 28px;border-radius:9px;border:1px solid var(--line-2);color:var(--ink);transition:.18s;display:inline-flex;gap:9px;align-items:center;cursor:pointer;background:rgba(8,9,11,.4);backdrop-filter:blur(6px)}
|
|
48
|
+
.btn:hover{border-color:var(--ink-3);transform:translateY(-1px)}
|
|
49
|
+
.btn.pri{background:var(--ac);color:#070809;border-color:var(--ac);font-weight:600}
|
|
50
|
+
.btn.pri:hover{box-shadow:0 8px 36px rgba(204,255,77,.3);transform:translateY(-2px)}
|
|
51
|
+
|
|
52
|
+
/* cinematic terminal */
|
|
53
|
+
.cine{position:relative;z-index:2;margin:60px 0 0;border:1px solid var(--line-2);border-radius:16px;overflow:hidden;background:var(--panel);backdrop-filter:blur(20px);box-shadow:0 60px 160px -40px rgba(0,0,0,.85),0 0 0 1px rgba(255,255,255,.02) inset;width:100%}
|
|
54
|
+
.cine .cb{display:flex;align-items:center;gap:12px;padding:15px 20px;border-bottom:1px solid var(--line)}
|
|
55
|
+
.cine .cb .d{width:11px;height:11px;border-radius:50%;background:#2a2c33}
|
|
56
|
+
.cine .cb .d.a{background:#ff5f57}.cine .cb .d.b{background:#febc2e}.cine .cb .d.c{background:#28c840}
|
|
57
|
+
.cine .cb .ttl{margin-left:10px;font-family:var(--mono);font-size:12.5px;color:var(--ink-3)}
|
|
58
|
+
.cine .cb .st{margin-left:auto;font-family:var(--mono);font-size:11px;color:var(--ac-dim);display:flex;align-items:center;gap:7px}
|
|
59
|
+
.cine .cb .st i{width:6px;height:6px;border-radius:50%;background:var(--ac);box-shadow:0 0 9px var(--ac);font-style:normal;animation:pulse 2s infinite}
|
|
60
|
+
.cine .scr{padding:26px 30px;font-family:var(--mono);font-size:14px;line-height:1.85;min-height:420px;color:var(--ink-2);white-space:pre-wrap;word-break:break-word}
|
|
61
|
+
.cine .scr .pr{color:var(--ac)}.cine .scr .cm{color:var(--ink-4)}.cine .scr .ok{color:var(--ac)}
|
|
62
|
+
.cine .scr .c2{color:var(--ac-2)}.cine .scr .mg{color:#ff79b0}.cine .scr .dim{color:var(--ink-4)}.cine .scr .w{color:var(--ink)}
|
|
63
|
+
.cur{display:inline-block;width:9px;height:17px;background:var(--ac);vertical-align:text-bottom;margin-left:2px;animation:cb 1.05s steps(1) infinite;box-shadow:0 0 8px rgba(204,255,77,.6)}
|
|
64
|
+
@keyframes cb{50%{opacity:0}}
|
|
65
|
+
.scrollcue{margin-top:40px;font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-4);display:flex;align-items:center;gap:12px}
|
|
66
|
+
.scrollcue .ln{width:1px;height:34px;background:linear-gradient(var(--ac),transparent);animation:cue 2s ease-in-out infinite}
|
|
67
|
+
@keyframes cue{0%,100%{opacity:.3;transform:scaleY(.6)}50%{opacity:1;transform:scaleY(1)}}
|
|
68
|
+
|
|
69
|
+
/* hero install one-liner */
|
|
70
|
+
.inst{display:flex;align-items:center;gap:12px;margin-top:22px;padding:13px 18px;border:1px solid var(--line-2);border-radius:9px;background:rgba(8,9,11,.55);backdrop-filter:blur(8px);font-family:var(--mono);font-size:13.5px;max-width:640px}
|
|
71
|
+
.inst .pr{color:var(--ac)}
|
|
72
|
+
.inst code{color:var(--ink-2);overflow-x:auto;white-space:nowrap;flex:1}
|
|
73
|
+
.inst .cp{margin-left:auto;border:none;background:transparent;color:var(--ink-4);font-family:var(--mono);font-size:11px;cursor:pointer;letter-spacing:.06em;transition:.15s;flex:none}
|
|
74
|
+
.inst .cp:hover{color:var(--ac)}
|
|
75
|
+
|
|
76
|
+
/* hero: Ghostty-style — centered, the live terminal is the centerpiece */
|
|
77
|
+
.herocenter{text-align:center}
|
|
78
|
+
.herocenter .kick{justify-content:center;margin-bottom:22px}
|
|
79
|
+
.herocenter .hl{text-align:center;font-size:clamp(46px,8.6vw,132px);line-height:.9;margin:0 auto}
|
|
80
|
+
.herocenter .cine{max-width:860px;margin:42px auto 0}
|
|
81
|
+
/* big two-line closing statement — crisp DOM at rest, canvas shred only during the burst */
|
|
82
|
+
.hsub{line-height:1.06;color:var(--ink);margin:0 auto;max-width:1100px;letter-spacing:-.03em}
|
|
83
|
+
.hsub-a,.hsub-b .l2{font-size:clamp(28px,4vw,54px);font-weight:700;line-height:1.06}
|
|
84
|
+
.hsub-a{display:inline-block;color:var(--ink);margin-bottom:10px}
|
|
85
|
+
.hsub-b{position:relative;display:inline-block}
|
|
86
|
+
.hsub-b .l2{display:inline-block}
|
|
87
|
+
.hsub-b .l2p{color:var(--ink)}
|
|
88
|
+
.hsub-b .l2h{color:var(--ac);text-shadow:0 0 24px rgba(204,255,77,.4)}
|
|
89
|
+
.hsub-b .ripcv{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);opacity:0;pointer-events:none}
|
|
90
|
+
@media(prefers-reduced-motion:reduce){.hsub-b .ripcv{display:none}}
|
|
91
|
+
.herocenter .cta{justify-content:center;margin-top:26px}
|
|
92
|
+
.herocenter .inst{margin:20px auto 0}
|
|
93
|
+
.herocenter .scrollcue{justify-content:center;margin-top:46px}
|
|
94
|
+
|
|
95
|
+
/* operator's three moves band */
|
|
96
|
+
.moves{position:relative;z-index:2;padding:0;border-top:1px solid var(--line)}
|
|
97
|
+
.moves .mv-in{max-width:var(--maxw);margin:0 auto;display:grid;grid-template-columns:repeat(3,1fr)}
|
|
98
|
+
.mv{padding:64px var(--gut);border-right:1px solid var(--line)}
|
|
99
|
+
.mv:last-child{border-right:none}
|
|
100
|
+
.mv .v{font-family:var(--disp);font-size:clamp(30px,3.6vw,52px);font-weight:700;letter-spacing:-.035em;color:var(--ink);line-height:1}
|
|
101
|
+
.mv .v .ac{color:var(--ac)}
|
|
102
|
+
.mv p{color:var(--ink-3);font-size:15.5px;margin:18px 0 0;line-height:1.55;max-width:300px}
|
|
103
|
+
.mv p b{color:var(--ink-2)}
|
|
104
|
+
a.mv{display:block;color:inherit;transition:background .25s}
|
|
105
|
+
a.mv:hover{background:rgba(204,255,77,.035)}
|
|
106
|
+
.mv .go{display:inline-block;margin-top:22px;font-family:var(--mono);font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-4);transition:color .2s,transform .2s}
|
|
107
|
+
a.mv:hover .go{color:var(--ac);transform:translateX(4px)}
|
|
108
|
+
@media(max-width:820px){.moves .mv-in{grid-template-columns:1fr}.mv{border-right:none;border-bottom:1px solid var(--line)}}
|
|
109
|
+
|
|
110
|
+
/* title chromatic-aberration glitch — subtle, periodic */
|
|
111
|
+
@keyframes glitch{0%,92%,100%{text-shadow:0 0 26px rgba(204,255,77,.28)}93%{text-shadow:-2px 0 rgba(86,216,255,.85),2px 0 rgba(255,121,176,.75),0 0 26px rgba(204,255,77,.28)}95%{text-shadow:2px 0 rgba(86,216,255,.85),-2px 0 rgba(255,121,176,.75),0 0 26px rgba(204,255,77,.28)}97%{text-shadow:0 0 26px rgba(204,255,77,.28)}}
|
|
112
|
+
.hl.gl .ac{animation:glitch 5.5s infinite}
|
|
113
|
+
@media(prefers-reduced-motion:reduce){.hl.gl .ac{animation:none}}
|
|
114
|
+
|
|
115
|
+
/* WHAT-IS clarity band (its own scene) */
|
|
116
|
+
.whatis{position:relative;z-index:2;padding:130px 0;border-top:1px solid var(--line)}
|
|
117
|
+
.whatis>*:not(.scene):not(.scene-veil){position:relative;z-index:3}
|
|
118
|
+
.whatis .wrapx{max-width:var(--maxw);margin:0 auto;padding:0 var(--gut)}
|
|
119
|
+
.whatis .eyebrow{margin-bottom:20px}
|
|
120
|
+
.whatis .big{font-family:var(--disp);font-size:clamp(27px,3.9vw,50px);font-weight:600;letter-spacing:-.03em;color:var(--ink);line-height:1.13;max-width:1120px;margin:0}
|
|
121
|
+
.whatis .big .ac{color:var(--ac)}.whatis .big .dim{color:var(--ink-3)}
|
|
122
|
+
.vcards{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:56px}
|
|
123
|
+
@media(max-width:900px){.vcards{grid-template-columns:1fr}}
|
|
124
|
+
.vcard{border:1px solid var(--line-2);border-radius:14px;padding:30px 28px;background:var(--glass);backdrop-filter:blur(10px);transition:.2s;position:relative;overflow:hidden}
|
|
125
|
+
.vcard::after{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--ac);transform:scaleY(0);transform-origin:top;transition:transform .3s}
|
|
126
|
+
.vcard:hover{border-color:var(--ink-3);transform:translateY(-3px)}
|
|
127
|
+
.vcard:hover::after{transform:scaleY(1)}
|
|
128
|
+
.vcard .vk{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--ac-dim);margin-bottom:14px}
|
|
129
|
+
.vcard h3{font-family:var(--disp);font-size:22px;font-weight:600;color:var(--ink);margin:0 0 12px;letter-spacing:-.01em}
|
|
130
|
+
.vcard p{font-size:15px;color:var(--ink-3);line-height:1.6;margin:0}.vcard p b{color:var(--ink-2)}
|
|
131
|
+
.vcard ul{margin:18px 0 0;padding-left:0;color:var(--ink-2);font-size:14.5px;list-style:none}
|
|
132
|
+
.vcard li{margin:11px 0;position:relative;padding-left:18px}.vcard li b{color:var(--ink)}
|
|
133
|
+
.vcard li::before{content:"";position:absolute;left:0;top:8px;width:5px;height:5px;border-radius:50%;background:var(--ac);box-shadow:0 0 7px rgba(204,255,77,.5)}
|
|
134
|
+
|
|
135
|
+
/* staged terminal lines — reveal in sequence when the .rv container lands
|
|
136
|
+
(inline-block: the .scr's pre-wrap source newlines provide the breaks) */
|
|
137
|
+
.cine .scr .tl{display:inline-block;opacity:0;transform:translateX(-8px);transition:opacity .45s cubic-bezier(.2,.7,.2,1),transform .45s cubic-bezier(.2,.7,.2,1)}
|
|
138
|
+
.rv.in .tl{opacity:1;transform:none}
|
|
139
|
+
|
|
140
|
+
/* live spinner glyph (JS cycles the braille frame) */
|
|
141
|
+
.spin{color:var(--ac);display:inline-block;width:1ch}
|
|
142
|
+
|
|
143
|
+
/* dogfood band */
|
|
144
|
+
.dog{text-align:center;padding:120px var(--gut)}
|
|
145
|
+
.dog>*:not(.scene){position:relative;z-index:3}
|
|
146
|
+
.dog h2{font-family:var(--disp);font-size:clamp(34px,6vw,84px);font-weight:700;letter-spacing:-.04em;color:var(--ink);line-height:1;margin:0}
|
|
147
|
+
.dog h2 .ac{color:var(--ac)}
|
|
148
|
+
.dog p{color:var(--ink-3);font-size:18px;max-width:660px;margin:26px auto 0;line-height:1.6}
|
|
149
|
+
.dog p b{color:var(--ink-2)}
|
|
150
|
+
|
|
151
|
+
.rv{opacity:0;transform:translateY(30px);transition:opacity .9s cubic-bezier(.2,.7,.2,1),transform .9s cubic-bezier(.2,.7,.2,1)}.rv.in{opacity:1;transform:none}
|
|
152
|
+
|
|
153
|
+
/* sections full-bleed, each is a stage-wrap with its own scene */
|
|
154
|
+
section{position:relative;z-index:2;padding:150px 0;border-top:1px solid var(--line)}
|
|
155
|
+
section>.shead,section>.split,section>.pipeline,section>.pkgs{position:relative;z-index:3}
|
|
156
|
+
.shead{max-width:780px;margin-bottom:74px;padding:0 var(--gut)}
|
|
157
|
+
.eyebrow{font-family:var(--mono);font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:var(--ac-dim);margin-bottom:18px}
|
|
158
|
+
.shead h2{font-family:var(--disp);font-size:clamp(36px,5.5vw,72px);font-weight:600;letter-spacing:-.035em;color:var(--ink);margin:0;line-height:1}
|
|
159
|
+
.shead p{color:var(--ink-3);font-size:18px;margin:22px 0 0;line-height:1.55;max-width:600px}
|
|
160
|
+
|
|
161
|
+
.pipeline{display:grid;grid-template-columns:repeat(5,1fr);border-top:1px solid var(--line);border-bottom:1px solid var(--line);background:rgba(7,8,9,.35);backdrop-filter:blur(3px)}
|
|
162
|
+
.stage{padding:44px var(--gut);border-right:1px solid var(--line);position:relative;transition:background .3s}
|
|
163
|
+
.stage:nth-child(5n){border-right:none}
|
|
164
|
+
.stage.on{background:rgba(204,255,77,.05)}
|
|
165
|
+
.stage .num{font-family:var(--mono);font-size:13px;color:var(--ink-4)}.stage.on .num{color:var(--ac)}
|
|
166
|
+
.stage h4{font-family:var(--disp);font-size:21px;font-weight:600;color:var(--ink);margin:16px 0 10px;letter-spacing:-.01em}
|
|
167
|
+
.stage p{font-size:14px;color:var(--ink-3);margin:0;line-height:1.5}
|
|
168
|
+
.stage .bar{position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--ac);transform:scaleX(0);transform-origin:left;transition:transform .5s}.stage.on .bar{transform:scaleX(1)}
|
|
169
|
+
@media(max-width:820px){.pipeline{grid-template-columns:1fr 1fr}.stage:nth-child(5n){border-right:1px solid var(--line)}}
|
|
170
|
+
|
|
171
|
+
.split{display:grid;grid-template-columns:1fr 1fr;gap:80px;align-items:center;padding:0 var(--gut);margin:0}
|
|
172
|
+
.split.rev{direction:rtl}.split.rev>*{direction:ltr}
|
|
173
|
+
.split h3{font-family:var(--disp);font-size:clamp(28px,3.6vw,46px);font-weight:600;color:var(--ink);letter-spacing:-.03em;margin:0 0 22px;line-height:1.04}
|
|
174
|
+
.split p{color:var(--ink-3);font-size:17px;line-height:1.6;margin:0 0 16px}.split p b{color:var(--ink-2)}
|
|
175
|
+
.panel{background:var(--panel);border:1px solid var(--line-2);border-radius:14px;backdrop-filter:blur(14px);overflow:hidden}
|
|
176
|
+
.panel .pb{padding:14px 18px;border-bottom:1px solid var(--line);font-family:var(--mono);font-size:12px;color:var(--ink-3)}
|
|
177
|
+
.panel .pp{padding:24px;font-family:var(--mono);font-size:13px;line-height:1.95;white-space:pre-wrap;word-break:break-word}
|
|
178
|
+
.pp .ac{color:var(--ac)}.pp .c2{color:var(--ac-2)}.pp .dim{color:var(--ink-4)}.pp .mg{color:#ff79b0}.pp .ok{color:var(--ac)}
|
|
179
|
+
|
|
180
|
+
.pkgs{display:grid;grid-template-columns:repeat(3,1fr);gap:0;border-top:1px solid var(--line);background:rgba(7,8,9,.35);backdrop-filter:blur(3px)}
|
|
181
|
+
.pk{display:block;color:inherit;padding:38px var(--gut);border-right:1px solid var(--line);border-bottom:1px solid var(--line);transition:.2s}
|
|
182
|
+
.pk:nth-child(3n){border-right:none}
|
|
183
|
+
.pk:hover{background:var(--bg-2)}
|
|
184
|
+
.pk .nm{font-family:var(--mono);font-size:15px;color:var(--ink);margin-bottom:10px}.pk:hover .nm{color:var(--ac)}
|
|
185
|
+
.pk .ds{font-size:14px;color:var(--ink-3);line-height:1.5}
|
|
186
|
+
@media(max-width:820px){.pkgs{grid-template-columns:1fr}.pk{border-right:none}}
|
|
187
|
+
|
|
188
|
+
.ctaband{text-align:center;padding:190px var(--gut)}
|
|
189
|
+
.ctaband>*:not(.scene){position:relative;z-index:3}
|
|
190
|
+
.ctaband h2{font-family:var(--disp);font-size:clamp(44px,9vw,140px);font-weight:700;letter-spacing:-.045em;color:var(--ink);line-height:.9;margin:0}
|
|
191
|
+
.ctaband h2 .ac{color:var(--ac)}
|
|
192
|
+
.ctaband p{color:var(--ink-3);font-size:20px;max-width:540px;margin:30px auto 0}
|
|
193
|
+
|
|
194
|
+
footer{position:relative;z-index:2;border-top:1px solid var(--line);padding:80px var(--gut) 100px;background:var(--bg)}
|
|
195
|
+
.foot{display:flex;flex-wrap:wrap;gap:60px;justify-content:space-between}
|
|
196
|
+
.foot .col h5{font-family:var(--mono);font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-4);margin:0 0 16px;font-weight:500}
|
|
197
|
+
.foot .col a{display:block;color:var(--ink-3);font-size:14px;padding:5px 0}.foot .col a:hover{color:var(--ink)}
|
|
198
|
+
.foot .sig{font-family:var(--mono);font-size:12px;color:var(--ink-4);max-width:300px;line-height:1.7}.foot .sig b{color:var(--ink-2);font-weight:400}
|
|
199
|
+
|
|
200
|
+
@media(max-width:900px){.split,.split.rev{grid-template-columns:1fr;direction:ltr;gap:40px}.nav-links a.ext{display:none}.nav-links{gap:18px}.herorow{flex-direction:column;align-items:flex-start}}
|
|
201
|
+
|
|
202
|
+
/* ASCII drone mascot inside hero terminal */
|
|
203
|
+
.cine .scr.mascot{min-height:470px;padding:20px 8px;overflow:hidden;display:flex;align-items:center;justify-content:center}
|
|
204
|
+
.cine .scr.mascot .sprite{white-space:pre;text-align:left;display:inline-block;font-size:13px;line-height:1.08;letter-spacing:1px}
|
|
205
|
+
@media(min-width:1100px){.cine .scr.mascot .sprite{font-size:16px;line-height:1.12}}
|
|
206
|
+
@media(max-width:700px){.cine .scr.mascot .sprite{font-size:10px;letter-spacing:.5px}}
|
|
207
|
+
.g-d{color:#ccff4d;text-shadow:0 0 6px rgba(204,255,77,.35)}
|
|
208
|
+
.g-m{color:#a9d63f}
|
|
209
|
+
.g-c{color:#56d8ff}
|
|
210
|
+
.g-r{color:#5f6b3a}
|
|
211
|
+
.g-s{color:#3a4a1e}
|
|
212
|
+
.g-rb{color:#7d9e34;text-shadow:0 0 4px rgba(204,255,77,.22)}
|
|
213
|
+
.g-eye{color:#eaffb0;text-shadow:0 0 10px rgba(204,255,77,.9),0 0 18px rgba(204,255,77,.5)}
|
|
214
|
+
.g-b{color:transparent}
|
|
215
|
+
|
|
216
|
+
/* ---- content container: wide but readable (full-bleed dividers/scenes stay edge-to-edge) ---- */
|
|
217
|
+
:root{--maxw:1520px}
|
|
218
|
+
.hero{align-items:center}
|
|
219
|
+
.hero>.kick,.hero>.hl,.hero>.scrollcue{width:100%;max-width:var(--maxw);margin-left:auto;margin-right:auto}
|
|
220
|
+
.shead{max-width:var(--maxw);margin-left:auto;margin-right:auto}
|
|
221
|
+
.shead h2,.shead p,.shead .eyebrow{max-width:860px}
|
|
222
|
+
.split{max-width:var(--maxw);margin-left:auto;margin-right:auto}
|
|
223
|
+
.pipeline{max-width:var(--maxw);margin-left:auto;margin-right:auto}
|
|
224
|
+
.pkgs{max-width:var(--maxw);margin-left:auto;margin-right:auto}
|
|
225
|
+
.ctaband>.rv,.ctaband>.cta{max-width:980px;margin-left:auto;margin-right:auto}
|
|
226
|
+
footer .foot{max-width:var(--maxw);margin-left:auto;margin-right:auto}
|
|
227
|
+
|
|
228
|
+
/* ---- atmosphere: grain, scanlines, aurora, divider accents, hover physics ---- */
|
|
229
|
+
body::after{content:"";position:fixed;inset:0;z-index:60;pointer-events:none;opacity:.05;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E")}
|
|
230
|
+
.hero::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;background:radial-gradient(60% 42% at 50% 10%,rgba(204,255,77,.07),transparent 62%),radial-gradient(42% 34% at 16% 80%,rgba(86,216,255,.05),transparent 65%),radial-gradient(46% 36% at 86% 72%,rgba(204,255,77,.04),transparent 65%)}
|
|
231
|
+
.cine .scr{position:relative}
|
|
232
|
+
.cine .scr::after,.panel .pp::after{content:"";position:absolute;inset:0;pointer-events:none;background:repeating-linear-gradient(0deg,rgba(255,255,255,.016) 0 1px,transparent 1px 3px)}
|
|
233
|
+
.panel .pp{position:relative}
|
|
234
|
+
section::before,.moves::before{content:"";position:absolute;top:-1px;left:50%;transform:translateX(-50%);width:min(560px,62%);height:1px;background:linear-gradient(90deg,transparent,rgba(204,255,77,.38),transparent);z-index:4;pointer-events:none}
|
|
235
|
+
.herocenter .cine{box-shadow:0 60px 160px -40px rgba(0,0,0,.85),0 0 110px -28px rgba(204,255,77,.16),0 0 0 1px rgba(255,255,255,.02) inset}
|
|
236
|
+
.panel{transition:transform .25s,border-color .25s,box-shadow .25s}
|
|
237
|
+
.panel:hover{transform:translateY(-3px);border-color:rgba(204,255,77,.22);box-shadow:0 28px 90px -38px rgba(0,0,0,.85)}
|
|
238
|
+
.panel::before{content:"";position:absolute;left:8%;right:8%;top:0;height:1px;background:linear-gradient(90deg,transparent,rgba(204,255,77,.55),transparent);opacity:0;transition:opacity .3s;z-index:2}
|
|
239
|
+
.panel:hover::before{opacity:1}
|
|
240
|
+
.panel{position:relative}
|
|
241
|
+
.stage:hover{background:rgba(204,255,77,.025)}
|
|
242
|
+
.pk:hover{transform:translateY(-2px)}
|
|
243
|
+
@media(prefers-reduced-motion:reduce){.panel:hover,.pk:hover{transform:none}}
|
|
244
|
+
</style><link rel="stylesheet" href="assets/site.css?v=v9"><link rel="icon" type="image/svg+xml" href="assets/favicon.svg"></head><body><nav class="nav"><div class="nav-in">
|
|
245
|
+
<a class="brand" href="./"><span class="mark"></span>Rig</a>
|
|
246
|
+
<div class="nav-links">
|
|
247
|
+
<a href="./" class="active">overview</a><a href="docs/index.html">docs</a>
|
|
248
|
+
<a href="plugins/index.html">plugins</a><a href="skills/index.html">skills</a>
|
|
249
|
+
<a href="cli/index.html">cli</a><a href="config/index.html">config</a>
|
|
250
|
+
<a href="https://github.com/humanity-org/rig" class="ext">github</a>
|
|
251
|
+
</div></div></nav>
|
|
252
|
+
|
|
253
|
+
<header class="hero stage-wrap herocenter">
|
|
254
|
+
<canvas class="scene" data-scene="dispatch"></canvas>
|
|
255
|
+
<h1 class="hl gl">Air superiority, <span class="ac">as a binary.</span></h1>
|
|
256
|
+
<div class="cine"><div class="cb"><span class="d a"></span><span class="d b"></span><span class="d c"></span><span class="ttl">rig — OMP session cnet</span><span class="st"><i></i>live</span></div><div class="scr" id="cine"></div></div>
|
|
257
|
+
<div class="inst"><span class="pr">$</span><code id="instcmd">curl -fsSL https://where.rig-does.work/install | bash</code><button class="cp" onclick="navigator.clipboard&&navigator.clipboard.writeText(document.getElementById('instcmd').innerText);this.innerText='copied';var b=this;setTimeout(function(){b.innerText='copy'},1200)">copy</button></div>
|
|
258
|
+
<div class="scrollcue"><span class="ln"></span>scroll to descend</div>
|
|
259
|
+
</header>
|
|
260
|
+
|
|
261
|
+
<section class="moves">
|
|
262
|
+
<div class="mv-in">
|
|
263
|
+
<a class="mv rv" href="#loop"><div class="v">Arm.</div><p>Install once, type bare <code>rig</code> — ground control opens with the cnet live, the fleet linked, and every verb loaded.</p><span class="go">open the loop →</span></a>
|
|
264
|
+
<a class="mv rv" href="#swarmer"><div class="v">Command.</div><p>Say it in chat — the <b>Swarm Commander</b> reads the cnet, picks the verb, and moves the fleet. Receipts, or it didn’t happen.</p><span class="go">meet the swarm commander →</span></a>
|
|
265
|
+
<a class="mv rv" href="#ops"><div class="v">Clear.</div><p>The cnet lives in your transcript — <code>/fleet</code>, <code>/tasks</code>, and <code>/drone</code> drop live cards inline; the one that needs you says so.</p><span class="go">the ops story →</span></a>
|
|
266
|
+
</div>
|
|
267
|
+
</section>
|
|
268
|
+
|
|
269
|
+
<section class="stage-wrap">
|
|
270
|
+
<canvas class="scene" data-scene="nightshift"></canvas>
|
|
271
|
+
<div class="shead rv"><div class="eyebrow">the night shift</div><h2>Yesterday’s backlog. This morning’s <span class="ac">merges.</span></h2><p>Ammunition comes from your real tracker — GitHub Issues, Linear, or your own source. A drone takes the task, flies the sortie in its own sealed session, fights the review, and lands a SHA-pinned merge. Close ground control — the sorties keep flying; reopen it and the fleet is right there in the cnet.</p></div>
|
|
272
|
+
</section>
|
|
273
|
+
|
|
274
|
+
<section id="loop" class="stage-wrap">
|
|
275
|
+
<canvas class="scene" data-scene="cnet"></canvas>
|
|
276
|
+
<div class="shead rv"><div class="eyebrow">the loop</div><h2>One terminal command. One live session.</h2><p>Install Rig, type <code>rig</code>, and run the war from the transcript. The cnet streams what the fleet is doing; every move you make comes back with a receipt.</p></div>
|
|
277
|
+
<div class="pipeline rv" id="pipe">
|
|
278
|
+
<div class="stage" data-i="0"><div class="num">01</div><h4>Install</h4><p>The one-line installer puts the self-contained <code>rig</code> binary on your PATH.</p><span class="bar"></span></div>
|
|
279
|
+
<div class="stage" data-i="1"><div class="num">02</div><h4>Open</h4><p>Type <code>rig</code>. The session opens with the fleet already wired.</p><span class="bar"></span></div>
|
|
280
|
+
<div class="stage" data-i="2"><div class="num">03</div><h4>Dispatch</h4><p>Dispatch from <code>/fleet</code> — or just tell the Commander what to launch.</p><span class="bar"></span></div>
|
|
281
|
+
<div class="stage" data-i="3"><div class="num">04</div><h4>Watch</h4><p>Fleet, active runs, and attention stream in as live cards.</p><span class="bar"></span></div>
|
|
282
|
+
<div class="stage" data-i="4"><div class="num">05</div><h4>Decide</h4><p>The card that needs you offers the verbs. One keystroke answers.</p><span class="bar"></span></div>
|
|
283
|
+
</div></section>
|
|
284
|
+
|
|
285
|
+
<section id="swarmer" class="stage-wrap">
|
|
286
|
+
<canvas class="scene" data-scene="swarmer"></canvas>
|
|
287
|
+
<div class="shead rv"><div class="eyebrow">the swarm commander</div><h2>Say the word. The swarm <span style="color:var(--ac)">moves.</span></h2><p>The Swarm Commander sits in your chat and speaks fleet. Ask for anything — it reads the cnet, picks the right verb, and executes with the receipt to prove it.</p></div>
|
|
288
|
+
<div class="split rv">
|
|
289
|
+
<div><h3>Every verb your build ships. Zero ceremony.</h3>
|
|
290
|
+
<p>Tasks, fleet state, dispatch, steering, stop, restart, model changes — plain chat. The Commander discovers whatever verbs your plugins contribute; a tailored <code>.rig/rig.config.ts</code> build hands it exactly your arsenal.</p>
|
|
291
|
+
<p>And it can’t hand-wave. Every action binds to the exact item and revision it saw, and nothing counts as done until the durable receipt lands. A send is not a success — the receipt is.</p>
|
|
292
|
+
</div>
|
|
293
|
+
<div class="cine" style="margin:0"><div class="cb"><span class="d a"></span><span class="d b"></span><span class="d c"></span><span class="ttl">rig — Commander role</span><span class="st"><i></i>operator turn</span></div><div class="scr" style="min-height:0"><span class="tl" style="transition-delay:.05s"><span class="pr">you</span> <span class="w">show ready tasks and dispatch #412</span></span>
|
|
294
|
+
<span class="tl" style="transition-delay:.3s"><span class="c2">swarmer</span> reading the tracker through the cnet</span>
|
|
295
|
+
<span class="tl" style="transition-delay:.55s"><span class="dim">cnet</span> tasks · 12 ready</span>
|
|
296
|
+
<span class="tl" style="transition-delay:.8s"><span class="c2">swarmer</span> dispatching task #412</span>
|
|
297
|
+
<span class="tl" style="transition-delay:1.05s"><span class="ok">receipt</span> applied · task #412 · run 0xA1</span>
|
|
298
|
+
<span class="tl" style="transition-delay:1.3s"><span class="pr">you</span> <span class="w">tell 0xA1 to rerun the focused spec</span></span>
|
|
299
|
+
<span class="tl" style="transition-delay:1.55s"><span class="c2">swarmer</span> steering run 0xA1</span>
|
|
300
|
+
<span class="tl" style="transition-delay:1.8s"><span class="dim">cnet</span> send direction · run 0xA1</span>
|
|
301
|
+
<span class="tl" style="transition-delay:2.05s"><span class="ok">receipt</span> delivered · on the record</span></div></div>
|
|
302
|
+
</div></section>
|
|
303
|
+
|
|
304
|
+
<section id="net" class="stage-wrap">
|
|
305
|
+
<canvas class="scene" data-scene="ircnet"></canvas>
|
|
306
|
+
<div class="shead rv"><div class="eyebrow">the fleet net</div><h2>Every callsign, one <span class="ac">net.</span></h2><p>Drones aren’t fire-and-forget. Every airframe is on the net: DM a drone mid-flight and it answers in the cnet; a drone that hits something worth your time raises you first. Every message lands in the run’s journal — part of the mission record, forever.</p></div>
|
|
307
|
+
<div class="split rv">
|
|
308
|
+
<div><h3>Message a parked drone. Watch it wake.</h3>
|
|
309
|
+
<p>The net is OMP’s own IRC, extended across the fleet: operator, Commander, and drones are addressable peers — send, reply, inbox, roster. Nothing rides outside the record; every send appends to the owning run’s journal.</p>
|
|
310
|
+
<p>Even sleep isn’t off the net. Message a parked drone and it revives — same run id, same branch, your DM read first.</p></div>
|
|
311
|
+
<div class="panel"><div class="pb">run 0xA1 · on the net</div><div class="pp"><span class="c2">drone</span> running · implement
|
|
312
|
+
<span class="c2">message</span> to operator · “APP_TOKEN is missing”
|
|
313
|
+
<span class="ok">receipt</span> journaled · seq 121
|
|
314
|
+
<span class="ac">operator</span> “use the staging token” → 0xA1
|
|
315
|
+
<span class="ok">receipt</span> delivered · read at the next step
|
|
316
|
+
<span class="dim">// DM a parked drone → same run wakes · message read first</span></div></div>
|
|
317
|
+
</div></section>
|
|
318
|
+
|
|
319
|
+
<section class="stage-wrap">
|
|
320
|
+
<canvas class="scene" data-scene="plansplit"></canvas>
|
|
321
|
+
<div class="shead rv"><div class="eyebrow">the tasking</div><h2>The backlog is the <span class="ac">ammo belt.</span></h2><p>Work arrives however you already track it — GitHub Issues, Linear, or your own source. <code>/tasks</code> shows what’s ready; a <code>/fleet</code> action or <code>rig run dispatch</code> sends a drone at it.</p></div>
|
|
322
|
+
<div class="split rv">
|
|
323
|
+
<div><h3>The tracker stays the boss.</h3>
|
|
324
|
+
<p>Rig never copies your backlog into a private database — it reads the source live and writes back through it. Dispatch a task, and when the merge lands the task closes where it lives.</p></div>
|
|
325
|
+
<div class="panel"><div class="pb">/tasks · configured source</div><div class="pp"><span class="ok">ready</span> #421 auth: token refresh
|
|
326
|
+
<span class="ok">ready</span> #430 api: rate limiter
|
|
327
|
+
<span class="c2">running</span> #433 ui: usage panel
|
|
328
|
+
<span class="ac">actions</span> Create task · Rename · Close
|
|
329
|
+
<span class="dim">// read live from the source · closed by the merge</span></div></div>
|
|
330
|
+
</div></section>
|
|
331
|
+
|
|
332
|
+
<section class="stage-wrap">
|
|
333
|
+
<canvas class="scene" data-scene="relay"></canvas>
|
|
334
|
+
<div class="shead rv"><div class="eyebrow">the walkthrough</div><h2>Install once. Type rig.</h2><p>The launcher drops you into the session. From there you talk, dispatch, watch the fleet, answer what needs you, and pull up any drone — without leaving the transcript.</p></div>
|
|
335
|
+
<div class="rv" style="position:relative;z-index:3;max-width:var(--maxw);margin:0 auto;padding:0 var(--gut)">
|
|
336
|
+
<div class="cine" style="margin:0"><div class="cb"><span class="d a"></span><span class="d b"></span><span class="d c"></span><span class="ttl">rig — task #418</span><span class="st"><i></i>one command</span></div><div class="scr" style="min-height:0"><span class="tl" style="transition-delay:.05s"><span class="pr">$</span> <span class="w">rig</span></span>
|
|
337
|
+
<span class="tl" style="transition-delay:.25s"><span class="c2">› open</span> OMP session · workspace linked · Rig extension <span class="ok">✓</span></span>
|
|
338
|
+
<span class="tl" style="transition-delay:.45s"><span class="c2">› cnet</span> live · the fleet in your transcript</span>
|
|
339
|
+
<span class="tl" style="transition-delay:.65s"><span class="c2">› commander</span> on station</span>
|
|
340
|
+
<span class="tl" style="transition-delay:.85s"><span class="c2">› tasks</span> <span class="w">/tasks</span> filter · task #418 ready to dispatch</span>
|
|
341
|
+
<span class="tl" style="transition-delay:1.05s"><span class="ac">› dispatch</span> task #418 → run 0xA1 · receipt in the cnet</span>
|
|
342
|
+
<span class="tl" style="transition-delay:1.25s"><span class="c2">› attention</span> the card that needs you renders inline</span>
|
|
343
|
+
<span class="tl" style="transition-delay:1.45s"><span class="c2">› cnet</span> <span class="w">/fleet</span> · <span class="w">/drone 0xA1</span> inline cards</span>
|
|
344
|
+
<span class="tl" style="transition-delay:1.65s"><span class="ac">› gate</span> <span class="w">@rig/pr-review-plugin</span> strict merge gate armed</span>
|
|
345
|
+
<span class="tl" style="transition-delay:1.85s"><span class="c2">› attach</span> <span class="w">rig attach 0xA1</span> · straight into the cockpit</span>
|
|
346
|
+
<span class="tl" style="transition-delay:2.05s"><span class="ok">› live</span> runId === sessionId · OMP JSONL journal</span></div></div>
|
|
347
|
+
</div></section>
|
|
348
|
+
|
|
349
|
+
<section class="stage-wrap">
|
|
350
|
+
<canvas class="scene" data-scene="lanes"></canvas>
|
|
351
|
+
<div class="split rev rv">
|
|
352
|
+
<div><h3>One CNet. Drones placed anywhere.</h3>
|
|
353
|
+
<p>Your session owns the conversation; the cnet shows the fleet. Local and remote are just parking spots — every drone flies the same contract wherever it runs, and one keystroke opens any of them.</p></div>
|
|
354
|
+
<div class="panel"><div class="pb">Rig session · live fleet</div><div class="pp"><span class="c2">0xA1</span> auth-fix run <span class="ok">local</span> <span class="dim">· active</span>
|
|
355
|
+
<span class="c2">0xB7</span> collab refactor <span class="ac">remote</span> <span class="dim">· live</span>
|
|
356
|
+
<span class="c2">0xC3</span> docs polish <span class="ok">local</span> <span class="dim">· merged</span>
|
|
357
|
+
<span class="c2">0xD9</span> design review <span class="ac">remote</span> <span class="dim">· needs attention</span>
|
|
358
|
+
<span class="dim">… +18 run sessions in the fleet</span>
|
|
359
|
+
|
|
360
|
+
<span class="dim">// OMP is authority · relay is coordination</span>
|
|
361
|
+
<span class="ok">/fleet → /drone</span> <span class="dim">· the cnet keeps the receipts</span></div></div>
|
|
362
|
+
</div></section>
|
|
363
|
+
|
|
364
|
+
<section class="stage-wrap">
|
|
365
|
+
<canvas class="scene" data-scene="hangar"></canvas>
|
|
366
|
+
<div class="shead rv"><div class="eyebrow">the harness</div><h2>Every drone gets its own hangar.</h2><p>A dispatched run launches from a sealed bay: its own git worktree, its own runtime <code>HOME</code> and credentials, an OS sandbox that fails closed, and a toolchain hardlinked from one binary. Sorties never share air.</p></div>
|
|
367
|
+
<div class="split rv">
|
|
368
|
+
<div><h3>Isolation is the airframe, not a checkbox.</h3>
|
|
369
|
+
<p>Two drones on the same repo can’t touch each other’s fuel: separate branches in separate worktrees, separate <code>HOME</code>, per-run identity with token keys stripped and auth through a state file. The OS sandbox is <b>enforce by default</b> — bwrap on Linux, seatbelt on macOS — and fails closed when the host can’t confine, instead of silently flying unprotected.</p>
|
|
370
|
+
<p>Crash one drone: the swarm doesn’t feel it. Close ground control: the sorties keep flying — every drone is its own process with the mission journal onboard.</p></div>
|
|
371
|
+
<div class="panel"><div class="pb">run 0xA1 — bay manifest</div><div class="pp"><span class="c2">worktree</span> .worktrees/0xA1 <span class="dim">· own branch, own index</span>
|
|
372
|
+
<span class="c2">home</span> .worktrees/0xA1/.rig/home <span class="dim">· isolated runtime state</span>
|
|
373
|
+
<span class="c2">identity</span> per-run credentials <span class="dim">· token keys stripped</span>
|
|
374
|
+
<span class="c2">sandbox</span> <span class="w">enforce</span> · seatbelt <span class="ok">✓</span> <span class="dim">· fails closed</span>
|
|
375
|
+
<span class="c2">toolchain</span> rig-run · rig-agent · rig-shell <span class="dim">→ hardlinks of one binary</span>
|
|
376
|
+
|
|
377
|
+
<span class="dim">// nothing shared · nothing leaked · nothing borrowed</span></div></div>
|
|
378
|
+
</div></section>
|
|
379
|
+
|
|
380
|
+
<section class="stage-wrap">
|
|
381
|
+
<canvas class="scene" data-scene="scramble"></canvas>
|
|
382
|
+
<div class="shead rv"><div class="eyebrow">the scramble</div><h2>Wheels-up before npm finds its <span class="ac">lockfile.</span></h2><p>Provisioning is native code, not npm scripts. The bay materializes straight from the compiled binary — worktree, sealed identity, dependency layer, toolchain — zero package installs on the runway.</p></div>
|
|
383
|
+
<div class="split rv">
|
|
384
|
+
<div><h3>One binary, every role.</h3>
|
|
385
|
+
<p>No interpreter boots and no package tree gets copied. The same executable wakes up as <code>rig-git</code>, the sandboxed shell, or the tool gateway depending on the name it answers to — the whole fleet shares one build, one disk footprint, one attack surface.</p>
|
|
386
|
+
<div class="panel"><div class="pb">bay 07 · provisioning</div><div class="pp"><span class="c2">worktree</span> run/0xA1 checked out <span class="ok">ready</span>
|
|
387
|
+
<span class="c2">identity</span> isolated HOME · scoped credentials <span class="ok">ready</span>
|
|
388
|
+
<span class="c2">deps</span> runtime layer hardlinked <span class="ok">ready</span>
|
|
389
|
+
<span class="c2">toolchain</span> multicall Rig binary <span class="ok">ready</span>
|
|
390
|
+
<span class="ac">status</span> armed · wheels-up</div></div>
|
|
391
|
+
</div></section>
|
|
392
|
+
|
|
393
|
+
<section class="stage-wrap">
|
|
394
|
+
<canvas class="scene" data-scene="carrier"></canvas>
|
|
395
|
+
<div class="shead rv"><div class="eyebrow">the extension</div><h2>One OMP session. Rig inside it.</h2><p>Rig launches Oh My Pi with the Rig extension aboard, pinned to an exact runtime version. The session opens with the fleet already loaded — no service to start, nothing to babysit.</p></div>
|
|
396
|
+
<div class="split rv">
|
|
397
|
+
<div><h3>Configured once. Loaded into every session.</h3>
|
|
398
|
+
<p>Bare <code>rig</code> carries your extension set and team packages from <code>runtime.pi.packages</code> into every session — yours and every drone’s. Same versions, same tools, every time; the cnet operates them all.</p>
|
|
399
|
+
<a class="btn" href="docs/pi-extensions/index.html" style="margin-top:8px">OMP/Pi extensions</a></div>
|
|
400
|
+
<div class="panel"><div class="pb">same extension, every session</div><div class="pp"><span class="c2">omp/pi</span> <span class="w" data-pi-version>16.3.4</span> <span class="dim">bundled · pinned</span>
|
|
401
|
+
<span class="c2">extensions</span> pi-subagents · pi-web-access · <span class="dim">your-ext</span>
|
|
402
|
+
<span class="dim">// runtime.pi.packages → OMP/Pi session packages</span>
|
|
403
|
+
|
|
404
|
+
<span class="ac">session</span> OMP + Rig · cnet ready <span class="ok">✓</span>
|
|
405
|
+
<span class="ac">drone 0xB7</span> remote placement · supervised <span class="ok">✓</span>
|
|
406
|
+
<span class="ac">attach 0xC3</span> terminal or web · one keystroke <span class="ok">✓</span>
|
|
407
|
+
<span class="dim">// same version + extension set, installed at session start</span></div></div>
|
|
408
|
+
</div></section>
|
|
409
|
+
|
|
410
|
+
<section id="cycle" class="stage-wrap">
|
|
411
|
+
<canvas class="scene" data-scene="strikeloop"></canvas>
|
|
412
|
+
<div class="shead rv"><div class="eyebrow">the recon-strike loop</div><h2>Reviews don’t wait for you.</h2><p>Recon confirms the target; the drone flies the sortie; assessment sends it back up. CI fails — the drone fixes and re-pushes. The reviewer <b>executes the code</b>, reproduces the bug it suspects, and pins the finding to lines — the drone answers it in the diff. Push by push, until the evidence is clean on the current head.</p></div>
|
|
413
|
+
<div class="split rev rv">
|
|
414
|
+
<div><h3>Target confirmed. Sortie. Assess. Again.</h3>
|
|
415
|
+
<p>No human relays anything. Review findings and failing checks feed the drone directly, and the loop runs on its own — the same unattended cycle that Rig’s own PRs fly through before they land.</p>
|
|
416
|
+
<p>Watched live on a real PR: finding → fix → deeper finding → the drone removed the root cause outright instead of patching around it → clean score → merged. Zero relayed instructions, receipts in the cnet.</p></div>
|
|
417
|
+
<div class="cine" style="margin:0"><div class="cb"><span class="d a"></span><span class="d b"></span><span class="d c"></span><span class="ttl">PR #418 — review loop</span><span class="st"><i></i>autonomous</span></div><div class="scr" style="min-height:0"><span class="tl" style="transition-delay:.05s"><span class="c2">recon</span> reviewer ran the code · bug reproduced · finding <span class="mg">P1</span> pinned to lines</span>
|
|
418
|
+
<span class="tl" style="transition-delay:.3s"><span class="ac">sortie 1</span> fix pushed · re-review triggered</span>
|
|
419
|
+
<span class="tl" style="transition-delay:.55s"><span class="c2">recon</span> new finding · stale id still collides on redelivery</span>
|
|
420
|
+
<span class="tl" style="transition-delay:.8s"><span class="ac">sortie 2</span> root cause removed · the colliding ids no longer exist</span>
|
|
421
|
+
<span class="tl" style="transition-delay:1.05s"><span class="c2">assess</span> score <span class="ok">5/5</span> · current head · CI green · threads resolved</span>
|
|
422
|
+
<span class="tl" style="transition-delay:1.3s"><span class="ok">cleared</span> gate unlocks · landing pinned to the reviewed SHA</span></div></div>
|
|
423
|
+
</div></section>
|
|
424
|
+
|
|
425
|
+
<section class="stage-wrap">
|
|
426
|
+
<canvas class="scene" data-scene="gatewall"></canvas>
|
|
427
|
+
<div class="shead rv"><div class="eyebrow">the gate</div><h2>Approved, or it dies.</h2><p>Every run has to prove the current head: GitHub review approval, green CI, resolved threads, and a SHA-pinned merge. Proof fails — the cnet says so and hands you the next verb. And completion is evidence, not a claim: no commits, no diff, no PR — no <i>complete</i>. A drone that can’t prove its work says needs-attention, on the record.</p></div>
|
|
428
|
+
<div class="split rv">
|
|
429
|
+
<div><h3>The gate pins the exact head.</h3>
|
|
430
|
+
<p><code>@rig/pr-review-plugin</code> keeps pushing the same PR through actionable feedback until the evidence is clean. The merge uses <code>--match-head-commit</code>: push one more commit after approval and the merge fails instead of shipping an unreviewed head.</p>
|
|
431
|
+
<a class="btn" href="docs/gate/index.html" style="margin-top:8px">Read the gate spec</a></div>
|
|
432
|
+
<div class="panel"><div class="pb">strict gate · PR #418</div><div class="pp"><span class="c2">attempt 1</span> review <span class="mg">changes requested</span> · CI red <span class="dim">→ steer run</span>
|
|
433
|
+
<span class="c2">attempt 2</span> review pending · <span class="mg">1 thread open</span> <span class="dim">→ continue</span>
|
|
434
|
+
<span class="c2">attempt 3</span> review <span class="ok">approved</span> · CI green · threads resolved <span class="ok">✓</span>
|
|
435
|
+
<span class="ac">merge</span> gh pr merge <span class="dim">--match-head-commit</span> 9f3c2e1 <span class="ok">✓</span>
|
|
436
|
+
<span class="ok">closed</span> issue #418 · branch deleted</div></div>
|
|
437
|
+
</div></section>
|
|
438
|
+
|
|
439
|
+
<section id="attach" class="stage-wrap">
|
|
440
|
+
<canvas class="scene" data-scene="harness"></canvas>
|
|
441
|
+
<div class="shead rv"><div class="eyebrow">operate</div><h2>When a run needs you, it says so.</h2><p>Runs, approvals, and questions surface as attention cards in the cnet. <code>/fleet</code> shows the whole board; <code>/drone [ref]</code> opens one run — status, progress, timeline, controls, attach.</p></div>
|
|
442
|
+
<div class="split rv">
|
|
443
|
+
<div><h3>Your decision stays in the session.</h3>
|
|
444
|
+
<p>Steer, switch models, or unblock a drone without leaving chat. Need hands-on? <code>rig attach <run-id></code> or the drone card drops your terminal or browser into that exact run — credentials stay Rig’s problem, not your clipboard’s.</p>
|
|
445
|
+
<p>Every action leaves its receipt in the transcript. And when something looks wrong, <code>rig doctor</code> reads the evidence before you reach for kill.</p>
|
|
446
|
+
<a class="btn" href="docs/operator/index.html" style="margin-top:8px">Read the operator guide</a></div>
|
|
447
|
+
<div class="pi-term" data-title="Attention → /drone — OMP live session" data-rows="14">
|
|
448
|
+
<script type="application/json">[
|
|
449
|
+
{"t":"dim","s":"⠹ opening Rig session"},
|
|
450
|
+
{"t":"out","s":"● cnet ready — the fleet in your transcript"},
|
|
451
|
+
{"t":"code","s":"Fleet · 4 runs · 1 active · 1 needs attention"},
|
|
452
|
+
{"t":"code","s":"Attention · run 0xA1 parked after recovery attempt"},
|
|
453
|
+
{"t":"code","s":" Send direction · Restart run · Stop run"},
|
|
454
|
+
{"t":"u","s":"/drone 0xA1"},
|
|
455
|
+
{"t":"code","s":"Run 0xA1 · needs attention · remote · recent timeline"},
|
|
456
|
+
{"t":"u","s":"/cnet-action 1"},
|
|
457
|
+
{"t":"u","s":"use the existing retry helper; do not add a new loop"},
|
|
458
|
+
{"t":"think","ms":1400},
|
|
459
|
+
{"t":"out","s":"receipt — direction delivered to run 0xA1."},
|
|
460
|
+
{"t":"dim","s":"inline drone card: status · progress · timeline · controls · attach"},
|
|
461
|
+
{"t":"pause","ms":3200}
|
|
462
|
+
]</script>
|
|
463
|
+
<div class="pi-term-status-data" hidden data-path="~/work/app (run/0xA1)" data-stats="↑21k ↓679 R161k $0.000 (sub) 18.4%/128k (auto)" data-model="team-default • thinking high"></div>
|
|
464
|
+
</div>
|
|
465
|
+
</div></section>
|
|
466
|
+
|
|
467
|
+
<section class="stage-wrap">
|
|
468
|
+
<canvas class="scene" data-scene="arsenal"></canvas>
|
|
469
|
+
<div class="shead rv"><div class="eyebrow">the arsenal</div><h2>Verbs for you. Tools for <span class="ac">them.</span></h2><p>The operator gets verbs in the cnet. The Swarm Commander gets the same verbs as tools. Every drone carries a typed mission pack — no memorized CLI strings, no shell games.</p></div>
|
|
470
|
+
<div class="pkgs rv">
|
|
471
|
+
<a class="pk" href="docs/operator/index.html"><div class="nm">operator deck</div><div class="ds">Inline /fleet, /tasks, /drone and attention cards · attach to any run · rig doctor.</div></a>
|
|
472
|
+
<a class="pk" href="docs/swarm-commander/index.html"><div class="nm">commander deck</div><div class="ds">Reads the cnet · every plugin-contributed verb · a receipt on every move.</div></a>
|
|
473
|
+
<a class="pk" href="docs/agent-tools/index.html"><div class="nm">drone deck</div><div class="ds">rig_task, rig_git, rig_repo_sync, rig_profile, rig_review, irc — strict schemas that refuse instead of guessing.</div></a>
|
|
474
|
+
</div></section>
|
|
475
|
+
|
|
476
|
+
<section class="stage-wrap">
|
|
477
|
+
<canvas class="scene" data-scene="journal"></canvas>
|
|
478
|
+
<div class="shead rv"><div class="eyebrow">the record</div><h2>Every run is a session record.</h2><p>A run is a detached session: <code>runId === sessionId</code>, and the whole mission — every message, decision, and receipt — lives in that drone’s journal. The cnet is the live view; the journal is the truth.</p></div>
|
|
479
|
+
<div class="split rev rv">
|
|
480
|
+
<div><h3>The record outlives the wire.</h3>
|
|
481
|
+
<p>Runs record themselves: lifecycle, messages, and receipts append to the owning session’s journal as they happen. The cnet projects it live — a view, never a second truth.</p>
|
|
482
|
+
<p>Reopen <code>rig</code> and the fleet is rediscovered from the records. If a run stalls, <code>rig doctor</code> shows you the evidence before you kill anything.</p>
|
|
483
|
+
<a class="btn" href="docs/runs/index.html" style="margin-top:8px">The run lifecycle</a></div>
|
|
484
|
+
<div class="panel"><div class="pb">cnet → records → drone card</div><div class="pp"><span class="dim">10:42:01</span> <span class="c2">open</span> session open · Rig aboard
|
|
485
|
+
<span class="dim">10:42:04</span> <span class="c2">session</span> run 0xA1 ready <span class="ok">✓</span>
|
|
486
|
+
<span class="dim">10:43:18</span> <span class="w">run</span> implementing · worktree isolated
|
|
487
|
+
<span class="dim">10:44:02</span> <span class="mg">receipt</span> direction accepted: “prefer the existing retry helper”
|
|
488
|
+
<span class="dim">10:51:40</span> <span class="ac">attention</span> approval resolved <span class="ok">✓</span>
|
|
489
|
+
<span class="dim">11:02:13</span> <span class="ac">attach</span> terminal attached · run <span class="w">0xA1</span>
|
|
490
|
+
<span class="dim">11:02:55</span> <span class="ok">gate</span> strict gate passed <span class="ok">✓</span>
|
|
491
|
+
|
|
492
|
+
<span class="dim">// one timeline · the whole mission on the record</span></div></div>
|
|
493
|
+
</div></section>
|
|
494
|
+
|
|
495
|
+
<section class="stage-wrap">
|
|
496
|
+
<canvas class="scene" data-scene="cipher"></canvas>
|
|
497
|
+
<div class="shead rv"><div class="eyebrow">the cockpit</div><h2>Address the drone, not the <span class="ac">credential.</span></h2><p>Pick a run by id — Rig finds it, holds the credential, and puts you in. Terminal or browser, the join secret never touches your command line or your chat history.</p></div>
|
|
498
|
+
<div class="split rv">
|
|
499
|
+
<div><h3>Any machine is a runway.</h3>
|
|
500
|
+
<p>Placement is a parameter: the same drone flies on your laptop or a remote box. Same run id, same journal, same verbs — the only difference is where the engine spins.</p>
|
|
501
|
+
<div class="panel"><div class="pb">attach · run 0xE4</div><div class="pp"><span class="c2">target</span> detached drone 0xE4 <span class="dim">· live</span>
|
|
502
|
+
<span class="c2">surface</span> terminal or web
|
|
503
|
+
<span class="c2">credential</span> resolved privately by Rig
|
|
504
|
+
<span class="ok">receipt</span> attached · you’re in the cockpit</div></div>
|
|
505
|
+
</div></section>
|
|
506
|
+
|
|
507
|
+
<section id="ops" class="stage-wrap">
|
|
508
|
+
<canvas class="scene" data-scene="heal"></canvas>
|
|
509
|
+
<div class="shead rv"><div class="eyebrow">ops</div><h2>Drop the relay. The run keeps writing.</h2><p>The mission journal rides in the airframe, not on the wire. Drop the relay or close an attached client and the run flies on; reopen ground control and the cnet rebuilds from the record.</p></div>
|
|
510
|
+
<div class="split rev rv">
|
|
511
|
+
<div><h3>The run is its own black box.</h3>
|
|
512
|
+
<p>The detached session is the authority on itself. Close a terminal, refresh the browser, lose the network — reconnect and everything is still there, because nothing was ever only on the wire.</p>
|
|
513
|
+
<p>And a frozen session gets no quiet burial — <code>rig doctor</code> lays out discovery, relay, transcript, and sandbox evidence for the post-mortem before you kill it.</p></div>
|
|
514
|
+
<div class="panel"><div class="pb">relay blip during a live session · what actually happens</div><div class="pp"><span class="dim">// network drops while OMP keeps the transcript open</span>
|
|
515
|
+
<span class="c2">relay</span> reconnecting to wss://where.rig-does.work <span class="ok">✓</span>
|
|
516
|
+
<span class="c2">session</span> OMP transcript unchanged <span class="dim">(authority local)</span>
|
|
517
|
+
<span class="c2">cnet</span> 0xA1 redisplayed <span class="dim">· rebuilt from the journal</span>
|
|
518
|
+
<span class="w">operator</span> reattaches by run id <span class="dim">· same detached session</span>
|
|
519
|
+
<span class="ok">live</span> OMP authority never moved
|
|
520
|
+
|
|
521
|
+
<span class="dim">// private credential rotated? discovery resolves it again</span>
|
|
522
|
+
<span class="dim">// run gone? rig doctor says that plainly instead of faking attach</span>
|
|
523
|
+
<span class="c2">stall</span> no transcript movement → diagnostics · operator choice</div></div>
|
|
524
|
+
</div></section>
|
|
525
|
+
|
|
526
|
+
<section class="stage-wrap">
|
|
527
|
+
<canvas class="scene" data-scene="engine"></canvas>
|
|
528
|
+
<div class="shead rv"><div class="eyebrow">the doctrine</div><h2>Everything is a <span class="ac">plugin.</span></h2><p>Rig is a stack of plugins over a three-package floor. The entrypoint, the cnet, the gate, dispatch — all plugin contributions. Don’t like a layer? Replace it, and forge a binary with your swap baked in.</p></div>
|
|
529
|
+
<div class="pkgs rv">
|
|
530
|
+
<a class="pk" href="docs/packages/index.html"><div class="nm">@rig/contracts</div><div class="ds">The floor: schemas, types, IPC shapes. One of only three non-plugins.</div></a>
|
|
531
|
+
<a class="pk" href="docs/packages/index.html"><div class="nm">@rig/core</div><div class="ds">The floor: defineConfig / definePlugin and the plugin host.</div></a>
|
|
532
|
+
<a class="pk" href="docs/packages/index.html"><div class="nm">@rig/kernel-seed</div><div class="ds">The floor: bootstrap seed, plugin ABI, capability resolver.</div></a>
|
|
533
|
+
<a class="pk" href="docs/packages/index.html"><div class="nm">apps/rig</div><div class="ds">The sole product application and first-party plugin graph.</div></a>
|
|
534
|
+
<a class="pk" href="docs/packages/index.html"><div class="nm">@rig/product-entrypoint-plugin</div><div class="ds">Bare rig: session launch, resume, help, history.</div></a>
|
|
535
|
+
<a class="pk" href="docs/packages/index.html"><div class="nm">@rig/omp-extension-plugin</div><div class="ds">The cnet runtime: inline cards, model control, attach.</div></a>
|
|
536
|
+
<a class="pk" href="docs/packages/index.html"><div class="nm">@rig/run-plugin</div><div class="ds">Run journal, read model, cnet projections, run controls.</div></a>
|
|
537
|
+
</div></section>
|
|
538
|
+
|
|
539
|
+
<section class="stage-wrap">
|
|
540
|
+
<canvas class="scene" data-scene="surfaces"></canvas>
|
|
541
|
+
<div class="shead rv"><div class="eyebrow">extend</div><h2>Two extension surfaces. One Rig session.</h2><p>Two places to plug in — the workflow automation Rig runs around the session, or the OMP session itself.</p></div>
|
|
542
|
+
<div class="split rv">
|
|
543
|
+
<div><h3>Choose the layer that owns the behavior.</h3>
|
|
544
|
+
<p><b>Rig plugins</b> extend the workflow automation layer — <code>definePlugin</code> from <code>@rig/core</code>, contract-tested, validators dispatch in-process, skills materialize into <code>.pi/skills/</code>.</p>
|
|
545
|
+
<p><b>OMP/Pi extensions</b> extend the live session — community npm via <code>rig pi add</code> or team-wide <code>runtime.pi.packages</code>, installed at session start.</p>
|
|
546
|
+
<a class="btn" href="plugins/index.html" style="margin-top:8px;margin-right:10px">Plugin authoring</a><a class="btn" href="docs/pi-extensions/index.html" style="margin-top:8px">OMP/Pi extensions</a></div>
|
|
547
|
+
<div class="panel"><div class="pb">rig pi — OMP/Pi packages</div><div class="pp"><span class="ac">$</span> rig pi search subagents
|
|
548
|
+
<span class="c2">pi-subagents</span> <span class="dim">Subagent orchestration for Pi</span>
|
|
549
|
+
<span class="ac">$</span> rig pi add pi-subagents
|
|
550
|
+
Added pi-subagents to .pi/settings.json.
|
|
551
|
+
<span class="dim">Pi installs missing packages automatically at
|
|
552
|
+
the next session start (local and worker).</span>
|
|
553
|
+
<span class="ac">$</span> rig pi list
|
|
554
|
+
Project OMP/Pi packages (.pi/settings.json):
|
|
555
|
+
pi-subagents
|
|
556
|
+
pi-web-access@1.2.0 <span class="dim">[from rig.config runtime.pi.packages]</span></div></div>
|
|
557
|
+
</div></section>
|
|
558
|
+
|
|
559
|
+
<section class="stage-wrap">
|
|
560
|
+
<canvas class="scene" data-scene="swap"></canvas>
|
|
561
|
+
<div class="shead rv"><div class="eyebrow">defaults</div><h2>Opinionated defaults. Zero lock-in.</h2><p>Rig works the second you run it — and every layer underneath is a contribution you can swap. Keep ours, or replace any of them.</p></div>
|
|
562
|
+
<div class="split rev rv">
|
|
563
|
+
<div><h3>Replace any part. Keep the rest.</h3>
|
|
564
|
+
<p>The defaults aren’t hardcoded — even GitHub Issues ships as the <code>rig-standard</code> plugin and resolves through the same factory as any custom kind. Keep the Rig session, or swap workflow automation pieces deliberately: task source, model, validators, reviewer, sandbox policy, extension packages.</p></div>
|
|
565
|
+
<div class="panel"><div class="pb">default → swappable</div><div class="pp"><span class="c2">task source</span> github-issues <span class="dim">→</span> <span class="w">linear · your kind</span>
|
|
566
|
+
<span class="c2">session</span> OMP/Pi <span class="dim">→</span> <span class="w">runtime.pi.packages</span>
|
|
567
|
+
<span class="c2">model</span> per role <span class="dim">→</span> <span class="w">runtime.agentRoles</span>
|
|
568
|
+
<span class="c2">validators</span> std:typecheck <span class="dim">→</span> <span class="w">your plugin validators</span>
|
|
569
|
+
<span class="c2">reviewer</span> github <span class="dim">→</span> <span class="w">review.provider</span>
|
|
570
|
+
<span class="c2">sandbox</span> enforce <span class="dim">→</span> <span class="w">workspace.sandbox</span></div></div>
|
|
571
|
+
</div></section>
|
|
572
|
+
|
|
573
|
+
<section class="stage-wrap">
|
|
574
|
+
<canvas class="scene" data-scene="forge"></canvas>
|
|
575
|
+
<div class="shead rv"><div class="eyebrow">the power path</div><h2>Your repo raises its own drone.</h2><p>Drop <code>.rig/rig.config.ts</code> into a project and rig doesn’t load plugins — it <b>builds an airframe</b>: a project-flavored rig, compiled once with your plugins baked in, cached by config + lockfile fingerprint at <code>.rig/rig</code>.</p></div>
|
|
576
|
+
<div class="split rev rv">
|
|
577
|
+
<div><h3>Compiled, not configured.</h3>
|
|
578
|
+
<p>The global binary detects the code config, forges <code>.rig/rig</code> with your validators, task sources, and hooks compiled into the binary itself, then hands the invocation over. Every drone dispatched in that repo flies <b>your</b> airframe — the per-run toolchain materializes as hardlinks of it, so the whole sortie runs one build of one binary.</p>
|
|
579
|
+
<p>Change the config or bump a plugin: the lockfile shifts the fingerprint and the next launch re-forges. Delete the config: back to the standard airframe. No daemon, no registry, no drift.</p></div>
|
|
580
|
+
<div class="panel"><div class="pb">power path — self-compilation</div><div class="pp"><span class="ac">$</span> rig
|
|
581
|
+
<span class="c2">› detect</span> .rig/rig.config.ts <span class="dim">· code config, no upward walk</span>
|
|
582
|
+
<span class="c2">› forge</span> building project binary <span class="w">.rig/rig</span> <span class="dim">· plugins baked in</span>
|
|
583
|
+
<span class="c2">› cache</span> fingerprint = rig.config.ts + bun.lock
|
|
584
|
+
<span class="ac">› exec</span> .rig/rig <span class="dim">— your airframe, this invocation</span>
|
|
585
|
+
|
|
586
|
+
<span class="dim">// drones here inherit it: rig-run → hardlink of .rig/rig</span></div></div>
|
|
587
|
+
</div></section>
|
|
588
|
+
|
|
589
|
+
<section class="dog stage-wrap">
|
|
590
|
+
<canvas class="scene" data-scene="ouro"></canvas>
|
|
591
|
+
<div class="rv"><div class="eyebrow" style="margin-bottom:18px">dogfood</div>
|
|
592
|
+
<h2>Rig ships <span class="ac">Rig.</span></h2>
|
|
593
|
+
<p>The drones you just met build the engine you just read about. Rig’s own backlog flies through the same session, the same cnet, the same gate — sorties dispatched, reviews fought, merges pinned to reviewed SHAs. The receipts are in the journals, not in the marketing.</p></div>
|
|
594
|
+
</section>
|
|
595
|
+
|
|
596
|
+
<section class="ctaband stage-wrap">
|
|
597
|
+
<canvas class="scene" data-scene="converge"></canvas>
|
|
598
|
+
<p class="hsub rv"><span class="hsub-a">Rig operators aren’t writing code.</span><br><span class="hsub-b"><span class="l2"><span class="l2p">They’re </span><span class="l2h">ripping their backlogs apart</span><span class="l2p">.</span></span><canvas class="ripcv" data-pre="They’re " data-hot="ripping their backlogs apart" data-post="." aria-hidden="true"></canvas></span></p>
|
|
599
|
+
<div class="rv" style="margin-top:36px;font-family:var(--mono);font-size:14px;color:var(--ink-2)"><span style="color:var(--ac)">$</span> curl -fsSL https://where.rig-does.work/install | bash</div>
|
|
600
|
+
<div class="cta rv" style="justify-content:center;margin-top:38px"><a class="btn pri" href="docs/index.html">Start building</a><a class="btn" href="https://github.com/humanity-org/rig">View source</a></div>
|
|
601
|
+
</section>
|
|
602
|
+
|
|
603
|
+
<footer><div class="foot">
|
|
604
|
+
<div class="col"><h5>orchestrate</h5><a href="docs/getting-started/index.html">getting started</a><a href="docs/runs/index.html">the run lifecycle</a><a href="docs/operator/index.html">operator guide</a><a href="docs/gate/index.html">the merge gate</a></div>
|
|
605
|
+
<div class="col"><h5>extend</h5><a href="plugins/index.html">plugin authoring</a><a href="skills/index.html">skills</a><a href="docs/pi-extensions/index.html">OMP/Pi extensions</a><a href="docs/packages/index.html">packages</a></div>
|
|
606
|
+
<div class="col"><h5>operate</h5><a href="docs/index.html">docs home</a><a href="cli/index.html">cli reference</a><a href="config/index.html">rig.config.ts</a></div>
|
|
607
|
+
<div class="col"><h5>source</h5><a href="https://github.com/humanity-org/rig">github</a><a href="https://where.rig-does.work/install">install script</a></div>
|
|
608
|
+
<div class="sig">Rig is the OMP session extension.<br><b>You are the operator.</b><br><br>release: rig --version</div>
|
|
609
|
+
</div></footer><script>
|
|
610
|
+
/* ============================================================
|
|
611
|
+
PER-SECTION SCENE ENGINE
|
|
612
|
+
Each <canvas class="scene" data-scene="X"> gets a bespoke
|
|
613
|
+
animated abstraction of what its section DOES. Only the
|
|
614
|
+
scenes whose section is on-screen run rAF (perf + intent).
|
|
615
|
+
============================================================ */
|
|
616
|
+
(function(){
|
|
617
|
+
var AC=[204,255,77], C2=[86,216,255], MG=[255,121,176];
|
|
618
|
+
function rgba(c,a){return 'rgba('+c[0]+','+c[1]+','+c[2]+','+a+')';}
|
|
619
|
+
var pointer={x:-1e4,y:-1e4,active:false};
|
|
620
|
+
addEventListener('mousemove',function(e){pointer.x=e.clientX;pointer.y=e.clientY;pointer.active=true;},{passive:true});
|
|
621
|
+
|
|
622
|
+
// ---- scene base: handles sizing, local pointer, lifecycle ----
|
|
623
|
+
// Every scene gets two free richness layers from the base:
|
|
624
|
+
// self.dim(a) — translucent dark fill instead of clearRect: persistence
|
|
625
|
+
// trails turn every moving particle into a comet.
|
|
626
|
+
// depth field — a parallax layer of drifting, twinkling motes painted
|
|
627
|
+
// BEHIND the scene art via destination-over compositing.
|
|
628
|
+
function Scene(canvas, build){
|
|
629
|
+
var ctx=canvas.getContext('2d'),DPR=Math.min(devicePixelRatio||1,2),W=0,H=0,t=0,running=false,inited=false;
|
|
630
|
+
var self={canvas:canvas,ctx:ctx,W:0,H:0,t:0,mx:-1e4,my:-1e4};
|
|
631
|
+
var motes=[],dimmed=false;
|
|
632
|
+
function seedMotes(){motes=[];var n=Math.min(120,Math.round(W*H/22000));for(var i=0;i<n;i++)motes.push({x:Math.random()*W,y:Math.random()*H,z:.25+.75*Math.random(),sz:.5+Math.random()*1.3,tw:Math.random()*6.28,hue:Math.random()<.18?C2:[170,176,190]});}
|
|
633
|
+
function drawMotes(){for(var i=0;i<motes.length;i++){var m=motes[i];m.x+=.05*m.z;if(m.x>W+4)m.x=-4;
|
|
634
|
+
var a=(.04+.07*m.z)*(0.55+0.45*Math.sin(t*.02+m.tw));
|
|
635
|
+
ctx.fillStyle=rgba(m.hue,a);ctx.beginPath();ctx.arc(m.x,m.y,m.sz*m.z,0,7);ctx.fill();}}
|
|
636
|
+
self.dim=function(a){dimmed=true;ctx.fillStyle='rgba(7,8,9,'+a+')';ctx.fillRect(0,0,W,H);drawMotes();};
|
|
637
|
+
function size(){var r=canvas.getBoundingClientRect();W=Math.max(1,r.width);H=Math.max(1,r.height);canvas.width=W*DPR;canvas.height=H*DPR;ctx.setTransform(DPR,0,0,DPR,0,0);self.W=W;self.H=H;seedMotes();}
|
|
638
|
+
var api;
|
|
639
|
+
function ensure(){if(!inited){size();api=build(self,ctx,rgba,{AC:AC,C2:C2,MG:MG});inited=true;if(api&&api.resize)api.resize();}}
|
|
640
|
+
function localPointer(){var r=canvas.getBoundingClientRect();if(pointer.active&&pointer.x>=r.left&&pointer.x<=r.right&&pointer.y>=r.top&&pointer.y<=r.bottom){self.mx=pointer.x-r.left;self.my=pointer.y-r.top;}else{self.mx=-1e4;self.my=-1e4;}}
|
|
641
|
+
function depth(){ctx.save();ctx.globalCompositeOperation='destination-over';drawMotes();ctx.restore();}
|
|
642
|
+
function frame(){if(!running)return;t++;self.t=t;var r=canvas.getBoundingClientRect();if(Math.abs(r.width-W)>1||Math.abs(r.height-H)>1){if(r.width>0&&r.height>0){size();if(api&&api.resize)api.resize();}}localPointer();dimmed=false;if(api){try{api.draw();}catch(e){if(api.resize)api.resize();}}if(!dimmed)depth();requestAnimationFrame(frame);}
|
|
643
|
+
addEventListener('resize',function(){if(inited){size();if(api.resize)api.resize();}});
|
|
644
|
+
return {start:function(){ensure();if(!running){running=true;requestAnimationFrame(frame);}},stop:function(){running=false;}};
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// =========================================================
|
|
648
|
+
// SCENE 1 — HERO: SESSION SWARM
|
|
649
|
+
// A bright session core emits projection packets that stream outward
|
|
650
|
+
// along curved lanes into the page. Cursor bends the swarm.
|
|
651
|
+
// "Bare rig opens the session."
|
|
652
|
+
// =========================================================
|
|
653
|
+
function buildDispatch(s,ctx,rgba,C){
|
|
654
|
+
var core={x:0,y:0}, lanes=[], drones=[], waves=[];
|
|
655
|
+
function setup(){
|
|
656
|
+
core.x=s.W*0.30; core.y=s.H*0.46;
|
|
657
|
+
lanes=[]; var N=11;
|
|
658
|
+
for(var i=0;i<N;i++){var ang=(-0.9+1.8*(i/(N-1)))*(Math.PI*0.5);lanes.push({ang:ang,len:s.W*(0.55+Math.random()*0.45),curve:(Math.random()-.5)*0.9});}
|
|
659
|
+
drones=[];for(var k=0;k<130;k++)spawn(true);
|
|
660
|
+
}
|
|
661
|
+
function spawn(rand){var l=(Math.random()*lanes.length)|0;drones.push({lane:l,p:rand?Math.random():0,spd:.0016+Math.random()*.0032,sz:1+Math.random()*2.4,hue:Math.random()<.22?C.C2:C.AC,a:.18+Math.random()*.5,w:(Math.random()-.5)*40});}
|
|
662
|
+
function pt(l,p){var L=lanes[l];var dist=L.len*p;var bend=Math.sin(p*Math.PI)*L.curve*180;var ux=Math.cos(L.ang),uy=Math.sin(L.ang);var px=-uy,py=ux;var x=core.x+ux*dist+px*bend,y=core.y+uy*dist+py*bend;return{x:x,y:y};}
|
|
663
|
+
return {resize:setup, draw:function(){
|
|
664
|
+
s.dim(.26);
|
|
665
|
+
// cursor nudges core
|
|
666
|
+
if(s.mx>-1e3){var dx=s.mx-core.x,dy=s.my-core.y,d=Math.hypot(dx,dy);if(d<360){core.x+=dx/d*Math.min(18,(360-d)*.05);core.y+=dy/d*Math.min(18,(360-d)*.05);} }
|
|
667
|
+
core.x+=(s.W*0.30-core.x)*.04; core.y+=(s.H*0.46-core.y)*.04;
|
|
668
|
+
// lanes (faint)
|
|
669
|
+
ctx.lineWidth=1;
|
|
670
|
+
for(var i=0;i<lanes.length;i++){ctx.beginPath();var seg=26;for(var q=0;q<=seg;q++){var P=pt(i,q/seg);if(q===0)ctx.moveTo(P.x,P.y);else ctx.lineTo(P.x,P.y);}var g=ctx.createLinearGradient(core.x,core.y,core.x+Math.cos(lanes[i].ang)*lanes[i].len,core.y+Math.sin(lanes[i].ang)*lanes[i].len);g.addColorStop(0,rgba(C.AC,.06));g.addColorStop(1,rgba(C.AC,0));ctx.strokeStyle=g;ctx.stroke();}
|
|
671
|
+
// drones
|
|
672
|
+
for(var k=drones.length-1;k>=0;k--){var dr=drones[k];dr.p+=dr.spd;if(dr.p>=1){drones.splice(k,1);spawn(false);continue;}var P=pt(dr.lane,dr.p);P.y+=dr.w*Math.sin(dr.p*6.28);var fade=dr.p<.1?dr.p/.1:(dr.p>.85?(1-dr.p)/.15:1);var a=dr.a*fade;ctx.fillStyle=rgba(dr.hue,a);ctx.beginPath();ctx.arc(P.x,P.y,dr.sz,0,7);ctx.fill();ctx.fillStyle=rgba(dr.hue,a*.12);ctx.beginPath();ctx.arc(P.x,P.y,dr.sz*3.4,0,7);ctx.fill();}
|
|
673
|
+
// dispatch shockwaves — periodic launch pulse rippling out of the core
|
|
674
|
+
if(s.t%150===0)waves.push({r:4});
|
|
675
|
+
for(var w=waves.length-1;w>=0;w--){var wv=waves[w];wv.r+=3.4;var wa=.3*(1-wv.r/(s.W*.42));
|
|
676
|
+
if(wa<=0){waves.splice(w,1);continue;}
|
|
677
|
+
ctx.strokeStyle=rgba(C.AC,wa);ctx.lineWidth=1.2;ctx.beginPath();ctx.arc(core.x,core.y,wv.r,0,7);ctx.stroke();}
|
|
678
|
+
// radar sweep rings around the core
|
|
679
|
+
ctx.save();ctx.translate(core.x,core.y);
|
|
680
|
+
ctx.rotate(s.t*.004);ctx.setLineDash([2,15]);ctx.strokeStyle=rgba(C.AC,.20);ctx.lineWidth=1;ctx.beginPath();ctx.arc(0,0,46,0,7);ctx.stroke();
|
|
681
|
+
ctx.rotate(-s.t*.011);ctx.strokeStyle=rgba(C.C2,.13);ctx.beginPath();ctx.arc(0,0,74,0,7);ctx.stroke();
|
|
682
|
+
ctx.setLineDash([]);ctx.restore();
|
|
683
|
+
// core glow
|
|
684
|
+
var pl=.7+.3*Math.sin(s.t*.05);
|
|
685
|
+
var gg=ctx.createRadialGradient(core.x,core.y,0,core.x,core.y,90);gg.addColorStop(0,rgba(C.AC,.5*pl));gg.addColorStop(.4,rgba(C.AC,.12*pl));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(core.x-90,core.y-90,180,180);
|
|
686
|
+
ctx.fillStyle=rgba(C.AC,.9);ctx.beginPath();ctx.arc(core.x,core.y,3.2,0,7);ctx.fill();
|
|
687
|
+
ctx.strokeStyle=rgba(C.AC,.3*pl);ctx.lineWidth=1;ctx.beginPath();ctx.arc(core.x,core.y,12+5*pl,0,7);ctx.stroke();
|
|
688
|
+
}};
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// =========================================================
|
|
692
|
+
// SCENE 2 — LOOP: INSTALL TO INLINE ATTENTION
|
|
693
|
+
// Packets flow left->right across the band, passing 5 gate
|
|
694
|
+
// lines; each packet changes color as it clears a step
|
|
695
|
+
// (install -> open -> dispatch -> cnet -> pin). The literal
|
|
696
|
+
// session-first loop.
|
|
697
|
+
// =========================================================
|
|
698
|
+
function buildCNet(s,ctx,rgba,C){
|
|
699
|
+
var packets=[], gates=[], glow=[0,0,0,0,0], baseY;
|
|
700
|
+
var stageHues=[[120,124,134],C.C2,[170,210,120],[255,200,90],C.AC]; // queued->...->done
|
|
701
|
+
function setup(){baseY=s.H*0.5;gates=[];for(var i=0;i<5;i++)gates.push(s.W*(0.12+0.76*(i/4)));packets=[];for(var k=0;k<80;k++){packets.push({x:Math.random()*s.W,y:baseY+(Math.random()-.5)*s.H*0.5,vy:(Math.random()-.5)*0.15,spd:.6+Math.random()*1.0,stage:0,sz:1.4+Math.random()*2.2});}}
|
|
702
|
+
function hueFor(st){return stageHues[Math.max(0,Math.min(4,st))];}
|
|
703
|
+
return {resize:setup, draw:function(){
|
|
704
|
+
s.dim(.3);
|
|
705
|
+
// gate posts — flare when a packet strikes through
|
|
706
|
+
for(var i=0;i<gates.length;i++){var gx=gates[i],pl=.4+.6*Math.abs(Math.sin(s.t*.03+i*.7));glow[i]*=.92;
|
|
707
|
+
ctx.strokeStyle=rgba(C.AC,.05+.05*pl+.3*glow[i]);ctx.lineWidth=1+glow[i];ctx.beginPath();ctx.moveTo(gx,s.H*0.16);ctx.lineTo(gx,s.H*0.84);ctx.stroke();
|
|
708
|
+
if(glow[i]>.04){var gg=ctx.createLinearGradient(gx-22,0,gx+22,0);gg.addColorStop(0,rgba(C.AC,0));gg.addColorStop(.5,rgba(C.AC,.08*glow[i]));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(gx-22,s.H*0.16,44,s.H*0.68);}
|
|
709
|
+
ctx.fillStyle=rgba(C.AC,.35*pl+.5*glow[i]);ctx.beginPath();ctx.arc(gx,s.H*0.16,2+glow[i]*2,0,7);ctx.fill();ctx.beginPath();ctx.arc(gx,s.H*0.84,2+glow[i]*2,0,7);ctx.fill();}
|
|
710
|
+
// packets
|
|
711
|
+
for(var k=0;k<packets.length;k++){var p=packets[k];var prevx=p.x;p.x+=p.spd;p.y+=p.vy;p.y+=( (baseY+(Math.sin(p.x*.004+k)*s.H*0.12)) - p.y)*.02;
|
|
712
|
+
for(var g=0;g<gates.length;g++){if(prevx<gates[g]&&p.x>=gates[g]){p.stage=g+1;glow[g]=Math.min(1,glow[g]+.5);}}
|
|
713
|
+
if(p.x>s.W+10){p.x=-10;p.stage=0;p.y=baseY+(Math.random()-.5)*s.H*0.5;}
|
|
714
|
+
var hue=hueFor(p.stage);var a=.25+.45*(p.stage/5+.3);
|
|
715
|
+
// trail
|
|
716
|
+
ctx.strokeStyle=rgba(hue,a*.3);ctx.lineWidth=p.sz*.8;ctx.beginPath();ctx.moveTo(p.x-10,p.y);ctx.lineTo(p.x,p.y);ctx.stroke();
|
|
717
|
+
ctx.fillStyle=rgba(hue,a);ctx.beginPath();ctx.arc(p.x,p.y,p.sz,0,7);ctx.fill();
|
|
718
|
+
ctx.fillStyle=rgba(hue,a*.14);ctx.beginPath();ctx.arc(p.x,p.y,p.sz*3.2,0,7);ctx.fill();
|
|
719
|
+
}
|
|
720
|
+
}};
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// =========================================================
|
|
724
|
+
// SCENE 3 — INLINE ATTENTION -> SESSION CORE
|
|
725
|
+
// Left: an ordered lattice (pin verbs and focused views)
|
|
726
|
+
// firing signal pulses rightward into a dense, churning
|
|
727
|
+
// OMP/Pi session core. "OMP owns. Rig surfaces."
|
|
728
|
+
// =========================================================
|
|
729
|
+
function buildHarness(s,ctx,rgba,C){
|
|
730
|
+
var nodes=[],pulses=[],core,flare=0;
|
|
731
|
+
function setup(){nodes=[];var rows=5,cols=3,gx=s.W*0.10,gw=s.W*0.26;for(var r=0;r<rows;r++)for(var c=0;c<cols;c++){nodes.push({x:gx+gw*(c/(cols-1)),y:s.H*(0.22+0.56*(r/(rows-1)))});}core={x:s.W*0.74,y:s.H*0.5};pulses=[];}
|
|
732
|
+
function emit(){var n=nodes[(Math.random()*nodes.length)|0];pulses.push({x:n.x,y:n.y,p:0,from:n});}
|
|
733
|
+
return {resize:setup, draw:function(){
|
|
734
|
+
s.dim(.3);
|
|
735
|
+
if(s.t%7===0)emit();
|
|
736
|
+
// control lattice
|
|
737
|
+
ctx.lineWidth=1;
|
|
738
|
+
for(var i=0;i<nodes.length;i++){var n=nodes[i];ctx.strokeStyle=rgba(C.C2,.2);if(i+1<nodes.length&&(i+1)%3!==0){ctx.beginPath();ctx.moveTo(n.x,n.y);ctx.lineTo(nodes[i+1].x,nodes[i+1].y);ctx.stroke();}if(i+3<nodes.length){ctx.beginPath();ctx.moveTo(n.x,n.y);ctx.lineTo(nodes[i+3].x,nodes[i+3].y);ctx.stroke();}var pl=.5+.5*Math.sin(s.t*.05+i);ctx.fillStyle=rgba(C.C2,.85*pl);ctx.beginPath();ctx.arc(n.x,n.y,4.5,0,7);ctx.strokeStyle=rgba(C.C2,.18);ctx.stroke();ctx.beginPath();ctx.arc(n.x,n.y,2,0,7);ctx.fill();}
|
|
739
|
+
// standing control links (always visible)
|
|
740
|
+
for(var z=0;z<nodes.length;z+=2){ctx.strokeStyle=rgba(C.C2,.05);ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(nodes[z].x,nodes[z].y);ctx.lineTo(core.x,core.y);ctx.stroke();}
|
|
741
|
+
// pulses travel to core
|
|
742
|
+
for(var k=pulses.length-1;k>=0;k--){var pu=pulses[k];pu.p+=.025;var ex=pu.from.x+(core.x-pu.from.x)*pu.p,ey=pu.from.y+(core.y-pu.from.y)*pu.p;if(pu.p>=1){pulses.splice(k,1);flare=1;continue;}ctx.strokeStyle=rgba(C.C2,.25*(1-pu.p));ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(pu.from.x,pu.from.y);ctx.lineTo(ex,ey);ctx.stroke();ctx.fillStyle=rgba(C.C2,.7);ctx.beginPath();ctx.arc(ex,ey,1.8,0,7);ctx.fill();}
|
|
743
|
+
// execution core — churning particle cluster
|
|
744
|
+
flare*=.92;
|
|
745
|
+
var R=54+flare*16;
|
|
746
|
+
var gg=ctx.createRadialGradient(core.x,core.y,0,core.x,core.y,R*2.2);gg.addColorStop(0,rgba(C.AC,.5+flare*.3));gg.addColorStop(.45,rgba(C.AC,.14));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(core.x-R*2.2,core.y-R*2.2,R*4.4,R*4.4);
|
|
747
|
+
for(var q=0;q<64;q++){var a=q/40*6.28+s.t*.02,rr=R*(.4+.6*Math.abs(Math.sin(q*1.7+s.t*.03)));var x=core.x+Math.cos(a)*rr,y=core.y+Math.sin(a)*rr*.8;ctx.fillStyle=rgba(C.AC,.55+flare*.4);ctx.beginPath();ctx.arc(x,y,1.2+flare*1.5,0,7);ctx.fill();}
|
|
748
|
+
ctx.strokeStyle=rgba(C.AC,.35);ctx.lineWidth=1;ctx.beginPath();ctx.arc(core.x,core.y,R,0,7);ctx.stroke();
|
|
749
|
+
}};
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// =========================================================
|
|
753
|
+
// SCENE 4 — ISOLATION: PER-RUN WORKTREE LANES
|
|
754
|
+
// Strict horizontal lanes separated by hairline barriers;
|
|
755
|
+
// particles run each lane and NEVER cross. Hovering a lane
|
|
756
|
+
// highlights it. "Runs don't collide."
|
|
757
|
+
// =========================================================
|
|
758
|
+
function buildLanes(s,ctx,rgba,C){
|
|
759
|
+
var lanes=[],NL=6;
|
|
760
|
+
function setup(){lanes=[];for(var i=0;i<NL;i++){var y=s.H*(0.16+0.68*(i/(NL-1)));var runners=[];var cnt=8+((Math.random()*5)|0);for(var k=0;k<cnt;k++)runners.push({p:Math.random(),spd:.0009+Math.random()*.0022,sz:1.3+Math.random()*2,hue:Math.random()<.2?C.C2:C.AC});lanes.push({y:y,runners:runners,hot:0});}}
|
|
761
|
+
return {resize:setup, draw:function(){
|
|
762
|
+
s.dim(.34);
|
|
763
|
+
var x0=s.W*0.08,x1=s.W*0.92;
|
|
764
|
+
for(var i=0;i<lanes.length;i++){var L=lanes[i];
|
|
765
|
+
// hover detect
|
|
766
|
+
var hov=(s.my>-1e3 && Math.abs(s.my-L.y)<((s.H*0.68/(NL-1))/2));
|
|
767
|
+
L.hot+=((hov?1:0)-L.hot)*.1;
|
|
768
|
+
// barrier rails (top+bottom of lane)
|
|
769
|
+
var lg=ctx.createLinearGradient(x0,L.y,x1,L.y);lg.addColorStop(0,rgba(C.AC,.02));lg.addColorStop(.5,rgba(C.AC,.12+.12*L.hot));lg.addColorStop(1,rgba(C.AC,.02));ctx.strokeStyle=lg;ctx.lineWidth=1;
|
|
770
|
+
ctx.beginPath();ctx.moveTo(x0,L.y);ctx.lineTo(x1,L.y);ctx.stroke();
|
|
771
|
+
// runners
|
|
772
|
+
for(var k=0;k<L.runners.length;k++){var r=L.runners[k];r.p+=r.spd;if(r.p>1)r.p-=1;var x=x0+(x1-x0)*r.p;var a=(.42+.4*L.hot)* (r.p<.04?r.p/.04:(r.p>.96?(1-r.p)/.04:1));
|
|
773
|
+
ctx.strokeStyle=rgba(r.hue,a*.4);ctx.lineWidth=r.sz*.7;ctx.beginPath();ctx.moveTo(x-9,L.y);ctx.lineTo(x,L.y);ctx.stroke();
|
|
774
|
+
ctx.fillStyle=rgba(r.hue,a+ .25*L.hot);ctx.beginPath();ctx.arc(x,L.y,r.sz,0,7);ctx.fill();
|
|
775
|
+
ctx.fillStyle=rgba(r.hue,(a)*.15);ctx.beginPath();ctx.arc(x,L.y,r.sz*3,0,7);ctx.fill();}
|
|
776
|
+
// lane label tick at start
|
|
777
|
+
ctx.fillStyle=rgba(C.AC,.25+.5*L.hot);ctx.beginPath();ctx.arc(x0,L.y,1.6,0,7);ctx.fill();
|
|
778
|
+
}
|
|
779
|
+
}};
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// =========================================================
|
|
783
|
+
// SCENE 5 — ENGINE: PACKAGE CONTRIBUTION GRAPH
|
|
784
|
+
// A central hub with 8 contribution sockets on a ring;
|
|
785
|
+
// plugin nodes orbit and dock signal-links into sockets,
|
|
786
|
+
// which light up. Cursor pulls the nearest plugin node.
|
|
787
|
+
// "Packages load into the session." (8 = the 8 contribution types)
|
|
788
|
+
// =========================================================
|
|
789
|
+
function buildEngine(s,ctx,rgba,C){
|
|
790
|
+
var hub,sockets=[],plugs=[],names=8;
|
|
791
|
+
function setup(){hub={x:s.W*0.5,y:s.H*0.5};var R=Math.min(s.W,s.H)*0.16;sockets=[];for(var i=0;i<names;i++){var a=i/names*6.28-1.57;sockets.push({a:a,x:hub.x+Math.cos(a)*R,y:hub.y+Math.sin(a)*R,lit:0});}plugs=[];for(var k=0;k<names;k++){var orb=R*(2.0+Math.random()*1.1);plugs.push({sock:k,ang:Math.random()*6.28,orb:orb,spd:(Math.random()<.5?1:-1)*(.002+Math.random()*.003),docked:0,fire:0});}}
|
|
792
|
+
return {resize:setup, draw:function(){
|
|
793
|
+
s.dim(.3);
|
|
794
|
+
var R=Math.min(s.W,s.H)*0.16;hub.x=s.W*0.5;hub.y=s.H*0.5;
|
|
795
|
+
// socket ring
|
|
796
|
+
ctx.strokeStyle=rgba(C.AC,.14);ctx.lineWidth=1;ctx.beginPath();ctx.arc(hub.x,hub.y,R,0,7);ctx.stroke();
|
|
797
|
+
for(var i=0;i<sockets.length;i++){var sk=sockets[i];sk.x=hub.x+Math.cos(sk.a)*R;sk.y=hub.y+Math.sin(sk.a)*R;sk.lit*=.94;ctx.fillStyle=rgba(C.AC,.3+.7*sk.lit);ctx.beginPath();ctx.arc(sk.x,sk.y,2+2*sk.lit,0,7);ctx.fill();}
|
|
798
|
+
// plugin nodes
|
|
799
|
+
for(var k=0;k<plugs.length;k++){var pg=plugs[k];pg.ang+=pg.spd;var px=hub.x+Math.cos(pg.ang)*pg.orb,py=hub.y+Math.sin(pg.ang)*pg.orb*0.78;
|
|
800
|
+
// cursor pull
|
|
801
|
+
if(s.mx>-1e3){var dx=s.mx-px,dy=s.my-py,d=Math.hypot(dx,dy);if(d<140){px+=dx*.18;py+=dy*.18;}}
|
|
802
|
+
var sk=sockets[pg.sock];var ddock=Math.hypot(px-sk.x,py-sk.y);
|
|
803
|
+
// periodic fire toward socket
|
|
804
|
+
pg.fire*=.9;
|
|
805
|
+
if(s.t%48===((k*6)%48)){pg.fire=1;sk.lit=1;}
|
|
806
|
+
if(pg.fire>.02){ctx.strokeStyle=rgba(C.AC,.4*pg.fire);ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(px,py);ctx.lineTo(sk.x,sk.y);ctx.stroke();var fx=px+(sk.x-px)*(1-pg.fire),fy=py+(sk.y-py)*(1-pg.fire);ctx.fillStyle=rgba(C.AC,.8);ctx.beginPath();ctx.arc(fx,fy,1.8,0,7);ctx.fill();}
|
|
807
|
+
else{ctx.strokeStyle=rgba(C.C2,.09);ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(px,py);ctx.lineTo(sk.x,sk.y);ctx.stroke();}
|
|
808
|
+
var hue=k%4===0?C.C2:C.AC;ctx.fillStyle=rgba(hue,.8);ctx.beginPath();ctx.arc(px,py,3,0,7);ctx.fill();ctx.fillStyle=rgba(hue,.16);ctx.beginPath();ctx.arc(px,py,9,0,7);ctx.fill();}
|
|
809
|
+
// hub
|
|
810
|
+
var pl=.6+.4*Math.sin(s.t*.05);var gg=ctx.createRadialGradient(hub.x,hub.y,0,hub.x,hub.y,56);gg.addColorStop(0,rgba(C.AC,.55*pl));gg.addColorStop(.5,rgba(C.AC,.12));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(hub.x-56,hub.y-56,112,112);
|
|
811
|
+
ctx.fillStyle=rgba(C.AC,.9);ctx.beginPath();ctx.arc(hub.x,hub.y,3,0,7);ctx.fill();
|
|
812
|
+
}};
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// =========================================================
|
|
816
|
+
// SCENE 6 — CTA: CONVERGENCE
|
|
817
|
+
// Everything (packets from all edges) streams inward and
|
|
818
|
+
// converges to a single bright point. "Open the session."
|
|
819
|
+
// =========================================================
|
|
820
|
+
function buildConverge(s,ctx,rgba,C){
|
|
821
|
+
var pts=[],rings=[],center;
|
|
822
|
+
function setup(){center={x:s.W*0.5,y:s.H*0.5};pts=[];rings=[];for(var k=0;k<90;k++)spawn(true);}
|
|
823
|
+
function spawn(rand){var edge=(Math.random()*4)|0,x,y;if(edge===0){x=Math.random()*s.W;y=-10;}else if(edge===1){x=s.W+10;y=Math.random()*s.H;}else if(edge===2){x=Math.random()*s.W;y=s.H+10;}else{x=-10;y=Math.random()*s.H;}pts.push({x:x,y:y,sx:x,sy:y,p:rand?Math.random():0,spd:.004+Math.random()*.006,hue:Math.random()<.25?C.C2:C.AC,sz:1+Math.random()*1.8});}
|
|
824
|
+
return {resize:setup, draw:function(){
|
|
825
|
+
s.dim(.28);center.x=s.W*0.5;center.y=s.H*0.5;
|
|
826
|
+
for(var k=pts.length-1;k>=0;k--){var p=pts[k];p.p+=p.spd;var e=p.p*p.p;var x=p.sx+(center.x-p.sx)*e,y=p.sy+(center.y-p.sy)*e;if(p.p>=1){pts.splice(k,1);if(Math.random()<.3)rings.push({r:5,a:.4});spawn(false);continue;}var a=.5*(1-Math.abs(p.p-.5)*2)+.1;ctx.strokeStyle=rgba(p.hue,a*.4);ctx.lineWidth=p.sz*.7;var bx=p.sx+(center.x-p.sx)*((p.p-.02)*(p.p-.02));var by=p.sy+(center.y-p.sy)*((p.p-.02)*(p.p-.02));ctx.beginPath();ctx.moveTo(bx,by);ctx.lineTo(x,y);ctx.stroke();ctx.fillStyle=rgba(p.hue,a);ctx.beginPath();ctx.arc(x,y,p.sz,0,7);ctx.fill();}
|
|
827
|
+
// arrival ripples
|
|
828
|
+
for(var r2=rings.length-1;r2>=0;r2--){var rg=rings[r2];rg.r+=1.8;rg.a*=.94;if(rg.a<.02){rings.splice(r2,1);continue;}
|
|
829
|
+
ctx.strokeStyle=rgba(C.AC,rg.a);ctx.lineWidth=1;ctx.beginPath();ctx.arc(center.x,center.y,rg.r,0,7);ctx.stroke();}
|
|
830
|
+
var pl=.6+.4*Math.sin(s.t*.06);var gg=ctx.createRadialGradient(center.x,center.y,0,center.x,center.y,70);gg.addColorStop(0,rgba(C.AC,.45*pl));gg.addColorStop(.4,rgba(C.AC,.1));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(center.x-70,center.y-70,140,140);
|
|
831
|
+
ctx.fillStyle=rgba(C.AC,.95);ctx.beginPath();ctx.arc(center.x,center.y,3.4,0,7);ctx.fill();
|
|
832
|
+
}};
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// =========================================================
|
|
836
|
+
// SCENE 7 — WALKTHROUGH: RIG BOOT TRACK
|
|
837
|
+
// One bright runner travels a single long track through 10
|
|
838
|
+
// stage beacons; each beacon flares lime as it's cleared and
|
|
839
|
+
// stays lit until the runner loops. "One command opens it."
|
|
840
|
+
// =========================================================
|
|
841
|
+
function buildRelay(s,ctx,rgba,C){
|
|
842
|
+
var beacons=[],runner,N=10,bg=[];
|
|
843
|
+
function setup(){beacons=[];for(var i=0;i<N;i++)beacons.push({x:s.W*(0.06+0.88*(i/(N-1))),y:s.H*0.5,lit:0,hold:false});runner={p:0,spd:.0018};bg=[];for(var k=0;k<26;k++)bg.push({x:Math.random()*s.W,y:s.H*(0.18+Math.random()*0.64),spd:.25+Math.random()*.5,sz:.8+Math.random()*1.3,a:.05+Math.random()*.12});}
|
|
844
|
+
return {resize:setup, draw:function(){
|
|
845
|
+
s.dim(.3);
|
|
846
|
+
// ambient drift
|
|
847
|
+
for(var k=0;k<bg.length;k++){var b=bg[k];b.x+=b.spd;if(b.x>s.W+5)b.x=-5;ctx.fillStyle=rgba(C.C2,b.a);ctx.beginPath();ctx.arc(b.x,b.y,b.sz,0,7);ctx.fill();}
|
|
848
|
+
var y=s.H*0.5,x0=beacons[0].x,x1=beacons[N-1].x;
|
|
849
|
+
// track
|
|
850
|
+
var lg=ctx.createLinearGradient(x0,y,x1,y);lg.addColorStop(0,rgba(C.AC,.04));lg.addColorStop(.5,rgba(C.AC,.14));lg.addColorStop(1,rgba(C.AC,.04));ctx.strokeStyle=lg;ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(x0,y);ctx.lineTo(x1,y);ctx.stroke();
|
|
851
|
+
// runner
|
|
852
|
+
runner.p+=runner.spd;if(runner.p>=1.12){runner.p=-0.04;for(var i=0;i<N;i++)beacons[i].hold=false;}
|
|
853
|
+
var rx=x0+(x1-x0)*Math.min(1,Math.max(0,runner.p));
|
|
854
|
+
// beacons
|
|
855
|
+
for(var i=0;i<N;i++){var bc=beacons[i];if(rx>=bc.x)bc.hold=true;bc.lit+=((bc.hold?1:0)-bc.lit)*.12;
|
|
856
|
+
ctx.strokeStyle=rgba(C.AC,.15+.25*bc.lit);ctx.lineWidth=1;ctx.beginPath();ctx.arc(bc.x,y,5+2*bc.lit,0,7);ctx.stroke();
|
|
857
|
+
ctx.fillStyle=rgba(C.AC,.25+.65*bc.lit);ctx.beginPath();ctx.arc(bc.x,y,2+1.4*bc.lit,0,7);ctx.fill();
|
|
858
|
+
if(bc.lit>.05){ctx.fillStyle=rgba(C.AC,.10*bc.lit);ctx.beginPath();ctx.arc(bc.x,y,14,0,7);ctx.fill();}}
|
|
859
|
+
// runner glow + comet trail
|
|
860
|
+
if(runner.p>=0&&runner.p<=1){ctx.strokeStyle=rgba(C.AC,.35);ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(Math.max(x0,rx-46),y);ctx.lineTo(rx,y);ctx.stroke();
|
|
861
|
+
var gg=ctx.createRadialGradient(rx,y,0,rx,y,26);gg.addColorStop(0,rgba(C.AC,.6));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(rx-26,y-26,52,52);
|
|
862
|
+
ctx.fillStyle=rgba(C.AC,.95);ctx.beginPath();ctx.arc(rx,y,3,0,7);ctx.fill();}
|
|
863
|
+
}};
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// =========================================================
|
|
867
|
+
// SCENE 8 — STRICT MERGE GATE: THE WALL
|
|
868
|
+
// Packets stream toward a vertical scan wall, queue briefly,
|
|
869
|
+
// get scanned (cyan flash), pass bright lime — or bounce as
|
|
870
|
+
// rejected. "Nothing merges on vibes."
|
|
871
|
+
// =========================================================
|
|
872
|
+
function buildGatewall(s,ctx,rgba,C){
|
|
873
|
+
var pk=[],frags=[],wallX,slotT=0;
|
|
874
|
+
function setup(){wallX=s.W*0.58;pk=[];frags=[];for(var k=0;k<46;k++)spawn(true);}
|
|
875
|
+
function spawn(rand){var bad=Math.random()<.12;pk.push({x:rand?Math.random()*s.W:-8,y:s.H*(0.2+Math.random()*0.6),spd:.7+Math.random()*.9,state:0,wait:0,bad:bad,sz:1.3+Math.random()*1.8});}
|
|
876
|
+
return {resize:setup, draw:function(){
|
|
877
|
+
s.dim(.3);wallX=s.W*0.58;slotT+=.02;
|
|
878
|
+
// the wall — dashed, with a pulsing scan slot
|
|
879
|
+
ctx.strokeStyle=rgba(C.AC,.16);ctx.lineWidth=1;ctx.setLineDash([3,7]);ctx.beginPath();ctx.moveTo(wallX,s.H*0.12);ctx.lineTo(wallX,s.H*0.88);ctx.stroke();ctx.setLineDash([]);
|
|
880
|
+
var pl=.5+.5*Math.sin(slotT*2.4);
|
|
881
|
+
ctx.strokeStyle=rgba(C.AC,.25+.3*pl);ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(wallX,s.H*0.12);ctx.lineTo(wallX,s.H*0.2);ctx.stroke();ctx.beginPath();ctx.moveTo(wallX,s.H*0.8);ctx.lineTo(wallX,s.H*0.88);ctx.stroke();
|
|
882
|
+
ctx.fillStyle=rgba(C.AC,.5+.4*pl);ctx.beginPath();ctx.arc(wallX,s.H*0.12,2,0,7);ctx.fill();ctx.beginPath();ctx.arc(wallX,s.H*0.88,2,0,7);ctx.fill();
|
|
883
|
+
for(var k=pk.length-1;k>=0;k--){var p=pk[k];
|
|
884
|
+
if(p.state===0){p.x+=p.spd;if(p.x>=wallX-14){p.state=1;p.wait=14+Math.random()*30;}}
|
|
885
|
+
else if(p.state===1){p.wait--;p.x+=(wallX-12-p.x)*.1;if(p.wait<=0){p.state=p.bad?3:2;
|
|
886
|
+
if(p.bad)for(var f=0;f<7;f++)frags.push({x:p.x,y:p.y,vx:-(.4+Math.random()*1.6),vy:(Math.random()-.5)*2.4,life:1});}}
|
|
887
|
+
else if(p.state===2){p.x+=p.spd*1.5;}
|
|
888
|
+
else{p.x-=p.spd*1.1;p.y+=.4;}
|
|
889
|
+
if(p.x>s.W+10||p.x<-12){pk.splice(k,1);spawn(false);continue;}
|
|
890
|
+
var hue=p.state===2?C.AC:(p.state===3?C.MG:[150,156,170]);
|
|
891
|
+
var a=p.state===2?.7:(p.state===3?.5:.3);
|
|
892
|
+
if(p.state===1&&p.wait<8){ctx.strokeStyle=rgba(C.C2,.5);ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(wallX,p.y-7);ctx.lineTo(wallX,p.y+7);ctx.stroke();}
|
|
893
|
+
ctx.strokeStyle=rgba(hue,a*.35);ctx.lineWidth=p.sz*.7;ctx.beginPath();ctx.moveTo(p.x-(p.state===3?-8:8),p.y);ctx.lineTo(p.x,p.y);ctx.stroke();
|
|
894
|
+
ctx.fillStyle=rgba(hue,a);ctx.beginPath();ctx.arc(p.x,p.y,p.sz,0,7);ctx.fill();
|
|
895
|
+
ctx.fillStyle=rgba(hue,a*.13);ctx.beginPath();ctx.arc(p.x,p.y,p.sz*3,0,7);ctx.fill();}
|
|
896
|
+
// rejection debris — the wall shatters what it bounces
|
|
897
|
+
for(var q=frags.length-1;q>=0;q--){var fr=frags[q];fr.x+=fr.vx;fr.y+=fr.vy;fr.vy+=.05;fr.life-=.025;
|
|
898
|
+
if(fr.life<=0){frags.splice(q,1);continue;}
|
|
899
|
+
ctx.fillStyle=rgba(C.MG,.55*fr.life);ctx.fillRect(fr.x,fr.y,1.6,1.6);}
|
|
900
|
+
}};
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// =========================================================
|
|
904
|
+
// SCENE 9 — SESSION RESUME: CUT & RE-KNIT
|
|
905
|
+
// A node chain carries packets; segments randomly "cut"
|
|
906
|
+
// (magenta snap, flow stalls), then a repair pulse re-knits
|
|
907
|
+
// the link (lime flash) and flow resumes. "The session heals."
|
|
908
|
+
// =========================================================
|
|
909
|
+
function buildHeal(s,ctx,rgba,C){
|
|
910
|
+
var nodes=[],pk=[],cut=null,NN=7;
|
|
911
|
+
function setup(){nodes=[];for(var i=0;i<NN;i++)nodes.push({x:s.W*(0.07+0.86*(i/(NN-1))),y:s.H*(0.5+0.16*Math.sin(i*1.9))});pk=[];for(var k=0;k<34;k++)pk.push({seg:(Math.random()*(NN-1))|0,p:Math.random(),spd:.004+Math.random()*.006,sz:1.2+Math.random()*1.7,hue:Math.random()<.2?C.C2:C.AC});cut=null;}
|
|
912
|
+
return {resize:setup, draw:function(){
|
|
913
|
+
s.dim(.34);
|
|
914
|
+
// schedule cuts + repairs
|
|
915
|
+
if(!cut&&s.t%240===120){cut={seg:1+((Math.random()*(NN-3))|0),age:0};}
|
|
916
|
+
if(cut){cut.age++;if(cut.age>150)cut=null;}
|
|
917
|
+
// links
|
|
918
|
+
for(var i=0;i<NN-1;i++){var a=nodes[i],b=nodes[i+1];var isCut=cut&&cut.seg===i&&cut.age<110;var healing=cut&&cut.seg===i&&cut.age>=110;
|
|
919
|
+
if(isCut){var mx=(a.x+b.x)/2,my=(a.y+b.y)/2;var fl=cut.age<14?(1-cut.age/14):0;
|
|
920
|
+
ctx.strokeStyle=rgba(C.MG,.3+.5*fl);ctx.lineWidth=1;
|
|
921
|
+
ctx.beginPath();ctx.moveTo(a.x,a.y);ctx.lineTo(mx-13,my+(Math.random()-.5)*3);ctx.stroke();
|
|
922
|
+
ctx.beginPath();ctx.moveTo(mx+13,my+(Math.random()-.5)*3);ctx.lineTo(b.x,b.y);ctx.stroke();
|
|
923
|
+
if(fl>0){ctx.fillStyle=rgba(C.MG,.6*fl);ctx.beginPath();ctx.arc(mx,my,4+10*(1-fl),0,7);ctx.fill();}}
|
|
924
|
+
else{var hl=healing?(cut.age-110)/40:0;ctx.strokeStyle=rgba(C.AC,.12+.5*hl);ctx.lineWidth=1+hl;ctx.beginPath();ctx.moveTo(a.x,a.y);ctx.lineTo(b.x,b.y);ctx.stroke();
|
|
925
|
+
if(healing){var rp=(cut.age-110)/40,rx=a.x+(b.x-a.x)*rp,ry=a.y+(b.y-a.y)*rp;ctx.fillStyle=rgba(C.AC,.9);ctx.beginPath();ctx.arc(rx,ry,2.6,0,7);ctx.fill();ctx.fillStyle=rgba(C.AC,.2);ctx.beginPath();ctx.arc(rx,ry,9,0,7);ctx.fill();}}}
|
|
926
|
+
// nodes
|
|
927
|
+
for(var i=0;i<NN;i++){var n=nodes[i],pl=.5+.5*Math.sin(s.t*.04+i*1.3);ctx.fillStyle=rgba(C.AC,.3+.4*pl);ctx.beginPath();ctx.arc(n.x,n.y,2.2,0,7);ctx.fill();ctx.strokeStyle=rgba(C.AC,.12);ctx.beginPath();ctx.arc(n.x,n.y,6,0,7);ctx.stroke();}
|
|
928
|
+
// packets — stall at a cut, resume on heal
|
|
929
|
+
for(var k=0;k<pk.length;k++){var q=pk[k];var blocked=cut&&cut.seg===q.seg&&cut.age<110&&q.p>.42;
|
|
930
|
+
if(!blocked){q.p+=q.spd;if(q.p>=1){q.p=0;q.seg=(q.seg+1)%(NN-1);}}else if(q.p>.46)q.p=.46;
|
|
931
|
+
var a=nodes[q.seg],b=nodes[q.seg+1],x=a.x+(b.x-a.x)*q.p,y=a.y+(b.y-a.y)*q.p;
|
|
932
|
+
var al=blocked?.18:.5;
|
|
933
|
+
ctx.fillStyle=rgba(q.hue,al);ctx.beginPath();ctx.arc(x,y,q.sz,0,7);ctx.fill();
|
|
934
|
+
ctx.fillStyle=rgba(q.hue,al*.14);ctx.beginPath();ctx.arc(x,y,q.sz*3,0,7);ctx.fill();}
|
|
935
|
+
}};
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// =========================================================
|
|
939
|
+
// SCENE 10 — DOGFOOD: OUROBOROS RING
|
|
940
|
+
// Packets circulate a ring; periodically one dives into the
|
|
941
|
+
// hub (a merge), the hub flares, and a fresh packet re-emits
|
|
942
|
+
// onto the ring. The session feeds itself. "Rig ships Rig."
|
|
943
|
+
// =========================================================
|
|
944
|
+
function buildOuro(s,ctx,rgba,C){
|
|
945
|
+
var orbs=[],divers=[],hub,R,flare=0;
|
|
946
|
+
function setup(){hub={x:s.W*0.5,y:s.H*0.5};R=Math.min(s.W,s.H)*0.30;orbs=[];for(var k=0;k<42;k++)orbs.push({a:Math.random()*6.28,spd:.004+Math.random()*.004,sz:1.1+Math.random()*1.8,hue:Math.random()<.2?C.C2:C.AC,al:.2+Math.random()*.4});divers=[];}
|
|
947
|
+
return {resize:setup, draw:function(){
|
|
948
|
+
s.dim(.26);hub.x=s.W*0.5;hub.y=s.H*0.5;R=Math.min(s.W,s.H)*0.30;
|
|
949
|
+
// ring
|
|
950
|
+
ctx.strokeStyle=rgba(C.AC,.10);ctx.lineWidth=1;ctx.beginPath();ctx.ellipse(hub.x,hub.y,R,R*.62,0,0,7);ctx.stroke();
|
|
951
|
+
// periodically send one diver inward
|
|
952
|
+
if(s.t%160===0&&orbs.length>20){var o=orbs.splice((Math.random()*orbs.length)|0,1)[0];divers.push({a:o.a,r:1,hue:o.hue});}
|
|
953
|
+
for(var k=divers.length-1;k>=0;k--){var d=divers[k];d.r-=.016;d.a+=.05;
|
|
954
|
+
if(d.r<=.04){divers.splice(k,1);flare=1;orbs.push({a:Math.random()*6.28,spd:.004+Math.random()*.004,sz:1.1+Math.random()*1.8,hue:Math.random()<.2?C.C2:C.AC,al:.2+Math.random()*.4});continue;}
|
|
955
|
+
var x=hub.x+Math.cos(d.a)*R*d.r,y=hub.y+Math.sin(d.a)*R*.62*d.r;
|
|
956
|
+
ctx.fillStyle=rgba(d.hue,.7);ctx.beginPath();ctx.arc(x,y,1.8,0,7);ctx.fill();
|
|
957
|
+
ctx.fillStyle=rgba(d.hue,.12);ctx.beginPath();ctx.arc(x,y,6,0,7);ctx.fill();}
|
|
958
|
+
// orbiters
|
|
959
|
+
for(var k=0;k<orbs.length;k++){var o=orbs[k];o.a+=o.spd;var x=hub.x+Math.cos(o.a)*R,y=hub.y+Math.sin(o.a)*R*.62;
|
|
960
|
+
ctx.fillStyle=rgba(o.hue,o.al);ctx.beginPath();ctx.arc(x,y,o.sz,0,7);ctx.fill();
|
|
961
|
+
ctx.fillStyle=rgba(o.hue,o.al*.14);ctx.beginPath();ctx.arc(x,y,o.sz*3,0,7);ctx.fill();}
|
|
962
|
+
// hub
|
|
963
|
+
flare*=.94;var pl=.6+.4*Math.sin(s.t*.05);
|
|
964
|
+
var gg=ctx.createRadialGradient(hub.x,hub.y,0,hub.x,hub.y,60+30*flare);gg.addColorStop(0,rgba(C.AC,(.45+.4*flare)*pl));gg.addColorStop(.5,rgba(C.AC,.1));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(hub.x-90,hub.y-90,180,180);
|
|
965
|
+
ctx.fillStyle=rgba(C.AC,.95);ctx.beginPath();ctx.arc(hub.x,hub.y,3+2*flare,0,7);ctx.fill();
|
|
966
|
+
}};
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// =========================================================
|
|
970
|
+
// SCENE 11 — WHAT-IS: SESSION TRIAD
|
|
971
|
+
// Three source nodes (operator / commander / fleet) on the left
|
|
972
|
+
// each stream packets along curved lanes into ONE bright
|
|
973
|
+
// convergence node that flares on arrival. "One session,
|
|
974
|
+
// one reviewed PR."
|
|
975
|
+
// =========================================================
|
|
976
|
+
function buildTriad(s,ctx,rgba,C){
|
|
977
|
+
var src=[],dst,flow=[],flare=0;
|
|
978
|
+
function setup(){
|
|
979
|
+
dst={x:s.W*0.80,y:s.H*0.5};
|
|
980
|
+
src=[];for(var i=0;i<3;i++)src.push({x:s.W*0.16,y:s.H*(0.30+0.20*i),hue:i===1?C.AC:C.C2});
|
|
981
|
+
flow=[];for(var k=0;k<66;k++)spawn(true);
|
|
982
|
+
}
|
|
983
|
+
function spawn(rand){flow.push({i:(Math.random()*3)|0,p:rand?Math.random():0,spd:.004+Math.random()*.006,sz:1+Math.random()*1.7});}
|
|
984
|
+
function pt(i,p){var a=src[i],cx=s.W*0.52,cy=dst.y+(a.y-dst.y)*0.16,iu=1-p;return{x:iu*iu*a.x+2*iu*p*cx+p*p*dst.x,y:iu*iu*a.y+2*iu*p*cy+p*p*dst.y};}
|
|
985
|
+
return {resize:setup, draw:function(){
|
|
986
|
+
s.dim(.3);
|
|
987
|
+
for(var i=0;i<3;i++){ctx.strokeStyle=rgba(src[i].hue,.05);ctx.lineWidth=1;ctx.beginPath();for(var q=0;q<=24;q++){var P=pt(i,q/24);if(q===0)ctx.moveTo(P.x,P.y);else ctx.lineTo(P.x,P.y);}ctx.stroke();
|
|
988
|
+
var pl=.5+.5*Math.sin(s.t*.05+i*2);ctx.fillStyle=rgba(src[i].hue,.5*pl);ctx.beginPath();ctx.arc(src[i].x,src[i].y,3,0,7);ctx.fill();ctx.strokeStyle=rgba(src[i].hue,.2);ctx.beginPath();ctx.arc(src[i].x,src[i].y,8,0,7);ctx.stroke();}
|
|
989
|
+
for(var k=flow.length-1;k>=0;k--){var f=flow[k];f.p+=f.spd;if(f.p>=1){flow.splice(k,1);flare=1;spawn(false);continue;}var P=pt(f.i,f.p),hue=src[f.i].hue,a=.3+.4*Math.sin(f.p*3.14);ctx.fillStyle=rgba(hue,a);ctx.beginPath();ctx.arc(P.x,P.y,f.sz,0,7);ctx.fill();ctx.fillStyle=rgba(hue,a*.13);ctx.beginPath();ctx.arc(P.x,P.y,f.sz*3,0,7);ctx.fill();}
|
|
990
|
+
flare*=.93;var pl=.6+.4*Math.sin(s.t*.06);
|
|
991
|
+
var gg=ctx.createRadialGradient(dst.x,dst.y,0,dst.x,dst.y,72+30*flare);gg.addColorStop(0,rgba(C.AC,(.45+.35*flare)*pl));gg.addColorStop(.45,rgba(C.AC,.1));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(dst.x-104,dst.y-104,208,208);
|
|
992
|
+
ctx.fillStyle=rgba(C.AC,.95);ctx.beginPath();ctx.arc(dst.x,dst.y,3.2+2*flare,0,7);ctx.fill();
|
|
993
|
+
ctx.strokeStyle=rgba(C.AC,.3*pl);ctx.lineWidth=1;ctx.beginPath();ctx.arc(dst.x,dst.y,13+5*flare,0,7);ctx.stroke();
|
|
994
|
+
}};
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// SCENE 12 — PI CARRIER: one bundled extension, loaded into every session
|
|
998
|
+
function buildCarrier(s,ctx,rgba,C){
|
|
999
|
+
var core,nodes=[],pks=[];
|
|
1000
|
+
function setup(){core={x:s.W*0.5,y:s.H*0.5};var N=7,R=Math.min(s.W,s.H)*0.32;nodes=[];for(var i=0;i<N;i++){var a=i/N*6.28-1.57;nodes.push({x:core.x+Math.cos(a)*R,y:core.y+Math.sin(a)*R*0.92,lit:0});}pks=[];}
|
|
1001
|
+
return {resize:setup, draw:function(){
|
|
1002
|
+
s.dim(.3);core.x=s.W*0.5;core.y=s.H*0.5;var R=Math.min(s.W,s.H)*0.32;
|
|
1003
|
+
if(s.t%13===0){var nn=nodes[(Math.random()*nodes.length)|0];pks.push({n:nn,p:0});}
|
|
1004
|
+
for(var i=0;i<nodes.length;i++){var n=nodes[i],a=i/nodes.length*6.28-1.57;n.x=core.x+Math.cos(a)*R;n.y=core.y+Math.sin(a)*R*0.92;n.lit*=.965;
|
|
1005
|
+
ctx.strokeStyle=rgba(C.AC,.04+.16*n.lit);ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(core.x,core.y);ctx.lineTo(n.x,n.y);ctx.stroke();
|
|
1006
|
+
ctx.fillStyle=rgba(C.AC,.28+.6*n.lit);ctx.beginPath();ctx.arc(n.x,n.y,2.2+1.6*n.lit,0,7);ctx.fill();
|
|
1007
|
+
ctx.strokeStyle=rgba(C.AC,.12+.3*n.lit);ctx.beginPath();ctx.arc(n.x,n.y,7+3*n.lit,0,7);ctx.stroke();}
|
|
1008
|
+
for(var k=pks.length-1;k>=0;k--){var pk=pks[k];pk.p+=.04;if(pk.p>=1){pk.n.lit=1;pks.splice(k,1);continue;}var x=core.x+(pk.n.x-core.x)*pk.p,y=core.y+(pk.n.y-core.y)*pk.p;ctx.fillStyle=rgba(C.AC,.85);ctx.beginPath();ctx.arc(x,y,1.8,0,7);ctx.fill();ctx.fillStyle=rgba(C.AC,.16);ctx.beginPath();ctx.arc(x,y,6,0,7);ctx.fill();}
|
|
1009
|
+
var pl=.6+.4*Math.sin(s.t*.05),gg=ctx.createRadialGradient(core.x,core.y,0,core.x,core.y,62);gg.addColorStop(0,rgba(C.AC,.5*pl));gg.addColorStop(.5,rgba(C.AC,.12));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(core.x-62,core.y-62,124,124);
|
|
1010
|
+
ctx.fillStyle=rgba(C.AC,.95);ctx.beginPath();ctx.arc(core.x,core.y,3.4,0,7);ctx.fill();ctx.strokeStyle=rgba(C.AC,.3*pl);ctx.beginPath();ctx.arc(core.x,core.y,12+5*pl,0,7);ctx.stroke();
|
|
1011
|
+
}};
|
|
1012
|
+
}
|
|
1013
|
+
// SCENE 13 — SWAP: HOT-SWAP RACK ON A LIVE BUS
|
|
1014
|
+
// Six modules seated on a data bus that never stops carrying
|
|
1015
|
+
// packets. Periodically one ejects (sparks, floats off) and a
|
|
1016
|
+
// fresh one drops in and LOCKS (ring flash). While the slot is
|
|
1017
|
+
// empty the bus traffic arcs OVER the gap — swap any part, the
|
|
1018
|
+
// session keeps flowing. "Zero lock-in, zero downtime."
|
|
1019
|
+
function buildSwap(s,ctx,rgba,C){
|
|
1020
|
+
var slots=[],pkts=[],sparks=[],sw=null,N=6,y;
|
|
1021
|
+
function setup(){y=s.H*0.52;slots=[];for(var i=0;i<N;i++)slots.push({hue:i%3===0?C.C2:C.AC,ring:0});
|
|
1022
|
+
pkts=[];for(var k=0;k<26;k++)pkts.push({p:Math.random(),spd:.0018+Math.random()*.003,sz:1+Math.random()*1.6,hue:Math.random()<.25?C.C2:C.AC});
|
|
1023
|
+
sparks=[];sw=null;}
|
|
1024
|
+
function sx(i){return s.W*(0.13+0.74*(i/(N-1)));}
|
|
1025
|
+
return {resize:setup, draw:function(){
|
|
1026
|
+
s.dim(.3);
|
|
1027
|
+
var w=48,h=32;
|
|
1028
|
+
// the bus
|
|
1029
|
+
var lg=ctx.createLinearGradient(s.W*0.06,y,s.W*0.94,y);lg.addColorStop(0,rgba(C.AC,.03));lg.addColorStop(.5,rgba(C.AC,.12));lg.addColorStop(1,rgba(C.AC,.03));
|
|
1030
|
+
ctx.strokeStyle=lg;ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(s.W*0.06,y);ctx.lineTo(s.W*0.94,y);ctx.stroke();
|
|
1031
|
+
// schedule swaps: eject with sparks, drop-in replacement
|
|
1032
|
+
if(!sw&&s.t%180===60){sw={i:(Math.random()*N)|0,age:0};
|
|
1033
|
+
for(var f=0;f<12;f++)sparks.push({x:sx(sw.i)+(Math.random()-.5)*18,y:y,vx:(Math.random()-.5)*2.4,vy:-(.5+Math.random()*2),life:1});}
|
|
1034
|
+
if(sw){sw.age++;if(sw.age>76){slots[sw.i].hue=(Math.random()<.4?C.C2:C.AC);slots[sw.i].ring=1;sw=null;}}
|
|
1035
|
+
// slots
|
|
1036
|
+
for(var i=0;i<N;i++){var X=sx(i),sl=slots[i];
|
|
1037
|
+
// socket frame + connector pins
|
|
1038
|
+
ctx.strokeStyle=rgba(C.AC,.10);ctx.lineWidth=1;ctx.strokeRect(X-w/2,y-h/2,w,h);
|
|
1039
|
+
for(var pn=0;pn<4;pn++){var px=X-w/2+7+(w-14)*(pn/3);ctx.fillStyle=rgba(C.AC,.16);ctx.fillRect(px,y+h/2,1.4,4);}
|
|
1040
|
+
var dy=0,a=1,inA=0;
|
|
1041
|
+
if(sw&&sw.i===i){var p=sw.age/76;if(p<.42){dy=-(p/.42)*46;a=1-p/.42;}else{a=0;inA=(p-.42)/.58;}}
|
|
1042
|
+
// resident (or ejecting) module with heartbeat LED
|
|
1043
|
+
if(a>0.02){var hue=sl.hue,hb=.5+.5*Math.sin(s.t*.1+i*2);
|
|
1044
|
+
ctx.fillStyle=rgba(hue,.10*a);ctx.fillRect(X-w/2+5,y-h/2+5+dy,w-10,h-10);
|
|
1045
|
+
ctx.strokeStyle=rgba(hue,.4*a);ctx.strokeRect(X-w/2+5,y-h/2+5+dy,w-10,h-10);
|
|
1046
|
+
ctx.fillStyle=rgba(hue,(.3+.6*hb)*a);ctx.beginPath();ctx.arc(X,y+dy,1.8,0,7);ctx.fill();}
|
|
1047
|
+
// replacement dropping in
|
|
1048
|
+
if(inA>0){var ny=y-(1-inA)*(h+30);
|
|
1049
|
+
ctx.fillStyle=rgba(C.AC,.12*inA);ctx.fillRect(X-w/2+5,ny-h/2+5,w-10,h-10);
|
|
1050
|
+
ctx.strokeStyle=rgba(C.AC,.5*inA);ctx.strokeRect(X-w/2+5,ny-h/2+5,w-10,h-10);}
|
|
1051
|
+
// lock-ring flash when the new module seats
|
|
1052
|
+
if(sl.ring>.03){sl.ring*=.93;var rr=8+(1-sl.ring)*26;
|
|
1053
|
+
ctx.strokeStyle=rgba(C.AC,.5*sl.ring);ctx.lineWidth=1.2;ctx.beginPath();ctx.arc(X,y,rr,0,7);ctx.stroke();}}
|
|
1054
|
+
// bus packets — they arc OVER an empty slot instead of stopping
|
|
1055
|
+
for(var k=0;k<pkts.length;k++){var q=pkts[k];q.p+=q.spd;if(q.p>1)q.p-=1;var x=s.W*(0.06+0.88*q.p);
|
|
1056
|
+
var lift=0;
|
|
1057
|
+
if(sw){var gx=sx(sw.i),d=Math.abs(x-gx);if(d<w*1.4)lift=-Math.cos(d/(w*1.4)*1.5708)*18;}
|
|
1058
|
+
ctx.fillStyle=rgba(q.hue,.6);ctx.beginPath();ctx.arc(x,y+lift,q.sz,0,7);ctx.fill();
|
|
1059
|
+
ctx.fillStyle=rgba(q.hue,.12);ctx.beginPath();ctx.arc(x,y+lift,q.sz*3,0,7);ctx.fill();}
|
|
1060
|
+
// eject sparks
|
|
1061
|
+
for(var sp=sparks.length-1;sp>=0;sp--){var k2=sparks[sp];k2.x+=k2.vx;k2.y+=k2.vy;k2.vy+=.07;k2.life-=.028;
|
|
1062
|
+
if(k2.life<=0){sparks.splice(sp,1);continue;}
|
|
1063
|
+
ctx.fillStyle=rgba(C.AC,.6*k2.life);ctx.fillRect(k2.x,k2.y,1.5,1.5);}
|
|
1064
|
+
}};
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// SCENE 14 — SURFACES: workflow automation and OMP session packages, one operator linking them
|
|
1068
|
+
function buildSurfaces(s,ctx,rgba,C){
|
|
1069
|
+
var topY,botY,N=6,pk=[];
|
|
1070
|
+
function setup(){topY=s.H*0.34;botY=s.H*0.66;pk=[];}
|
|
1071
|
+
function nx(i){return s.W*(0.12+0.76*(i/(N-1)));}
|
|
1072
|
+
return {resize:setup, draw:function(){
|
|
1073
|
+
s.dim(.32);topY=s.H*0.34;botY=s.H*0.66;
|
|
1074
|
+
ctx.lineWidth=1;ctx.strokeStyle=rgba(C.C2,.09);ctx.beginPath();ctx.moveTo(s.W*0.1,topY);ctx.lineTo(s.W*0.9,topY);ctx.stroke();
|
|
1075
|
+
ctx.strokeStyle=rgba(C.AC,.09);ctx.beginPath();ctx.moveTo(s.W*0.1,botY);ctx.lineTo(s.W*0.9,botY);ctx.stroke();
|
|
1076
|
+
for(var i=0;i<N;i++){var x=nx(i),pt=.5+.5*Math.sin(s.t*.04+i),pb=.5+.5*Math.sin(s.t*.04+i+2);
|
|
1077
|
+
ctx.fillStyle=rgba(C.C2,.28+.4*pt);ctx.beginPath();ctx.arc(x,topY,2.3,0,7);ctx.fill();
|
|
1078
|
+
ctx.fillStyle=rgba(C.AC,.28+.4*pb);ctx.beginPath();ctx.arc(x,botY,2.3,0,7);ctx.fill();}
|
|
1079
|
+
if(s.t%9===0){var lane=Math.random()<.5;pk.push({lane:lane,p:0,spd:.008+Math.random()*.006,hue:lane?C.C2:C.AC});}
|
|
1080
|
+
if(s.t%64===0){pk.push({link:(Math.random()*N)|0,p:0});}
|
|
1081
|
+
for(var k=pk.length-1;k>=0;k--){var p=pk[k];p.p+=(p.link!==undefined?.022:p.spd);if(p.p>=1){pk.splice(k,1);continue;}
|
|
1082
|
+
if(p.link!==undefined){var x=nx(p.link),y=topY+(botY-topY)*p.p;ctx.strokeStyle=rgba(C.AC,.10);ctx.beginPath();ctx.moveTo(x,topY);ctx.lineTo(x,botY);ctx.stroke();ctx.fillStyle=rgba([234,255,176],.8);ctx.beginPath();ctx.arc(x,y,1.9,0,7);ctx.fill();}
|
|
1083
|
+
else{var x2=s.W*(0.1+0.8*p.p),y2=p.lane?topY:botY;ctx.fillStyle=rgba(p.hue,.7);ctx.beginPath();ctx.arc(x2,y2,1.6,0,7);ctx.fill();ctx.fillStyle=rgba(p.hue,.14);ctx.beginPath();ctx.arc(x2,y2,5,0,7);ctx.fill();}}
|
|
1084
|
+
}};
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// =========================================================
|
|
1088
|
+
// SCENE 15 — RECORD: SESSION JOURNAL TAPE
|
|
1089
|
+
// Events fall out of the run and lock onto an append-only
|
|
1090
|
+
// tape (ticks only ever ADD on the right; the tape scrolls
|
|
1091
|
+
// left). A cyan replay head periodically sweeps the whole
|
|
1092
|
+
// history, re-lighting every tick it passes. "The cnet replays."
|
|
1093
|
+
// ============================================================
|
|
1094
|
+
function buildJournal(s,ctx,rgba,C){
|
|
1095
|
+
var ticks=[],fall=[],head=null,y,x0,x1,SCROLL=.34;
|
|
1096
|
+
function mkTick(x){return{x:x,h:5+Math.random()*16,hue:Math.random()<.16?C.C2:C.AC,lit:0,a:.22+Math.random()*.3};}
|
|
1097
|
+
function setup(){y=s.H*0.8;x0=s.W*0.06;x1=s.W*0.94;ticks=[];fall=[];head=null;
|
|
1098
|
+
for(var x=x0;x<x1-40;x+=9+Math.random()*26)ticks.push(mkTick(x));}
|
|
1099
|
+
return {resize:setup, draw:function(){
|
|
1100
|
+
s.dim(.3);
|
|
1101
|
+
// tape line
|
|
1102
|
+
var lg=ctx.createLinearGradient(x0,y,x1,y);lg.addColorStop(0,rgba(C.AC,.03));lg.addColorStop(.5,rgba(C.AC,.13));lg.addColorStop(1,rgba(C.AC,.05));
|
|
1103
|
+
ctx.strokeStyle=lg;ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(x0,y);ctx.lineTo(x1,y);ctx.stroke();
|
|
1104
|
+
// append-only: events fall from the run above and lock onto the tape's right end
|
|
1105
|
+
if(s.t%30===0)fall.push({x:x1-24,y:y-s.H*0.2-Math.random()*s.H*0.06,vy:0,hue:Math.random()<.2?C.C2:C.AC});
|
|
1106
|
+
for(var k=fall.length-1;k>=0;k--){var f=fall[k];f.vy+=.14;f.y+=f.vy;
|
|
1107
|
+
if(f.y>=y){fall.splice(k,1);var t2=mkTick(f.x);t2.hue=f.hue;t2.lit=1;ticks.push(t2);continue;}
|
|
1108
|
+
ctx.fillStyle=rgba(f.hue,.7);ctx.beginPath();ctx.arc(f.x,f.y,1.8,0,7);ctx.fill();
|
|
1109
|
+
ctx.fillStyle=rgba(f.hue,.12);ctx.beginPath();ctx.arc(f.x,f.y,6,0,7);ctx.fill();}
|
|
1110
|
+
// tape scrolls left; history never rewrites, it only slides off the edge
|
|
1111
|
+
for(var i=ticks.length-1;i>=0;i--){var tk=ticks[i];tk.x-=SCROLL;if(tk.x<x0){ticks.splice(i,1);continue;}
|
|
1112
|
+
tk.lit*=.95;
|
|
1113
|
+
var edge=Math.min(1,(tk.x-x0)/60)*Math.min(1,(x1-tk.x)/40);
|
|
1114
|
+
var al=(tk.a+ .6*tk.lit)*edge;
|
|
1115
|
+
ctx.strokeStyle=rgba(tk.hue,al);ctx.lineWidth=1.4;
|
|
1116
|
+
ctx.beginPath();ctx.moveTo(tk.x,y-tk.h);ctx.lineTo(tk.x,y+tk.h*.5);ctx.stroke();
|
|
1117
|
+
if(tk.lit>.05){ctx.fillStyle=rgba(tk.hue,.16*tk.lit*edge);ctx.beginPath();ctx.arc(tk.x,y-tk.h*.3,8,0,7);ctx.fill();}}
|
|
1118
|
+
// replay head: a cyan cursor sweeps the laid-down history, re-lighting it
|
|
1119
|
+
if(!head&&s.t%420===200)head={x:x0};
|
|
1120
|
+
if(head){head.x+=(x1-x0)*.006;
|
|
1121
|
+
if(head.x>x1){head=null;}
|
|
1122
|
+
else{for(var j=0;j<ticks.length;j++){if(Math.abs(ticks[j].x-head.x)<4)ticks[j].lit=1;}
|
|
1123
|
+
var hg=ctx.createLinearGradient(head.x,y-s.H*0.22,head.x,y+s.H*0.1);hg.addColorStop(0,rgba(C.C2,0));hg.addColorStop(.5,rgba(C.C2,.5));hg.addColorStop(1,rgba(C.C2,0));
|
|
1124
|
+
ctx.strokeStyle=hg;ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(head.x,y-s.H*0.12);ctx.lineTo(head.x,y+s.H*0.07);ctx.stroke();
|
|
1125
|
+
ctx.fillStyle=rgba(C.C2,.8);ctx.beginPath();ctx.arc(head.x,y,2.2,0,7);ctx.fill();
|
|
1126
|
+
ctx.fillStyle=rgba(C.C2,.14);ctx.beginPath();ctx.arc(head.x,y,9,0,7);ctx.fill();}}
|
|
1127
|
+
}};
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// =========================================================
|
|
1131
|
+
// SCENE — SWARMER: THE DRONE OF DRONES
|
|
1132
|
+
// A commander drone holds a dashed patrol ring (the standing
|
|
1133
|
+
// order). Worker drones fly loose formation. Event pulses fly
|
|
1134
|
+
// IN from workers; the commander flares awake, banks, and
|
|
1135
|
+
// fires a vector beam back OUT (dispatch/steer/stop). Every
|
|
1136
|
+
// action drops a tick into the cnet strip along the bottom.
|
|
1137
|
+
// =========================================================
|
|
1138
|
+
function buildSwarmer(s,ctx,rgba,C){
|
|
1139
|
+
var cmd={x:0,y:0},workers=[],events=[],beams=[],ticks=[],wake=0;
|
|
1140
|
+
function setup(){cmd.x=s.W*0.32;cmd.y=s.H*0.44;workers=[];var N=9;
|
|
1141
|
+
for(var i=0;i<N;i++){var a=(i/N)*6.28;workers.push({a:a,r:s.W*0.16+Math.random()*s.W*0.14,w:.0015+Math.random()*.0025,ph:Math.random()*6.28,x:0,y:0});}}
|
|
1142
|
+
function wpos(w){var r=w.r+Math.sin(s.t*.01+w.ph)*14;return{x:cmd.x+Math.cos(w.a)*r*1.35,y:cmd.y+Math.sin(w.a)*r*.62};}
|
|
1143
|
+
return {resize:setup, draw:function(){
|
|
1144
|
+
s.dim(.3);
|
|
1145
|
+
var i,w,P;
|
|
1146
|
+
// cnet strip along the bottom
|
|
1147
|
+
var ry=s.H*0.88;
|
|
1148
|
+
ctx.strokeStyle=rgba(C.C2,.10);ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(s.W*0.06,ry);ctx.lineTo(s.W*0.94,ry);ctx.stroke();
|
|
1149
|
+
for(i=ticks.length-1;i>=0;i--){var tk=ticks[i];tk.x+=.55;tk.a*=.997;if(tk.x>s.W*0.94||tk.a<.03){ticks.splice(i,1);continue;}
|
|
1150
|
+
ctx.fillStyle=rgba(tk.hue,tk.a);ctx.fillRect(tk.x,ry-5,2,10);}
|
|
1151
|
+
// workers in formation
|
|
1152
|
+
for(i=0;i<workers.length;i++){w=workers[i];w.a+=w.w;P=wpos(w);w.x=P.x;w.y=P.y;
|
|
1153
|
+
var pl=.5+.5*Math.sin(s.t*.06+w.ph);
|
|
1154
|
+
ctx.fillStyle=rgba(C.C2,.5+.3*pl);ctx.beginPath();ctx.arc(P.x,P.y,2.1,0,7);ctx.fill();
|
|
1155
|
+
ctx.fillStyle=rgba(C.C2,.08);ctx.beginPath();ctx.arc(P.x,P.y,7,0,7);ctx.fill();
|
|
1156
|
+
// occasionally a worker emits an event pulse toward the commander
|
|
1157
|
+
if(Math.random()<.0035&&events.length<4)events.push({from:i,p:0});}
|
|
1158
|
+
// event pulses inbound
|
|
1159
|
+
for(i=events.length-1;i>=0;i--){var ev=events[i];ev.p+=.02;w=workers[ev.from];
|
|
1160
|
+
var ex=w.x+(cmd.x-w.x)*ev.p,ey=w.y+(cmd.y-w.y)*ev.p;
|
|
1161
|
+
if(ev.p>=1){events.splice(i,1);wake=1;
|
|
1162
|
+
beams.push({to:ev.from,p:0,hue:Math.random()<.25?C.MG:C.AC});
|
|
1163
|
+
ticks.push({x:s.W*0.06,a:.8,hue:C.C2});continue;}
|
|
1164
|
+
ctx.fillStyle=rgba(C.MG,.75*(1-ev.p*.4));ctx.beginPath();ctx.arc(ex,ey,1.8,0,7);ctx.fill();
|
|
1165
|
+
ctx.strokeStyle=rgba(C.MG,.16*(1-ev.p));ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(w.x,w.y);ctx.lineTo(ex,ey);ctx.stroke();}
|
|
1166
|
+
// verb beams outbound
|
|
1167
|
+
for(i=beams.length-1;i>=0;i--){var b=beams[i];b.p+=.028;w=workers[b.to];
|
|
1168
|
+
var bx=cmd.x+(w.x-cmd.x)*b.p,by=cmd.y+(w.y-cmd.y)*b.p;
|
|
1169
|
+
if(b.p>=1){beams.splice(i,1);ticks.push({x:s.W*0.06,a:.9,hue:b.hue});continue;}
|
|
1170
|
+
ctx.strokeStyle=rgba(b.hue,.4*(1-b.p*.5));ctx.lineWidth=1.4;ctx.beginPath();ctx.moveTo(cmd.x,cmd.y);ctx.lineTo(bx,by);ctx.stroke();
|
|
1171
|
+
ctx.fillStyle=rgba(b.hue,.9);ctx.beginPath();ctx.arc(bx,by,2.2,0,7);ctx.fill();}
|
|
1172
|
+
// commander: current-projection ring + operator-turn flare
|
|
1173
|
+
wake*=.94;
|
|
1174
|
+
ctx.save();ctx.translate(cmd.x,cmd.y);ctx.rotate(s.t*.003);
|
|
1175
|
+
ctx.setLineDash([3,12]);ctx.strokeStyle=rgba(C.AC,.22+.4*wake);ctx.lineWidth=1;ctx.beginPath();ctx.arc(0,0,34,0,7);ctx.stroke();ctx.setLineDash([]);ctx.restore();
|
|
1176
|
+
var gg=ctx.createRadialGradient(cmd.x,cmd.y,0,cmd.x,cmd.y,70);gg.addColorStop(0,rgba(C.AC,.4+.4*wake));gg.addColorStop(.5,rgba(C.AC,.1));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(cmd.x-70,cmd.y-70,140,140);
|
|
1177
|
+
// commander body: a quad glyph
|
|
1178
|
+
ctx.strokeStyle=rgba(C.AC,.9);ctx.lineWidth=1.4;
|
|
1179
|
+
ctx.beginPath();ctx.moveTo(cmd.x-7,cmd.y-7);ctx.lineTo(cmd.x+7,cmd.y+7);ctx.moveTo(cmd.x+7,cmd.y-7);ctx.lineTo(cmd.x-7,cmd.y+7);ctx.stroke();
|
|
1180
|
+
for(var q=0;q<4;q++){var qa=q*1.5708+.7854;ctx.beginPath();ctx.arc(cmd.x+Math.cos(qa)*9.9,cmd.y+Math.sin(qa)*9.9,2.6+wake*1.6,0,7);ctx.stroke();}
|
|
1181
|
+
}};
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// =========================================================
|
|
1185
|
+
// SCENE — HANGAR: SEALED BAYS
|
|
1186
|
+
// A grid of sealed bays, one drone patrolling inside each.
|
|
1187
|
+
// Walls flare when their drone approaches — nothing crosses.
|
|
1188
|
+
// Periodically a bay door opens, its drone launches out along
|
|
1189
|
+
// a lane (a sortie), the bay seals and respawns.
|
|
1190
|
+
// =========================================================
|
|
1191
|
+
function buildHangar(s,ctx,rgba,C){
|
|
1192
|
+
var bays=[],CO=3,RO=2;
|
|
1193
|
+
function setup(){bays=[];var gw=s.W*0.72,gh=s.H*0.62,x0=s.W*0.14,y0=s.H*0.16;
|
|
1194
|
+
for(var r=0;r<RO;r++)for(var c=0;c<CO;c++){var bw=gw/CO-18,bh=gh/RO-18;
|
|
1195
|
+
bays.push({x:x0+c*(gw/CO),y:y0+r*(gh/RO),w:bw,h:bh,dx:Math.random()*bw,dy:Math.random()*bh,vx:.6+Math.random()*.7,vy:.4+Math.random()*.6,flare:0,door:0,out:null,respawn:0});}}
|
|
1196
|
+
return {resize:setup, draw:function(){
|
|
1197
|
+
s.dim(.32);
|
|
1198
|
+
for(var i=0;i<bays.length;i++){var b=bays[i];
|
|
1199
|
+
// launch cycle: occasionally open the door and fly out
|
|
1200
|
+
if(!b.out&&b.respawn<=0&&Math.random()<.0009)b.out={p:0};
|
|
1201
|
+
if(b.respawn>0)b.respawn--;
|
|
1202
|
+
var doorT=b.out?Math.min(1,b.door+=.04):(b.door=Math.max(0,b.door-.05));
|
|
1203
|
+
// walls (door = gap in the right wall when open)
|
|
1204
|
+
b.flare*=.9;
|
|
1205
|
+
ctx.strokeStyle=rgba(C.AC,.14+.5*b.flare);ctx.lineWidth=1;
|
|
1206
|
+
ctx.beginPath();ctx.moveTo(b.x,b.y);ctx.lineTo(b.x+b.w,b.y);ctx.stroke();
|
|
1207
|
+
ctx.beginPath();ctx.moveTo(b.x,b.y+b.h);ctx.lineTo(b.x+b.w,b.y+b.h);ctx.stroke();
|
|
1208
|
+
ctx.beginPath();ctx.moveTo(b.x,b.y);ctx.lineTo(b.x,b.y+b.h);ctx.stroke();
|
|
1209
|
+
var gap=b.h*.5*doorT;
|
|
1210
|
+
ctx.beginPath();ctx.moveTo(b.x+b.w,b.y);ctx.lineTo(b.x+b.w,b.y+b.h/2-gap/2);ctx.moveTo(b.x+b.w,b.y+b.h/2+gap/2);ctx.lineTo(b.x+b.w,b.y+b.h);ctx.stroke();
|
|
1211
|
+
// corner rivets
|
|
1212
|
+
ctx.fillStyle=rgba(C.AC,.35);[[b.x,b.y],[b.x+b.w,b.y],[b.x,b.y+b.h],[b.x+b.w,b.y+b.h]].forEach(function(pt){ctx.fillRect(pt[0]-1.5,pt[1]-1.5,3,3);});
|
|
1213
|
+
if(b.out){ // sortie: fly out through the door and off-canvas
|
|
1214
|
+
b.out.p+=.012;var sx=b.x+b.dx,sy=b.y+b.dy,tx=s.W+40,ty=b.y+b.h/2;
|
|
1215
|
+
var ox=sx+(tx-sx)*b.out.p,oy=sy+(ty-sy)*Math.min(1,b.out.p*1.4);
|
|
1216
|
+
ctx.fillStyle=rgba(C.AC,.9);ctx.beginPath();ctx.arc(ox,oy,2.4,0,7);ctx.fill();
|
|
1217
|
+
ctx.strokeStyle=rgba(C.AC,.25);ctx.beginPath();ctx.moveTo(ox-16,oy);ctx.lineTo(ox,oy);ctx.stroke();
|
|
1218
|
+
if(b.out.p>=1){b.out=null;b.respawn=240;b.dx=b.w*.5;b.dy=b.h*.5;}
|
|
1219
|
+
continue;}
|
|
1220
|
+
if(b.respawn>0)continue; // bay resealing, empty
|
|
1221
|
+
// patrol inside; bounce off walls, flare them
|
|
1222
|
+
b.dx+=b.vx;b.dy+=b.vy;
|
|
1223
|
+
if(b.dx<8||b.dx>b.w-8){b.vx*=-1;b.flare=1;}
|
|
1224
|
+
if(b.dy<8||b.dy>b.h-8){b.vy*=-1;b.flare=1;}
|
|
1225
|
+
var px=b.x+Math.max(4,Math.min(b.w-4,b.dx)),py=b.y+Math.max(4,Math.min(b.h-4,b.dy));
|
|
1226
|
+
ctx.fillStyle=rgba(C.C2,.75);ctx.beginPath();ctx.arc(px,py,2,0,7);ctx.fill();
|
|
1227
|
+
ctx.fillStyle=rgba(C.C2,.09);ctx.beginPath();ctx.arc(px,py,8,0,7);ctx.fill();}
|
|
1228
|
+
}};
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
// =========================================================
|
|
1232
|
+
// SCENE — STRIKELOOP: RECON -> SORTIE -> ASSESS
|
|
1233
|
+
// A drone flies a holding ellipse left of a gate arch. Each
|
|
1234
|
+
// pass it fires a push-packet at the gate; early passes the
|
|
1235
|
+
// gate flashes a finding (magenta) back; final pass clears
|
|
1236
|
+
// green and the drone exits THROUGH the gate in a hard line.
|
|
1237
|
+
// =========================================================
|
|
1238
|
+
function buildStrikeloop(s,ctx,rgba,C){
|
|
1239
|
+
var orbit={a:0},pass=0,packet=null,verdict=0,exit=null,gx,gy,gh2;
|
|
1240
|
+
function setup(){gx=s.W*0.72;gy=s.H*0.5;gh2=s.H*0.22;pass=0;packet=null;exit=null;}
|
|
1241
|
+
function dpos(){var cx=s.W*0.30,cy=s.H*0.5;return{x:cx+Math.cos(orbit.a)*s.W*0.13,y:cy+Math.sin(orbit.a)*s.H*0.2};}
|
|
1242
|
+
return {resize:setup, draw:function(){
|
|
1243
|
+
s.dim(.3);
|
|
1244
|
+
verdict*=.95;
|
|
1245
|
+
// gate arch
|
|
1246
|
+
var cleared=pass>=3;
|
|
1247
|
+
var hue=verdict>0.05?(cleared?C.AC:C.MG):C.AC;
|
|
1248
|
+
ctx.strokeStyle=rgba(hue,.35+.5*verdict);ctx.lineWidth=1.6;
|
|
1249
|
+
ctx.beginPath();ctx.moveTo(gx,gy-gh2);ctx.lineTo(gx,gy+gh2);ctx.stroke();
|
|
1250
|
+
ctx.strokeStyle=rgba(hue,.18+.3*verdict);
|
|
1251
|
+
ctx.beginPath();ctx.moveTo(gx+14,gy-gh2);ctx.lineTo(gx+14,gy+gh2);ctx.stroke();
|
|
1252
|
+
ctx.fillStyle=rgba(hue,.5+.4*verdict);ctx.beginPath();ctx.arc(gx,gy-gh2,2.5,0,7);ctx.fill();ctx.beginPath();ctx.arc(gx,gy+gh2,2.5,0,7);ctx.fill();
|
|
1253
|
+
if(exit){ // cleared: hard line through the gate and off
|
|
1254
|
+
exit.x+=7;
|
|
1255
|
+
ctx.fillStyle=rgba(C.AC,.95);ctx.beginPath();ctx.arc(exit.x,gy,3,0,7);ctx.fill();
|
|
1256
|
+
ctx.strokeStyle=rgba(C.AC,.4);ctx.lineWidth=1.6;ctx.beginPath();ctx.moveTo(exit.x-34,gy);ctx.lineTo(exit.x,gy);ctx.stroke();
|
|
1257
|
+
if(exit.x>s.W+40){exit=null;pass=0;}
|
|
1258
|
+
return;}
|
|
1259
|
+
// holding pattern
|
|
1260
|
+
orbit.a+=.016;var D=dpos();
|
|
1261
|
+
ctx.strokeStyle=rgba(C.C2,.08);ctx.lineWidth=1;ctx.beginPath();
|
|
1262
|
+
for(var q=0;q<=40;q++){var qa=(q/40)*6.28;var qx=s.W*0.30+Math.cos(qa)*s.W*0.13,qy=s.H*0.5+Math.sin(qa)*s.H*0.2;q===0?ctx.moveTo(qx,qy):ctx.lineTo(qx,qy);}ctx.stroke();
|
|
1263
|
+
ctx.fillStyle=rgba(C.AC,.9);ctx.beginPath();ctx.arc(D.x,D.y,2.6,0,7);ctx.fill();
|
|
1264
|
+
ctx.fillStyle=rgba(C.AC,.1);ctx.beginPath();ctx.arc(D.x,D.y,9,0,7);ctx.fill();
|
|
1265
|
+
// fire a push-packet once per pass (when crossing rightmost point)
|
|
1266
|
+
if(!packet&&Math.cos(orbit.a)>0.996)packet={x:D.x,y:D.y,ret:false};
|
|
1267
|
+
if(packet){
|
|
1268
|
+
if(!packet.ret){packet.x+=5.2;packet.y+=(gy-packet.y)*.06;
|
|
1269
|
+
ctx.fillStyle=rgba(C.AC,.85);ctx.beginPath();ctx.arc(packet.x,packet.y,2,0,7);ctx.fill();
|
|
1270
|
+
if(packet.x>=gx){pass++;verdict=1;
|
|
1271
|
+
if(pass>=3){packet=null;exit={x:gx};}
|
|
1272
|
+
else packet.ret=true;}}
|
|
1273
|
+
else{packet.x-=4.4;packet.y+=(D.y-packet.y)*.08; // finding flies back
|
|
1274
|
+
ctx.fillStyle=rgba(C.MG,.85);ctx.beginPath();ctx.arc(packet.x,packet.y,2,0,7);ctx.fill();
|
|
1275
|
+
ctx.strokeStyle=rgba(C.MG,.15);ctx.beginPath();ctx.moveTo(packet.x,packet.y);ctx.lineTo(packet.x+14,packet.y);ctx.stroke();
|
|
1276
|
+
if(packet.x<=D.x+8)packet=null;}}
|
|
1277
|
+
}};
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// =========================================================
|
|
1281
|
+
// SCENE — FORGE: SOURCE -> ONE BINARY -> HARDLINKED WING
|
|
1282
|
+
// Source motes (cyan) get drawn into a forge point; it pulses
|
|
1283
|
+
// and a bright bar (the binary) charges; at full charge it
|
|
1284
|
+
// stamps a wing of hardlinked drones that lift off rightward.
|
|
1285
|
+
// =========================================================
|
|
1286
|
+
function buildForge(s,ctx,rgba,C){
|
|
1287
|
+
var motes=[],charge=0,fleet=[],fx,fy;
|
|
1288
|
+
function setup(){fx=s.W*0.38;fy=s.H*0.5;motes=[];for(var i=0;i<70;i++)motes.push(mk());fleet=[];charge=0;}
|
|
1289
|
+
function mk(){var a=Math.random()*6.28,r=s.W*(0.18+Math.random()*0.22);return{x:fx+Math.cos(a)*r,y:fy+Math.sin(a)*r*.6,sp:.006+Math.random()*.012};}
|
|
1290
|
+
return {resize:setup, draw:function(){
|
|
1291
|
+
s.dim(.3);
|
|
1292
|
+
// source motes spiral into the forge
|
|
1293
|
+
for(var i=0;i<motes.length;i++){var m=motes[i];
|
|
1294
|
+
m.x+=(fx-m.x)*m.sp;m.y+=(fy-m.y)*m.sp;
|
|
1295
|
+
var d=Math.hypot(m.x-fx,m.y-fy);
|
|
1296
|
+
if(d<6){charge=Math.min(1,charge+.012);motes[i]=mk();continue;}
|
|
1297
|
+
ctx.fillStyle=rgba(C.C2,.5);ctx.beginPath();ctx.arc(m.x,m.y,1.3,0,7);ctx.fill();}
|
|
1298
|
+
// the binary bar charging
|
|
1299
|
+
var bw=90,bh=10;
|
|
1300
|
+
ctx.strokeStyle=rgba(C.AC,.4);ctx.lineWidth=1;ctx.strokeRect(fx-bw/2,fy-bh/2,bw,bh);
|
|
1301
|
+
ctx.fillStyle=rgba(C.AC,.25+.55*charge);ctx.fillRect(fx-bw/2+1,fy-bh/2+1,(bw-2)*charge,bh-2);
|
|
1302
|
+
var gg=ctx.createRadialGradient(fx,fy,0,fx,fy,80+60*charge);gg.addColorStop(0,rgba(C.AC,.25+.35*charge));gg.addColorStop(1,rgba(C.AC,0));ctx.fillStyle=gg;ctx.fillRect(fx-140,fy-140,280,280);
|
|
1303
|
+
// at full charge: stamp a wing of hardlinks
|
|
1304
|
+
if(charge>=1){charge=0;for(var k=0;k<5;k++)fleet.push({x:fx+bw/2,y:fy,ty:s.H*(0.2+0.15*k),p:0});}
|
|
1305
|
+
for(var f=fleet.length-1;f>=0;f--){var fl=fleet[f];fl.p+=.008;
|
|
1306
|
+
fl.x+=3.2;fl.y+=(fl.ty-fl.y)*.04;
|
|
1307
|
+
if(fl.x>s.W+30){fleet.splice(f,1);continue;}
|
|
1308
|
+
ctx.fillStyle=rgba(C.AC,.85);ctx.beginPath();ctx.arc(fl.x,fl.y,2.2,0,7);ctx.fill();
|
|
1309
|
+
ctx.strokeStyle=rgba(C.AC,.2);ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(fl.x-18,fl.y);ctx.lineTo(fl.x,fl.y);ctx.stroke();}
|
|
1310
|
+
}};
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// =========================================================
|
|
1314
|
+
// SCENE — NIGHTSHIFT: moon crosses; sorties arc up off the
|
|
1315
|
+
// horizon and land back as green merge checkmarks by morning.
|
|
1316
|
+
// =========================================================
|
|
1317
|
+
function buildNightshift(s,ctx,rgba,C){
|
|
1318
|
+
var t=0,sorties=[],stamps=[];
|
|
1319
|
+
function setup(){t=0;sorties=[];stamps=[];}
|
|
1320
|
+
return {resize:setup, draw:function(){
|
|
1321
|
+
s.dim(.3);t+=.0022;var prog=t%1;
|
|
1322
|
+
var hy=s.H*0.72;
|
|
1323
|
+
ctx.strokeStyle=rgba(C.C2,.14);ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(s.W*0.08,hy);ctx.lineTo(s.W*0.92,hy);ctx.stroke();
|
|
1324
|
+
var ma=Math.PI*(1-prog),mx=s.W*0.5+Math.cos(ma)*s.W*0.38,my=hy-Math.sin(ma)*s.H*0.42;
|
|
1325
|
+
ctx.fillStyle=rgba(C.C2,.65);ctx.beginPath();ctx.arc(mx,my,3.6,0,7);ctx.fill();
|
|
1326
|
+
ctx.fillStyle=rgba(C.C2,.07);ctx.beginPath();ctx.arc(mx,my,14,0,7);ctx.fill();
|
|
1327
|
+
if(Math.random()<.018&&sorties.length<6)sorties.push({x:s.W*(0.14+Math.random()*0.64),y:hy,vy:-(1.5+Math.random()*.8),age:0});
|
|
1328
|
+
for(var i=sorties.length-1;i>=0;i--){var o=sorties[i];o.age+=.01;o.y+=o.vy;o.vy+=.017;
|
|
1329
|
+
if(o.y>=hy&&o.age>.25){sorties.splice(i,1);stamps.push({x:o.x,a:1});if(stamps.length>14)stamps.shift();continue;}
|
|
1330
|
+
ctx.fillStyle=rgba(C.AC,.85);ctx.beginPath();ctx.arc(o.x,o.y,1.9,0,7);ctx.fill();
|
|
1331
|
+
ctx.strokeStyle=rgba(C.AC,.14);ctx.beginPath();ctx.moveTo(o.x,o.y);ctx.lineTo(o.x,Math.min(hy,o.y+16));ctx.stroke();}
|
|
1332
|
+
for(var k=0;k<stamps.length;k++){var st=stamps[k];st.a=Math.max(.35,st.a*.997);
|
|
1333
|
+
ctx.strokeStyle=rgba(C.AC,.2+.6*st.a);ctx.lineWidth=1.6;
|
|
1334
|
+
ctx.beginPath();ctx.moveTo(st.x-4,hy+9);ctx.lineTo(st.x-1,hy+13);ctx.lineTo(st.x+5,hy+4);ctx.stroke();}
|
|
1335
|
+
}};
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
// =========================================================
|
|
1339
|
+
// SCENE — PLANSPLIT: a PRD block feeds a dependency DAG;
|
|
1340
|
+
// ready nodes complete in waves, unlocking their children.
|
|
1341
|
+
// =========================================================
|
|
1342
|
+
function buildPlansplit(s,ctx,rgba,C){
|
|
1343
|
+
var nodes=[],links=[],t=0,hold=0;
|
|
1344
|
+
function setup(){nodes=[];links=[];t=0;hold=0;
|
|
1345
|
+
for(var c=0;c<4;c++){var n=2+((c*5+1)%3);
|
|
1346
|
+
for(var r=0;r<n;r++)nodes.push({c:c,i:r,n:n,done:0});}
|
|
1347
|
+
for(var k=0;k<nodes.length;k++){var b=nodes[k];if(b.c===0)continue;
|
|
1348
|
+
var prevs=nodes.filter(function(m){return m.c===b.c-1;});
|
|
1349
|
+
links.push({a:prevs[k%prevs.length],b:b});}}
|
|
1350
|
+
function pos(nd){return{x:s.W*(0.24+nd.c*0.19),y:s.H*(0.5+(nd.i-(nd.n-1)/2)*0.19)};}
|
|
1351
|
+
return {resize:setup, draw:function(){
|
|
1352
|
+
s.dim(.3);t+=.016;
|
|
1353
|
+
var px=s.W*0.08,py=s.H*0.5;
|
|
1354
|
+
ctx.strokeStyle=rgba(C.C2,.4);ctx.lineWidth=1.2;ctx.strokeRect(px-13,py-19,26,38);
|
|
1355
|
+
ctx.fillStyle=rgba(C.C2,.18);for(var q=0;q<4;q++)ctx.fillRect(px-8,py-13+q*9,16,2);
|
|
1356
|
+
if(nodes.every(function(n){return n.done>=1;})){hold+=.016;if(hold>1.6){nodes.forEach(function(n){n.done=0;});hold=0;}}
|
|
1357
|
+
nodes.forEach(function(nd){
|
|
1358
|
+
var parents=links.filter(function(l){return l.b===nd;}).map(function(l){return l.a;});
|
|
1359
|
+
var gate=parents.length?Math.min.apply(null,parents.map(function(p){return p.done;})):1;
|
|
1360
|
+
if(gate>=1)nd.done=Math.min(1,nd.done+.005);});
|
|
1361
|
+
ctx.strokeStyle=rgba(C.C2,.25);ctx.beginPath();ctx.moveTo(px+13,py);ctx.lineTo(pos(nodes[0]).x-7,pos(nodes[0]).y);ctx.stroke();
|
|
1362
|
+
links.forEach(function(l){var A=pos(l.a),B=pos(l.b);
|
|
1363
|
+
ctx.strokeStyle=rgba(l.a.done>=1?C.AC:C.C2,l.a.done>=1?.3:.1);ctx.lineWidth=1;
|
|
1364
|
+
ctx.beginPath();ctx.moveTo(A.x,A.y);ctx.lineTo(B.x,B.y);ctx.stroke();});
|
|
1365
|
+
nodes.forEach(function(nd){var P=pos(nd);var active=nd.done>0&&nd.done<1;
|
|
1366
|
+
ctx.fillStyle=rgba(nd.done>0?C.AC:C.C2,nd.done>=1?.85:(active?.7:.3));
|
|
1367
|
+
ctx.beginPath();ctx.arc(P.x,P.y,active?3.1:2.3,0,7);ctx.fill();
|
|
1368
|
+
if(active){ctx.strokeStyle=rgba(C.AC,.25);ctx.beginPath();ctx.arc(P.x,P.y,6.5+2.5*Math.sin(t*5),0,7);ctx.stroke();}});
|
|
1369
|
+
}};
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
// =========================================================
|
|
1373
|
+
// SCENE — SCRAMBLE: one binary block hardlinks parts into a
|
|
1374
|
+
// bay in fast bursts; the armed drone lifts off; next bay.
|
|
1375
|
+
// =========================================================
|
|
1376
|
+
function buildScramble(s,ctx,rgba,C){
|
|
1377
|
+
var t=0,slot=0,fill=0,links=[],lift=null;
|
|
1378
|
+
function setup(){t=0;slot=0;fill=0;links=[];lift=null;}
|
|
1379
|
+
return {resize:setup, draw:function(){
|
|
1380
|
+
s.dim(.3);t+=.016;
|
|
1381
|
+
var bx=s.W*0.22,by=s.H*0.5;
|
|
1382
|
+
ctx.strokeStyle=rgba(C.AC,.5);ctx.lineWidth=1.4;ctx.strokeRect(bx-32,by-11,64,22);
|
|
1383
|
+
ctx.fillStyle=rgba(C.AC,.28);ctx.fillRect(bx-30,by-9,60,18);
|
|
1384
|
+
var gx=s.W*(0.62),gy=s.H*(0.3+0.2*slot);
|
|
1385
|
+
if(!lift){
|
|
1386
|
+
if(Math.random()<.3&&links.length<3&&fill<5)links.push({p:0,tx:gx-18+9*fill,ty:gy});
|
|
1387
|
+
for(var i=links.length-1;i>=0;i--){var L=links[i];L.p+=.09;
|
|
1388
|
+
var lx=bx+32+(L.tx-bx-32)*L.p,ly=by+(L.ty-by)*L.p;
|
|
1389
|
+
ctx.strokeStyle=rgba(C.C2,.5*(1-L.p)+.1);ctx.lineWidth=1;
|
|
1390
|
+
ctx.beginPath();ctx.moveTo(bx+32,by);ctx.lineTo(lx,ly);ctx.stroke();
|
|
1391
|
+
ctx.fillStyle=rgba(C.C2,.8);ctx.beginPath();ctx.arc(lx,ly,1.8,0,7);ctx.fill();
|
|
1392
|
+
if(L.p>=1){links.splice(i,1);fill++;}}
|
|
1393
|
+
for(var f=0;f<fill;f++){ctx.fillStyle=rgba(C.AC,.7);ctx.fillRect(gx-20+9*f,gy-3,6,6);}
|
|
1394
|
+
ctx.strokeStyle=rgba(C.C2,.25);ctx.strokeRect(gx-24,gy-8,52,16);
|
|
1395
|
+
if(fill>=5){lift={x:gx,y:gy};fill=0;links=[];}
|
|
1396
|
+
} else {
|
|
1397
|
+
lift.x+=4.2;lift.y-=1.3;
|
|
1398
|
+
ctx.fillStyle=rgba(C.AC,.9);ctx.beginPath();ctx.arc(lift.x,lift.y,2.4,0,7);ctx.fill();
|
|
1399
|
+
ctx.strokeStyle=rgba(C.AC,.25);ctx.beginPath();ctx.moveTo(lift.x-20,lift.y+7);ctx.lineTo(lift.x,lift.y);ctx.stroke();
|
|
1400
|
+
if(lift.x>s.W+30){lift=null;slot=(slot+1)%3;}}
|
|
1401
|
+
}};
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
// =========================================================
|
|
1405
|
+
// SCENE — CIPHER: host -> relay -> guest. Packets leave the
|
|
1406
|
+
// host green, turn to magenta noise inside the relay band,
|
|
1407
|
+
// and clear green again at the guest. Keys stay at the ends.
|
|
1408
|
+
// =========================================================
|
|
1409
|
+
function buildCipher(s,ctx,rgba,C){
|
|
1410
|
+
var pk=[],t=0;
|
|
1411
|
+
function setup(){pk=[];t=0;}
|
|
1412
|
+
function key(x,y){ctx.strokeStyle=rgba(C.AC,.7);ctx.lineWidth=1.4;
|
|
1413
|
+
ctx.beginPath();ctx.arc(x,y,3.4,0,7);ctx.stroke();
|
|
1414
|
+
ctx.beginPath();ctx.moveTo(x+3.4,y);ctx.lineTo(x+11,y);ctx.moveTo(x+8,y);ctx.lineTo(x+8,y+4);ctx.stroke();}
|
|
1415
|
+
return {resize:setup, draw:function(){
|
|
1416
|
+
s.dim(.3);t+=.016;
|
|
1417
|
+
var hx=s.W*0.16,gx2=s.W*0.84,cy=s.H*0.5,r1=s.W*0.42,r2=s.W*0.58;
|
|
1418
|
+
ctx.strokeStyle=rgba(C.MG,.28);ctx.lineWidth=1;
|
|
1419
|
+
ctx.strokeRect(r1,cy-s.H*0.26,r2-r1,s.H*0.52);
|
|
1420
|
+
ctx.fillStyle=rgba(C.MG,.05);ctx.fillRect(r1,cy-s.H*0.26,r2-r1,s.H*0.52);
|
|
1421
|
+
ctx.strokeStyle=rgba(C.C2,.4);ctx.strokeRect(hx-16,cy-22,32,44);
|
|
1422
|
+
ctx.strokeRect(gx2-16,cy-22,32,44);
|
|
1423
|
+
key(hx-4,cy+34);key(gx2-4,cy+34);
|
|
1424
|
+
if(Math.random()<.06)pk.push({x:hx+16,y:cy-14+Math.random()*28,v:2.2+Math.random()});
|
|
1425
|
+
if(Math.random()<.03)pk.push({x:gx2-16,y:cy-14+Math.random()*28,v:-(2.2+Math.random())});
|
|
1426
|
+
for(var i=pk.length-1;i>=0;i--){var p=pk[i];p.x+=p.v;
|
|
1427
|
+
if(p.x>s.W||p.x<0){pk.splice(i,1);continue;}
|
|
1428
|
+
var inRelay=p.x>r1&&p.x<r2;
|
|
1429
|
+
if(inRelay){ctx.fillStyle=rgba(C.MG,.7);
|
|
1430
|
+
ctx.fillRect(p.x-2+(Math.random()*2-1),p.y-2+(Math.random()*2-1),4,4);}
|
|
1431
|
+
else{ctx.fillStyle=rgba(C.AC,.8);ctx.beginPath();ctx.arc(p.x,p.y,1.9,0,7);ctx.fill();}}
|
|
1432
|
+
}};
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
// =========================================================
|
|
1436
|
+
// SCENE — ARSENAL: three racks of slots; a scanline sweeps
|
|
1437
|
+
// and arms each slot green; racks cycle like an ordnance check.
|
|
1438
|
+
// =========================================================
|
|
1439
|
+
function buildArsenal(s,ctx,rgba,C){
|
|
1440
|
+
var t=0;
|
|
1441
|
+
function setup(){t=0;}
|
|
1442
|
+
return {resize:setup, draw:function(){
|
|
1443
|
+
s.dim(.3);t+=.016;
|
|
1444
|
+
var racks=3,slots=6,sweep=(t*.35)%(racks+0.6);
|
|
1445
|
+
for(var r=0;r<racks;r++){
|
|
1446
|
+
var rx=s.W*(0.25+r*0.25),top=s.H*0.24,bh=s.H*0.52;
|
|
1447
|
+
ctx.strokeStyle=rgba(C.C2,.25);ctx.lineWidth=1;
|
|
1448
|
+
ctx.strokeRect(rx-30,top,60,bh);
|
|
1449
|
+
for(var k=0;k<slots;k++){var sy=top+bh*(k+0.5)/slots;
|
|
1450
|
+
var armed=sweep>r+(k/slots)*0.9;
|
|
1451
|
+
ctx.fillStyle=rgba(armed?C.AC:C.C2,armed?.75:.18);
|
|
1452
|
+
ctx.fillRect(rx-22,sy-3,44,6);
|
|
1453
|
+
if(armed){ctx.fillStyle=rgba(C.AC,.9);ctx.beginPath();ctx.arc(rx+28,sy,1.6,0,7);ctx.fill();}}}
|
|
1454
|
+
var lx=s.W*(0.25+((sweep%1))*0.5);
|
|
1455
|
+
ctx.strokeStyle=rgba(C.AC,.12);ctx.beginPath();ctx.moveTo(lx,s.H*0.2);ctx.lineTo(lx,s.H*0.8);ctx.stroke();
|
|
1456
|
+
}};
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
// =========================================================
|
|
1460
|
+
// SCENE — IRCNET: callsigns on a ring; DMs travel chords in
|
|
1461
|
+
// both directions; broadcasts pulse to everyone; a parked
|
|
1462
|
+
// (dim) node that receives a packet lights up — revived.
|
|
1463
|
+
// =========================================================
|
|
1464
|
+
function buildIrcnet(s,ctx,rgba,C){
|
|
1465
|
+
var N=7,peers=[],pk=[],pulse=null,t=0;
|
|
1466
|
+
function setup(){t=0;pk=[];pulse=null;peers=[];
|
|
1467
|
+
for(var i=0;i<N;i++)peers.push({a:(i/N)*6.28-1.57,parked:i===4,glow:0});}
|
|
1468
|
+
function pos(p){return{x:s.W*0.5+Math.cos(p.a)*s.W*0.26,y:s.H*0.5+Math.sin(p.a)*s.H*0.3};}
|
|
1469
|
+
return {resize:setup, draw:function(){
|
|
1470
|
+
s.dim(.3);t+=.016;
|
|
1471
|
+
// ring
|
|
1472
|
+
ctx.strokeStyle=rgba(C.C2,.07);ctx.lineWidth=1;ctx.beginPath();
|
|
1473
|
+
for(var q=0;q<=48;q++){var qa=(q/48)*6.28;var qx=s.W*0.5+Math.cos(qa)*s.W*0.26,qy=s.H*0.5+Math.sin(qa)*s.H*0.3;q===0?ctx.moveTo(qx,qy):ctx.lineTo(qx,qy);}ctx.stroke();
|
|
1474
|
+
// peers
|
|
1475
|
+
peers.forEach(function(p,i){var P=pos(p);p.glow*=.94;
|
|
1476
|
+
var live=!p.parked||p.glow>.2;
|
|
1477
|
+
ctx.fillStyle=rgba(live?C.AC:C.C2,live?.5+.5*Math.min(1,p.glow+.4):.18);
|
|
1478
|
+
ctx.beginPath();ctx.arc(P.x,P.y,live?3:2.4,0,7);ctx.fill();
|
|
1479
|
+
if(p.glow>.05){ctx.strokeStyle=rgba(C.AC,.3*p.glow);ctx.beginPath();ctx.arc(P.x,P.y,8+6*(1-p.glow),0,7);ctx.stroke();}});
|
|
1480
|
+
// random DM chords
|
|
1481
|
+
if(Math.random()<.045&&pk.length<5){var a=Math.floor(Math.random()*N),b=Math.floor(Math.random()*N);
|
|
1482
|
+
if(a!==b)pk.push({f:a,to:b,p:0});}
|
|
1483
|
+
for(var i=pk.length-1;i>=0;i--){var m=pk[i];m.p+=.03;
|
|
1484
|
+
var A=pos(peers[m.f]),B=pos(peers[m.to]);
|
|
1485
|
+
var mx=A.x+(B.x-A.x)*m.p,my=A.y+(B.y-A.y)*m.p;
|
|
1486
|
+
ctx.strokeStyle=rgba(C.C2,.10);ctx.beginPath();ctx.moveTo(A.x,A.y);ctx.lineTo(B.x,B.y);ctx.stroke();
|
|
1487
|
+
ctx.fillStyle=rgba(C.AC,.85);ctx.beginPath();ctx.arc(mx,my,1.8,0,7);ctx.fill();
|
|
1488
|
+
if(m.p>=1){peers[m.to].glow=1;if(peers[m.to].parked&&Math.random()<.5)peers[m.to].parked=false;pk.splice(i,1);}}
|
|
1489
|
+
// occasional broadcast pulse
|
|
1490
|
+
if(!pulse&&Math.random()<.006)pulse={src:Math.floor(Math.random()*N),r:0};
|
|
1491
|
+
if(pulse){pulse.r+=4.5;var S=pos(peers[pulse.src]);
|
|
1492
|
+
ctx.strokeStyle=rgba(C.AC,Math.max(0,.4-pulse.r/(s.W*0.9)));ctx.lineWidth=1.4;
|
|
1493
|
+
ctx.beginPath();ctx.arc(S.x,S.y,pulse.r,0,7);ctx.stroke();
|
|
1494
|
+
peers.forEach(function(p){var P=pos(p);if(Math.abs(Math.hypot(P.x-S.x,P.y-S.y)-pulse.r)<5)p.glow=1;});
|
|
1495
|
+
if(pulse.r>s.W*0.6)pulse=null;}
|
|
1496
|
+
// re-park one node occasionally so the revive story loops
|
|
1497
|
+
if(Math.random()<.002){var idx=1+Math.floor(Math.random()*(N-1));peers[idx].parked=true;}
|
|
1498
|
+
}};
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
var BUILDERS={dispatch:buildDispatch,cnet:buildCNet,harness:buildHarness,lanes:buildLanes,engine:buildEngine,converge:buildConverge,relay:buildRelay,gatewall:buildGatewall,heal:buildHeal,ouro:buildOuro,triad:buildTriad,carrier:buildCarrier,swap:buildSwap,surfaces:buildSurfaces,journal:buildJournal,swarmer:buildSwarmer,hangar:buildHangar,strikeloop:buildStrikeloop,forge:buildForge,nightshift:buildNightshift,plansplit:buildPlansplit,scramble:buildScramble,cipher:buildCipher,arsenal:buildArsenal,ircnet:buildIrcnet};
|
|
1502
|
+
|
|
1503
|
+
// ---- wire up: build a Scene per canvas, run only when on-screen ----
|
|
1504
|
+
var scenes=[];
|
|
1505
|
+
document.querySelectorAll('canvas.scene').forEach(function(cv){
|
|
1506
|
+
var kind=cv.getAttribute('data-scene');var b=BUILDERS[kind];if(!b)return;
|
|
1507
|
+
var sc=Scene(cv,b);scenes.push({cv:cv,sc:sc});
|
|
1508
|
+
});
|
|
1509
|
+
// start every scene immediately (lightweight 2D); IO only pauses fully-offscreen ones for perf
|
|
1510
|
+
scenes.forEach(function(s){s.sc.start();});
|
|
1511
|
+
if('IntersectionObserver' in window){
|
|
1512
|
+
var io=new IntersectionObserver(function(es){es.forEach(function(e){var s=scenes.find(function(x){return x.cv===e.target;});if(!s)return;if(e.isIntersecting)s.sc.start();else s.sc.stop();});},{rootMargin:'200px',threshold:0});
|
|
1513
|
+
scenes.forEach(function(s){io.observe(s.cv);});
|
|
1514
|
+
}
|
|
1515
|
+
})();
|
|
1516
|
+
|
|
1517
|
+
/* ===== HERO ASCII DRONE FLEET (grid compositor — lead drone + a squad) =====
|
|
1518
|
+
One blank char-grid per frame; each drone is STAMPED at an offset with its
|
|
1519
|
+
own bob/drift phase, then the whole grid is colorized. The !!! (rotor) and ?
|
|
1520
|
+
(eye) tokens survive stamping as literal chars, so a single per-line token
|
|
1521
|
+
pass animates every drone. Minis use dimmer glyphs (%,=,(,)) -> depth. */
|
|
1522
|
+
(function(){
|
|
1523
|
+
var el=document.getElementById('cine');if(!el)return;
|
|
1524
|
+
el.classList.add('mascot');
|
|
1525
|
+
// lead drone — bright body ($ @), big quad-rotor frame
|
|
1526
|
+
var ART=[" .-=-. .-=-. ", " ( !!! ) ( !!! ) ", " '-=-'._ _.'-=-' ", " '._ _.' ", " '=$$$$$$$=.' ", " =$$$$$$$$$$$= ", " $$$@@@@@@@@@@$$$ ", " $$$@@ @@$$$ ", " $$@ ? @$$$ ", " $$$@ '-' @$$$ ", " $$$@@ @@$$$ ", " $$$@@@@@@@@@@$$$ ", " =$$$$$$$$$$$= ", " '=$$$$$$$=.' ", " _.' '._ ", " .-=-.' '.-=-. ", " ( !!! ) ( !!! ) ", " '-=-' '-=-' "];
|
|
1527
|
+
// companion drone — dim body (% =), compact quad
|
|
1528
|
+
var MINI=["(!!!) (!!!)", " \\%==%/ ", " %%?%% ", " /%==%\\ ", "(!!!) (!!!)"];
|
|
1529
|
+
var BL=['---','\\\\\\','|||','///'];
|
|
1530
|
+
var GW=52,GH=27;
|
|
1531
|
+
// fleet: lead centered, four companions clustered tight at its corners
|
|
1532
|
+
var FLEET=[
|
|
1533
|
+
{s:MINI,x:0, y:2, amp:1,sp:0.050,ph:0.0, dx:1,dsp:0.020},
|
|
1534
|
+
{s:MINI,x:39, y:2, amp:1,sp:0.044,ph:2.1, dx:1,dsp:0.017},
|
|
1535
|
+
{s:MINI,x:1, y:20, amp:1,sp:0.048,ph:4.2, dx:1,dsp:0.023},
|
|
1536
|
+
{s:MINI,x:38, y:20, amp:1,sp:0.041,ph:1.3, dx:1,dsp:0.015},
|
|
1537
|
+
{s:ART, x:10, y:5, amp:2,sp:0.040,ph:0.0, dx:0,dsp:0.011}
|
|
1538
|
+
];
|
|
1539
|
+
var t=0,phase=0;
|
|
1540
|
+
function esc(c){return c==='&'?'&':c==='<'?'<':c==='>'?'>':c;}
|
|
1541
|
+
function cls(ch){
|
|
1542
|
+
if(ch==='$'||ch==='@')return 'd';
|
|
1543
|
+
if(ch==='='||ch==='%')return 'm';
|
|
1544
|
+
if(ch==='\\'||ch==='/')return 'r';
|
|
1545
|
+
if(ch==='('||ch===')'||ch==='-'||ch==='|'||ch==="'"||ch==='.')return 'c';
|
|
1546
|
+
return 'b';
|
|
1547
|
+
}
|
|
1548
|
+
function paint(s){var html='',run='',rc='';for(var j=0;j<s.length;j++){var ch=s[j],c=cls(ch);if(c===rc)run+=esc(ch);else{if(run)html+='<span class="g-'+rc+'">'+run+'</span>';run=esc(ch);rc=c;}}if(run)html+='<span class="g-'+rc+'">'+run+'</span>';return html;}
|
|
1549
|
+
function frame(){
|
|
1550
|
+
t++; if(t%4===0)phase++;
|
|
1551
|
+
var blade=BL[phase%4];
|
|
1552
|
+
var p=Math.sin(t*0.07);
|
|
1553
|
+
var core=p>0.45?'@':(p>-0.1?'o':'.');
|
|
1554
|
+
// blank grid
|
|
1555
|
+
var grid=[];for(var r=0;r<GH;r++){var row=[];for(var c=0;c<GW;c++)row.push(' ');grid.push(row);}
|
|
1556
|
+
// stamp each drone (companions first, lead last so it sits in front)
|
|
1557
|
+
for(var f=0;f<FLEET.length;f++){var d=FLEET[f];
|
|
1558
|
+
var oy=d.y+Math.round(d.amp*Math.sin(t*d.sp+d.ph));
|
|
1559
|
+
var ox=d.x+Math.round(d.dx*Math.sin(t*d.dsp+d.ph));
|
|
1560
|
+
for(var i=0;i<d.s.length;i++){var ln=d.s[i],ry=oy+i;if(ry<0||ry>=GH)continue;
|
|
1561
|
+
for(var j=0;j<ln.length;j++){var ch=ln[j];if(ch===' ')continue;var rx=ox+j;if(rx<0||rx>=GW)continue;grid[ry][rx]=ch;}}
|
|
1562
|
+
}
|
|
1563
|
+
// colorize grid line by line (same token pass as the single-drone build)
|
|
1564
|
+
var out=[];
|
|
1565
|
+
for(var r=0;r<GH;r++){
|
|
1566
|
+
var line=grid[r].join('');var html='';var k=0;
|
|
1567
|
+
while(k<line.length){
|
|
1568
|
+
if(line.substr(k,3)==='!!!'){ html+='<span class="g-rb">'+blade+'</span>'; k+=3; }
|
|
1569
|
+
else if(line[k]==='?'){ html+='<span class="g-eye">'+core+'</span>'; k+=1; }
|
|
1570
|
+
else { var nb=line.indexOf('!!!',k); var nc=line.indexOf('?',k);
|
|
1571
|
+
var nxt=Math.min(nb<0?1e9:nb, nc<0?1e9:nc, line.length);
|
|
1572
|
+
html+=paint(line.slice(k,nxt)); k=nxt; }
|
|
1573
|
+
}
|
|
1574
|
+
out.push(html);
|
|
1575
|
+
}
|
|
1576
|
+
el.innerHTML='<span class="sprite">'+out.join('\n')+'</span>';
|
|
1577
|
+
requestAnimationFrame(frame);
|
|
1578
|
+
}
|
|
1579
|
+
frame();
|
|
1580
|
+
})();
|
|
1581
|
+
|
|
1582
|
+
/* ===== attach-mock live spinner (mirrors the real SPINNER_FRAMES braille set) ===== */
|
|
1583
|
+
(function(){
|
|
1584
|
+
var F=['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏'];
|
|
1585
|
+
var s1=document.getElementById('sp1'),s2=document.getElementById('sp2');if(!s1&&!s2)return;
|
|
1586
|
+
var t1=document.getElementById('spt1');
|
|
1587
|
+
var stages=['opening OMP session','loading Rig session'];
|
|
1588
|
+
var i=0,st=0;
|
|
1589
|
+
setInterval(function(){i=(i+1)%F.length;if(s1)s1.textContent=F[i];if(s2)s2.textContent=F[(i+4)%F.length];},150);
|
|
1590
|
+
setInterval(function(){st=(st+1)%stages.length;if(t1)t1.textContent=stages[st];},2600);
|
|
1591
|
+
})();
|
|
1592
|
+
|
|
1593
|
+
/* ===== scroll reveal + pipeline cycle ===== */
|
|
1594
|
+
(function(){var io=new IntersectionObserver(function(es){es.forEach(function(e){if(e.isIntersecting)e.target.classList.add('in');});},{threshold:.16});document.querySelectorAll('.rv').forEach(function(el){io.observe(el);});})();
|
|
1595
|
+
(function(){var st=document.querySelectorAll('#pipe .stage');if(!st.length)return;var i=0;setInterval(function(){st.forEach(function(s){s.classList.remove('on');});st[i].classList.add('on');i=(i+1)%st.length;},1300);})();
|
|
1596
|
+
|
|
1597
|
+
/* ===== closing kill-line: crisp DOM text at rest, canvas shred only during the burst ===== */
|
|
1598
|
+
(function(){
|
|
1599
|
+
var cv=document.querySelector('.ripcv'); if(!cv) return;
|
|
1600
|
+
var host=cv.parentElement, l2=host&&host.querySelector('.l2'); if(!l2) return;
|
|
1601
|
+
var ctx=cv.getContext('2d'); var DPR=Math.min(devicePixelRatio||1,2);
|
|
1602
|
+
var pre=cv.dataset.pre||'', hot=cv.dataset.hot||'', post=cv.dataset.post||'';
|
|
1603
|
+
var reduce=matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
1604
|
+
var off=document.createElement('canvas'), octx=off.getContext('2d');
|
|
1605
|
+
var W=0,H=0,fs=40,preW=0,hotW=0,postW=0,x0=0,hx=0,GP=20,t=0,BANDS=7,shredding=false;
|
|
1606
|
+
function fontStr(){return '700 '+fs+"px 'Space Grotesk',system-ui,sans-serif";}
|
|
1607
|
+
function build(){
|
|
1608
|
+
fs=parseFloat(getComputedStyle(l2).fontSize)||40; GP=Math.round(fs*0.5);
|
|
1609
|
+
ctx.font=fontStr();
|
|
1610
|
+
preW=ctx.measureText(pre).width; hotW=ctx.measureText(hot).width; postW=ctx.measureText(post).width;
|
|
1611
|
+
var lineW=preW+hotW+postW, padX=Math.round(fs);
|
|
1612
|
+
W=Math.ceil(lineW+padX*2); H=Math.ceil(fs*1.75);
|
|
1613
|
+
cv.width=W*DPR; cv.height=H*DPR; cv.style.width=W+'px'; cv.style.height=H+'px';
|
|
1614
|
+
ctx.setTransform(DPR,0,0,DPR,0,0);
|
|
1615
|
+
x0=Math.round((W-lineW)/2); hx=x0+preW;
|
|
1616
|
+
off.width=Math.ceil((hotW+GP*2)*DPR); off.height=Math.ceil(H*DPR);
|
|
1617
|
+
octx.setTransform(DPR,0,0,DPR,0,0); octx.clearRect(0,0,off.width,off.height);
|
|
1618
|
+
octx.font=fontStr(); octx.textBaseline='middle';
|
|
1619
|
+
octx.shadowColor='rgba(204,255,77,.5)'; octx.shadowBlur=Math.max(8,Math.round(fs*0.2)); octx.fillStyle='#ccff4d';
|
|
1620
|
+
octx.fillText(hot, GP, H/2); octx.shadowBlur=0;
|
|
1621
|
+
}
|
|
1622
|
+
function ink(){ ctx.font=fontStr(); ctx.textBaseline='middle'; ctx.fillStyle='#f2f3f6'; ctx.fillText(pre,x0,H/2); ctx.fillText(post,hx+hotW,H/2); }
|
|
1623
|
+
function frame(){
|
|
1624
|
+
t++;
|
|
1625
|
+
var cycle=170, ph=t%cycle;
|
|
1626
|
+
var rip = ph<26 ? Math.pow(1-ph/26,1.7)*(ph<3?ph/3:1) : 0;
|
|
1627
|
+
if(rip<0.015){
|
|
1628
|
+
if(shredding){ shredding=false; cv.style.opacity='0'; l2.style.visibility='visible'; ctx.clearRect(0,0,W,H); }
|
|
1629
|
+
requestAnimationFrame(frame); return;
|
|
1630
|
+
}
|
|
1631
|
+
if(!shredding){ shredding=true; cv.style.opacity='1'; l2.style.visibility='hidden'; }
|
|
1632
|
+
ctx.clearRect(0,0,W,H); ink();
|
|
1633
|
+
var bandH=H/BANDS;
|
|
1634
|
+
for(var i=0;i<BANDS;i++){
|
|
1635
|
+
var mid=(i+0.5)/BANDS-0.5;
|
|
1636
|
+
var dx=(i%2?1:-1)*rip*(fs*0.12+Math.abs(mid)*fs*0.9);
|
|
1637
|
+
var dy=mid*rip*fs*0.42;
|
|
1638
|
+
ctx.drawImage(off, 0, Math.floor(i*bandH*DPR), off.width, Math.ceil(bandH*DPR), hx-GP+dx, i*bandH+dy, hotW+GP*2, bandH+0.6);
|
|
1639
|
+
}
|
|
1640
|
+
ctx.save(); ctx.globalAlpha=Math.min(0.92,rip); ctx.font=fontStr(); ctx.textBaseline='middle';
|
|
1641
|
+
ctx.shadowColor='rgba(204,255,77,.85)'; ctx.shadowBlur=Math.round(fs*0.35); ctx.fillStyle='#f3ffce'; ctx.fillText(hot,hx,H/2); ctx.restore();
|
|
1642
|
+
ctx.save(); ctx.globalAlpha=Math.min(1,rip*1.4); var ty=H/2+Math.sin(t*0.7)*2;
|
|
1643
|
+
var g=ctx.createLinearGradient(hx-12,0,hx+hotW+12,0);
|
|
1644
|
+
g.addColorStop(0,'rgba(204,255,77,0)'); g.addColorStop(.5,'rgba(255,255,255,.95)'); g.addColorStop(1,'rgba(204,255,77,0)');
|
|
1645
|
+
ctx.fillStyle=g; ctx.shadowColor='#ccff4d'; ctx.shadowBlur=12; ctx.fillRect(hx-12,ty-Math.max(2,fs*0.045),hotW+24,Math.max(3,fs*0.08)); ctx.restore();
|
|
1646
|
+
requestAnimationFrame(frame);
|
|
1647
|
+
}
|
|
1648
|
+
function start(){ build(); if(reduce)return; requestAnimationFrame(frame); }
|
|
1649
|
+
if(document.fonts&&document.fonts.ready) document.fonts.ready.then(start); else start();
|
|
1650
|
+
var rz; addEventListener('resize',function(){clearTimeout(rz);rz=setTimeout(build,150);});
|
|
1651
|
+
})();
|
|
1652
|
+
|
|
1653
|
+
</script><script src="assets/site.js?v=v9"></script></body></html>
|