// DiveDex — OceanDex archetype + variant + registry system. // Runs under Babel standalone. ES modules unavailable. Only public renderer + registries // are exposed on window; archetype renderers stay module-local inside the IIFE. (function () { // ── helpers ───────────────────────────────────────────────────────── const EYE = (cx, cy, r = 2.6) => ( ); // accent helpers — applied by archetypes when variant requests them const Spots = ({ points, fill = '#EAF5FF', op = 0.55, r = 2 }) => {points.map(([x,y,rr],i) => )}; const Stripes = ({ lines, stroke = '#021321', op = 0.5, w = 1.2 }) => {lines.map((d,i)=>)}; // ── ARCHETYPES (each returns ; side-profile faces RIGHT) ───────── // Each archetype accepts (props) — variant.style is destructured for accents. const A = {}; // archetype registry A.hammerhead = ({ color = '#D7B46A', style = {} }) => { const headW = style.headW ?? 1.0; // 1.0 scalloped, 1.18 great, 0.95 smooth const scallop = style.scallop !== false; const offX = 222 + (headW-1)*22; return ( {scallop && <> } {EYE(offX-10, 62, 2.4)} {style.school && [0,1,2,3].map(i => ( ))} ); }; A.reefShark = ({ color = '#82ECFF', style = {} }) => ( {style.finTip && } {style.finTip && } {style.belly && } {style.stripes && `M${x} 60 Q ${x+2} 76 ${x-2} 90`)} w={1.2}/>} {/* Saddle bands along the back — for banded reef sharks (e.g. houndshark) */} {style.bands && ( {[ { cx: 80, rx: 12, ry: 4.5 }, { cx: 110, rx: 13, ry: 4.5 }, { cx: 140, rx: 12, ry: 4.5 }, { cx: 170, rx: 10, ry: 4 }, ].map((b, i) => ( ))} )} {EYE(200, 70, 2.4)} ); A.whaleShark = ({ color = '#82ECFF', style = {} }) => ( {EYE(206, 66, 1.8)} {style.spots !== false && } ); A.zebraShark = ({ color = '#D7B46A', style = {} }) => ( {EYE(204, 74, 2.2)} ); A.thresherShark = ({ color = '#82ECFF' }) => ( {/* huge upper tail lobe — defining feature */} {EYE(170, 70, 2.2)} ); A.bullheadShark = ({ color = '#D7B46A' }) => ( {EYE(196, 80, 2)} ); A.nurseShark = ({ color = '#B0A07A' }) => ( {EYE(200, 74, 2.2)} ); // ── rays ──────────────────────────────────────────────────────────── A.mantaRay = ({ color = '#8B7BFF', style = {} }) => ( {EYE(96, 50, 2.2)}{EYE(144, 50, 2.2)} {style.underspots && } ); A.eagleRay = ({ color = '#82ECFF' }) => ( {EYE(96, 56, 1.8)}{EYE(144, 56, 1.8)} ); A.stingray = ({ color = '#A89070', style = {} }) => ( {style.bluespots && } {EYE(102, 60, 1.8)}{EYE(138, 60, 1.8)} ); A.devilRay = ({ color = '#5A7BBF' }) => ( {EYE(100, 50, 2)}{EYE(140, 50, 2)} ); // ── turtles ───────────────────────────────────────────────────────── A.turtle = ({ color = '#63FFD2', style = {} }) => ( {style.beak ? : } {EYE(28, 62, 2)} {style.leatherback ? <> : <> } {style.patternedShell && } ); // ── eels & morays ─────────────────────────────────────────────────── A.moray = ({ color = '#FF7A6B', style = {} }) => ( {style.dragon && } {EYE(20, 34, 1.8)} {style.bands && [200,180,160,140,120,100,80,60,40].map((x,i)=> 120?(x-120)*0.2:0) + (i%2?2:-2)} rx="3" ry="6" fill="#021321" opacity="0.35" transform={`rotate(${(x-120)*0.4} ${x} 70)`}/>)} {style.spots && } ); A.ribbonEel = ({ color = '#31D7FF' }) => ( {EYE(34, 44, 1.6)} ); A.gardenEel = ({ color = '#9BB6CC' }) => ( {EYE(40, 36, 1.4)}{EYE(90, 50, 1.4)}{EYE(136, 34, 1.4)}{EYE(182, 54, 1.4)} ); // ── pipefish / seahorse ───────────────────────────────────────────── A.pipefish = ({ color = '#D7B46A', style = {} }) => ( {style.ornate && <> } {style.banded && `M${x} 76 L ${x} 90`)} w={2} op={0.55}/>} {style.longsnout && } {EYE(220, 80, 1.4)} ); A.seahorse = ({ color = '#D7B46A', style = {} }) => ( {style.snoutLong && } {!style.snoutLong && } {style.thorny && [62,55,48,42,52,68,78,84,90].map((y,i) => )} {style.pygmy && } {EYE(160, 40, 1.6)} ); // ── reef fish ─────────────────────────────────────────────────────── A.clownfish = ({ color = '#FFA86B', style = {} }) => ( {style.anemone && {[20,40,60,200,220].map((x,i) => )} } {EYE(158, 64, 2.6)} ); A.angelfish = ({ color = '#31D7FF', style = {} }) => ( {style.bands && } {style.queen && } {EYE(170, 60, 2.4)} ); A.butterflyfish = ({ color = '#FFD86B' }) => ( {EYE(202, 70, 1.8)} ); A.parrotfish = ({ color = '#31D7FF', style = {} }) => ( {style.stoplight && <> } {EYE(206, 70, 2.4)} ); A.wrasse = ({ color = '#82ECFF', style = {} }) => ( {style.hump && } {style.rainbow && } {EYE(64, 70, 2.4)} ); A.surgeonfish = ({ color = '#31D7FF', style = {} }) => ( {style.sohal && } {EYE(196, 64, 2.2)} ); A.tang = ({ color = '#31D7FF' }) => ( {EYE(196, 64, 2.2)} ); A.damselfish = ({ color = '#31D7FF', style = {} }) => ( {style.spots && } {EYE(184, 68, 2.2)} ); A.grouper = ({ color = '#5A6E8C', style = {} }) => ( {style.dusky && } {EYE(202, 68, 2.4)} ); A.trevally = ({ color = '#9DB6CC' }) => ( {EYE(202, 64, 2.4)} ); A.tarpon = ({ color = '#B4C8D8' }) => ( {[60,80,100,120,140,160,180].map((x,i)=>)} {EYE(206, 68, 2.4)} ); A.tuna = ({ color = '#5C7DB8' }) => ( {[150,170,190].map((x,i)=>)} {[150,170,190].map((x,i)=>)} {EYE(210, 70, 2.2)} ); A.barracuda = ({ color = '#9DB8CC', style = {} }) => ( `M${x} 60 L ${x+3} 86`)} w={1} op={0.5}/> {style.school && [-1,1,2].map(i => ( ))} {EYE(44, 68, 2.4)} ); // ── pelagic predators / cetaceans ─────────────────────────────────── A.dolphin = ({ color = '#9DC8E0' }) => ( {EYE(212, 72, 1.8)} ); A.whale = ({ color = '#8E9BB2' }) => ( {EYE(220, 70, 1.8)} ); A.seal = ({ color = '#7A8AA0' }) => ( {EYE(54, 66, 2)} ); A.dugong = ({ color = '#A89070' }) => ( {EYE(54, 60, 1.8)} ); // ── cephalopods ───────────────────────────────────────────────────── A.octopus = ({ color = '#FF7A6B', style = {} }) => ( {[ "M76 80 Q 50 96 36 124 Q 50 116 64 104 Q 70 96 78 90", "M92 84 Q 76 110 70 132 Q 86 116 94 102 Q 96 96 98 90", "M108 84 Q 102 112 102 134 Q 112 118 114 104 Q 114 96 114 90", "M124 84 Q 130 112 128 134 Q 138 118 138 104 Q 138 96 134 90", "M140 84 Q 154 110 158 132 Q 144 116 138 102 Q 134 96 132 90", "M156 82 Q 178 106 192 132 Q 178 116 164 102 Q 156 94 152 88", "M168 76 Q 192 86 210 100 Q 190 94 172 88", "M70 70 Q 46 76 26 88 Q 50 80 70 80", ].map((d, i) => )} ); A.cuttlefish = ({ color = '#A89070' }) => ( {[50,70,90,110,130,150].map((x,i)=>)} ); A.squid = ({ color = '#FF7A6B' }) => ( {[0,1,2,3,4,5].map(i => )} ); // ── macro / inverts ───────────────────────────────────────────────── A.nudibranch = ({ color = '#FF7A6B', style = {} }) => ( {style.frilly && } {style.gills && [60,80,100,120,140,160,180].map((x,i)=>)} {style.gills && [55,75,95,115,135,155,175,195].map((x,i)=>)} {style.cerata && [40,60,80,100,120,140,160,180,200].map((x,i)=> )} {style.mantleSpots && } ); A.frogfish = ({ color = '#FF7A6B', style = {} }) => ( {style.hairy && [50,70,90,110,130,150,170,190].map((x,i)=> )} {style.sargassum && } {EYE(168, 70, 2.4)} ); A.lionfish = ({ color = '#FF7A6B' }) => ( `M${x} 56 Q ${x+2} 72 ${x-2} 88`)} w={4} op={0.65} stroke="#EAF5FF"/> {[88,108,128,148].map((x,i)=>)} {[78,98,118,138,158].map((x,i)=>)} {EYE(184, 70, 2.2)} ); A.crocodilefish = ({ color = '#A89070' }) => ( ); A.giantClam = ({ color = '#31D7FF' }) => ( ); A.shrimp = ({ color = '#FF7A6B' }) => ( ); A.crab = ({ color = '#FF7A6B', style = {} }) => ( {style.arrow && } ); A.lobster = ({ color = '#A8462B', style = {} }) => ( `M${x} 70 L ${x} 96`)} w={1} op={0.55}/> {style.spiny && [50,70,90,110,130,150,170,190].map((x,i)=> )} ); A.seaStar = ({ color = '#FF7A6B' }) => ( ); A.jellyfish = ({ color = '#82ECFF' }) => ( ); A.trunkfish = ({ color = '#FFD86B' }) => ( {EYE(192, 70, 2)} ); A.tigerShark = ({ color = '#82ECFF' }) => ( `M${x} 60 Q ${x+2} 76 ${x-2} 90`)} w={1.4} op={0.55}/> {EYE(200, 70, 2.4)} ); // ── non-creature archetypes (wrecks, aircraft, coral, sponges) ────── // These slot into the same sprite system so they pipe through the Dex, // sightings picker, first-spotter attribution and Memories timeline. A.coral = ({ color = '#FF9DB0', style = {} }) => { // shape: 'soft' | 'brain' | 'fan' | 'staghorn' | 'black' | 'table' const shape = style.shape || 'soft'; if (shape === 'brain') { return ( {/* Brain coral — dome with grooved surface */} ); } if (shape === 'fan') { return ( {/* Sea fan / gorgonian — vertical fan with ribbed branching */} {/* Cross ribs */} {/* Base */} ); } if (shape === 'staghorn') { return ( {/* Staghorn coral — branched antler-like clusters */} {/* Branch tips */} {[[94,50],[78,60],[86,78],[168,50],[150,50],[142,64],[144,92],[160,84]].map(([x,y],i) => ( ))} ); } if (shape === 'black') { return ( {/* Black coral — dark feathery fern */} ); } if (shape === 'table') { return ( {/* Table coral — flat plate on a stem */} ); } // 'soft' — Mikomoto-style pink soft coral cluster (default) return ( {/* Bulbous tips */} {[ { cx: 122, cy: 60, r: 16 }, { cx: 88, cy: 72, r: 14 }, { cx: 156, cy: 70, r: 14 }, { cx: 100, cy: 44, r: 11 }, { cx: 144, cy: 42, r: 11 }, { cx: 122, cy: 36, r: 9 }, ].map((b, i) => ( ))} {/* Connecting stems */} ); }; A.sponge = ({ color = '#FFB37A', style = {} }) => { // shape: 'barrel' | 'tube' | 'rope' | 'encrusting' const shape = style.shape || 'barrel'; if (shape === 'tube') { // Cluster of vertical tubes with hollow openings return ( {[ { x: 78, w: 18, h: 70 }, { x: 104, w: 22, h: 86 }, { x: 134, w: 18, h: 64 }, { x: 158, w: 16, h: 76 }, ].map((t, i) => ( ))} ); } if (shape === 'rope') { // Looping rope sponge return ( ); } if (shape === 'encrusting') { // Reef-coating colored patches return ( ); } // 'barrel' — single drum-shaped sponge (default) return ( {/* Surface texture lines */} ); }; A.wreck = ({ color = '#6B7A88', style = {} }) => { // shape: 'small-hull' | 'large-hull' — different proportions const isLarge = style.shape === 'large-hull'; return ( {/* Sloped hull, listing slightly */} {/* Deck */} {/* Cabin / superstructure */} {isLarge && } {/* Mast / funnel */} {/* Portholes */} {[[60,98],[80,96],[100,94],[140,90],[160,88],[180,86]].map(([x,y],i) => ( ))} {/* Coral growth speckle */} ); }; A.aircraft = ({ color = '#8FA2B5', style = {} }) => { // Top-down silhouette of a propeller fighter / small aircraft. return ( {/* Fuselage */} {/* Wings */} {/* Tail wings */} {/* Vertical stabilizer */} {/* Cockpit canopy */} {/* Propeller hub + blade hint */} {/* Rust / coral specks for the sunken vibe */} ); }; // ── extras / fallback ─────────────────────────────────────────────── A.mystery = ({ color = '#7A93AB' }) => ( ? ); // ── FAMILY TYPE STYLE DEFAULTS ────────────────────────────────────── const FAMILY_TYPE_STYLE = { shark: { base: '#9DB6CC' }, pelagic: { base: '#5C7DB8' }, ray: { base: '#8B7BFF' }, turtle: { base: '#63FFD2' }, reefFish: { base: '#31D7FF' }, macro: { base: '#FF7A6B' }, cephalopod: { base: '#C97BFF' }, crustacean: { base: '#D7B46A' }, mammal: { base: '#9DC8E0' }, invertebrate:{ base: '#FF7A6B' }, // Non-creature sightings — same data pipeline, different vibe. coral: { base: '#FF9DB0' }, // soft pink default; variants override sponge: { base: '#FFB37A' }, // warm orange default wreck: { base: '#6B7A88' }, // weathered steel grey aircraft: { base: '#8FA2B5' }, // aluminium grey }; // ── VARIANT SKINS ─────────────────────────────────────────────────── // { archetype, color?, style? } — style is forwarded to the archetype const CREATURE_VARIANTS = { // hammerheads 'scalloped-hammerhead': { archetype: 'hammerhead', color: '#D7B46A', style: { scallop: true, headW: 1.0 }}, 'great-hammerhead': { archetype: 'hammerhead', color: '#B7C8D8', style: { scallop: false, headW: 1.18 }}, 'smooth-hammerhead': { archetype: 'hammerhead', color: '#9FB3C8', style: { scallop: false, headW: 0.95 }}, 'hammerhead-school': { archetype: 'hammerhead', color: '#D7B46A', style: { scallop: true, school: true }}, // reef sharks 'banded-houndshark': { archetype: 'reefShark', color: '#7A8694', style: { bands: '#2C3946', tailTip: '#3A4754' }}, 'blacktip-reef-shark': { archetype: 'reefShark', color: '#9DB6CC', style: { finTip: '#021321' }}, 'whitetip-reef-shark': { archetype: 'reefShark', color: '#8AA0B8', style: { finTip: '#F6FCFF' }}, 'grey-reef-shark': { archetype: 'reefShark', color: '#8A99AA', style: { tailTip: '#021321' }}, 'caribbean-reef-shark': { archetype: 'reefShark', color: '#8DB0C8', style: {}}, 'oceanic-whitetip': { archetype: 'reefShark', color: '#7A92AB', style: { finTip: '#F6FCFF', belly: '#F6FCFF' }}, 'reef-shark': { archetype: 'reefShark', color: '#82ECFF' }, 'tiger-shark': { archetype: 'tigerShark', color: '#A8C2D8' }, 'zebra-shark': { archetype: 'zebraShark', color: '#D7B46A' }, 'thresher-shark': { archetype: 'thresherShark', color: '#7A92AB' }, 'japanese-bullhead-shark': { archetype: 'bullheadShark', color: '#B0A07A' }, 'nurse-shark': { archetype: 'nurseShark', color: '#A8946C' }, 'tawny-nurse-shark': { archetype: 'nurseShark', color: '#B7A074' }, // whale shark 'whale-shark': { archetype: 'whaleShark', color: '#5A7DB8' }, // rays 'reef-manta': { archetype: 'mantaRay', color: '#7B8BCC' }, 'giant-manta': { archetype: 'mantaRay', color: '#5A6BBF', style: { giant: true, underspots: true }}, 'spotted-eagle-ray': { archetype: 'eagleRay', color: '#5C7DB8' }, 'eagle-ray': { archetype: 'eagleRay', color: '#5C7DB8' }, 'blue-spotted-ray': { archetype: 'stingray', color: '#9F8B66', style: { bluespots: true }}, 'southern-stingray': { archetype: 'stingray', color: '#B59E78', style: {}}, 'mediterranean-devil-ray':{ archetype: 'devilRay', color: '#5A7DB8' }, // turtles 'green-turtle': { archetype: 'turtle', color: '#63FFD2', style: {}}, 'hawksbill-turtle': { archetype: 'turtle', color: '#D7B46A', style: { beak: true, patternedShell: true }}, 'loggerhead-turtle': { archetype: 'turtle', color: '#A88B55', style: { bigHead: true }}, 'leatherback-turtle': { archetype: 'turtle', color: '#3E4A66', style: { leatherback: true }}, // eels 'giant-moray': { archetype: 'moray', color: '#B7A074', style: { spots: true }}, 'dragon-moray': { archetype: 'moray', color: '#FF7A6B', style: { dragon: true, spots: true }}, 'zebra-moray': { archetype: 'moray', color: '#1B3A56', style: { bands: true }}, 'green-moray': { archetype: 'moray', color: '#63FFD2', style: {}}, 'mediterranean-moray': { archetype: 'moray', color: '#5C7DB8', style: { spots: true }}, 'ribbon-eel': { archetype: 'ribbonEel', color: '#31D7FF' }, 'garden-eel': { archetype: 'gardenEel', color: '#9BB6CC' }, // pipefish & seahorse 'ornate-ghost-pipefish':{ archetype: 'pipefish', color: '#FFD86B', style: { ornate: true }}, 'robust-ghost-pipefish':{ archetype: 'pipefish', color: '#A88B55', style: { ornate: true }}, 'banded-pipefish': { archetype: 'pipefish', color: '#D7B46A', style: { banded: true }}, 'mediterranean-pipefish':{ archetype: 'pipefish', color: '#7A9476', style: {}}, 'longsnout-pipefish': { archetype: 'pipefish', color: '#9DB6CC', style: { longsnout: true }}, 'pygmy-seahorse': { archetype: 'seahorse', color: '#FF7A6B', style: { pygmy: true }}, 'thorny-seahorse': { archetype: 'seahorse', color: '#D7B46A', style: { thorny: true }}, 'longsnout-seahorse': { archetype: 'seahorse', color: '#D7B46A', style: { snoutLong: true }}, 'short-snouted-seahorse':{ archetype: 'seahorse', color: '#B59E78', style: {}}, // reef fish 'common-clownfish': { archetype: 'clownfish', color: '#FFA86B', style: { anemone: true }}, 'maldives-anemonefish': { archetype: 'clownfish', color: '#FF8866', style: { anemone: true, anemoneColor: '#FFD86B' }}, 'red-sea-anemonefish': { archetype: 'clownfish', color: '#E26B4B', style: { anemone: true, anemoneColor: '#A8462B' }}, 'queen-angelfish': { archetype: 'angelfish', color: '#31D7FF', style: { queen: true, accent: '#FFD86B' }}, 'french-angelfish': { archetype: 'angelfish', color: '#2A3A50', style: { accent: '#FFD86B' }}, 'butterflyfish': { archetype: 'butterflyfish', color: '#FFD86B' }, 'stoplight-parrotfish': { archetype: 'parrotfish', color: '#5BCC7A', style: { stoplight: true, stripe: '#FF7A6B', stripe2: '#FFD86B', beak: '#FFD86B' }}, 'parrotfish': { archetype: 'parrotfish', color: '#31D7FF', style: { beak: '#FFD86B' }}, 'napoleon-wrasse': { archetype: 'wrasse', color: '#5BCC7A', style: { hump: true }}, 'rainbow-wrasse': { archetype: 'wrasse', color: '#FFD86B', style: { rainbow: true, stripe: '#31D7FF' }}, 'ornate-wrasse': { archetype: 'wrasse', color: '#5BCC7A', style: { rainbow: true, stripe: '#FF7A6B' }}, 'wrasse': { archetype: 'wrasse', color: '#82ECFF', style: { hump: true }}, 'powder-blue-surgeonfish': { archetype: 'surgeonfish', color: '#5C9FE0', style: { tailColor: '#FFD86B' }}, 'sohal-surgeonfish': { archetype: 'surgeonfish', color: '#7A92AB', style: { sohal: true, tailColor: '#31D7FF', scalpel: '#FF7A6B' }}, 'caribbean-blue-tang': { archetype: 'tang', color: '#31D7FF' }, 'mediterranean-damselfish':{ archetype: 'damselfish', color: '#3E5A8C' }, 'dusky-grouper': { archetype: 'grouper', color: '#5A4A3A', style: { dusky: true }}, 'giant-trevally': { archetype: 'trevally', color: '#9DB6CC' }, 'tarpon': { archetype: 'tarpon', color: '#C0D2E0' }, 'bluefin-tuna': { archetype: 'tuna', color: '#3E5A8C' }, 'atlantic-bluefin-tuna':{ archetype: 'tuna', color: '#3E5A8C' }, 'great-barracuda': { archetype: 'barracuda', color: '#9DB8CC' }, 'yellowmouth-barracuda':{ archetype: 'barracuda', color: '#A8C2D8' }, 'barracuda-school': { archetype: 'barracuda', color: '#9DB8CC', style: { school: true }}, 'barracuda': { archetype: 'barracuda', color: '#9DB8CC' }, 'lionfish': { archetype: 'lionfish', color: '#A8462B' }, 'crocodilefish': { archetype: 'crocodilefish', color: '#A89070' }, // cephalopods 'common-octopus': { archetype: 'octopus', color: '#A8462B' }, 'caribbean-reef-octopus':{ archetype: 'octopus', color: '#7BCFAA' }, 'common-cuttlefish': { archetype: 'cuttlefish', color: '#A89070' }, 'squid': { archetype: 'squid', color: '#FF7A6B' }, // macro 'spanish-dancer': { archetype: 'nudibranch', color: '#FF3A4B', style: { frilly: true, gills: true }}, 'chromodoris': { archetype: 'nudibranch', color: '#C97BFF', style: { frilly: true, gills: true, mantleSpots: true }}, 'hypselodoris': { archetype: 'nudibranch', color: '#5C9FE0', style: { gills: true, mantleSpots: true }}, 'flabellina': { archetype: 'nudibranch', color: '#FF7A6B', style: { cerata: true, cerataColor: '#31D7FF' }}, 'nudibranch': { archetype: 'nudibranch', color: '#FF7A6B', style: { frilly: true, gills: true }}, 'painted-frogfish': { archetype: 'frogfish', color: '#FF7A6B', style: { lure: '#FFD86B' }}, 'giant-frogfish': { archetype: 'frogfish', color: '#A89070', style: { lure: '#FFD86B' }}, 'hairy-frogfish': { archetype: 'frogfish', color: '#D7B46A', style: { hairy: true, lure: '#FFD86B' }}, 'sargassum-fish': { archetype: 'frogfish', color: '#5BCC7A', style: { sargassum: true }}, 'frogfish': { archetype: 'frogfish', color: '#FF7A6B', style: { lure: '#FFD86B' }}, // inverts 'arrow-crab': { archetype: 'crab', color: '#FFD86B', style: { arrow: true }}, 'spiny-lobster': { archetype: 'lobster', color: '#A8462B', style: { spiny: true }}, 'shrimp': { archetype: 'shrimp', color: '#FF7A6B' }, 'sea-star': { archetype: 'seaStar', color: '#FF7A6B' }, 'jellyfish': { archetype: 'jellyfish', color: '#82ECFF' }, 'giant-clam': { archetype: 'giantClam', color: '#31D7FF' }, 'smooth-trunkfish': { archetype: 'trunkfish', color: '#FFD86B' }, // mammals 'dolphin': { archetype: 'dolphin', color: '#9DC8E0' }, 'whale': { archetype: 'whale', color: '#8E9BB2' }, 'monk-seal': { archetype: 'seal', color: '#7A8AA0' }, 'dugong': { archetype: 'dugong', color: '#A89070' }, // corals 'pink-soft': { archetype: 'coral', color: '#FFA1B8', style: { shape: 'soft' }}, 'brain': { archetype: 'coral', color: '#D4B98F', style: { shape: 'brain' }}, 'fan': { archetype: 'coral', color: '#FF7A6B', style: { shape: 'fan' }}, 'staghorn': { archetype: 'coral', color: '#F0CE9C', style: { shape: 'staghorn' }}, 'black': { archetype: 'coral', color: '#2E3D4D', style: { shape: 'black' }}, 'table': { archetype: 'coral', color: '#D2A37A', style: { shape: 'table' }}, // sponges 'barrel': { archetype: 'sponge', color: '#C77860', style: { shape: 'barrel' }}, 'tube': { archetype: 'sponge', color: '#9D6BAF', style: { shape: 'tube' }}, 'rope': { archetype: 'sponge', color: '#FFB37A', style: { shape: 'rope' }}, 'encrusting': { archetype: 'sponge', color: '#FF6B8E', style: { shape: 'encrusting' }}, // wrecks 'small-hull': { archetype: 'wreck', color: '#6B7A88', style: { shape: 'small-hull' }}, 'large-hull': { archetype: 'wreck', color: '#5C6B7A', style: { shape: 'large-hull' }}, // aircraft 'fighter': { archetype: 'aircraft', color: '#8FA2B5', style: { shape: 'fighter' }}, // fallback 'mystery': { archetype: 'mystery', color: '#7A93AB' }, }; // ── REGISTRY ──────────────────────────────────────────────────────── // creatureId → { name, sci, archetype-via-variant, family, rarity, regions, habitats, sizeClass, flavorText, achievementName? } const R = (name, sci, family, rarity, regions, flavor, habitats=['reef'], sizeClass='M', ach=null) => ({ commonName: name, scientificName: sci, familyType: family, rarity, regions, habitats, sizeClass, flavorText: flavor, achievementName: ach }); const CREATURE_REGISTRY = { // ── Japan ───────────────────────────────────────────────────────── 'scalloped-hammerhead': R('Scalloped Hammerhead','Sphyrna lewini','shark','legendary',['japan','red-sea','indian-ocean'],'Schools by day, hunts at night. Mikomoto signature.',['pelagic','seamount'],'L','Mikomoto Mover'), 'hammerhead-school': R('Hammerhead School','Sphyrna lewini','shark','mythic',['japan','red-sea'],'Twenty pairs of eyes. One slow-motion ballet.',['pelagic'],'XL','Wall of Eyes'), 'great-hammerhead': R('Great Hammerhead','Sphyrna mokarran','shark','legendary',['red-sea','caribbean'],'Bigger, blockier, lonelier.',['pelagic'],'XL'), 'smooth-hammerhead': R('Smooth Hammerhead','Sphyrna zygaena','shark','epic',['japan'],'No notches. Just a curve and conviction.',['pelagic'],'L'), 'japanese-bullhead-shark': R('Japanese Bullhead Shark','Heterodontus japonicus','shark','rare',['japan'],'Reef bottoms. Looks like a beginner sketch of a shark.',['reef'],'S'), 'thresher-shark': R('Thresher Shark','Alopias pelagicus','shark','epic',['japan','indian-ocean'],'Slaps sardines stupid with its tail.',['pelagic'],'L'), 'whale-shark': R('Whale Shark','Rhincodon typus','shark','mythic',['japan','indian-ocean','red-sea','caribbean'],'Polka dots the size of dinner plates.',['pelagic'],'XL','Polka Dots'), 'reef-manta': R('Reef Manta','Mobula alfredi','ray','epic',['japan','indian-ocean','red-sea'],'Mantas don\'t flap. They glide.',['reef','pelagic'],'L'), 'green-turtle': R('Green Turtle','Chelonia mydas','turtle','uncommon',['japan','indian-ocean','red-sea','caribbean'],'Looks unbothered. Probably is.',['reef'],'L'), 'hawksbill-turtle': R('Hawksbill Turtle','Eretmochelys imbricata','turtle','rare',['japan','indian-ocean','red-sea','caribbean'],'Hooked beak. Mosaic shell.',['reef'],'M'), 'dragon-moray': R('Dragon Moray','Enchelycore pardalis','reefFish','legendary',['japan'],'Horns, fangs, and a permanent scowl.',['reef'],'M','Here Be Dragons'), 'zebra-moray': R('Zebra Moray','Gymnomuraena zebra','reefFish','rare',['japan','indian-ocean'],'Black-and-white pyjamas, cracks crabs for breakfast.',['reef'],'M'), 'giant-moray': R('Giant Moray','Gymnothorax javanicus','reefFish','rare',['japan','indian-ocean','red-sea'],'The classic moray. Mouth open, asking nothing.',['reef'],'L'), 'ribbon-eel': R('Ribbon Eel','Rhinomuraena quaesita','reefFish','epic',['japan','indian-ocean'],'Switches sex and colour through life. Cool flex.',['reef'],'S'), 'garden-eel': R('Garden Eel','Heteroconger hassi','reefFish','uncommon',['japan','indian-ocean','red-sea'],'Sand lawns of nervous noodles.',['sand'],'S'), 'ornate-ghost-pipefish':R('Ornate Ghost Pipefish','Solenostomus paradoxus','macro','epic',['japan','indian-ocean','red-sea'],'A leaf with a face. Macro royalty.',['reef'],'XS','Macro Eye'), 'robust-ghost-pipefish':R('Robust Ghost Pipefish','Solenostomus cyanopterus','macro','rare',['japan','indian-ocean'],'Same costume, sturdier build.',['reef'],'XS'), 'pygmy-seahorse': R('Pygmy Seahorse','Hippocampus bargibanti','macro','epic',['japan','indian-ocean'],'2 cm of pure smug.',['reef'],'XS'), 'painted-frogfish': R('Painted Frogfish','Antennarius pictus','macro','rare',['japan','indian-ocean'],'Sits. Wiggles lure. Eats things its own size.',['reef'],'S'), 'nudibranch': R('Nudibranch','Various','macro','uncommon',['japan','indian-ocean','red-sea','mediterranean'],'A sea slug that dresses better than you.',['reef'],'XS'), 'common-octopus': R('Common Octopus','Octopus vulgaris','cephalopod','rare',['japan','mediterranean','caribbean'],'Three hearts, nine brains, zero shame.',['reef'],'M'), 'giant-trevally': R('Giant Trevally','Caranx ignobilis','pelagic','rare',['japan','indian-ocean','red-sea'],'A torpedo with attitude.',['pelagic'],'L'), 'barracuda-school': R('Barracuda School','Sphyraena qenie','pelagic','epic',['japan','indian-ocean','red-sea'],'A wall of teeth doing a slow circle.',['pelagic'],'L','Tornado'), 'bluefin-tuna': R('Bluefin Tuna','Thunnus orientalis','pelagic','legendary',['japan','mediterranean'],'600 kg of muscle that never stops moving.',['pelagic'],'XL'), // ── Indian Ocean ────────────────────────────────────────────────── 'grey-reef-shark': R('Grey Reef Shark','Carcharhinus amblyrhynchos','shark','rare',['indian-ocean','red-sea'],'The reef\'s neighbourhood patrol.',['reef'],'M'), 'blacktip-reef-shark': R('Blacktip Reef Shark','Carcharhinus melanopterus','shark','uncommon',['indian-ocean','red-sea','caribbean'],'Shy kid with painted fingertips.',['reef'],'M'), 'whitetip-reef-shark': R('Whitetip Reef Shark','Triaenodon obesus','shark','uncommon',['indian-ocean','red-sea','caribbean'],'Naps in caves all afternoon.',['reef'],'M'), 'zebra-shark': R('Zebra Shark','Stegostoma fasciatum','shark','rare',['indian-ocean'],'Stripy as a pup, spotted as an adult.',['reef'],'L'), 'tawny-nurse-shark': R('Tawny Nurse Shark','Nebrius ferrugineus','shark','uncommon',['indian-ocean','red-sea'],'Big, brown, mostly snoozing.',['reef'],'L'), 'napoleon-wrasse': R('Napoleon Wrasse','Cheilinus undulatus','reefFish','epic',['indian-ocean','red-sea'],'A reef sage with a giant forehead.',['reef'],'L','Forehead Friend'), 'maldives-anemonefish': R('Maldives Anemonefish','Amphiprion nigripes','reefFish','uncommon',['indian-ocean'],'Same vibes as Nemo. Different passport.',['reef'],'XS'), 'powder-blue-surgeonfish': R('Powder Blue Surgeonfish','Acanthurus leucosternon','reefFish','rare',['indian-ocean'],'A pop of impossible blue.',['reef'],'S'), 'spanish-dancer': R('Spanish Dancer','Hexabranchus sanguineus','macro','epic',['indian-ocean','red-sea'],'When it swims, the reef stops talking.',['reef'],'M','Encore'), 'dugong': R('Dugong','Dugong dugon','mammal','legendary',['indian-ocean','red-sea'],'A sea cow with a sad-looking face. Heart of gold.',['seagrass'],'XL','Sea Cow'), 'giant-manta': R('Giant Manta','Mobula birostris','ray','mythic',['indian-ocean','japan'],'Up to 7 metres wing-to-wing. A flying carpet.',['pelagic'],'XL'), // ── Caribbean ───────────────────────────────────────────────────── 'caribbean-reef-shark': R('Caribbean Reef Shark','Carcharhinus perezi','shark','rare',['caribbean'],'The signature shark of the Bahamas wall.',['reef'],'M'), 'nurse-shark': R('Nurse Shark','Ginglymostoma cirratum','shark','uncommon',['caribbean'],'Sandy bottom, sandy nap.',['reef'],'M'), 'tiger-shark': R('Tiger Shark','Galeocerdo cuvier','shark','legendary',['caribbean','indian-ocean'],'Eats everything. Sometimes a licence plate.',['pelagic'],'XL','Apex'), 'spotted-eagle-ray': R('Spotted Eagle Ray','Aetobatus narinari','ray','rare',['caribbean','red-sea'],'White polka dots on midnight wings.',['pelagic'],'L'), 'southern-stingray': R('Southern Stingray','Hypanus americanus','ray','uncommon',['caribbean'],'Buries itself in sand and waits.',['sand'],'M'), 'loggerhead-turtle': R('Loggerhead Turtle','Caretta caretta','turtle','rare',['caribbean','mediterranean'],'A big head for cracking conch shells.',['reef'],'L'), 'queen-angelfish': R('Queen Angelfish','Holacanthus ciliaris','reefFish','rare',['caribbean'],'Wears a crown of yellow.',['reef'],'S'), 'french-angelfish': R('French Angelfish','Pomacanthus paru','reefFish','uncommon',['caribbean'],'Dark with gold-scale stippling.',['reef'],'S'), 'stoplight-parrotfish': R('Stoplight Parrotfish','Sparisoma viride','reefFish','uncommon',['caribbean'],'Crunches coral. Poops sand.',['reef'],'M'), 'caribbean-blue-tang': R('Caribbean Blue Tang','Acanthurus coeruleus','reefFish','uncommon',['caribbean'],'Forgetful but vibrant.',['reef'],'S'), 'tarpon': R('Tarpon','Megalops atlanticus','pelagic','rare',['caribbean'],'Silver king of the mangroves.',['pelagic'],'L'), 'great-barracuda': R('Great Barracuda','Sphyraena barracuda','pelagic','rare',['caribbean','red-sea'],'Watches everything. Forgives nothing.',['reef','pelagic'],'L'), 'green-moray': R('Green Moray','Gymnothorax funebris','reefFish','rare',['caribbean'],'A green ghost in coral.',['reef'],'L'), 'caribbean-reef-octopus': R('Caribbean Reef Octopus','Octopus briareus','cephalopod','rare',['caribbean'],'Changes colour mid-thought.',['reef'],'M'), 'longsnout-seahorse': R('Longsnout Seahorse','Hippocampus reidi','macro','rare',['caribbean'],'A long-nosed romantic.',['reef'],'XS'), 'banded-pipefish': R('Banded Pipefish','Doryrhamphus dactyliophorus','macro','uncommon',['caribbean','indian-ocean'],'A pencil sketch of a fish.',['reef'],'XS'), 'arrow-crab': R('Arrow Crab','Stenorhynchus seticornis','crustacean','uncommon',['caribbean'],'Pointy. Spidery. Slightly judgmental.',['reef'],'XS'), 'smooth-trunkfish': R('Smooth Trunkfish','Lactophrys triqueter','reefFish','uncommon',['caribbean'],'Boxy little tank of yellow dots.',['reef'],'S'), // ── Red Sea ─────────────────────────────────────────────────────── 'oceanic-whitetip': R('Oceanic Whitetip','Carcharhinus longimanus','shark','epic',['red-sea'],'The blue-water shark of legend.',['pelagic'],'L','Brothers'), 'red-sea-anemonefish': R('Red Sea Anemonefish','Amphiprion bicinctus','reefFish','uncommon',['red-sea'],'Endemic. Two stripes. One attitude.',['reef'],'XS'), 'sohal-surgeonfish': R('Sohal Surgeonfish','Acanthurus sohal','reefFish','rare',['red-sea'],'Owns the upper reef. Will tell you so.',['reef'],'S'), 'lionfish': R('Lionfish','Pterois volitans','reefFish','rare',['red-sea','caribbean','indian-ocean'],'Beautiful. Do not touch.',['reef'],'S'), 'crocodilefish': R('Crocodilefish','Papilloculiceps longiceps','reefFish','rare',['red-sea'],'Long flat face on the sand. Disappears.',['sand'],'M'), 'blue-spotted-ray': R('Blue-spotted Ribbontail Ray','Taeniura lymma','ray','rare',['red-sea','indian-ocean'],'Pocket-sized neon.',['reef'],'S'), 'giant-clam': R('Giant Clam','Tridacna gigas','invertebrate','uncommon',['red-sea','indian-ocean'],'Half a metre of psychedelic mantle.',['reef'],'M'), // ── Mediterranean ───────────────────────────────────────────────── 'dusky-grouper': R('Dusky Grouper','Epinephelus marginatus','reefFish','epic',['mediterranean'],'The grandad of every Med wreck.',['wreck','reef'],'L'), 'mediterranean-moray': R('Mediterranean Moray','Muraena helena','reefFish','rare',['mediterranean'],'Black-and-white speckled, ageless.',['reef'],'M'), 'common-cuttlefish': R('Common Cuttlefish','Sepia officinalis','cephalopod','rare',['mediterranean'],'Disco hypnotist with W-shaped pupils.',['reef'],'S'), 'yellowmouth-barracuda':R('Yellowmouth Barracuda','Sphyraena viridensis','pelagic','rare',['mediterranean'],'The Med\'s school predator.',['pelagic'],'L'), 'rainbow-wrasse': R('Rainbow Wrasse','Coris julis','reefFish','common',['mediterranean'],'Tiny flicker of pink and blue.',['reef'],'XS'), 'ornate-wrasse': R('Ornate Wrasse','Thalassoma pavo','reefFish','uncommon',['mediterranean'],'Bright stripes on the rocky reef.',['reef'],'XS'), 'mediterranean-damselfish': R('Mediterranean Damselfish','Chromis chromis','reefFish','common',['mediterranean'],'Clouds of little blue-black sparks.',['reef'],'XS'), 'mediterranean-devil-ray':R('Mediterranean Devil Ray','Mobula mobular','ray','epic',['mediterranean'],'Manta\'s smaller, rarer cousin.',['pelagic'],'L'), 'short-snouted-seahorse':R('Short-snouted Seahorse','Hippocampus hippocampus','macro','rare',['mediterranean'],'Hides in seagrass. Hard to spot.',['seagrass'],'XS'), 'mediterranean-pipefish':R('Mediterranean Pipefish','Syngnathus typhle','macro','uncommon',['mediterranean'],'A blade of grass with a face.',['seagrass'],'XS'), 'atlantic-bluefin-tuna':R('Atlantic Bluefin Tuna','Thunnus thynnus','pelagic','epic',['mediterranean'],'Migrates through the Strait of Messina.',['pelagic'],'XL'), 'spiny-lobster': R('Spiny Lobster','Palinurus elephas','crustacean','rare',['mediterranean','caribbean'],'No claws. All antennae.',['reef'],'S'), 'monk-seal': R('Mediterranean Monk Seal','Monachus monachus','mammal','mythic',['mediterranean'],'Fewer than a thousand left. Sees you first.',['cave'],'L','Last of the Last'), // ── extras / utility ────────────────────────────────────────────── 'mystery': R('Unidentified','—','reefFish','common',[],'Logged but not classified.',['reef'],'M'), }; // ── RARITY / FRAME ────────────────────────────────────────────────── const RARITY_COLOR = { common: '#B7CCDE', uncommon: '#63FFD2', rare: '#31D7FF', epic: '#8B7BFF', legendary: '#D7B46A', mythic: '#82ECFF', }; // Back-compat: legacy spriteKey names → creatureId const LEGACY_SPRITE_TO_CREATURE = { 'hammerhead': 'scalloped-hammerhead', 'whale-shark': 'whale-shark', 'reef-shark': 'caribbean-reef-shark', 'tiger-shark': 'tiger-shark', 'manta': 'reef-manta', 'eagle-ray': 'spotted-eagle-ray', 'turtle': 'green-turtle', 'moray': 'giant-moray', 'nudibranch': 'spanish-dancer', 'clownfish': 'common-clownfish', 'octopus': 'common-octopus', 'barracuda': 'great-barracuda', 'wrasse': 'napoleon-wrasse', 'mystery': 'mystery', }; function resolveCreature(creatureId, spriteKey, id) { const key = creatureId || LEGACY_SPRITE_TO_CREATURE[spriteKey || id] || (spriteKey || id) || 'mystery'; const variant = CREATURE_VARIANTS[key] || CREATURE_VARIANTS[LEGACY_SPRITE_TO_CREATURE[key]] || CREATURE_VARIANTS.mystery; const meta = CREATURE_REGISTRY[key] || CREATURE_REGISTRY.mystery; const Archetype = A[variant.archetype] || A.mystery; return { key, variant, meta, Archetype }; } // ── frame component ───────────────────────────────────────────────── function CreatureSpriteFrame({ creatureId, spriteKey, id, rarity, locked = false, size = 140, color, className, glow = true, animate = true, bg = false, frame = false, }) { const { variant, meta, Archetype } = resolveCreature(creatureId, spriteKey, id); const effRarity = rarity || meta.rarity || 'common'; const frameC = RARITY_COLOR[effRarity] || '#82ECFF'; const drawColor = locked ? '#1B3A56' : (color || variant.color || FAMILY_TYPE_STYLE[meta.familyType]?.base || frameC); const filterCss = locked ? 'none' : (glow ? `drop-shadow(0 0 8px ${frameC}66) drop-shadow(0 4px 14px ${frameC}44)` : 'none'); const h = size * 140 / 240; // Only clip overflow when a visible frame/bg defines a rectangle. Without // one, the drop-shadow glow should be free to extend past the SVG bounds // — clipping it produces visible rectangular edges around the silhouette. const needsClip = bg || frame; return (
{locked && (
?
)}
); } function CrSilhouette({ id, size = 120, color, glow = true }) { return ; } // animation + locked silhouette CSS if (!document.getElementById('dd-creature-anim')) { const s = document.createElement('style'); s.id = 'dd-creature-anim'; s.textContent = ` @keyframes dd-float { 0%,100% { transform: translateY(0) } 50% { transform: translateY(-3px) } } .dd-locked-silhouette * { fill: #1B3A56 !important; stroke: #1B3A56 !important; } .dd-locked-silhouette text { fill: #2A4C68 !important; } `; document.head.appendChild(s); } Object.assign(window, { CreatureSpriteFrame, CrSilhouette, CREATURE_REGISTRY, CREATURE_VARIANTS, FAMILY_TYPE_STYLE, RARITY_COLOR, }); })();