/* ============================================================ ROOY · 01 HOME(IQ 反射宝石徽章 · 数值=顶点) ─────────────────────────────────────────────────────────── IQ 数字(173)右侧一枚「反射宝石徽章」——既是等级徽章(抛光宝石的 视觉分量),又把 6 项能力数值编码进宝石剪影:6 能力值 = 宝石 6 顶点 半径(强外推、弱内收),形状即数据。 排版:↑6 作 173 右上角小上标、本季 落在 ↑6 正下方(成绩 + 趋势角注); 徽章 80、与数字群组聚拢(gap 14)、marginTop 负 nudge 对齐字身中心。 反射宝石(单色抛光 rooy):rooy 辉光底盘(浮起感)+ 满量程骨架(细 rooy rim + 6 轴心连线,露在宝石负空间 = 离满量程的距离)+ 6 琢面 + 两 层高光(柔光 + 锐 sparkle)。琢面深浅 = 统一左上光照(主,相干)+ 该 顶点能力值(次)——光照保证读作一整颗宝石,能力值区分同向暗面、不至 糊成一团(单一 rooy 家族,非多色花宝石)。无描边、无顶点白点。 跨文件依赖:IQFlat / StatColFlat / IQJudgeRow / SeasonCardF / LearningCardF / SeasonStatsOriginal(均来自 home-f.jsx)。 本文件须排在 home-f 之后加载。 ============================================================ */ /* HOME_CAPS — 六能力值,与 review.jsx RCAPS 一致(徽章剪影与 05 复盘 雷达同形)。顺序对应六边形 6 个顶点:顶 → 平衡,顺时针 压力 / 旋转 / 立刃(底) / 节奏 / 协调。 */ const HOME_CAPS = [ { id: 'balance', v: 78 }, { id: 'pressure', v: 71 }, { id: 'rotation', v: 55 }, { id: 'edge', v: 84 }, { id: 'tempo', v: 62 }, { id: 'coord', v: 68 }, ]; /* HexGemBadge — 数值即顶点的反射宝石。pointy-top。顶点半径按数据自身 范围归一化(最弱→rMin、最强→rMax)。分层(自下而上): ⓪ rooy 氛围:外层 halo(淡淡)+ 内层辉光底盘(径向柔光)— 浮起感。 ① 满量程骨架:细 rooy rim + 6 轴心连线(圆心→框顶点),浅 rooy 35%+白(不透明,同 05n 内圈), 画在琢面之下——骨架露在负空间 = 各项「离满量程的距离」。 ② 6 琢面(中心→顶点i→顶点i+1),fill 深浅 = 光照(0.68) + 能力值(0.32) 映射 color-mix(rooy 38~92%, white)。光照主相干、能力值区分同向面。 ③ 两层高光:柔光(radial ~27%)+ 锐 sparkle(radial ~50%),clip 在剪影内。 颜色全走 color-mix(var(--r-rooy)),Tweaks 跟着变。 */ function HexGemBadge({ caps, size = 80 }) { const uid = React.useId().replace(/[:]/g, ''); const cx = 50, cy = 50; const rMin = 20, rMax = 44, rOut = 47; const ang = (i) => -Math.PI / 2 + i * (Math.PI / 3); const polyAt = (r) => Array.from({ length: 6 }, (_, i) => [cx + Math.cos(ang(i)) * r, cy + Math.sin(ang(i)) * r].map(n => n.toFixed(2)).join(',')).join(' '); const vs = caps.map(c => c.v); const vmin = Math.min(...vs), vmax = Math.max(...vs); const rv = (v) => rMin + (rMax - rMin) * ((v - vmin) / (vmax - vmin)); const vp = (i) => [cx + Math.cos(ang(i)) * rv(caps[i].v), cy + Math.sin(ang(i)) * rv(caps[i].v)]; const pts = caps.map((_, i) => vp(i).map(n => n.toFixed(2)).join(',')).join(' '); const framePts = polyAt(rOut); const frameStroke = 'color-mix(in srgb, var(--r-rooy) 35%, white)'; // 不透明(= 05n 内圈轮廓色),避免线条叠加重影 // 统一光照(左上)— 琢面 i 法线 ≈ 其两外顶点中点角 const lightAng = -3 * Math.PI / 4; const lx = Math.cos(lightAng), ly = Math.sin(lightAng); const facetBright = (i) => Math.max(0, Math.cos(ang(i) + Math.PI / 6) * lx + Math.sin(ang(i) + Math.PI / 6) * ly); // 琢面深浅:光照(主) + 能力值(次,区分同向暗面) — 05o 光影 38..92 const mixFor = (i) => { const vf = (caps[i].v - vmin) / (vmax - vmin); const b = facetBright(i) * 0.68 + vf * 0.32; return Math.round(92 - b * 54); }; return ( {/* ⓪ rooy 氛围:外层 halo(淡淡)+ 内层辉光底盘 */} {/* ① 满量程骨架:细 rim + 6 轴心连线(深 rooy,在琢面之下) */} {caps.map((_, i) => { const a = ang(i); return ; })} {/* ② 6 琢面(光照 + 能力值 双重深浅) */} {caps.map((_, i) => { const j = (i + 1) % 6; return ( ); })} {/* ③ 两层高光(柔光 + 锐 sparkle),clip 在剪影内 */} ); } /* IQTrendSup — 173 右上角小角注。固定宽度(占位恒定)+ ↑6 在角上、 本季 就在 ↑6 正下方(marginTop 1,贴近)。固定宽度让 delta 占位不随 本季 位置变 → 徽章位置稳定、不被牵着漂移。 */ function IQTrendSup() { return (
↑ 6
本季
); } /* IQHeroQ — 数字(带 ↑6/本季 上标)+ 宝石徽章。pill 行(含 ›)/ 浮白卡 (立刃·压力 + 判断行)复用 01m。tap 整块 → review。 */ function IQHeroQ({ onNav }) { return (
onNav && onNav('review')} style={{ cursor: 'pointer' }}>
ROOY 指数
); } /* HomeScreenQ(01)— 雪季置顶 → IQ hero(反射宝石徽章)→ 正在学习。 */ function HomeScreenQ({ onNav }) { return (

5 月 3 日 · 周五

你好,Yuki

onNav && onNav('settings')} style={{ marginTop: 12 }}/>
onNav && onNav(tab)}/>
); } Object.assign(window, { HomeScreenQ, IQHeroQ, HexGemBadge, IQTrendSup, HOME_CAPS });