/* One Piece Wiki — original, procedurally generated portrait/icon artwork. Every character gets a role-themed line-art medallion; every Devil Fruit gets a stylized fruit-shape icon colored by type. All shapes are drawn from scratch here — no external art or copyrighted imagery is used anywhere in this file. */ function radialLines(cx, cy, rInner, rOuter, count, strokeWidth) { let out = ''; for (let i = 0; i < count; i++) { const a = (Math.PI * 2 * i) / count; const x1 = cx + rInner * Math.cos(a), y1 = cy + rInner * Math.sin(a); const x2 = cx + rOuter * Math.cos(a), y2 = cy + rOuter * Math.sin(a); out += ``; } return out; } function starPoints(cx, cy, rOuter, rInner, count) { const pts = []; for (let i = 0; i < count * 2; i++) { const r = i % 2 === 0 ? rOuter : rInner; const a = (Math.PI * i) / count - Math.PI / 2; pts.push(`${(cx + r * Math.cos(a)).toFixed(1)},${(cy + r * Math.sin(a)).toFixed(1)}`); } return pts.join(' '); } /* Simple original line-art built from primitive shapes (circles/lines/polygons) — one per archetype. */ const ROLE_ICONS = { sword: '', compass: `${radialLines(32, 32, 15, 18, 12, 2)}`, target: '', cross: '', scroll: '', gear: `${radialLines(32, 32, 12, 18, 8, 3)}`, note: '', chefhat: '', flask: '', anchor: '', crown: '', tiara: '', flag: '', dagger: '', skull: '', paw: '', wing: '', star: ``, }; const ROLE_ICON_RULES = [ [/navigat/, 'compass'], [/sniper|marksman|sharpshoot/, 'target'], [/doctor|medic|surgeon/, 'cross'], [/archaeolog|scholar/, 'scroll'], [/shipwright|engineer|mechanic/, 'gear'], [/musician|singer/, 'note'], [/cook|chef/, 'chefhat'], [/scientist/, 'flask'], [/helmsman|admiral|marine|navy|warden/, 'anchor'], [/king|emperor|empress|yonko|shogun/, 'crown'], [/princess|prince/, 'tiara'], [/revolutionary/, 'flag'], [/agent|spy|officer|assassin|cp0|cp9/, 'dagger'], [/mink|beast|tiger|lion|leopard|wolf|dragon/, 'paw'], [/phoenix|bird|wing|flight/, 'wing'], [/swordsm|santoryu|blade|commander|combatant/, 'sword'], [/captain|warlord|pirate/, 'skull'], ]; function iconKeyForCharacter(c) { const haystack = `${c.role} ${c.epithet || ''} ${c.affiliation}`.toLowerCase(); for (const [re, key] of ROLE_ICON_RULES) { if (re.test(haystack)) return key; } return 'star'; } function characterPortraitSVG(c) { const accent = accentFor(c); const hue2 = (hashHue(c.id + 'x') + 45) % 360; const icon = ROLE_ICONS[iconKeyForCharacter(c)] || ROLE_ICONS.star; const uid = c.id.replace(/[^a-z0-9]/g, ''); const rotation = hashHue(c.name) % 90; const fruit = c.devilFruit ? findFruit(c.devilFruit) : null; return ` ${icon} ${fruit ? `${fruit.icon}` : ''} `; } const CATEGORY_HEX = { Paramecia: '#a06cd5', Zoan: '#4c9a5a', Logia: '#3f9bd0' }; function fruitPortraitSVG(f) { const color = CATEGORY_HEX[f.category] || '#e3b04b'; const glow = f.subtype && /mythical|special/i.test(f.subtype); const uid = f.id.replace(/[^a-z0-9]/g, ''); return ` ${f.icon} `; }