M3.6 glyph lift — 29 archetypes now render Design's real 74-mark set
Replaced the generic reused shapes (triangle/star/plus/bolt…) with Design's real per-archetype marks from the authoritative glyphDefs() (HANDOFF), and aligned each archetype's color to Design's deduped palette — frontend lib/archetypes.js + backend archetypeService.js kept in color-sync (the cross-file test iterates the backend set). Badge test color expectations updated to Design (BOMBER #FF9F45, CONDUCTOR #6C8CFF, ALPHA #7C5CFF, FORTRESS #4C6FA5, …). Scope + honesty: - 29 non-combat archetypes wired to real marks + Design colors. - COMBAT namespace (STRIKER/GRAPPLER/PRESSURE/COUNTER/FINISHER/GRINDER) left untouched — it uses unicode CHAR glyphs + its own pinned colors + test (FINISHER deliberately doesn't collide with the soccer FINISHER). Combat could adopt Design's SVG marks in a follow-up. - 39 Design marks are INERT (no classify() producer yet) — the 74 SVGs live in specs/design-reference/assets/glyphs/; they light up when classify() expands. - 9 backend archetypes have NO Design mark (BRUSH/CONNECTOR/DISTRIBUTOR/ FASTBREAK/FLEX/HYBRID/SWITCH/SWITCHBOARD/WHIFF) — kept on their generic glyph, flagged for Design. VISUALLY UNVERIFIED at 390px/desktop — archetype marks + colors on the audit list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,25 +25,25 @@ const ARCHETYPES = {
|
||||
education: 'Torches carry a heavy shot diet, so their points props track usage closely. When they get their normal touches, points clear reliably; assists and threes swing with game script.',
|
||||
},
|
||||
CONDUCTOR: {
|
||||
legacyName: 'FLOOR GENERAL', tag: 'CONDUCTOR', sport: 'nba', color: '#4A9EFF', glyph: 'node',
|
||||
legacyName: 'FLOOR GENERAL', tag: 'CONDUCTOR', sport: 'nba', color: '#6C8CFF', glyph: 'node',
|
||||
description: 'Assist-heavy playmaker',
|
||||
propDNA: { reliable: ['assists'], volatile: ['points', 'threes'] },
|
||||
education: 'Conductors create for others first. Assists are their most stable prop because the offense runs through them; their scoring fluctuates with shot selection and matchup.',
|
||||
},
|
||||
FORTRESS: {
|
||||
legacyName: 'TWO-WAY ANCHOR', tag: 'FORTRESS', sport: 'nba', color: '#A78BFA', glyph: 'shield',
|
||||
legacyName: 'TWO-WAY ANCHOR', tag: 'FORTRESS', sport: 'nba', color: '#4C6FA5', glyph: 'shield',
|
||||
description: 'Defense, rebounds, blocks',
|
||||
propDNA: { reliable: ['rebounds', 'blocks'], volatile: ['points', 'assists'] },
|
||||
education: 'A Fortress generates value on the defensive glass and at the rim. Rebounds and blocks are matchup-resilient; their scoring depends on how much offense flows their way.',
|
||||
},
|
||||
ARTILLERY: {
|
||||
legacyName: 'STRETCH BIG', tag: 'ARTILLERY', sport: 'nba', color: '#159AAE', glyph: 'target',
|
||||
legacyName: 'STRETCH BIG', tag: 'ARTILLERY', sport: 'nba', color: '#C98A5A', glyph: 'target',
|
||||
description: 'Floor-spacing shooting big',
|
||||
propDNA: { reliable: ['threes', 'rebounds'], volatile: ['assists', 'blocks'] },
|
||||
education: 'Artillery bigs space the floor and crash the glass. Threes and rebounds are their bread and butter; assists and blocks are situational.',
|
||||
},
|
||||
SURGE: {
|
||||
legacyName: 'USAGE SPONGE', tag: 'SURGE', sport: 'nba', color: '#FFB347', glyph: 'uparrow',
|
||||
legacyName: 'USAGE SPONGE', tag: 'SURGE', sport: 'nba', color: '#FFA24A', glyph: 'uparrow',
|
||||
description: 'Usage spikes when stars sit',
|
||||
propDNA: { reliable: ['points'], volatile: ['assists', 'rebounds'] },
|
||||
education: 'A Surge soaks up shots when a star sits or is injured. Their points props spike on cascade nights — read the injury report before trusting the baseline.',
|
||||
@@ -73,7 +73,7 @@ const ARCHETYPES = {
|
||||
education: 'A Paint Boss operates in the paint. Points and rebounds are reliable against most fronts; perimeter props are noise.',
|
||||
},
|
||||
LOCKDOWN: {
|
||||
legacyName: 'DEFENSIVE SPECIALIST', tag: 'LOCKDOWN', sport: 'nba', color: '#6366F1', glyph: 'shieldCheck',
|
||||
legacyName: 'DEFENSIVE SPECIALIST', tag: 'LOCKDOWN', sport: 'nba', color: '#5A6474', glyph: 'shieldCheck',
|
||||
description: 'Perimeter stopper, low usage',
|
||||
propDNA: { reliable: ['steals'], volatile: ['points', 'assists'] },
|
||||
education: 'Lockdowns earn minutes with their on-ball defense. Steals and blocks carry their card; offensive props are low-volume and streaky.',
|
||||
@@ -85,25 +85,25 @@ const ARCHETYPES = {
|
||||
education: 'Switchboards run the offense from a wing or big body, so points, assists, and rebounds all stay live. Their three-point output is the swing factor.',
|
||||
},
|
||||
ARCHITECT: {
|
||||
legacyName: 'SLASHER', tag: 'ARCHITECT', sport: 'nba', color: '#FB923C', glyph: 'slash',
|
||||
legacyName: 'SLASHER', tag: 'ARCHITECT', sport: 'nba', color: '#B07CFF', glyph: 'slash',
|
||||
description: 'Self-created shot maker, rim-attacking',
|
||||
propDNA: { reliable: ['points'], volatile: ['threes', 'assists'] },
|
||||
education: 'Architects manufacture their own shot at the rim and the line. Points are stable; their three-point props are volatile because they rarely settle for jumpers.',
|
||||
},
|
||||
PISTON: {
|
||||
legacyName: 'RIM RUNNER', tag: 'PISTON', sport: 'nba', color: '#F472B6', glyph: 'arc',
|
||||
legacyName: 'RIM RUNNER', tag: 'PISTON', sport: 'nba', color: '#E87B4A', glyph: 'arc',
|
||||
description: 'Lob and putback finisher',
|
||||
propDNA: { reliable: ['rebounds'], volatile: ['points', 'assists'] },
|
||||
education: 'Pistons finish lobs and putbacks. Rebounds are reliable; their scoring depends entirely on feeds from creators.',
|
||||
},
|
||||
SENTINEL: {
|
||||
legacyName: '3-AND-D', tag: 'SENTINEL', sport: 'nba', color: '#818CF8', glyph: 'crosshair',
|
||||
legacyName: '3-AND-D', tag: 'SENTINEL', sport: 'nba', color: '#4FA0C4', glyph: 'crosshair',
|
||||
description: 'Catch-and-shoot plus defense',
|
||||
propDNA: { reliable: ['threes'], volatile: ['points', 'assists'] },
|
||||
education: 'Sentinels catch and shoot. Threes are their signature prop; total points swing with how many open looks the offense generates.',
|
||||
},
|
||||
IGNITER: {
|
||||
legacyName: 'SIXTH MAN', tag: 'IGNITER', sport: 'nba', color: '#FACC15', glyph: 'bolt',
|
||||
legacyName: 'SIXTH MAN', tag: 'IGNITER', sport: 'nba', color: '#FF8A3D', glyph: 'bolt',
|
||||
description: 'Bench scoring spark',
|
||||
propDNA: { reliable: ['points'], volatile: ['rebounds', 'assists'] },
|
||||
education: 'Igniters provide instant offense off the bench. Their points props depend on minutes — confirm the rotation before betting overs.',
|
||||
@@ -117,25 +117,25 @@ const ARCHETYPES = {
|
||||
education: 'Distributors orchestrate from the elbow and block. Assists and rebounds are reliable; perimeter shooting is the volatile leg.',
|
||||
},
|
||||
SHIELD: {
|
||||
legacyName: 'TWO-WAY WING', tag: 'SHIELD', sport: 'wnba', color: '#A78BFA', glyph: 'shieldCheck',
|
||||
legacyName: 'TWO-WAY WING', tag: 'SHIELD', sport: 'wnba', color: '#5A8CA8', glyph: 'shieldCheck',
|
||||
description: 'Two-way perimeter forward',
|
||||
propDNA: { reliable: ['points', 'steals'], volatile: ['assists'] },
|
||||
education: 'Shields contribute on both ends. Points and defensive stats stay live; their playmaking is secondary.',
|
||||
},
|
||||
RANGE: {
|
||||
legacyName: 'STRETCH FORWARD', tag: 'RANGE', sport: 'wnba', color: '#159AAE', glyph: 'target',
|
||||
legacyName: 'STRETCH FORWARD', tag: 'RANGE', sport: 'wnba', color: '#C77CE0', glyph: 'target',
|
||||
description: 'Floor-spacing forward',
|
||||
propDNA: { reliable: ['threes', 'points'], volatile: ['assists', 'blocks'] },
|
||||
education: 'Range forwards space the floor from the four. Threes and points are reliable; interior props are matchup-dependent.',
|
||||
},
|
||||
SPARK: {
|
||||
legacyName: 'SLASHING GUARD', tag: 'SPARK', sport: 'wnba', color: '#FB923C', glyph: 'slash',
|
||||
legacyName: 'SLASHING GUARD', tag: 'SPARK', sport: 'wnba', color: '#F0A93D', glyph: 'slash',
|
||||
description: 'Downhill scoring guard',
|
||||
propDNA: { reliable: ['points'], volatile: ['threes', 'assists'] },
|
||||
education: 'Sparks attack downhill. Points are stable; three-point props are the volatile leg since they prioritize the rim.',
|
||||
},
|
||||
ANCHOR: {
|
||||
legacyName: 'INTERIOR ANCHOR', tag: 'ANCHOR', sport: 'wnba', color: '#6366F1', glyph: 'shield',
|
||||
legacyName: 'INTERIOR ANCHOR', tag: 'ANCHOR', sport: 'wnba', color: '#4C86C4', glyph: 'shield',
|
||||
description: 'Dominant paint defender and rebounder',
|
||||
propDNA: { reliable: ['rebounds', 'blocks'], volatile: ['points', 'assists'] },
|
||||
education: 'Anchors own the paint. Rebounds and blocks are reliable; their scoring depends on post touches.',
|
||||
@@ -143,7 +143,7 @@ const ARCHETYPES = {
|
||||
|
||||
// ───────── MLB (15) ─────────
|
||||
BOMBER: {
|
||||
legacyName: 'POWER SLUGGER', tag: 'BOMBER', sport: 'mlb', color: '#FF6B4A', glyph: 'triangle',
|
||||
legacyName: 'POWER SLUGGER', tag: 'BOMBER', sport: 'mlb', color: '#FF9F45', glyph: 'triangle',
|
||||
description: 'Middle-of-the-order power producer',
|
||||
propDNA: { reliable: ['total_bases', 'home_runs'], volatile: ['hits'] },
|
||||
education: 'Bombers drive the ball over the fence. Total bases and home-run props carry their value; their batting-average-driven props (hits) are the volatile leg from strikeout risk.',
|
||||
@@ -155,13 +155,13 @@ const ARCHETYPES = {
|
||||
education: 'Brush hitters rarely strike out, so their hits props are among the most reliable in baseball. Power props (HR, TB) are the volatile leg.',
|
||||
},
|
||||
DRIVER: {
|
||||
legacyName: 'RUN PRODUCER', tag: 'DRIVER', sport: 'mlb', color: '#4A9EFF', glyph: 'diamond',
|
||||
legacyName: 'RUN PRODUCER', tag: 'DRIVER', sport: 'mlb', color: '#5A7D9A', glyph: 'diamond',
|
||||
description: 'RBI-dependent, lineup context',
|
||||
propDNA: { reliable: ['rbi'], volatile: ['hits', 'home_runs'] },
|
||||
education: 'Drivers hit in the heart of the order. RBI props track lineup context — strong with runners on base; their individual hit props are more variable.',
|
||||
},
|
||||
ALPHA: {
|
||||
legacyName: 'ACE', tag: 'ALPHA', sport: 'mlb', color: '#A78BFA', glyph: 'star',
|
||||
legacyName: 'ACE', tag: 'ALPHA', sport: 'mlb', color: '#7C5CFF', glyph: 'star',
|
||||
description: 'High K/9, low WHIP, deep games',
|
||||
propDNA: { reliable: ['strikeouts', 'innings_pitched'], volatile: ['earned_runs'] },
|
||||
education: 'Alphas miss bats and go deep. Strikeout and innings props are their most reliable; earned-run props are noisier because one swing can change a line.',
|
||||
@@ -173,7 +173,7 @@ const ARCHETYPES = {
|
||||
education: 'Whiffs rack up strikeouts but allow more baserunners than an Alpha. The strikeout prop is reliable; earned-run and innings props swing with their traffic.',
|
||||
},
|
||||
GHOST: {
|
||||
legacyName: 'SPEED THREAT', tag: 'GHOST', sport: 'mlb', color: '#159AAE', glyph: 'chevrons',
|
||||
legacyName: 'SPEED THREAT', tag: 'GHOST', sport: 'mlb', color: '#3FD8E0', glyph: 'chevrons',
|
||||
description: 'Stolen bases, speed score',
|
||||
propDNA: { reliable: ['stolen_bases', 'runs'], volatile: ['home_runs'] },
|
||||
education: 'Ghosts turn singles into runs. Stolen-base and runs props are their lane; power props rarely clear.',
|
||||
@@ -191,37 +191,37 @@ const ARCHETYPES = {
|
||||
education: 'Flex players move around the lineup and the diamond. Their props are matchup- and slot-dependent — confirm they are starting before betting.',
|
||||
},
|
||||
WORKHORSE: {
|
||||
legacyName: 'INNINGS EATER', tag: 'WORKHORSE', sport: 'mlb', color: '#818CF8', glyph: 'clock',
|
||||
legacyName: 'INNINGS EATER', tag: 'WORKHORSE', sport: 'mlb', color: '#C89B5A', glyph: 'clock',
|
||||
description: 'Durable, deep-start arm',
|
||||
propDNA: { reliable: ['innings_pitched'], volatile: ['strikeouts', 'earned_runs'] },
|
||||
education: 'Workhorses pitch deep without elite stuff. Innings props are reliable; strikeout and earned-run props are more variable since they pitch to contact.',
|
||||
},
|
||||
CATALYST: {
|
||||
legacyName: 'TABLE SETTER', tag: 'CATALYST', sport: 'mlb', color: '#38BDF8', glyph: 'diamondLine',
|
||||
legacyName: 'TABLE SETTER', tag: 'CATALYST', sport: 'mlb', color: '#E88AC0', glyph: 'diamondLine',
|
||||
description: 'On-base leadoff catalyst',
|
||||
propDNA: { reliable: ['hits', 'runs'], volatile: ['rbi', 'home_runs'] },
|
||||
education: 'Catalysts get on base and score. Hits and runs props are their lane; RBI and power props sit lower in their profile.',
|
||||
},
|
||||
MIRROR: {
|
||||
legacyName: 'GAP HITTER', tag: 'MIRROR', sport: 'mlb', color: '#8FC04A', glyph: 'uparrow',
|
||||
legacyName: 'GAP HITTER', tag: 'MIRROR', sport: 'mlb', color: '#B0B6C8', glyph: 'uparrow',
|
||||
description: 'Gap-to-gap line-drive bat',
|
||||
propDNA: { reliable: ['total_bases', 'hits'], volatile: ['home_runs'] },
|
||||
education: 'Mirror hitters spray doubles to both gaps. Total bases and hits are reliable; home-run props are the volatile leg of their extra-base profile.',
|
||||
},
|
||||
HAMMER: {
|
||||
legacyName: 'CLOSER', tag: 'HAMMER', sport: 'mlb', color: '#FB7185', glyph: 'lock',
|
||||
legacyName: 'CLOSER', tag: 'HAMMER', sport: 'mlb', color: '#FF4D6D', glyph: 'lock',
|
||||
description: 'Ninth-inning save specialist',
|
||||
propDNA: { reliable: ['strikeouts'], volatile: ['earned_runs', 'innings_pitched'] },
|
||||
education: 'Hammers throw one high-leverage inning. Strikeout props can hit in a clean save; everything else is a one-inning coin flip.',
|
||||
},
|
||||
SINKER: {
|
||||
legacyName: 'SWINGMAN', tag: 'SINKER', sport: 'mlb', color: '#FBBF24', glyph: 'swap',
|
||||
legacyName: 'SWINGMAN', tag: 'SINKER', sport: 'mlb', color: '#5A9AB0', glyph: 'swap',
|
||||
description: 'Groundball spot-starter / long relief',
|
||||
propDNA: { reliable: [], volatile: ['strikeouts', 'innings_pitched', 'earned_runs'] },
|
||||
education: 'Sinkers bounce between starting and relief and pitch to contact. Their workload is unpredictable, so all of their props carry role risk — confirm the assignment.',
|
||||
},
|
||||
BRIDGE: {
|
||||
legacyName: 'BULLPEN ARM', tag: 'BRIDGE', sport: 'mlb', color: '#6366F1', glyph: 'shieldCheck',
|
||||
legacyName: 'BULLPEN ARM', tag: 'BRIDGE', sport: 'mlb', color: '#6C9CB0', glyph: 'shieldCheck',
|
||||
description: 'Setup / high-leverage middle relief',
|
||||
propDNA: { reliable: ['strikeouts'], volatile: ['earned_runs', 'innings_pitched'] },
|
||||
education: 'Bridges throw short, high-leverage outings. Strikeout props can hit in one inning; innings and earned-run props are too small a sample to trust.',
|
||||
@@ -241,31 +241,31 @@ const ARCHETYPES = {
|
||||
education: 'Finishers score inside the box. Shots-on-target and goals are their props; they rarely create for others.',
|
||||
},
|
||||
MAESTRO: {
|
||||
legacyName: 'CREATOR', tag: 'MAESTRO', sport: 'soccer', color: '#4A9EFF', glyph: 'node',
|
||||
legacyName: 'CREATOR', tag: 'MAESTRO', sport: 'soccer', color: '#D9A441', glyph: 'node',
|
||||
description: 'Chance-creating playmaker',
|
||||
propDNA: { reliable: ['assists', 'passes'], volatile: ['goals'] },
|
||||
education: 'Maestros set the table. Assists and passing props are reliable; their goal output is the volatile leg.',
|
||||
},
|
||||
TOWER: {
|
||||
legacyName: 'TARGET MAN', tag: 'TOWER', sport: 'soccer', color: '#FF6B4A', glyph: 'triangle',
|
||||
legacyName: 'TARGET MAN', tag: 'TOWER', sport: 'soccer', color: '#6C9CB0', glyph: 'triangle',
|
||||
description: 'Hold-up aerial striker',
|
||||
propDNA: { reliable: ['shots', 'shots_on_target'], volatile: ['goals', 'assists'] },
|
||||
education: 'Towers win aerial duels and hold the ball up. Shot props are reliable; conversion to goals is variable.',
|
||||
},
|
||||
MOTOR: {
|
||||
legacyName: 'BOX-TO-BOX', tag: 'MOTOR', sport: 'soccer', color: '#1EA6D8', glyph: 'chevrons',
|
||||
legacyName: 'BOX-TO-BOX', tag: 'MOTOR', sport: 'soccer', color: '#E0A03D', glyph: 'chevrons',
|
||||
description: 'All-action central midfielder',
|
||||
propDNA: { reliable: ['tackles', 'passes'], volatile: ['goals', 'shots'] },
|
||||
education: 'Motors cover every blade of grass. Tackles and passing props are reliable; their attacking output swings by role.',
|
||||
},
|
||||
BLADE: {
|
||||
legacyName: 'WING WIZARD', tag: 'BLADE', sport: 'soccer', color: '#159AAE', glyph: 'slash',
|
||||
legacyName: 'WING WIZARD', tag: 'BLADE', sport: 'soccer', color: '#B36CFF', glyph: 'slash',
|
||||
description: 'Dribbling wide threat',
|
||||
propDNA: { reliable: ['shots', 'assists'], volatile: ['goals'] },
|
||||
education: 'Blades beat defenders wide. Shots and assists are their lane; goals come in streaks.',
|
||||
},
|
||||
WALL: {
|
||||
legacyName: 'SWEEPER KEEPER', tag: 'WALL', sport: 'soccer', color: '#A78BFA', glyph: 'shield',
|
||||
legacyName: 'SWEEPER KEEPER', tag: 'WALL', sport: 'soccer', color: '#5A7D9A', glyph: 'shield',
|
||||
description: 'Distributing goalkeeper',
|
||||
propDNA: { reliable: ['saves', 'passes'], volatile: ['goals_conceded'] },
|
||||
education: 'Walls distribute and defend space. Saves and passing props are reliable; goals-conceded depends on the team in front of them.',
|
||||
|
||||
@@ -11,27 +11,27 @@ const svc = require('../../src/services/archetypeService');
|
||||
describe('archetypes lib — badge styling', () => {
|
||||
it('full variant fills with the archetype color + white text', () => {
|
||||
const s = arch.badgeStyle('BOMBER', 'full', 'md');
|
||||
expect(s.bg).toBe('#FF6B4A');
|
||||
expect(s.bg).toBe('#FF9F45');
|
||||
expect(s.textColor).toBe('#FFFFFF');
|
||||
expect(s.borderColor).toBe('#FF6B4A');
|
||||
expect(s.borderColor).toBe('#FF9F45');
|
||||
});
|
||||
|
||||
it('ghost variant is transparent with a colored border', () => {
|
||||
const s = arch.badgeStyle('CONDUCTOR', 'ghost', 'sm');
|
||||
expect(s.bg).toBe('transparent');
|
||||
expect(s.textColor).toBe('#4A9EFF');
|
||||
expect(s.borderColor).toBe('#4A9EFFCC');
|
||||
expect(s.textColor).toBe('#6C8CFF');
|
||||
expect(s.borderColor).toBe('#6C8CFFCC');
|
||||
});
|
||||
|
||||
it('tint variant (default) uses a low-alpha tinted background', () => {
|
||||
const s = arch.badgeStyle('ALPHA');
|
||||
expect(s.bg).toBe('#A78BFA1F');
|
||||
expect(s.borderColor).toBe('#A78BFA52');
|
||||
expect(s.bg).toBe('#7C5CFF1F');
|
||||
expect(s.borderColor).toBe('#7C5CFF52');
|
||||
});
|
||||
|
||||
it('archetypeColor matches and is case-insensitive', () => {
|
||||
expect(arch.archetypeColor('ace')).toBe('#A78BFA');
|
||||
expect(arch.archetypeColor('Two-Way Anchor')).toBe('#A78BFA');
|
||||
expect(arch.archetypeColor('ace')).toBe('#7C5CFF');
|
||||
expect(arch.archetypeColor('Two-Way Anchor')).toBe('#4C6FA5');
|
||||
});
|
||||
|
||||
it('glyphSvg returns a 16x16 svg wrapper', () => {
|
||||
|
||||
+60
-29
@@ -8,6 +8,37 @@
|
||||
|
||||
/* Glyph SVG inner-markup keyed by name (drawn in a 0 0 16 16 viewBox). */
|
||||
const GLYPHS = {
|
||||
/* Design 74-mark library — real archetype marks (HANDOFF) */
|
||||
'alpha': '<path fill="currentColor" fill-opacity=".16" d="M12 3 4 20h16z"/><path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round" d="M12 3 4 20h16zM8.5 14h7"/>',
|
||||
'anchor': '<circle cx="12" cy="5" r="2.2" fill="none" stroke="currentColor" stroke-width="2.1"/><path fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" d="M12 7v12M6 13c0 4 3 6 6 6s6-2 6-6M4 13h4M16 13h4"/>',
|
||||
'architect': '<path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round" d="M12 3 4 19h16z"/><path fill="currentColor" fill-opacity=".18" d="m12 9 4 8H8z"/>',
|
||||
'artillery': '<path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" d="M3 20C7 8 14 6 20 6"/><path fill="currentColor" d="M20 6l-4 .3 2 3.4z"/><path stroke="currentColor" stroke-width="1.8" stroke-linecap="round" d="M19 4v-2M22 7h-2"/>',
|
||||
'blade': '<path fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" d="M4 20C10 18 16 12 20 4"/><path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" d="M13 5l7-1-1 7"/>',
|
||||
'bomber': '<path fill="currentColor" fill-opacity=".18" d="M12 3l7 9h-4v8H9v-8H5z"/><path fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" d="M12 3l7 9h-4v8H9v-8H5z"/>',
|
||||
'bridge': '<path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" d="M4 18v-8a8 8 0 0 1 16 0v8M4 14h16M9 18v-4M15 18v-4"/>',
|
||||
'catalyst': '<path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" d="M3 12h11M10 7l5 5-5 5"/><path fill="currentColor" fill-opacity=".2" d="M16 8h5v8h-5z"/><path fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" d="M16 8h5v8h-5z"/>',
|
||||
'conductor': '<circle cx="12" cy="16" r="2.6" fill="currentColor"/><path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" d="M12 14 6 5M12 14l6-9M12 14v-4"/>',
|
||||
'driver': '<path fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" d="M5 19 17 7"/><circle cx="19" cy="5" r="2.2" fill="currentColor"/><path fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" d="M4 14a10 10 0 0 0 6 6"/>',
|
||||
'fortress': '<path fill="currentColor" fill-opacity=".16" d="M5 5h3v2h2V5h4v2h2V5h3v6c0 5-4 7-7 8-3-1-7-3-7-8V5Z"/><path fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" d="M5 5h3v2h2V5h4v2h2V5h3v6c0 5-4 7-7 8-3-1-7-3-7-8V5Z"/>',
|
||||
'ghost': '<path fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" d="M4 6l6 6-6 6M11 6l6 6-6 6"/>',
|
||||
'hammer': '<path fill="currentColor" fill-opacity=".18" d="M6 4h11v5H6z"/><path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" d="M6 4h11v5H6zM11.5 9v11M8 20h7"/>',
|
||||
'igniter': '<path fill="currentColor" d="M12 2c.6 4.8 2.4 6.6 7.2 7.2C14.4 9.8 12.6 11.6 12 16.4 11.4 11.6 9.6 9.8 4.8 9.2 9.6 8.6 11.4 6.8 12 2Z"/><path fill="currentColor" d="M18 15c.3 2 1 2.7 3 3-2 .3-2.7 1-3 3-.3-2-1-2.7-3-3 2-.3 2.7-1 3-3Z"/>',
|
||||
'lockdown': '<path fill="currentColor" fill-opacity=".16" d="M5 10h14v10H5z"/><path fill="none" stroke="currentColor" stroke-width="2.1" stroke-linejoin="round" d="M5 10h14v10H5zM8 10V7a4 4 0 0 1 8 0v3"/><circle cx="12" cy="15" r="1.6" fill="currentColor"/>',
|
||||
'maestro': '<path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" d="M5 19 16 6"/><circle cx="17" cy="5" r="1.9" fill="currentColor"/><path fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" d="M5 9c2-2 5-2 7 0M4 13c2.5-2.5 6-2.5 9 0"/>',
|
||||
'mirror': '<path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" d="M9 5 4 12l5 7M15 5l5 7-5 7"/><path stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-dasharray="2 2.6" d="M12 4v16"/>',
|
||||
'motor': '<path fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" stroke-linejoin="round" d="M6 8a7 7 0 0 1 12 2M18 16a7 7 0 0 1-12-2"/><path fill="currentColor" d="M18 5l1.4 4.2-4.2-1zM6 19l-1.4-4.2 4.2 1z"/>',
|
||||
'piston': '<path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" d="M8 4h8v16H8zM12 8v8M9.5 10.5 12 8l2.5 2.5M9.5 13.5 12 16l2.5-2.5"/>',
|
||||
'range': '<path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" d="M4 17a8 8 0 0 1 16 0"/><path stroke="currentColor" stroke-width="2.2" stroke-linecap="round" d="M12 17V7"/><path fill="currentColor" d="M12 5l-2.4 4h4.8z"/>',
|
||||
'sentinel': '<path fill="currentColor" fill-opacity=".16" d="M12 3 5 6v5c0 5 3.5 7.5 7 9 3.5-1.5 7-4 7-9V6z"/><path fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" d="M12 3 5 6v5c0 5 3.5 7.5 7 9 3.5-1.5 7-4 7-9V6z"/><circle cx="12" cy="11" r="2" fill="currentColor"/>',
|
||||
'shield': '<path fill="currentColor" fill-opacity=".16" d="M12 3 5 6v5c0 5 3.5 7.5 7 9 3.5-1.5 7-4 7-9V6z"/><path fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" d="M12 3 5 6v5c0 5 3.5 7.5 7 9 3.5-1.5 7-4 7-9V6z"/><path stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="m9 11 2 2 4-4"/>',
|
||||
'sinker': '<path fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" d="M5 5c6 1 9 5 9 13"/><path fill="currentColor" d="M14 20l-3-4.5 6 .4z"/>',
|
||||
'spark': '<circle cx="12" cy="12" r="3" fill="currentColor"/><path fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" d="M12 3v3M12 18v3M4.5 7.5l2.2 2.2M17.3 14.3l2.2 2.2M4.5 16.5l2.2-2.2M17.3 9.7l2.2-2.2"/>',
|
||||
'surge': '<path fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" d="M4 18l4-4 3 2 5-6"/><path stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" d="M16 10h4v4"/>',
|
||||
'torch': '<path fill="currentColor" fill-opacity=".16" d="M12 2c3.5 4.5 5.5 6 5.5 10a5.5 5.5 0 0 1-11 0C6.5 8 8.5 6.5 12 2Z"/><path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linejoin="round" d="M12 7c2 2.6 3 3.8 3 6a3 3 0 0 1-6 0c0-2.2 1-3.4 3-6Z"/>',
|
||||
'tower': '<circle cx="12" cy="6" r="2.6" fill="currentColor"/><path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" d="M12 9v8M8 20l4-3 4 3M8 13h8"/>',
|
||||
'wall': '<path fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" d="M4 5h16v14H4z"/><path stroke="currentColor" stroke-width="1.8" d="M4 9.7h16M4 14.3h16M11 5v4.7M8 9.7v4.6M15 9.7v4.6M11 14.3V19"/>',
|
||||
'workhorse': '<path fill="none" stroke="currentColor" stroke-width="2.8" stroke-linecap="round" d="M4 7h16M4 12h16M4 17h16"/>',
|
||||
|
||||
triangle: '<path d="M8 2 L14 14 L2 14 Z" fill="currentColor"/>',
|
||||
node: '<circle cx="8" cy="8" r="2.3" fill="currentColor"/><path d="M8 5.7V1.5M5.4 9.3 2.4 13M10.6 9.3 13.6 13" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>',
|
||||
shield: '<path d="M8 1.6 L13.4 4 V8.2 C13.4 11.2 8 14.4 8 14.4 C8 14.4 2.6 11.2 2.6 8.2 V4 Z" fill="currentColor"/>',
|
||||
@@ -38,50 +69,50 @@ const GLYPHS = {
|
||||
`legacy` is the old descriptive label, kept for reference (never displayed). */
|
||||
const ARCHETYPE_MAP = {
|
||||
// NBA
|
||||
TORCH: { c: '#FF6B4A', d: 'High usage, shot-dependent scorer', g: 'triangle', legacy: 'VOLUME SCORER' },
|
||||
CONDUCTOR: { c: '#4A9EFF', d: 'Assist-heavy playmaker', g: 'node', legacy: 'FLOOR GENERAL' },
|
||||
FORTRESS: { c: '#A78BFA', d: 'Defense, rebounds, blocks', g: 'shield', legacy: 'TWO-WAY ANCHOR' },
|
||||
ARTILLERY: { c: '#159AAE', d: 'Floor-spacing shooting big', g: 'target', legacy: 'STRETCH BIG' },
|
||||
SURGE: { c: '#FFB347', d: 'Usage spikes when stars sit', g: 'uparrow', legacy: 'USAGE SPONGE' },
|
||||
TORCH: { c: '#FF6B4A', d: 'High usage, shot-dependent scorer', g: 'torch', legacy: 'VOLUME SCORER' },
|
||||
CONDUCTOR: { c: '#6C8CFF', d: 'Assist-heavy playmaker', g: 'conductor', legacy: 'FLOOR GENERAL' },
|
||||
FORTRESS: { c: '#4C6FA5', d: 'Defense, rebounds, blocks', g: 'fortress', legacy: 'TWO-WAY ANCHOR' },
|
||||
ARTILLERY: { c: '#C98A5A', d: 'Floor-spacing shooting big', g: 'artillery', legacy: 'STRETCH BIG' },
|
||||
SURGE: { c: '#FFA24A', d: 'Usage spikes when stars sit', g: 'surge', legacy: 'USAGE SPONGE' },
|
||||
'DUAL THREAT': { c: '#1EA6D8', d: 'Scoring + playmaking hybrid', g: 'twin', legacy: 'COMBO GUARD' },
|
||||
CONNECTOR: { c: '#9499A8', d: 'Low-usage specialist', g: 'chain', legacy: 'ROLE GLUE' },
|
||||
FASTBREAK: { c: '#22D3EE', d: 'Pace-pushing fast-break threat', g: 'chevrons', legacy: 'TRANSITION ENGINE' },
|
||||
'PAINT BOSS': { c: '#FF5C5C', d: 'Back-to-basket interior scorer', g: 'postup', legacy: 'POST SCORER' },
|
||||
LOCKDOWN: { c: '#6366F1', d: 'Perimeter stopper, low usage', g: 'shieldCheck', legacy: 'DEFENSIVE SPECIALIST' },
|
||||
LOCKDOWN: { c: '#5A6474', d: 'Perimeter stopper, low usage', g: 'lockdown', legacy: 'DEFENSIVE SPECIALIST' },
|
||||
SWITCHBOARD: { c: '#38BDF8', d: 'Oversized primary creator', g: 'half', legacy: 'POINT FORWARD' },
|
||||
ARCHITECT: { c: '#FB923C', d: 'Self-created shot maker, rim-attacking', g: 'slash', legacy: 'SLASHER' },
|
||||
PISTON: { c: '#F472B6', d: 'Lob and putback finisher', g: 'arc', legacy: 'RIM RUNNER' },
|
||||
SENTINEL: { c: '#818CF8', d: 'Catch-and-shoot plus defense', g: 'crosshair', legacy: '3-AND-D' },
|
||||
IGNITER: { c: '#FACC15', d: 'Bench scoring spark', g: 'bolt', legacy: 'SIXTH MAN' },
|
||||
ARCHITECT: { c: '#B07CFF', d: 'Self-created shot maker, rim-attacking', g: 'architect', legacy: 'SLASHER' },
|
||||
PISTON: { c: '#E87B4A', d: 'Lob and putback finisher', g: 'piston', legacy: 'RIM RUNNER' },
|
||||
SENTINEL: { c: '#4FA0C4', d: 'Catch-and-shoot plus defense', g: 'sentinel', legacy: '3-AND-D' },
|
||||
IGNITER: { c: '#FF8A3D', d: 'Bench scoring spark', g: 'igniter', legacy: 'SIXTH MAN' },
|
||||
// WNBA-unique
|
||||
DISTRIBUTOR: { c: '#C084FC', d: 'Playmaking hub from the post', g: 'node', legacy: 'POST FACILITATOR' },
|
||||
SHIELD: { c: '#A78BFA', d: 'Two-way perimeter forward', g: 'shieldCheck', legacy: 'TWO-WAY WING' },
|
||||
RANGE: { c: '#159AAE', d: 'Floor-spacing forward', g: 'target', legacy: 'STRETCH FORWARD' },
|
||||
SPARK: { c: '#FB923C', d: 'Downhill scoring guard', g: 'slash', legacy: 'SLASHING GUARD' },
|
||||
ANCHOR: { c: '#6366F1', d: 'Dominant paint defender and rebounder', g: 'shield', legacy: 'INTERIOR ANCHOR' },
|
||||
SHIELD: { c: '#5A8CA8', d: 'Two-way perimeter forward', g: 'shield', legacy: 'TWO-WAY WING' },
|
||||
RANGE: { c: '#C77CE0', d: 'Floor-spacing forward', g: 'range', legacy: 'STRETCH FORWARD' },
|
||||
SPARK: { c: '#F0A93D', d: 'Downhill scoring guard', g: 'spark', legacy: 'SLASHING GUARD' },
|
||||
ANCHOR: { c: '#4C86C4', d: 'Dominant paint defender and rebounder', g: 'anchor', legacy: 'INTERIOR ANCHOR' },
|
||||
// MLB
|
||||
BOMBER: { c: '#FF6B4A', d: 'Middle-of-the-order power producer', g: 'triangle', legacy: 'POWER SLUGGER' },
|
||||
BOMBER: { c: '#FF9F45', d: 'Middle-of-the-order power producer', g: 'bomber', legacy: 'POWER SLUGGER' },
|
||||
BRUSH: { c: '#C0C63C', d: 'High average, low strikeout', g: 'crosshair', legacy: 'CONTACT' },
|
||||
DRIVER: { c: '#4A9EFF', d: 'RBI-dependent, lineup context', g: 'diamond', legacy: 'RUN PRODUCER' },
|
||||
ALPHA: { c: '#A78BFA', d: 'High K/9, low WHIP, deep games', g: 'star', legacy: 'ACE' },
|
||||
DRIVER: { c: '#5A7D9A', d: 'RBI-dependent, lineup context', g: 'driver', legacy: 'RUN PRODUCER' },
|
||||
ALPHA: { c: '#7C5CFF', d: 'High K/9, low WHIP, deep games', g: 'alpha', legacy: 'ACE' },
|
||||
WHIFF: { c: '#FFB347', d: 'Bat-missing arm, high K with traffic', g: 'bolt', legacy: 'STRIKEOUT ARTIST' },
|
||||
GHOST: { c: '#159AAE', d: 'Stolen bases, speed score', g: 'chevrons', legacy: 'SPEED THREAT' },
|
||||
GHOST: { c: '#3FD8E0', d: 'Stolen bases, speed score', g: 'ghost', legacy: 'SPEED THREAT' },
|
||||
HYBRID: { c: '#F472B6', d: 'Bats and pitches at elite level', g: 'half', legacy: 'TWO-WAY PLAYER' },
|
||||
FLEX: { c: '#22D3EE', d: 'Multi-position lineup flex', g: 'plus', legacy: 'UTILITY PLAYER' },
|
||||
WORKHORSE: { c: '#818CF8', d: 'Durable, deep-start arm', g: 'clock', legacy: 'INNINGS EATER' },
|
||||
CATALYST: { c: '#38BDF8', d: 'On-base leadoff catalyst', g: 'diamondLine', legacy: 'TABLE SETTER' },
|
||||
MIRROR: { c: '#8FC04A', d: 'Gap-to-gap line-drive bat', g: 'uparrow', legacy: 'GAP HITTER' },
|
||||
HAMMER: { c: '#FB7185', d: 'Ninth-inning save specialist', g: 'lock', legacy: 'CLOSER' },
|
||||
SINKER: { c: '#FBBF24', d: 'Groundball spot-starter / long relief', g: 'swap', legacy: 'SWINGMAN' },
|
||||
BRIDGE: { c: '#6366F1', d: 'Setup / high-leverage middle relief', g: 'shieldCheck', legacy: 'BULLPEN ARM' },
|
||||
WORKHORSE: { c: '#C89B5A', d: 'Durable, deep-start arm', g: 'workhorse', legacy: 'INNINGS EATER' },
|
||||
CATALYST: { c: '#E88AC0', d: 'On-base leadoff catalyst', g: 'catalyst', legacy: 'TABLE SETTER' },
|
||||
MIRROR: { c: '#B0B6C8', d: 'Gap-to-gap line-drive bat', g: 'mirror', legacy: 'GAP HITTER' },
|
||||
HAMMER: { c: '#FF4D6D', d: 'Ninth-inning save specialist', g: 'hammer', legacy: 'CLOSER' },
|
||||
SINKER: { c: '#5A9AB0', d: 'Groundball spot-starter / long relief', g: 'sinker', legacy: 'SWINGMAN' },
|
||||
BRIDGE: { c: '#6C9CB0', d: 'Setup / high-leverage middle relief', g: 'bridge', legacy: 'BULLPEN ARM' },
|
||||
SWITCH: { c: '#FF5C5C', d: 'Platoon-leveraged, glove-first bat', g: 'batball', legacy: 'DEFENSIVE WIZARD' },
|
||||
// Soccer
|
||||
FINISHER: { c: '#FF5C5C', d: 'Penalty-box finisher', g: 'crosshair', legacy: 'POACHER' },
|
||||
MAESTRO: { c: '#4A9EFF', d: 'Chance-creating playmaker', g: 'node', legacy: 'CREATOR' },
|
||||
TOWER: { c: '#FF6B4A', d: 'Hold-up aerial striker', g: 'triangle', legacy: 'TARGET MAN' },
|
||||
MOTOR: { c: '#1EA6D8', d: 'All-action central midfielder', g: 'chevrons', legacy: 'BOX-TO-BOX' },
|
||||
BLADE: { c: '#159AAE', d: 'Dribbling wide threat', g: 'slash', legacy: 'WING WIZARD' },
|
||||
WALL: { c: '#A78BFA', d: 'Distributing goalkeeper', g: 'shield', legacy: 'SWEEPER KEEPER' },
|
||||
MAESTRO: { c: '#D9A441', d: 'Chance-creating playmaker', g: 'maestro', legacy: 'CREATOR' },
|
||||
TOWER: { c: '#6C9CB0', d: 'Hold-up aerial striker', g: 'tower', legacy: 'TARGET MAN' },
|
||||
MOTOR: { c: '#E0A03D', d: 'All-action central midfielder', g: 'motor', legacy: 'BOX-TO-BOX' },
|
||||
BLADE: { c: '#B36CFF', d: 'Dribbling wide threat', g: 'blade', legacy: 'WING WIZARD' },
|
||||
WALL: { c: '#5A7D9A', d: 'Distributing goalkeeper', g: 'wall', legacy: 'SWEEPER KEEPER' },
|
||||
};
|
||||
|
||||
/* Combat archetype visual map (Wave 6 — MMA/UFC). SEPARATE from ARCHETYPE_MAP:
|
||||
|
||||
Reference in New Issue
Block a user