concept1-tactical.jsx
1 // Concept 1 — ORBITAL TACTICAL HUD 2 // Holographic cyan-on-deep-navy. Threat/flight-computer vibe. 3 // Central ship silhouette framed by crosshair brackets, orbited by 4 // radial gauges. Think: locking-on dossier before purchase. 5 6 function Concept1_Tactical({ seed = "C1-default" }) { 7 const ship = makeShip(seed); 8 const cyan = "#5df0ff"; 9 const cyanDim = "#2a6a75"; 10 const navy = "#040b14"; 11 const navy2 = "#0a1624"; 12 const amber = "#ffb347"; 13 14 // Radial gauge (SVG arc) 15 const Radial = ({ label, value, max = 100, color = cyan }) => { 16 const r = 34, c = 2*Math.PI*r; 17 const pct = Math.min(1, value/max); 18 return ( 19 <div style={{display:"flex", flexDirection:"column", alignItems:"center", gap:4}}> 20 <svg width={84} height={84} style={{filter:`drop-shadow(0 0 4px ${color})`}}> 21 <circle cx={42} cy={42} r={r} fill="none" stroke={cyanDim} strokeWidth={1} opacity={0.4}/> 22 <circle cx={42} cy={42} r={r} fill="none" stroke={color} strokeWidth={3} 23 strokeDasharray={`${c*pct} ${c}`} transform="rotate(-90 42 42)" strokeLinecap="butt"/> 24 {/* tick marks */} 25 {Array.from({length: 24}).map((_,i) => { 26 const a = (i/24)*2*Math.PI - Math.PI/2; 27 const r0 = r+4, r1 = r+7; 28 return <line key={i} x1={42+Math.cos(a)*r0} y1={42+Math.sin(a)*r0} 29 x2={42+Math.cos(a)*r1} y2={42+Math.sin(a)*r1} stroke={color} strokeWidth={1} opacity={0.5}/>; 30 })} 31 <text x={42} y={40} textAnchor="middle" fill={color} fontFamily="Orbitron" fontSize={14} fontWeight={700}>{value}</text> 32 <text x={42} y={54} textAnchor="middle" fill={color} fontFamily="JetBrains Mono" fontSize={8} opacity={0.7}>/{max}</text> 33 </svg> 34 <div style={{fontFamily:"JetBrains Mono", fontSize:9, color:color, letterSpacing:1, opacity:0.8}}>{label}</div> 35 </div> 36 ); 37 }; 38 39 const Chip = ({ children, warn, ok }) => ( 40 <span style={{ 41 border: `1px solid ${warn ? amber : ok ? "#5cffa1" : cyan}`, 42 color: warn ? amber : ok ? "#5cffa1" : cyan, 43 padding: "2px 8px", fontFamily:"JetBrains Mono", fontSize:10, letterSpacing:1.5, 44 background: "rgba(0,0,0,0.3)", 45 }}>{children}</span> 46 ); 47 48 // Corner brackets 49 const Bracket = ({ corner }) => { 50 const size = 22; 51 const s = { position:"absolute", width:size, height:size, borderColor: cyan }; 52 if (corner === "tl") return <div style={{...s, top:0, left:0, borderTop:`2px solid ${cyan}`, borderLeft:`2px solid ${cyan}`}}/>; 53 if (corner === "tr") return <div style={{...s, top:0, right:0, borderTop:`2px solid ${cyan}`, borderRight:`2px solid ${cyan}`}}/>; 54 if (corner === "bl") return <div style={{...s, bottom:0, left:0, borderBottom:`2px solid ${cyan}`, borderLeft:`2px solid ${cyan}`}}/>; 55 return <div style={{...s, bottom:0, right:0, borderBottom:`2px solid ${cyan}`, borderRight:`2px solid ${cyan}`}}/>; 56 }; 57 58 // Scanlines background 59 const scanlines = `repeating-linear-gradient(0deg, transparent 0 2px, rgba(93,240,255,0.025) 2px 3px)`; 60 61 return ( 62 <div style={{ 63 width:1280, height:880, background: `radial-gradient(ellipse at center, ${navy2} 0%, ${navy} 80%)`, 64 color: cyan, fontFamily:"'Space Grotesk', sans-serif", position:"relative", overflow:"hidden", 65 }}> 66 {/* bg scanlines + grid */} 67 <div style={{position:"absolute", inset:0, background: scanlines, pointerEvents:"none"}}/> 68 <div style={{position:"absolute", inset:0, backgroundImage:` 69 linear-gradient(${cyan}11 1px, transparent 1px), 70 linear-gradient(90deg, ${cyan}11 1px, transparent 1px)`, 71 backgroundSize:"40px 40px", pointerEvents:"none"}}/> 72 73 {/* TOP BAR */} 74 <div style={{display:"flex", justifyContent:"space-between", alignItems:"center", padding:"14px 32px", borderBottom:`1px solid ${cyan}44`, position:"relative", zIndex:2}}> 75 <div style={{display:"flex", alignItems:"center", gap:24}}> 76 <div style={{fontFamily:"Orbitron", fontWeight:900, fontSize:16, letterSpacing:4, color:cyan}}>◈ FLEET.PROCURE</div> 77 <div style={{fontFamily:"JetBrains Mono", fontSize:10, color:cyanDim, letterSpacing:2}}>NODE 07 // SECTOR G-4 // AUTH:COMMODORE</div> 78 </div> 79 <div style={{display:"flex", gap:16, fontFamily:"JetBrains Mono", fontSize:10, color:cyanDim, letterSpacing:2}}> 80 <span>STARDATE 2396.114</span> 81 <span style={{color:"#5cffa1"}}>● LINK STABLE</span> 82 <span>LAT 14°44'N</span> 83 </div> 84 </div> 85 86 {/* BREADCRUMB */} 87 <div style={{padding:"10px 32px", fontFamily:"JetBrains Mono", fontSize:10, color:cyanDim, letterSpacing:2, borderBottom:`1px solid ${cyan}22`}}> 88 CATALOG ▸ {ship.cls.name.toUpperCase()} ▸ {ship.mfg.name.toUpperCase()} ▸ <span style={{color:cyan}}>{ship.serial}</span> 89 </div> 90 91 {/* MAIN — 3col */} 92 <div style={{display:"grid", gridTemplateColumns:"280px 1fr 280px", gap:0, height: "calc(100% - 140px)"}}> 93 94 {/* LEFT — dossier */} 95 <div style={{borderRight:`1px solid ${cyan}22`, padding:"20px 22px"}}> 96 <div style={{fontFamily:"JetBrains Mono", fontSize:9, color:cyanDim, letterSpacing:2, marginBottom:6}}>▸ DOSSIER</div> 97 <div style={{fontFamily:"Orbitron", fontWeight:700, fontSize:22, color:cyan, lineHeight:1.1, letterSpacing:1}}>{ship.model}</div> 98 <div style={{fontFamily:"JetBrains Mono", fontSize:10, color:cyanDim, marginTop:6, letterSpacing:1}}>{ship.serial}</div> 99 100 <div style={{marginTop:18, display:"flex", flexWrap:"wrap", gap:6}}> 101 <Chip>{ship.cls.code} · {ship.cls.name.toUpperCase()}</Chip> 102 <Chip>{ship.mfg.code}</Chip> 103 <Chip warn>{ship.avail}</Chip> 104 </div> 105 106 <div style={{marginTop:24, fontFamily:"JetBrains Mono", fontSize:11, color:cyan, lineHeight:1.9}}> 107 <Row k="MFG" v={ship.mfg.name}/> 108 <Row k="ORIGIN" v={ship.mfg.loc}/> 109 <Row k="YEAR" v={ship.year}/> 110 <Row k="HULL" v={ship.cond}/> 111 <Row k="FACTION" v={ship.faction}/> 112 <Row k="DRIVE" v={ship.drive}/> 113 <Row k="WARRANTY" v={ship.warranty}/> 114 </div> 115 116 <div style={{marginTop:24, fontFamily:"JetBrains Mono", fontSize:9, color:cyanDim, letterSpacing:2, marginBottom:10}}>▸ THREAT PROFILE</div> 117 <ThreatBars ship={ship} color={cyan} dim={cyanDim}/> 118 </div> 119 120 {/* CENTER — silhouette stage */} 121 <div style={{position:"relative", padding:"20px", display:"flex", flexDirection:"column"}}> 122 {/* Stage */} 123 <div style={{flex:1, position:"relative", border:`1px solid ${cyan}33`, background:"rgba(10,22,36,0.6)"}}> 124 <Bracket corner="tl"/><Bracket corner="tr"/><Bracket corner="bl"/><Bracket corner="br"/> 125 {/* crosshair */} 126 <div style={{position:"absolute", inset:0, pointerEvents:"none"}}> 127 <div style={{position:"absolute", left:"50%", top:0, bottom:0, width:1, background:`${cyan}22`}}/> 128 <div style={{position:"absolute", top:"50%", left:0, right:0, height:1, background:`${cyan}22`}}/> 129 </div> 130 {/* ship */} 131 <div style={{position:"absolute", inset:"12% 10%"}}> 132 <ShipSilhouette ship={ship} stroke={cyan} fill="rgba(93,240,255,0.06)" glow/> 133 </div> 134 {/* callouts */} 135 <Callout top="18%" left="18%" label="FORWARD ARRAY" val={`${ship.hardpoints} HP`} color={cyan}/> 136 <Callout top="72%" left="60%" label="DRIVE" val={ship.drive.toUpperCase()} color={amber}/> 137 <Callout top="38%" left="78%" label="COCKPIT" val={`CREW ${ship.crew}`} color={cyan}/> 138 {/* stamp */} 139 <div style={{position:"absolute", bottom:14, left:14, fontFamily:"JetBrains Mono", fontSize:9, color:cyanDim, letterSpacing:2}}> 140 VIEW.PORT 03 · PLANAR · ORTHO · SCALE 1:{Math.round(ship.length_m/12)} 141 </div> 142 <div style={{position:"absolute", bottom:14, right:14, fontFamily:"JetBrains Mono", fontSize:9, color:cyanDim, letterSpacing:2}}> 143 ◉ SCAN COMPLETE · INTEGRITY 98.4% 144 </div> 145 </div> 146 147 {/* radial strip */} 148 <div style={{display:"flex", justifyContent:"space-around", marginTop:16, padding:"14px 8px", border:`1px solid ${cyan}33`, background:"rgba(10,22,36,0.6)"}}> 149 <Radial label="THRUST" value={ship.thrust} max={100}/> 150 <Radial label="MANEUVER" value={ship.maneuver} max={100}/> 151 <Radial label="SIG" value={ship.signature} max={100} color={amber}/> 152 <Radial label="JUMP" value={ship.jumpRange} max={40}/> 153 <Radial label="SPEED" value={Math.round(ship.topSpeed/30)} max={100}/> 154 <Radial label="CARGO" value={Math.round(ship.cargo_t/100)} max={100}/> 155 </div> 156 </div> 157 158 {/* RIGHT — procure */} 159 <div style={{borderLeft:`1px solid ${cyan}22`, padding:"20px 22px", display:"flex", flexDirection:"column"}}> 160 <div style={{fontFamily:"JetBrains Mono", fontSize:9, color:cyanDim, letterSpacing:2, marginBottom:6}}>▸ VALUATION</div> 161 <div style={{fontFamily:"Orbitron", fontWeight:900, fontSize:36, color:cyan, letterSpacing:1, lineHeight:1}}> 162 ₵ {formatCred(ship.price)} 163 </div> 164 <div style={{fontFamily:"JetBrains Mono", fontSize:10, color:cyanDim, marginTop:4, letterSpacing:1}}> 165 UNIT PRICE · FOB {ship.mfg.loc.toUpperCase()} 166 </div> 167 168 <div style={{marginTop:20, fontFamily:"JetBrains Mono", fontSize:11, color:cyan, lineHeight:2}}> 169 <Row k="DELIVERY" v={`${ship.delivery} CYCLES`}/> 170 <Row k="LEASE/MO" v={`₵ ${formatCred(Math.round(ship.price/120))}`}/> 171 <Row k="INSURE" v={`₵ ${formatCred(Math.round(ship.price*0.018))}`}/> 172 <Row k="ESCROW" v="STELLAR BANK"/> 173 </div> 174 175 <div style={{marginTop:20, fontFamily:"JetBrains Mono", fontSize:9, color:cyanDim, letterSpacing:2, marginBottom:8}}>▸ LOADOUT CONFIG</div> 176 <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:6}}> 177 {["STANDARD","TACTICAL","CARGO","CIVIL"].map((p,i) => ( 178 <div key={p} style={{ 179 border:`1px solid ${i===1?cyan:cyan+"33"}`, padding:"10px 8px", textAlign:"center", 180 fontFamily:"JetBrains Mono", fontSize:10, letterSpacing:2, color: i===1?cyan:cyanDim, 181 background: i===1 ? `${cyan}11` : "transparent", 182 }}>{p}</div> 183 ))} 184 </div> 185 186 <div style={{marginTop:"auto"}}> 187 <div style={{border:`1px solid ${amber}`, padding:10, background:`${amber}11`, fontFamily:"JetBrains Mono", fontSize:10, color:amber, letterSpacing:1, marginBottom:12}}> 188 ⚠ EXPORT LICENSE REQUIRED · CLASS {ship.cls.code} 189 </div> 190 <button style={{ 191 width:"100%", padding:"18px 0", background: cyan, color: navy, border:"none", 192 fontFamily:"Orbitron", fontWeight:900, letterSpacing:4, fontSize:14, cursor:"pointer", 193 boxShadow:`0 0 24px ${cyan}aa`, 194 }}>▸ PROCURE UNIT</button> 195 <button style={{ 196 marginTop:8, width:"100%", padding:"14px 0", background: "transparent", color: cyan, 197 border: `1px solid ${cyan}`, fontFamily:"Orbitron", fontWeight:700, letterSpacing:3, fontSize:11, cursor:"pointer", 198 }}>REQUEST DEMO FLIGHT</button> 199 </div> 200 </div> 201 </div> 202 203 {/* BOTTOM TICKER */} 204 <div style={{position:"absolute", bottom:0, left:0, right:0, padding:"8px 32px", borderTop:`1px solid ${cyan}33`, background:`${navy}`, fontFamily:"JetBrains Mono", fontSize:10, color:cyanDim, letterSpacing:2, display:"flex", justifyContent:"space-between"}}> 205 <span>◉ 14,208 SIMILAR UNITS · 87 WATCHERS · PEER AVG ₵ {formatCred(Math.round(ship.price*1.05))}</span> 206 <span>v7.4.2 · FLEET-PROCURE © COALITION COMMONS</span> 207 </div> 208 </div> 209 ); 210 } 211 212 function Row({k, v}) { 213 return ( 214 <div style={{display:"flex", justifyContent:"space-between", alignItems:"baseline", borderBottom:"1px dashed rgba(93,240,255,0.15)", paddingBottom:2}}> 215 <span style={{color:"rgba(93,240,255,0.55)", fontSize:10, letterSpacing:2}}>{k}</span> 216 <span style={{color:"#5df0ff", fontWeight:500}}>{v}</span> 217 </div> 218 ); 219 } 220 221 function Callout({ top, left, label, val, color }) { 222 return ( 223 <div style={{position:"absolute", top, left, fontFamily:"JetBrains Mono", fontSize:9, color, letterSpacing:1.5}}> 224 <div style={{width:40, height:1, background:color, marginBottom:4, boxShadow:`0 0 6px ${color}`}}/> 225 <div style={{opacity:0.7}}>{label}</div> 226 <div style={{fontWeight:700}}>{val}</div> 227 </div> 228 ); 229 } 230 231 function ThreatBars({ ship, color, dim }) { 232 const rows = [ 233 ["HULL", Math.min(100, Math.round(ship.armor/30))], 234 ["SHIELD", Math.min(100, Math.round(ship.shields/20))], 235 ["EW", Math.min(100, Math.round(ship.signature))], 236 ["DPS", Math.min(100, ship.hardpoints*12)], 237 ]; 238 return ( 239 <div style={{display:"flex", flexDirection:"column", gap:8}}> 240 {rows.map(([k,v]) => ( 241 <div key={k}> 242 <div style={{display:"flex", justifyContent:"space-between", fontFamily:"JetBrains Mono", fontSize:10, color, letterSpacing:1.5}}> 243 <span style={{color:dim}}>{k}</span><span>{v}</span> 244 </div> 245 <div style={{height:6, background:`${color}22`, marginTop:3, position:"relative"}}> 246 <div style={{position:"absolute", inset:0, width:`${v}%`, background:color, boxShadow:`0 0 8px ${color}`}}/> 247 {Array.from({length:9}).map((_,i)=>( 248 <div key={i} style={{position:"absolute", left:`${(i+1)*10}%`, top:0, bottom:0, width:1, background:"#040b14"}}/> 249 ))} 250 </div> 251 </div> 252 ))} 253 </div> 254 ); 255 } 256 257 Object.assign(window, { Concept1_Tactical });