/ concepts / concept3-holowire.jsx
concept3-holowire.jsx
  1  // Concept 3 — HOLO WIREFRAME TURNTABLE
  2  // Pure holographic. Glassmorphic panels floating over deep purple-black.
  3  // Ship centered, shown as translucent wireframe with overlapping
  4  // orthographic planes. Feminine-industrial; think Destiny/Horizon holo.
  5  
  6  function Concept3_HoloWire({ seed = "C3-default" }) {
  7    const ship = makeShip(seed);
  8    const bg1 = "#070415";
  9    const bg2 = "#120a2e";
 10    const violet = "#b88cff";
 11    const mint = "#7affd0";
 12    const pink = "#ff7adc";
 13    const dim = "rgba(184,140,255,0.55)";
 14    const glass = "rgba(184,140,255,0.06)";
 15  
 16    const Panel = ({ children, style, flush }) => (
 17      <div style={{
 18        background: glass, backdropFilter:"blur(6px)", border:`1px solid ${violet}33`,
 19        padding: flush ? 0 : 18, borderRadius: 2, ...style,
 20      }}>{children}</div>
 21    );
 22  
 23    const Stat = ({ k, v, unit, accent = violet }) => (
 24      <div>
 25        <div style={{fontFamily:"JetBrains Mono", fontSize:9, letterSpacing:2, color:dim, textTransform:"uppercase"}}>{k}</div>
 26        <div style={{fontFamily:"Orbitron", fontWeight:500, fontSize:22, color:accent, letterSpacing:1, lineHeight:1.1, marginTop:2}}>
 27          {v}<span style={{fontSize:11, color:dim, marginLeft:4, fontFamily:"JetBrains Mono", fontWeight:400}}>{unit}</span>
 28        </div>
 29      </div>
 30    );
 31  
 32    return (
 33      <div style={{
 34        width:1280, height:880, position:"relative", overflow:"hidden",
 35        background: `radial-gradient(ellipse at 30% 20%, ${bg2} 0%, ${bg1} 60%),
 36                     radial-gradient(ellipse at 70% 80%, rgba(255,122,220,0.08) 0%, transparent 60%)`,
 37        color: violet, fontFamily:"'Space Grotesk', sans-serif",
 38      }}>
 39        {/* Ambient particles */}
 40        <svg style={{position:"absolute", inset:0, pointerEvents:"none", opacity:0.6}} width="100%" height="100%">
 41          {Array.from({length: 70}).map((_,i) => {
 42            const rng = mulberry32(hashStr(seed+"p"+i));
 43            return <circle key={i} cx={rng()*1280} cy={rng()*880} r={rng()*1.4} fill={violet} opacity={0.3+rng()*0.5}/>;
 44          })}
 45        </svg>
 46  
 47        {/* Top nav — floating island */}
 48        <div style={{position:"absolute", top:20, left:"50%", transform:"translateX(-50%)", display:"flex", gap:2, background:"rgba(7,4,21,0.6)", border:`1px solid ${violet}33`, borderRadius:100, padding:4, backdropFilter:"blur(10px)"}}>
 49          {["Catalog","Fleet","Brokers","Orders","Account"].map((t,i) => (
 50            <div key={t} style={{
 51              padding:"8px 18px", fontFamily:"JetBrains Mono", fontSize:10, letterSpacing:2, textTransform:"uppercase",
 52              borderRadius:100, background: i===0 ? `${violet}22` : "transparent", color: i===0 ? "#fff" : dim, cursor:"pointer",
 53            }}>{t}</div>
 54          ))}
 55        </div>
 56  
 57        {/* Left floating specs cluster */}
 58        <div style={{position:"absolute", top:90, left:32, width:300, display:"flex", flexDirection:"column", gap:14}}>
 59          <Panel>
 60            <div style={{fontFamily:"JetBrains Mono", fontSize:9, letterSpacing:2, color:dim}}>▸ {ship.cls.name.toUpperCase()} · {ship.mfg.code}</div>
 61            <div style={{fontFamily:"Orbitron", fontWeight:700, fontSize:28, color:"#fff", letterSpacing:1, marginTop:6, lineHeight:1.05}}>{ship.model}</div>
 62            <div style={{fontFamily:"JetBrains Mono", fontSize:10, color:dim, marginTop:8, letterSpacing:1}}>SN · {ship.serial}</div>
 63            <div style={{display:"flex", gap:6, marginTop:12, flexWrap:"wrap"}}>
 64              <Pill color={mint}>◉ {ship.avail}</Pill>
 65              <Pill color={violet}>{ship.faction}</Pill>
 66              <Pill color={pink}>{ship.cond}</Pill>
 67            </div>
 68          </Panel>
 69  
 70          <Panel>
 71            <div style={{fontFamily:"JetBrains Mono", fontSize:9, letterSpacing:2, color:dim, marginBottom:10}}>▸ CORE SPECS</div>
 72            <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:14}}>
 73              <Stat k="Length"   v={ship.length_m} unit="m"/>
 74              <Stat k="Mass"     v={ship.mass.toLocaleString()} unit="t" accent={mint}/>
 75              <Stat k="Jump"     v={ship.jumpRange} unit="ly" accent={pink}/>
 76              <Stat k="Top spd"  v={(ship.topSpeed/1000).toFixed(1)} unit="k m/s"/>
 77            </div>
 78          </Panel>
 79  
 80          <Panel>
 81            <div style={{fontFamily:"JetBrains Mono", fontSize:9, letterSpacing:2, color:dim, marginBottom:10}}>▸ LINEAGE</div>
 82            <div style={{fontFamily:"JetBrains Mono", fontSize:11, color:"rgba(255,255,255,0.85)", lineHeight:1.8}}>
 83              <div style={{display:"flex", justifyContent:"space-between"}}><span style={{color:dim}}>Forge</span><span>{ship.mfg.name}</span></div>
 84              <div style={{display:"flex", justifyContent:"space-between"}}><span style={{color:dim}}>Yards</span><span>{ship.mfg.loc}</span></div>
 85              <div style={{display:"flex", justifyContent:"space-between"}}><span style={{color:dim}}>Era</span><span>{ship.year} cmn</span></div>
 86              <div style={{display:"flex", justifyContent:"space-between"}}><span style={{color:dim}}>Drive</span><span>{ship.drive}</span></div>
 87            </div>
 88          </Panel>
 89        </div>
 90  
 91        {/* Right floating cluster */}
 92        <div style={{position:"absolute", top:90, right:32, width:320, display:"flex", flexDirection:"column", gap:14}}>
 93          <Panel>
 94            <div style={{fontFamily:"JetBrains Mono", fontSize:9, letterSpacing:2, color:dim}}>▸ PROCUREMENT VALUE</div>
 95            <div style={{fontFamily:"Orbitron", fontWeight:900, fontSize:40, color:"#fff", letterSpacing:1, marginTop:4, lineHeight:1,
 96              background:`linear-gradient(90deg, ${violet}, ${pink})`, WebkitBackgroundClip:"text", WebkitTextFillColor:"transparent",
 97            }}>₵{formatCred(ship.price)}</div>
 98            <div style={{fontFamily:"JetBrains Mono", fontSize:10, color:dim, marginTop:6, letterSpacing:1}}>or lease ₵{formatCred(Math.round(ship.price/120))}/cycle</div>
 99          </Panel>
100  
101          <Panel>
102            <div style={{fontFamily:"JetBrains Mono", fontSize:9, letterSpacing:2, color:dim, marginBottom:12}}>▸ PERFORMANCE ENVELOPE</div>
103            <RadarChart ship={ship} violet={violet} mint={mint} pink={pink}/>
104          </Panel>
105  
106          <Panel>
107            <div style={{fontFamily:"JetBrains Mono", fontSize:9, letterSpacing:2, color:dim, marginBottom:10}}>▸ RECENT OBSERVATIONS</div>
108            <div style={{fontFamily:"JetBrains Mono", fontSize:11, color:"rgba(255,255,255,0.8)", lineHeight:1.7}}>
109              {[["14h", "HANGAR SCAN · HULL 98.4%"],
110                ["2d", "FLIGHT LOG · 412 JUMPS"],
111                ["9d", "OVERHAUL · DRIVE CORE"],
112                ["31d", "LISTED · BROKER VNT"],
113              ].map(([t, txt]) => (
114                <div key={t} style={{display:"flex", gap:10, padding:"3px 0"}}>
115                  <span style={{color:mint, width:28}}>{t}</span>
116                  <span>{txt}</span>
117                </div>
118              ))}
119            </div>
120          </Panel>
121        </div>
122  
123        {/* CENTER — holo stage */}
124        <div style={{position:"absolute", left:360, right:368, top:110, bottom:120, display:"flex", flexDirection:"column", alignItems:"center"}}>
125          {/* Stage ring */}
126          <div style={{position:"relative", width:"100%", height:"70%"}}>
127            {/* concentric circles */}
128            <svg style={{position:"absolute", inset:0}} width="100%" height="100%" viewBox="0 0 520 440" preserveAspectRatio="xMidYMid meet">
129              <defs>
130                <radialGradient id="disk" cx="50%" cy="70%" r="60%">
131                  <stop offset="0%" stopColor={violet} stopOpacity="0.25"/>
132                  <stop offset="100%" stopColor={violet} stopOpacity="0"/>
133                </radialGradient>
134              </defs>
135              <ellipse cx="260" cy="340" rx="240" ry="40" fill="url(#disk)"/>
136              <ellipse cx="260" cy="340" rx="240" ry="40" fill="none" stroke={violet} strokeOpacity="0.4" strokeWidth="1"/>
137              <ellipse cx="260" cy="340" rx="180" ry="30" fill="none" stroke={violet} strokeOpacity="0.3" strokeWidth="1" strokeDasharray="4,4"/>
138              <ellipse cx="260" cy="340" rx="120" ry="20" fill="none" stroke={violet} strokeOpacity="0.25" strokeWidth="1"/>
139              {/* tick marks around the ring */}
140              {Array.from({length: 24}).map((_,i) => {
141                const a = (i/24)*2*Math.PI;
142                const rx = 240, ry = 40, cx = 260, cy = 340;
143                const x = cx + Math.cos(a)*rx;
144                const y = cy + Math.sin(a)*ry;
145                return <circle key={i} cx={x} cy={y} r={1.5} fill={violet} opacity={0.6}/>;
146              })}
147            </svg>
148  
149            {/* layered orthographic wireframes */}
150            <div style={{position:"absolute", inset:"5% 10% 30%", filter:`drop-shadow(0 0 20px ${violet}88)`}}>
151              <ShipSilhouette ship={ship} stroke={violet} fill="rgba(184,140,255,0.08)" glow={false} strokeWidth={1.2}/>
152            </div>
153            {/* secondary plane (top view, smaller, offset) */}
154            <div style={{position:"absolute", top:"6%", left:"6%", width:180, opacity:0.55, transform:"rotate(-6deg)"}}>
155              <ShipSilhouette ship={ship} stroke={mint} strokeWidth={1} glow detail="min"/>
156            </div>
157            <div style={{position:"absolute", top:"14%", right:"4%", width:140, opacity:0.45, transform:"rotate(90deg)"}}>
158              <ShipSilhouette ship={ship} stroke={pink} strokeWidth={1} glow detail="min"/>
159            </div>
160  
161            {/* ring labels */}
162            <div style={{position:"absolute", bottom:"10%", left:"8%", fontFamily:"JetBrains Mono", fontSize:10, color:dim, letterSpacing:2}}>AZ 000°</div>
163            <div style={{position:"absolute", bottom:"10%", right:"8%", fontFamily:"JetBrains Mono", fontSize:10, color:dim, letterSpacing:2}}>AZ 180°</div>
164  
165            {/* Floating callouts */}
166            <FloatCallout top="22%" left="18%" color={mint} label="HARDPOINTS" value={ship.hardpoints}/>
167            <FloatCallout top="30%" right="14%" color={pink} label="SHIELD" value={`${ship.shields} GJ`}/>
168            <FloatCallout top="58%" left="22%" color={violet} label="CREW" value={ship.crew}/>
169          </div>
170  
171          {/* view selector */}
172          <div style={{display:"flex", gap:8, marginTop:12}}>
173            {["ORTHO","TOP","SIDE","INTERIOR","SECTION"].map((v,i) => (
174              <div key={v} style={{
175                padding:"6px 14px", fontFamily:"JetBrains Mono", fontSize:10, letterSpacing:2,
176                border:`1px solid ${violet}44`, color: i===0 ? "#fff" : dim,
177                background: i===0 ? `${violet}22` : "transparent", borderRadius:2,
178              }}>{v}</div>
179            ))}
180          </div>
181        </div>
182  
183        {/* BOTTOM floating action bar */}
184        <div style={{position:"absolute", left:"50%", bottom:24, transform:"translateX(-50%)", display:"flex", gap:10, alignItems:"center", padding:8, background:"rgba(7,4,21,0.7)", border:`1px solid ${violet}44`, borderRadius:100, backdropFilter:"blur(12px)"}}>
185          <div style={{padding:"10px 20px", fontFamily:"JetBrains Mono", fontSize:10, color:dim, letterSpacing:2}}>DELIVERY · {ship.delivery} CYC</div>
186          <div style={{padding:"10px 20px", fontFamily:"JetBrains Mono", fontSize:10, color:dim, letterSpacing:2, borderLeft:`1px solid ${violet}33`}}>WARRANTY · {ship.warranty}</div>
187          <button style={{
188            padding:"12px 28px", background:"transparent", color:"#fff", border:`1px solid ${violet}`,
189            fontFamily:"Orbitron", fontWeight:700, fontSize:11, letterSpacing:3, cursor:"pointer", borderRadius:100,
190          }}>SAVE</button>
191          <button style={{
192            padding:"12px 36px", background:`linear-gradient(90deg, ${violet}, ${pink})`, color:"#0a0520", border:"none",
193            fontFamily:"Orbitron", fontWeight:900, fontSize:12, letterSpacing:3, cursor:"pointer", borderRadius:100,
194            boxShadow:`0 0 24px ${violet}aa`,
195          }}>◈ PROCURE · ₵{formatCred(ship.price)}</button>
196        </div>
197      </div>
198    );
199  }
200  
201  function Pill({ color, children }) {
202    return <span style={{
203      padding:"3px 8px", fontFamily:"JetBrains Mono", fontSize:9, letterSpacing:1.5,
204      border:`1px solid ${color}`, color, borderRadius:2,
205    }}>{children}</span>;
206  }
207  
208  function FloatCallout({ top, left, right, color, label, value }) {
209    return (
210      <div style={{position:"absolute", top, left, right, fontFamily:"JetBrains Mono", letterSpacing:1.5}}>
211        <div style={{width:50, height:1, background:color, opacity:0.6, marginBottom:5}}/>
212        <div style={{fontSize:9, color:`${color}aa`}}>{label}</div>
213        <div style={{fontSize:14, color:"#fff", fontWeight:500, marginTop:2, fontFamily:"Orbitron"}}>{value}</div>
214      </div>
215    );
216  }
217  
218  function RadarChart({ ship, violet, mint, pink }) {
219    const axes = [
220      ["THRUST", Math.min(1, ship.thrust/100)],
221      ["SPEED",  Math.min(1, ship.topSpeed/3000)],
222      ["MANEUV", Math.min(1, ship.maneuver/100)],
223      ["SHIELD", Math.min(1, ship.shields/2000)],
224      ["ARMOR",  Math.min(1, ship.armor/2000)],
225      ["JUMP",   Math.min(1, ship.jumpRange/40)],
226    ];
227    const cx = 140, cy = 100, r = 80;
228    const pts = axes.map((ax,i) => {
229      const a = (i/axes.length)*2*Math.PI - Math.PI/2;
230      const rr = r*ax[1];
231      return [cx + Math.cos(a)*rr, cy + Math.sin(a)*rr];
232    });
233    return (
234      <svg width={280} height={200} style={{display:"block", margin:"0 auto"}}>
235        {/* rings */}
236        {[0.33, 0.66, 1].map(f => {
237          const rpts = axes.map((_,i) => {
238            const a = (i/axes.length)*2*Math.PI - Math.PI/2;
239            return [cx + Math.cos(a)*r*f, cy + Math.sin(a)*r*f];
240          });
241          return <polygon key={f} points={rpts.map(p=>p.join(",")).join(" ")} fill="none" stroke={violet} strokeOpacity={0.3} strokeWidth={1}/>;
242        })}
243        {/* axes */}
244        {axes.map((ax,i) => {
245          const a = (i/axes.length)*2*Math.PI - Math.PI/2;
246          return <line key={i} x1={cx} y1={cy} x2={cx+Math.cos(a)*r} y2={cy+Math.sin(a)*r} stroke={violet} strokeOpacity={0.2}/>;
247        })}
248        {/* polygon */}
249        <polygon points={pts.map(p=>p.join(",")).join(" ")} fill={`${mint}33`} stroke={mint} strokeWidth={1.5} style={{filter:`drop-shadow(0 0 8px ${mint})`}}/>
250        {pts.map((p,i) => <circle key={i} cx={p[0]} cy={p[1]} r={2.5} fill={mint}/>)}
251        {/* labels */}
252        {axes.map((ax,i) => {
253          const a = (i/axes.length)*2*Math.PI - Math.PI/2;
254          const lx = cx + Math.cos(a)*(r+14);
255          const ly = cy + Math.sin(a)*(r+14);
256          return <text key={i} x={lx} y={ly} textAnchor="middle" dominantBaseline="middle" fontFamily="JetBrains Mono" fontSize={9} fill="rgba(184,140,255,0.7)" letterSpacing={1.5}>{ax[0]}</text>;
257        })}
258      </svg>
259    );
260  }
261  
262  Object.assign(window, { Concept3_HoloWire });