dsh-metaphysics 0.64.0 → 0.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -362,7 +362,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
362
362
  <div class="wrap">
363
363
  <header>
364
364
  <div class="brand-row">
365
- <div class="brand"><span class="seal" aria-hidden="true">命</span><span class="brand-txt">命理排盘<span class="ver">v0.64.0</span><small>八字 · 紫微 · 六爻 · 梅花 · 六壬 · 奇门 · 合盘 · 塔罗 全部在本机计算</small></span></div>
365
+ <div class="brand"><span class="seal" aria-hidden="true">命</span><span class="brand-txt">命理排盘<span class="ver">v0.65.0</span><small>八字 · 紫微 · 六爻 · 梅花 · 六壬 · 奇门 · 合盘 · 塔罗 全部在本机计算</small></span></div>
366
366
  <div class="view-switch">
367
367
  <span class="hint">熟练了可以换回平铺</span>
368
368
  <span class="seg" role="group" aria-label="首屏样式">
@@ -653,7 +653,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
653
653
  <h3>对拍:把典籍当期望值</h3>
654
654
  <ul><li>六爻:京房八宫卦序与世应,64 卦全表;旬空六旬表</li><li>六壬:日干寄宫、中气换将;紫微:纳音定五行局、紫微天府相照</li><li>卦例:《增删卜易》9 条 +《卜筮正宗》128 条(93 成对 + 35 静卦),核本变卦 / 动爻数 / 卦宫 / 缺爻 / 旬空</li><li>奇门:20 个时辰 × 9 宫,核四柱 / 局数 / 值符 / 值使 / 星门神 / 天盘干</li></ul>
655
655
  <h3>工程验证</h3>
656
- <ul><li>测试:164 个测试文件 / 8891 条断言;七道闸(回归 · 断言基线 · 测试可失败自检 · HTML 注入面 · 工程约定 · 产物宿主形态 · 随机扫射)</li><li>可复现:seed / asOf 显式;同一输入同一输出</li><li>口径:晚子时、真太阳时、奇门三流派、闰月归月都可切换,并有字段级差异对照</li></ul>
656
+ <ul><li>测试:165 个测试文件 / 9019 条断言;七道闸(回归 · 断言基线 · 测试可失败自检 · HTML 注入面 · 工程约定 · 产物宿主形态 · 随机扫射)</li><li>可复现:seed / asOf 显式;同一输入同一输出</li><li>口径:晚子时、真太阳时、奇门三流派、闰月归月都可切换,并有字段级差异对照</li></ul>
657
657
 
658
658
  <h3>已知边界(不猜)</h3>
659
659
  <ul><li>六爻应期(具体哪天应验)不做;卦例只录动爻个数,不录爻位</li><li>财富/健康只给结构判断与档位,不给金额区间、不作诊断</li><li>紫微飞星已做「单一支化逐宫追到成环」与「三方四正 16 条按落宫归堆」,但都未叠大限流年四化、不折吉凶;八字交运日已能算到日/时,但未与第三方排盘案例批量对拍</li></ul>
@@ -1241,6 +1241,12 @@ const CALIBER_SWITCHES = {
1241
1241
  阳武府相: '庚干 阳武府相', 阳武同相: '庚干 阳武同相', 巨阳武昌: '辛干 巨阳武昌',
1242
1242
  梁紫府武: '壬干 梁紫府武', 梁紫相武: '壬干 梁紫相武', 破巨阳贪: '癸干 破巨阳贪',
1243
1243
  }),
1244
+ ziweiSchoolSwitch('jieluSchool', '截路空亡:照常 / 不排(中州派)', '截路空亡', 'off', 'zhongzhou', {
1245
+ off: '照常(截空/副截/旬空/副旬)', zhongzhou: '不排(中州派)',
1246
+ }),
1247
+ ziweiSchoolSwitch('suipoSchool', '岁前十二神:照常 / 大耗改岁破(中州派)', '岁前十二神', 'off', 'zhongzhou', {
1248
+ off: '照常(大耗)', zhongzhou: '大耗改岁破',
1249
+ }),
1244
1250
  ],
1245
1251
  qimen: [
1246
1252
  {
@@ -9476,7 +9482,7 @@ return { PALACE_FIELD, STAR_EXTRA, STAR_PAIR, SHA_STAR, MAIN_SHA, FU_STAR, HUA_R
9476
9482
 
9477
9483
  __mods.ziwei = (function () {
9478
9484
  // 紫微斗数安星:命身宫 → 五行局 → 紫微/天府 → 十四主星 → 诸辅煞杂曜 → 十二宫 → 四化 → 大限小限流年 → 格局
9479
- const { STEMS, BRANCHES, ganzhiName, sexagenaryIndex, jdToParts, partsToJd, formatJd } = (__mods.calendar || {});
9485
+ const { STEMS, BRANCHES, ganzhiName, sexagenaryIndex, jdToParts, partsToJd, formatJd, dayGanzhiIndex } = (__mods.calendar || {});
9480
9486
  const { solarToLunar } = (__mods.lunar || {});
9481
9487
  const { applyTrueSolar } = (__mods.bazi || {});
9482
9488
  const { applyDst } = (__mods.dst || {});
@@ -9576,6 +9582,13 @@ const ZIWEI_SCHOOL_DEFAULTS = Object.freeze({
9576
9582
  zuoyaoSchool: 'minimal',
9577
9583
  liunianSihua: 'year-stem',
9578
9584
  sihuaVariant: 'default',
9585
+ // 中州派成组差异:off 全部用通行本(默认,默认盘逐字节不变);zhongzhou 表示
9586
+ // 「跟随 tianshiTianshang 的 zhongzhou 档」—— 那把开关切到中州派时,这一组跟着生效;
9587
+ // 单独选 off/zhongzhou 而不动 tianshiTianshang 也可。
9588
+ // jieluSchool 截路空亡:zhongzhou 不排(截空、副截、旬空、副旬整组不出)
9589
+ // suipoSchool 岁前十二神:zhongzhou 把「大耗」改记作「岁破」(宫位不变,只换名字)
9590
+ jieluSchool: 'off',
9591
+ suipoSchool: 'off',
9579
9592
  });
9580
9593
 
9581
9594
  const ZIWEI_SCHOOL_OPTIONS = Object.freeze({
@@ -9601,6 +9614,11 @@ const ZIWEI_SCHOOL_OPTIONS = Object.freeze({
9601
9614
  // 只列与 default 不同的那一档(default 之外全是「换掉某一干」的显式选择)。
9602
9615
  sihuaVariant: ['default', '廉破曲阳', '贪阴阳机', '阳武同阴', '阳武府同', '阳武府相',
9603
9616
  '阳武同相', '巨阳武昌', '梁紫府武', '梁紫相武', '破巨阳贪'],
9617
+ // 中州派成组差异(两档各自独立,可单独开):
9618
+ // jieluSchool off 截路空亡照常 / zhongzhou 整组不排(截空、副截、旬空、副旬都不出)
9619
+ // suipoSchool off 岁前十二神照常 / zhongzhou 把「大耗」改记作「岁破」
9620
+ jieluSchool: ['off', 'zhongzhou'],
9621
+ suipoSchool: ['off', 'zhongzhou'],
9604
9622
  });
9605
9623
 
9606
9624
  function ziweiSchoolsOf(input = {}) {
@@ -10063,7 +10081,11 @@ function buildZiwei(input) {
10063
10081
  if (schools.tiankongSchool !== 'off') {
10064
10082
  put(schools.tiankongSchool === 'shun-jia-shi' ? yb + hb : yb + 1, '天空', '杂曜');
10065
10083
  }
10066
- if (schools.jiekongSchool !== 'off') {
10084
+ // 截路空亡:zhongzhou(中州派)整组不排——截空、副截、旬空、副旬都不出。
10085
+ // 依据《中州派紫微斗数》:截路空亡不入中州派体系;通行本才排。
10086
+ // 这一组只影响杂曜清单,不动宫盘、主星、十二宫位置。
10087
+ const skipJielu = schools.jieluSchool === 'zhongzhou';
10088
+ if (schools.jiekongSchool !== 'off' && !skipJielu) {
10067
10089
  const jk = JIEKONG[schools.jiekongSchool][yearStem];
10068
10090
  if (Array.isArray(jk)) {
10069
10091
  put(jk[0], '截空', '杂曜');
@@ -10130,13 +10152,17 @@ function buildZiwei(input) {
10130
10152
  const csStart = schools.changshengSchool === 'huo-tu' && bureau.number === 5
10131
10153
  ? 2
10132
10154
  : CHANGSHENG_START[bureau.number];
10155
+ // 岁前十二神:中州派把「大耗」改记作「岁破」(宫位不变,只换名字)。
10156
+ const renameDahao = schools.suipoSchool === 'zhongzhou';
10133
10157
  const shenshaAt = (branch) => {
10134
10158
  const d = forward ? 1 : -1;
10159
+ let suiqi = SUIQI_NAMES[fix(branch - yb)];
10160
+ if (renameDahao && suiqi === '大耗') suiqi = '岁破';
10135
10161
  return {
10136
10162
  changsheng: CHANGSHENG_NAMES[fix(d * (branch - csStart))],
10137
10163
  boshi: BOSHI_NAMES[fix(d * (branch - lucun))],
10138
10164
  jiangqian: JIANGQIAN_NAMES[fix(branch - JIANGXING[triad])],
10139
- suiqi: SUIQI_NAMES[fix(branch - yb)],
10165
+ suiqi,
10140
10166
  };
10141
10167
  };
10142
10168
 
@@ -10173,6 +10199,10 @@ function buildZiwei(input) {
10173
10199
  });
10174
10200
  }
10175
10201
 
10202
+ // 来因宫(iztro 口径):生年天干与宫干相同的宫,子丑两宫除外(这两支五虎遁永不排甲己…的生年干)。
10203
+ // 之所以叫「来因」:此宫是今生命局展开的起点,主「因何而来」,看一个人的先天因缘与执念方向。
10204
+ const laiyin = palaces.find((p) => p.stem === yearStem && p.branch !== '子' && p.branch !== '丑') || null;
10205
+
10176
10206
  // 昌曲专论:与丑未的关系、是否入命三方、吸收面的清杂
10177
10207
  const changqu = (() => {
10178
10208
  const set = new Set([wenchang, wenqu]);
@@ -10252,7 +10282,20 @@ function buildZiwei(input) {
10252
10282
  liutuo: BRANCHES[fix(lu - 1)],
10253
10283
  liukui: BRANCHES[kuiyueTable[gz.stem][0]],
10254
10284
  liuyue: BRANCHES[kuiyueTable[gz.stem][1]],
10285
+ // 流曜补全(流昌曲按流年干、流马按流年支三合、流鸾流喜按流年支、年解按流年支)
10286
+ ...(() => {
10287
+ const s = horoscopeStarsByBranch(gz, true);
10288
+ const out = {};
10289
+ for (const [name, br] of Object.entries(s)) {
10290
+ if (name === '流禄' || name === '流羊' || name === '流陀' || name === '流魁' || name === '流钺') continue;
10291
+ out[name] = br;
10292
+ }
10293
+ return out;
10294
+ })(),
10255
10295
  mutagen: Object.entries(sihuaTableOf(lnStemOf, schools)).map(([s, k]) => `${s}化${k}`),
10296
+ // 流年十二神:岁前/将前随流年支重安(iztro getYearly12 口径)
10297
+ lnSuiqi: suiqiByBranch(gz.branch, schools.suipoSchool),
10298
+ lnJiangqian: jiangqianByBranch(gz.branch),
10256
10299
  daxian: dxPalace
10257
10300
  ? { palace: dxPalace.palace, start: dxPalace.daxian.start, end: dxPalace.daxian.end }
10258
10301
  : null,
@@ -10297,6 +10340,30 @@ function buildZiwei(input) {
10297
10340
  },
10298
10341
  hourBranch,
10299
10342
  yearGanzhi: yearGanzhi.name,
10343
+ ...((() => {
10344
+ // 非节气四柱(紫微斗数口径,文墨「显示非节气四柱」开关的数据源):
10345
+ // 紫微按农历排盘,年柱以正月初一换岁(lunarYear 已是此口径)、月柱按农历月配五虎遁;
10346
+ // 日柱、时柱与节气版完全一致(日时不受节气影响)。与八字(节气)四柱只在立春前后的
10347
+ // 出生者上年/月两柱有差异,正好给用户对照。
10348
+ const yIdx = (((lunarRaw.lunarYear - 4) % 60) + 60) % 60;
10349
+ const nYinStem = ((STEMS.indexOf(yearGanzhi.stem) % 5) * 2 + 2) % 10;
10350
+ const mBranchIdx = 2 + (lunarMonth - 1) >= 12 ? 2 + (lunarMonth - 1) - 12 : 2 + (lunarMonth - 1); // 正月建寅
10351
+ const mStemIdx = (nYinStem + lunarMonth - 1) % 10;
10352
+ const nJd = partsToJd({ year, month, day, hour: 12 });
10353
+ const dIdx = dayGanzhiIndex(Math.floor(nJd + 0.5));
10354
+ const dStemIdx = dIdx % 10;
10355
+ const ziStem = ((dStemIdx % 5) * 2) % 10;
10356
+ const hIdx = sexagenaryIndex((ziStem + hb) % 10, hb);
10357
+ return {
10358
+ nonJieqi: {
10359
+ year: ganzhiName(yIdx).name,
10360
+ month: ganzhiName(sexagenaryIndex(mStemIdx, mBranchIdx)).name,
10361
+ day: ganzhiName(dIdx).name,
10362
+ hour: ganzhiName(hIdx).name,
10363
+ note: '非节气(农历)口径:年以正月初一、月以朔为界;与八字节气四柱仅立春前后出生者有差',
10364
+ },
10365
+ };
10366
+ })()),
10300
10367
  soul: {
10301
10368
  palace: '命宫',
10302
10369
  branch: BRANCHES[soulIndex],
@@ -10334,6 +10401,8 @@ function buildZiwei(input) {
10334
10401
  ziwei: BRANCHES[ziwei],
10335
10402
  tianfu: BRANCHES[tianfu],
10336
10403
  changqu,
10404
+ // 来因宫:{branch, palace, ganzhi} 或 null(理论上不 null,防御性保留)
10405
+ laiyin: laiyin ? { branch: laiyin.branch, palace: laiyin.palace, ganzhi: laiyin.ganzhi } : null,
10337
10406
  // 杂曜全表的这一层只写「这一盘怎么定宫」:面板、独立页与「复制提问」共用。
10338
10407
  // 默认(minimal)时 placed 为空,但 skipped 照旧给出,说明为什么少了两颗。
10339
10408
  zuoyao: {
@@ -10365,7 +10434,7 @@ function buildZiwei(input) {
10365
10434
  rules: {
10366
10435
  ziweiPlacement: '借数法:局数除日数取商,商数自寅宫顺行,借数奇逆偶顺',
10367
10436
  mutagen: '生年四化用中州派常用表;庚干可按流派切换(默认阳武阴同,另有同科阴忌、府科、府科相忌、同科相忌)',
10368
- schools: `流派开关:亮度 ${schools.brightnessSchool}、庚干四化 ${schools.gengYearSihua}、天马 ${schools.tianmaSchool}、天空 ${schools.tiankongSchool}、截空 ${schools.jiekongSchool}、魁钺 ${schools.kuiyueSchool}、天伤天使 ${schools.tianshiTianshang}、长生 ${schools.changshengSchool}、晚子时 ${schools.lateZishi}、身主 ${schools.shenzhuSchool}(common 子午皆火星 / verse 子铃午火)、命主 ${schools.mingzhuSchool}(soul-branch 按命宫地支 / year-branch 按生年年支)、杂曜 ${schools.zuoyaoSchool}(minimal 49 颗 / full 61 颗)、流年四化取干 ${schools.liunianSihua}(year-stem 按流年天干 / life-palace-stem 按流年命宫宫干)、十干四化 ${schools.sihuaVariant}(default 各干通行表,其余为文墨变体整表替换);庚干四化只作用于生年四化,sihuaVariant 换的是宫干自化、大限宫干、飞星与流年共用的那张表`,
10437
+ schools: `流派开关:亮度 ${schools.brightnessSchool}、庚干四化 ${schools.gengYearSihua}、天马 ${schools.tianmaSchool}、天空 ${schools.tiankongSchool}、截空 ${schools.jiekongSchool}、魁钺 ${schools.kuiyueSchool}、天伤天使 ${schools.tianshiTianshang}、长生 ${schools.changshengSchool}、晚子时 ${schools.lateZishi}、身主 ${schools.shenzhuSchool}(common 子午皆火星 / verse 子铃午火)、命主 ${schools.mingzhuSchool}(soul-branch 按命宫地支 / year-branch 按生年年支)、杂曜 ${schools.zuoyaoSchool}(minimal 49 颗 / full 61 颗)、流年四化取干 ${schools.liunianSihua}(year-stem 按流年天干 / life-palace-stem 按流年命宫宫干)、十干四化 ${schools.sihuaVariant}(default 各干通行表,其余为文墨变体整表替换)、截路空亡 ${schools.jieluSchool}(off 照常排 / zhongzhou 整组不排)、岁前十二神 ${schools.suipoSchool}(off 照常 / zhongzhou 大耗改岁破);庚干四化只作用于生年四化,sihuaVariant 换的是宫干自化、大限宫干、飞星与流年共用的那张表`,
10369
10438
  zuoyao: schools.zuoyaoSchool === 'full'
10370
10439
  ? `全表十二颗已安:生月 解神、天巫、天月、阴煞;生年干 天官、天福、天厨;生年支 蜚廉、天德、年解;命宫+生年支 天才、身宫+生年支 天寿。蜚廉与博士十二神的飞廉同名异星,年解与月解(解神)分列,天德与岁前十二神的天德同名异宫。`
10371
10440
  : `本盘按 49 颗的通行简盘安星,未排全表杂曜。开 zuoyaoSchool: "full" 追加十二颗:解神、天巫、天月、阴煞(生月)、天官、天福、天厨(生年干)、蜚廉、天德、年解(生年支)、天才(命宫+生年支)、天寿(身宫+生年支),每颗都带安星诀。`,
@@ -10650,6 +10719,34 @@ const PATTERN_TONE = {
10650
10719
  刑囚夹印: 'bad', 泛水桃花: 'bad',
10651
10720
  };
10652
10721
 
10722
+ // ── 限流十二神(iztro 口径):随流年干支重安的只有岁前/将前两组 ──
10723
+ // 长生十二神、博士十二神只在本命排盘算一次,horoscope scope 不重算(iztro
10724
+ // FunctionalAstrolabe._getHoroscopeBySolarDate 里 yearlyDecStar=getYearly12(solarDate)
10725
+ // 只重出 suiqian12/jiangqian12,长生与博士留在本命宫位上)。
10726
+ // 岁前:流年支起岁建,顺数 SUIQI_NAMES;将前:寅午戌起午、申子辰起子、巳酉丑起酉、亥卯未起卯。
10727
+ function suiqiByBranch(branch, suipoSchool) {
10728
+ const b = BRANCHES.indexOf(branch);
10729
+ if (b < 0) return {};
10730
+ const out = {};
10731
+ for (let i = 0; i < 12; i++) {
10732
+ let name = SUIQI_NAMES[i];
10733
+ if (suipoSchool === 'zhongzhou' && name === '大耗') name = '岁破';
10734
+ out[name] = BRANCHES[fix(b + i)];
10735
+ }
10736
+ return out;
10737
+ }
10738
+
10739
+ function jiangqianByBranch(branch) {
10740
+ const b = BRANCHES.indexOf(branch);
10741
+ if (b < 0) return {};
10742
+ const triad = ['寅午戌', '申子辰', '巳酉丑', '亥卯未'].find((t) => t.includes(branch));
10743
+ if (!triad) return {};
10744
+ const start = JIANGXING[triad];
10745
+ const out = {};
10746
+ for (let i = 0; i < 12; i++) out[JIANGQIAN_NAMES[i]] = BRANCHES[fix(start + i)];
10747
+ return out;
10748
+ }
10749
+
10653
10750
  // ── 大限一览:宫干四化落宫、三方主星 ──────────────────────────
10654
10751
 
10655
10752
  function daxianList(chart) {
@@ -10672,6 +10769,11 @@ function daxianList(chart) {
10672
10769
  selfHua: p.selfHua,
10673
10770
  sanfang: p.sanfang,
10674
10771
  mainStars: mainOf(p.sanfang),
10772
+ // 运曜:按大限宫干支安 10 颗(魁钺昌曲禄羊陀马鸾喜),映射 星名→地支
10773
+ yunStars: horoscopeStarsByBranch(p.ganzhi, false),
10774
+ // 限流十二神:随大限宫支重安的岁前/将前两组(长生、博士不随限流变)
10775
+ yunSuiqi: suiqiByBranch(p.branch, chart.schools.suipoSchool),
10776
+ yunJiangqian: jiangqianByBranch(p.branch),
10675
10777
  mutagenHits: Object.entries(sihuaTableOf(p.stem, chart.schools)).map(([star, type]) => {
10676
10778
  const b = starBranchOf(chart, star);
10677
10779
  return { star, type, branch: b >= 0 ? BRANCHES[b] : null, palace: b >= 0 ? chart.palaces.find((x) => x.branch === BRANCHES[b])?.palace ?? null : null };
@@ -10854,7 +10956,61 @@ function flyComposite(chart, { from = '命宫' } = {}) {
10854
10956
  };
10855
10957
  }
10856
10958
 
10857
- // ── 流年四化落宫 ────────────────────────────────────────────
10959
+ // ── 限流星曜(运曜/流曜)────────────────────────────────────
10960
+ // 口径依据 iztro star/horoscopeStar.ts + star/location.ts(本命同表换干支重算):
10961
+ // · 魁钺、昌曲、禄羊陀 按运限天干;天马按运限地支三合;红鸾天喜按运限地支(卯起逆数)。
10962
+ // · 流年另加「年解」:戌上起子,逆数至流年地支。
10963
+ // 与本命安星的差异只有两点:昌曲在本命按时支(戌起逆数/辰起顺数),限流按天干
10964
+ //(甲昌巳曲酉、乙昌午曲申、丙戊昌申曲午、丁己昌酉曲巳、庚昌亥曲卯、辛昌子曲寅、壬昌寅曲辰、癸昌卯曲巳);
10965
+ // 火铃不随限流重安(iztro 同样只安这 10+1 颗)。
10966
+ const LIU_CHANGQU = {
10967
+ 甲: [5, 9], 乙: [6, 8], 丙: [8, 6], 戊: [8, 6], 丁: [9, 5], 己: [9, 5],
10968
+ 庚: [11, 3], 辛: [0, 2], 壬: [2, 4], 癸: [3, 5],
10969
+ };
10970
+
10971
+ const NIANJIE_OF = { 子: 10, 丑: 9, 寅: 8, 卯: 7, 辰: 6, 巳: 5, 午: 4, 未: 3, 申: 2, 酉: 1, 戌: 0, 亥: 11 };
10972
+
10973
+ /** 前缀:大限叫运X、流年叫流X(iztro 同款命名) */
10974
+ const HS_PREFIX = (yearly) => (yearly ? '流' : '运');
10975
+
10976
+ /** 按一组干支安限流星曜,返回 12 宫(按地支序)各宫的星名数组。yearly=true 时前缀用「流」并加年解。 */
10977
+ function horoscopeStarsOf(gz, yearly = false) {
10978
+ const stem = gz.stem ?? String(gz).replace(/[子丑寅卯辰巳午未申酉戌亥]$/, '');
10979
+ const branch = gz.branch ?? String(gz).slice(-1);
10980
+ const sb = BRANCHES.indexOf(branch);
10981
+ const pre = HS_PREFIX(yearly);
10982
+ const lu = LUCUN[stem];
10983
+ const [kui, yue] = KUI_YUE[stem];
10984
+ const [chang, qu] = LIU_CHANGQU[stem];
10985
+ const ma = TIANMA[triadOf(sb)];
10986
+ const luang = fix(3 - sb);
10987
+ const byBranch = Array.from({ length: 12 }, () => []);
10988
+ const add = (idx, name) => byBranch[fix(idx)].push(name);
10989
+ add(kui, `${pre}魁`);
10990
+ add(yue, `${pre}钺`);
10991
+ add(chang, `${pre}昌`);
10992
+ add(qu, `${pre}曲`);
10993
+ add(lu, `${pre}禄`);
10994
+ add(lu + 1, `${pre}羊`);
10995
+ add(lu - 1, `${pre}陀`);
10996
+ add(ma, `${pre}马`);
10997
+ add(luang, `${pre}鸾`);
10998
+ add(luang + 6, `${pre}喜`);
10999
+ if (yearly) add(NIANJIE_OF[branch], '年解');
11000
+ return byBranch;
11001
+ }
11002
+
11003
+ /** 把 12 宫的星名数组转成 {星名: 地支}(供 daxianList/liunian 挂字段) */
11004
+ function horoscopeStarsByBranch(gz, yearly = false) {
11005
+ const byBranch = horoscopeStarsOf(gz, yearly);
11006
+ const out = {};
11007
+ byBranch.forEach((stars, i) => {
11008
+ for (const name of stars) out[name] = BRANCHES[i];
11009
+ });
11010
+ return out;
11011
+ }
11012
+
11013
+
10858
11014
 
10859
11015
  function enrichLiunian(chart) {
10860
11016
  for (const ln of chart.liunian) {
@@ -10964,7 +11120,7 @@ function flowOf(chart, asOf) {
10964
11120
  };
10965
11121
  }
10966
11122
 
10967
- return { PALACE_NAMES, BRIGHTNESS, MUTAGEN, ZIWEI_SCHOOL_DEFAULTS, ZIWEI_SCHOOL_OPTIONS, ziweiSchoolsOf, BRIGHTNESS_SCHOOLS, schoolBrightness, SIHUA_VARIANTS, sihuaTableOf, natalSihuaTableOf, KUI_YUE_SCHOOLS, LUCUN, KUI_YUE, MING_ZHU, SHEN_ZHU, triadOf, HUO_START, LING_START, TIANMA, XIANCHI, HUAGAI, JIANGXING, GUCHEN, GUASU, posuIndex, XIAOXIAN_START, CHANGSHENG_NAMES, BOSHI_NAMES, JIANGQIAN_NAMES, SUIQI_NAMES, CHANGSHENG_START, hourBranchIndex, ziweiTianfuIndex, xiaoxianAge, LEAP_POLICIES, leapPolicyOf, effectiveLunarMonth, buildZiwei, detectPatterns, PATTERN_BREAK_RULES, PATTERN_TONE, daxianList, FLY_TYPES, flyStarOf, flyStars, flyChain, flyChains, flyComposite, enrichLiunian, asOfParts, flowOf };
11123
+ return { PALACE_NAMES, BRIGHTNESS, MUTAGEN, ZIWEI_SCHOOL_DEFAULTS, ZIWEI_SCHOOL_OPTIONS, ziweiSchoolsOf, BRIGHTNESS_SCHOOLS, schoolBrightness, SIHUA_VARIANTS, sihuaTableOf, natalSihuaTableOf, KUI_YUE_SCHOOLS, LUCUN, KUI_YUE, MING_ZHU, SHEN_ZHU, triadOf, HUO_START, LING_START, TIANMA, XIANCHI, HUAGAI, JIANGXING, GUCHEN, GUASU, posuIndex, XIAOXIAN_START, CHANGSHENG_NAMES, BOSHI_NAMES, JIANGQIAN_NAMES, SUIQI_NAMES, CHANGSHENG_START, hourBranchIndex, ziweiTianfuIndex, xiaoxianAge, LEAP_POLICIES, leapPolicyOf, effectiveLunarMonth, buildZiwei, detectPatterns, PATTERN_BREAK_RULES, PATTERN_TONE, suiqiByBranch, jiangqianByBranch, daxianList, FLY_TYPES, flyStarOf, flyStars, flyChain, flyChains, flyComposite, horoscopeStarsOf, horoscopeStarsByBranch, enrichLiunian, asOfParts, flowOf };
10968
11124
  })();
10969
11125
 
10970
11126
  __mods['tarot-cards'] = (function () {
@@ -27274,6 +27430,7 @@ const ZIWEI_SCHOOL_KEYS = [
27274
27430
  'brightnessSchool', 'gengYearSihua', 'tianmaSchool', 'tiankongSchool', 'jiekongSchool',
27275
27431
  'kuiyueSchool', 'tianshiTianshang', 'changshengSchool', 'lateZishi', 'shenzhuSchool',
27276
27432
  'mingzhuSchool', 'zuoyaoSchool', 'liunianSihua', 'sihuaVariant',
27433
+ 'jieluSchool', 'suipoSchool',
27277
27434
  ];
27278
27435
 
27279
27436
  /** 紫微流派参数原样透传;非法值交给引擎按默认口径回退 */
@@ -27408,6 +27565,7 @@ function ziweiText(r) {
27408
27565
  jiekongSchool: '截空', kuiyueSchool: '魁钺', tianshiTianshang: '天伤天使',
27409
27566
  changshengSchool: '长生', lateZishi: '晚子时', shenzhuSchool: '身主', mingzhuSchool: '命主取法',
27410
27567
  zuoyaoSchool: '杂曜全表', liunianSihua: '流年四化取干', sihuaVariant: '十干四化变体',
27568
+ jieluSchool: '截路空亡', suipoSchool: '岁前十二神',
27411
27569
  };
27412
27570
  const diff = Object.entries(labels)
27413
27571
  .filter(([key]) => r.schools[key] && r.schools[key] !== ZIWEI_SCHOOL_DEFAULTS[key])
@@ -29309,7 +29467,7 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, parseDate
29309
29467
  })();
29310
29468
 
29311
29469
  window.Engine = __mods.index;
29312
- window.__MP_VER = "0.64.0";
29470
+ window.__MP_VER = "0.65.0";
29313
29471
  </script>
29314
29472
  <script>
29315
29473
  // 两个 UI 共用的表单规则:宿主面板(src/app.js)与独立页(src/web-ui.js)。
@@ -29518,6 +29676,9 @@ window.__MP_VER = "0.64.0";
29518
29676
  .pp-body 是 static 定位的整块视图容器,::after 却是 absolute,
29519
29677
  结果每次排盘都会在文档左上角飘出一个孤立的灰色「身」方块。已删除。 */
29520
29678
  .pp-shen::after{content:"身";position:absolute;top:4px;left:4px;font-size:12px;color:var(--on-accent);background:var(--muted);padding:0 3px;border-radius:2px;z-index:1}
29679
+ /* 来因宫角标:右上角「因」,与身宫左上角对称;开关 ppm-d-laiyin 控显隐(默认勾) */
29680
+ .pp-laiyin::after{content:"因";position:absolute;top:4px;right:4px;font-size:12px;color:var(--on-accent);background:var(--ji);padding:0 3px;border-radius:2px;z-index:1}
29681
+ #ppm-d-laiyin:not(:checked)~.pp-body .pp-laiyin::after{display:none}
29521
29682
  .pp-legend{display:flex;gap:10px;align-items:center;justify-content:center;font-size:12px;color:var(--muted);margin-top:6px}
29522
29683
  .pp-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;font-family:system-ui,sans-serif}
29523
29684
  .pp-chip{font-size:12.5px;padding:3px 9px;border:1px solid var(--line);color:var(--muted);background:var(--bg)}
@@ -29600,6 +29761,18 @@ window.__MP_VER = "0.64.0";
29600
29761
  .pp-fx i{font-style:normal;white-space:nowrap;margin-right:4px}
29601
29762
  .pp-fx i em{font-style:normal;color:var(--faint)}
29602
29763
  #ppm-sc-feixing:checked~.pp-body .pp-fx{display:block}
29764
+ /* 运曜/流曜行:默认隐藏,勾选「显示运曜和流曜」才显示(限流盘显示组,纯增强) */
29765
+ .pp-hs{display:none;margin-top:3px;font-size:10.5px;line-height:1.55;color:var(--muted);border-top:1px dashed var(--hair);padding-top:2px}
29766
+ .pp-hs i{font-style:normal;white-space:nowrap;margin-right:4px}
29767
+ .pp-hs i em{font-style:normal;color:var(--faint)}
29768
+ #ppm-d-hs:checked~.pp-body .pp-hs{display:block}
29769
+ /* 日干四化:宫格下方一行小字(禄权科忌四颗化星落宫),默认隐藏,勾 ppm-d-rigan 才显示 */
29770
+ .pp-rigan{display:none;margin-top:6px;padding:5px 11px;border:1px solid var(--line);background:var(--band);font-size:12px;line-height:1.7;color:var(--muted)}
29771
+ .pp-rigan b{color:var(--ink);font-weight:600;margin-right:8px}
29772
+ .pp-rigan i{font-style:normal;margin-right:10px;white-space:nowrap}
29773
+ .pp-rigan i em{font-style:normal}
29774
+ .pp-rigan i .rl{color:var(--lu)}.pp-rigan i .rq{color:var(--quan)}.pp-rigan i .rk{color:var(--ke)}.pp-rigan i .rj{color:var(--ji)}
29775
+ #ppm-d-rigan:checked~.pp-rigan{display:block}
29603
29776
  #ppm-sc-feixing:checked~.pp-body .pp-m.view,
29604
29777
  #ppm-sc-feixing:checked~.pp-body .pp-viewhua{display:none}
29605
29778
  /* 三合派:四化信息整体退场(生年/自化/大限流年/图例/飞星链 chips/自化箭头) */
@@ -30848,12 +31021,71 @@ window.__MP_VER = "0.64.0";
30848
31021
  .pp table tbody tr:hover{background:var(--hover)}
30849
31022
  /* 结果卡阴影分层:默认最轻,hover 时浮起一档(只对可交互的卡,避免整页抖动) */
30850
31023
  .pp{transition:box-shadow var(--dur) var(--ease)}
31024
+
31025
+ /* —— 文墨式「显示设置」14 项(学文墨天机 group_fxp / group_4hb / group_3hp)——
31026
+ 纯 CSS 显隐:勾了盘面立刻变,不重排盘、不进引擎、不进工具 schema。
31027
+ 复选框必须是 .pp 的直接子元素,才能用 ~ 命中后面的 .pp-body / .pp-zhlegend。
31028
+ 组1/组2 默认勾(:not(:checked) 才隐藏),组3 默认不勾(:checked 才增强,默认盘观感不变)。 */
31029
+ .pp-disp{font-family:var(--sans);border-bottom:1px solid var(--line);background:var(--band);font-size:12px}
31030
+ .pp-disp>summary{cursor:pointer;padding:5px 12px;color:var(--muted);user-select:none;list-style:none;min-height:32px;display:flex;align-items:center}
31031
+ .pp-disp>summary::-webkit-details-marker{display:none}
31032
+ .pp-disp>summary::before{content:"▸";margin-right:6px;font-size:10px;color:var(--label)}
31033
+ .pp-disp[open]>summary::before{content:"▾"}
31034
+ .pp-disp-g{display:flex;flex-wrap:wrap;gap:2px 14px;padding:3px 12px 8px;border-top:1px dashed var(--hair)}
31035
+ .pp-disp-g>span{width:100%;font-size:11px;color:var(--label);letter-spacing:.06em;margin-bottom:1px}
31036
+ .pp-disp label{display:inline-flex;align-items:center;gap:5px;cursor:pointer;color:var(--ink2);user-select:none;padding:2px 0;min-height:26px}
31037
+ .pp-disp-box{width:13px;height:13px;border:1px solid var(--line);border-radius:3px;background:var(--card);display:inline-block;flex:none}
31038
+ .pp-disp label:hover .pp-disp-box{border-color:var(--lu)}
31039
+ /* 勾选态:12 条 :checked 各自点亮自己 label 的方框(复选框与 .pp-disp 同为 .pp 直接子元素) */
31040
+ #ppm-d-ss:checked~.pp-disp label[for="ppm-d-ss"] .pp-disp-box,
31041
+ #ppm-d-sbg:checked~.pp-disp label[for="ppm-d-sbg"] .pp-disp-box,
31042
+ #ppm-d-zha:checked~.pp-disp label[for="ppm-d-zha"] .pp-disp-box,
31043
+ #ppm-d-ages:checked~.pp-disp label[for="ppm-d-ages"] .pp-disp-box,
31044
+ #ppm-d-sizhu:checked~.pp-disp label[for="ppm-d-sizhu"] .pp-disp-box,
31045
+ #ppm-d-small:checked~.pp-disp label[for="ppm-d-small"] .pp-disp-box,
31046
+ #ppm-d-shen:checked~.pp-disp label[for="ppm-d-shen"] .pp-disp-box,
31047
+ #ppm-d-hua:checked~.pp-disp label[for="ppm-d-hua"] .pp-disp-box,
31048
+ #ppm-d-sf:checked~.pp-disp label[for="ppm-d-sf"] .pp-disp-box,
31049
+ #ppm-d-laiyin:checked~.pp-disp label[for="ppm-d-laiyin"] .pp-disp-box,
31050
+ #ppm-d-zha-bold:checked~.pp-disp label[for="ppm-d-zha-bold"] .pp-disp-box,
31051
+ #ppm-d-bad-ink:checked~.pp-disp label[for="ppm-d-bad-ink"] .pp-disp-box,
31052
+ #ppm-d-bold:checked~.pp-disp label[for="ppm-d-bold"] .pp-disp-box,
31053
+ #ppm-d-hs:checked~.pp-disp label[for="ppm-d-hs"] .pp-disp-box{background:var(--lu);border-color:var(--lu);box-shadow:inset 0 0 0 2px var(--card)}
31054
+ /* 组1 飞星派显示(默认全勾,取消才隐藏) */
31055
+ #ppm-d-ss:not(:checked)~.pp-body .pp-ss-txt{display:none}
31056
+ #ppm-d-sbg:not(:checked)~.pp-body .pp-st.st-sbg{display:none}
31057
+ #ppm-d-zha:not(:checked)~.pp-body .pp-zha{display:none}
31058
+ #ppm-d-zha:not(:checked)~.pp-zhlegend{display:none}
31059
+ #ppm-d-ages:not(:checked)~.pp-body .pp-ages{display:none}
31060
+ #ppm-d-sizhu:not(:checked)~.pp-body .ct-t3{display:none}
31061
+ /* 非节气四柱行:默认隐藏,勾 ppm-d-njq 才显示(纯增强,不改默认观感) */
31062
+ .ct-t3nj{font-size:11.5px;letter-spacing:.2em;font-weight:500;color:var(--muted)}
31063
+ .ct-t3nj .nj-tag{font-style:normal;letter-spacing:.08em;font-size:10px;color:var(--lu);border:1px solid currentColor;border-radius:3px;padding:0 3px;margin-left:6px;vertical-align:1px}
31064
+ #ppm-d-njq:not(:checked)~.pp-body .ct-t3nj{display:none}
31065
+ /* 太极点转换信息:详情面板「太极转换」行,默认隐藏,勾 ppm-d-tjz 才显示 */
31066
+ #ppm-d-tjz:not(:checked)~.pp-body .pp-detail .dt-taiji{display:none}
31067
+ /* 组2 四化派显示(默认全勾,取消才隐藏) */
31068
+ #ppm-d-small:not(:checked)~.pp-body .pp-st.aux{display:none}
31069
+ #ppm-d-shen:not(:checked)~.pp-body .pp-shen::after{display:none}
31070
+ #ppm-d-hua:not(:checked)~.pp-body .pp-m{display:none}
31071
+ #ppm-d-sf:not(:checked)~.pp-body .pp-cell.pp-tri{background:var(--bg)}
31072
+ #ppm-d-sf:not(:checked)~.pp-body .pp-cell.pp-link{background:var(--bg);box-shadow:none}
31073
+ #ppm-d-sf:not(:checked)~.pp-body svg.pp-sf{display:none}
31074
+ /* 组3 限流盘增强(默认不勾,勾了才生效;不改默认盘观感) */
31075
+ #ppm-d-zha-bold:checked~.pp-body .pp-zha .z-shaft{stroke-width:2.8}
31076
+ #ppm-d-bad-ink:checked~.pp-body .pp-st.bad{color:var(--ink)}
31077
+ #ppm-d-bad-ink:checked~.pp-body .pp-st.bad::before{content:none}
31078
+ #ppm-d-bold:checked~.pp-body .pp-st.main,#ppm-d-bold:checked~.pp-body .pp-st.good{font-weight:700}
30851
31079
  `;
30852
31080
  const pp = (window.__PP = window.__PP || {});
30853
31081
  pp.CSS = CSS;
30854
31082
 
30855
31083
  const TYPE_CLASS = { 主星: 'main', 吉星: 'good', 煞星: 'bad', 辅星: 'aux', 杂曜: 'aux' };
30856
31084
  const MUT = { 禄: 'lu', 权: 'quan', 科: 'ke', 忌: 'ji' };
31085
+ // 「显示三台八座恩光天贵」专用:这四颗是日系吉星,引擎给它们 type='吉星',
31086
+ // 与其它吉星共用 .pp-st.good。只给这四颗追加 st-sbg 供 CSS 单独显隐;
31087
+ // 其余星(尤其十四主星)的 class 串保持字面不变,别动 upgrade.test.mjs 的顺序断言。
31088
+ const SBG = new Set(['三台', '八座', '恩光', '天贵']);
30857
31089
  // 庙旺得利平不陷 → 三档视觉权重:吉(庙旺)/ 中(得利平)/ 忌(不陷)
30858
31090
  const BR_CLASS = { 庙: 'good', 旺: 'good', 得: 'mid', 利: 'mid', 平: 'mid', 不: 'bad', 陷: 'bad' };
30859
31091
  const POS = {
@@ -30936,9 +31168,11 @@ window.__MP_VER = "0.64.0";
30936
31168
  // 所以读作「←这笔化飞回本宫」而不是「从这颗星飞出去」。放星名前是关键:
30937
31169
  // 放星名后箭头朝右,视觉上就成了「飞出本宫」,意思正好反了
30938
31170
  const zh = (selfHuaMap && selfHuaMap[s.name]) ? zhaMark(selfHuaMap[s.name], s.name) : '';
31171
+ // 日系四吉星单独可寻址(文墨「显示三台八座恩光天贵」);其余星 class 串一字不改
31172
+ const extra = SBG.has(s.name) ? ' st-sbg' : '';
30939
31173
  // 顺序:自化箭头 → 星名 → 亮度灰字 → 四化色块。灰字紧贴星名变成一体,彩色实心框独立在末尾,
30940
31174
  // 避免两者字号差导致视觉叠压(试过 星名→四化→亮度,10px 字形会压住 8.5px 的框)
30941
- return `<span class="pp-st ${cls}">${zh}${s.name}${b}${tm}${m}${vm}</span>`;
31175
+ return `<span class="pp-st ${cls}${extra}">${zh}${s.name}${b}${tm}${m}${vm}</span>`;
30942
31176
  }).join('');
30943
31177
  }
30944
31178
 
@@ -30953,13 +31187,14 @@ window.__MP_VER = "0.64.0";
30953
31187
  const fx = (n) => ((n % 12) + 12) % 12;
30954
31188
  const isTrine = (b, m) => b !== m && [fx(m + 4), fx(m + 8), fx(m + 6)].includes(b);
30955
31189
 
30956
- function cellHTML(p, soulIdx, view, allPalaces, viewHua, flyByBranch) {
31190
+ function cellHTML(p, soulIdx, view, allPalaces, viewHua, flyByBranch, hsByBranch, laiyinBranch) {
30957
31191
  const pos = POS[p.branch] || [1, 1];
30958
31192
  const b = BR.indexOf(p.branch);
30959
31193
  const cls = ['pp-cell'];
30960
31194
  if (b === soulIdx) cls.push('pp-soul');
30961
31195
  else if (isTrine(b, soulIdx)) cls.push('pp-tri');
30962
31196
  if (p.isBody) cls.push('pp-shen');
31197
+ if (laiyinBranch && p.branch === laiyinBranch) cls.push('pp-laiyin');
30963
31198
  if (pos[0] === 4) cls.push('pp-lastrow');
30964
31199
  if (pos[1] === 4) cls.push('pp-lastcol');
30965
31200
  const ss = p.shensha || {};
@@ -30981,14 +31216,15 @@ window.__MP_VER = "0.64.0";
30981
31216
  ${borrow}
30982
31217
  <div class="pp-ages">${agesHTML(p.xiaoxian.age)}</div>
30983
31218
  ${fxLineHTML(p, flyByBranch)}
31219
+ ${hsLineHTML(p, hsByBranch)}
30984
31220
  <div class="pp-foot">
30985
31221
  <div class="ft-l">
30986
- <span class="ft-dx">${ss.boshi} ${p.daxian.start}-${p.daxian.end}</span>
30987
- <span>${ss.jiangqian}</span>
30988
- <span>${ss.suiqi}</span>
31222
+ <span class="ft-dx"><span class="pp-ss-txt">${ss.boshi}</span> ${p.daxian.start}-${p.daxian.end}</span>
31223
+ <span class="pp-ss-txt">${ss.jiangqian}</span>
31224
+ <span class="pp-ss-txt">${ss.suiqi}</span>
30989
31225
  </div>
30990
31226
  <div class="ft-r">
30991
- <span>${ss.changsheng}</span>
31227
+ <span class="pp-ss-txt">${ss.changsheng}</span>
30992
31228
  <span>${p.ganzhi}</span>
30993
31229
  <span class="ft-pn">${pname}</span>
30994
31230
  </div>
@@ -31030,6 +31266,16 @@ window.__MP_VER = "0.64.0";
31030
31266
  return `<div class="pp-fx">${esc(p.ganzhi)}宫干 ${items}</div>`;
31031
31267
  }
31032
31268
 
31269
+ /* 运曜/流曜小字行(文墨天机「显示运曜和流曜」):宫格内一行小字,形如「运禄巳 运羊午 …」。
31270
+ 大限视图传该宫的 yunStars({星名:地支}),流年视图传流X 键值对;默认隐藏,勾选 ppm-d-hs 才显示。
31271
+ 返回空串时不占位(本命视图、无数据时不渲染)。 */
31272
+ function hsLineHTML(p, hsByBranch) {
31273
+ const o = (hsByBranch && hsByBranch[p.branch]) || null;
31274
+ if (!o) return '';
31275
+ const items = Object.entries(o).map(([k, br]) => `<i>${esc(k)}<em>${esc(br)}</em></i>`).join('');
31276
+ return `<div class="pp-hs">${items}</div>`;
31277
+ }
31278
+
31033
31279
  function sizhuOf(r) {
31034
31280
  try {
31035
31281
  const E = window.Engine || (window.__PP && window.__PP.Engine);
@@ -31043,6 +31289,25 @@ window.__MP_VER = "0.64.0";
31043
31289
  } catch (e) { return ''; }
31044
31290
  }
31045
31291
 
31292
+ /* 日干四化:取日柱天干,查十干四化表,四颗化星按本命落宫归堆。
31293
+ 口径:日干起四化(文墨飞星派「显示日干四化」);表用 sihuaTableOf 的通行表
31294
+ 这里无法直接调引擎内部表,改用宫干自化同源法——宫干 = 生年干那颗的四化已由
31295
+ mutagenMarks 体现,日干四化是另一层。实现:window.Engine 不暴露 sihuaTableOf,
31296
+ 改从宫干四化反推——十二宫宫干覆盖十干(寅申两支各占两干),日干对应的宫干四化
31297
+ 可从 daxianList[].mutagenHits(按宫干分组)直接借。 */
31298
+ function dayStemOf(r) {
31299
+ try {
31300
+ const E = window.Engine || (window.__PP && window.__PP.Engine);
31301
+ if (!E || !E.buildBazi || !r.input) return null;
31302
+ const b = E.buildBazi({
31303
+ year: r.input.year, month: r.input.month, day: r.input.day,
31304
+ hour: r.input.hour, minute: r.input.minute,
31305
+ gender: r.input.gender, trueSolar: false,
31306
+ });
31307
+ return b.pillars.day.stem;
31308
+ } catch (e) { return null; }
31309
+ }
31310
+
31046
31311
  pp.ziweiHTML = function (r) {
31047
31312
  const soulIdx = BR.indexOf(r.soul.branch);
31048
31313
  const ln = (r.liunian && r.liunian[0]) || null;
@@ -31062,7 +31327,51 @@ window.__MP_VER = "0.64.0";
31062
31327
 
31063
31328
  const flyByBranch = {};
31064
31329
  for (const d of r.daxianList || []) flyByBranch[d.branch] = d.mutagenHits || [];
31065
- const grid = (m, kind) => r.palaces.map((p) => cellHTML(p, m, kind, r.palaces, huaByView[kind] || null, flyByBranch)).join('');
31330
+
31331
+ // 日干四化:借宫干四化反推——daxianList[].mutagenHits 按「宫干→四化星」分组,
31332
+ // 找到宫干 === 日干的那一宫,其 mutagenHits 就是日干四化(同一张十干四化表)。
31333
+ // 星 → 落宫:palaces[].stars 里找星名。
31334
+ const riGanHits = (() => {
31335
+ const ds = dayStemOf(r);
31336
+ if (!ds) return null;
31337
+ const hit = (r.daxianList || []).find((d) => d.stem === ds);
31338
+ if (!hit) return null;
31339
+ const starBranch = {};
31340
+ for (const p of r.palaces) for (const s of p.stars || []) if (!(s.name in starBranch)) starBranch[s.name] = p.branch;
31341
+ return {
31342
+ stem: ds,
31343
+ items: (hit.mutagenHits || []).map((h) => ({
31344
+ type: h.type, star: h.star,
31345
+ branch: starBranch[h.star] || null,
31346
+ palace: starBranch[h.star] ? (r.palaces.find((p) => p.branch === starBranch[h.star]) || {}).palace : null,
31347
+ })),
31348
+ };
31349
+ })();
31350
+ // 运曜/流曜:按宫位摊。大限视图用 daxianList[].yunStars({星名:地支}),流年视图用 ln 的 流X/年解 键。
31351
+ let lnHsByBranch = null;
31352
+ if (ln) {
31353
+ lnHsByBranch = {};
31354
+ for (const [k, br] of Object.entries(ln)) if (/^(流|年解)/.test(k) && typeof br === 'string' && BR.includes(br)) lnHsByBranch[br] = lnHsByBranch[br] || {}, lnHsByBranch[br][k] = br;
31355
+ }
31356
+ const hsByView = {
31357
+ da: dxObj && dxObj.yunStars
31358
+ ? (() => {
31359
+ const o = {};
31360
+ for (const [k, br] of Object.entries(dxObj.yunStars)) (o[br] = o[br] || {})[k] = br;
31361
+ // 限流十二神(随大限宫支重安的岁前/将前)并入同一小字行
31362
+ if (dxObj.yunSuiqi) for (const [k, br] of Object.entries(dxObj.yunSuiqi)) (o[br] = o[br] || {})[k] = br;
31363
+ if (dxObj.yunJiangqian) for (const [k, br] of Object.entries(dxObj.yunJiangqian)) (o[br] = o[br] || {})[k] = br;
31364
+ return o;
31365
+ })()
31366
+ : null,
31367
+ ln: lnHsByBranch,
31368
+ };
31369
+ if (r.liunian && r.liunian.length) {
31370
+ const ln0 = r.liunian.find((x) => x.ganzhi === (r._lnSel || r.liunian[0].ganzhi)) || r.liunian[0];
31371
+ if (ln0.lnSuiqi) for (const [k, br] of Object.entries(ln0.lnSuiqi)) (lnHsByBranch[br] = lnHsByBranch[br] || {})[k] = br;
31372
+ if (ln0.lnJiangqian) for (const [k, br] of Object.entries(ln0.lnJiangqian)) (lnHsByBranch[br] = lnHsByBranch[br] || {})[k] = br;
31373
+ }
31374
+ const grid = (m, kind) => r.palaces.map((p) => cellHTML(p, m, kind, r.palaces, huaByView[kind] || null, flyByBranch, hsByView[kind] || null, r.laiyin && r.laiyin.branch)).join('');
31066
31375
  const center = (m, kind) => {
31067
31376
  const mode = kind === 'da'
31068
31377
  ? `<div class="ct-t1">大限 ${dxPalace.ganzhi} ${dxPalace.daxian.start}-${dxPalace.daxian.end}岁</div>`
@@ -31074,6 +31383,7 @@ window.__MP_VER = "0.64.0";
31074
31383
  <div class="ct-t2">公历 ${r.input.year}-${String(r.input.month).padStart(2, '0')}-${String(r.input.day).padStart(2, '0')} ${String(r.input.hour).padStart(2, '0')}:${String(r.input.minute).padStart(2, '0')}</div>
31075
31384
  <div class="ct-t2">农历 ${r.lunar.year}年${r.lunar.isLeap ? `闰${r.lunar.monthRaw || r.lunar.month}` : r.lunar.month}月${r.lunar.day}日${r.hourBranch}时${r.lunar.isLeap && r.lunar.monthRaw && r.lunar.month !== r.lunar.monthRaw ? `(按${r.lunar.month}月起盘)` : ''}</div>
31076
31385
  ${sizhuOf(r) ? `<div class="ct-t3">${sizhuOf(r)}</div>` : ''}
31386
+ ${r.nonJieqi ? `<div class="ct-t3 ct-t3nj" title="${esc(r.nonJieqi.note)}">${r.nonJieqi.year} ${r.nonJieqi.month} ${r.nonJieqi.day} ${r.nonJieqi.hour}<em class="nj-tag">非节气</em></div>` : ''}
31077
31387
  <div class="ct-t4">命主 ${r.lifeMaster}${r.lifeMasterNote ? `<span class="pp-dim" title="${esc(r.lifeMasterNote)}">*</span>` : ''} 身主 ${r.bodyMaster}${r.bodyMasterNote ? `<span class="pp-dim" title="${esc(r.bodyMasterNote)}">*</span>` : ''}</div>
31078
31388
  <div class="ct-t4">命宫 ${r.soul.branch} 身宫 ${r.body.branch} 五行局 ${r.bureau.name}</div>
31079
31389
  <div class="ct-t4">子年斗君 ${r.doujun ? r.doujun.zinian : '—'} 流年斗君 ${ln && ln.doujun ? ln.doujun : '—'}</div>
@@ -31163,6 +31473,51 @@ window.__MP_VER = "0.64.0";
31163
31473
  <input type="radio" name="ppm-sc" id="ppm-sc-sihe" class="pp-r" checked>
31164
31474
  <input type="radio" name="ppm-sc" id="ppm-sc-feixing" class="pp-r">
31165
31475
  <input type="radio" name="ppm-sc" id="ppm-sc-sanhe" class="pp-r">
31476
+ <!-- 文墨式显示设置:14 个复选框必须与 .pp-body / .pp-zhlegend 同层(.pp 的直接子元素)。
31477
+ 组1/组2 默认勾(观感与旧版一致),组3 默认不勾(纯增强)。不重排盘、不进引擎。 -->
31478
+ <input type="checkbox" id="ppm-d-ss" class="pp-r" checked>
31479
+ <input type="checkbox" id="ppm-d-sbg" class="pp-r" checked>
31480
+ <input type="checkbox" id="ppm-d-zha" class="pp-r" checked>
31481
+ <input type="checkbox" id="ppm-d-ages" class="pp-r" checked>
31482
+ <input type="checkbox" id="ppm-d-sizhu" class="pp-r" checked>
31483
+ <input type="checkbox" id="ppm-d-small" class="pp-r" checked>
31484
+ <input type="checkbox" id="ppm-d-shen" class="pp-r" checked>
31485
+ <input type="checkbox" id="ppm-d-hua" class="pp-r" checked>
31486
+ <input type="checkbox" id="ppm-d-sf" class="pp-r" checked>
31487
+ <input type="checkbox" id="ppm-d-laiyin" class="pp-r" checked>
31488
+ <input type="checkbox" id="ppm-d-zha-bold" class="pp-r">
31489
+ <input type="checkbox" id="ppm-d-bad-ink" class="pp-r">
31490
+ <input type="checkbox" id="ppm-d-bold" class="pp-r">
31491
+ <input type="checkbox" id="ppm-d-hs" class="pp-r">
31492
+ <input type="checkbox" id="ppm-d-rigan" class="pp-r">
31493
+ <input type="checkbox" id="ppm-d-njq" class="pp-r">
31494
+ <input type="checkbox" id="ppm-d-tjz" class="pp-r">
31495
+ <details class="pp-disp">
31496
+ <summary>显示设置 · 17 项(学文墨天机)</summary>
31497
+ <div class="pp-disp-g"><span>飞星派显示</span>
31498
+ <label for="ppm-d-ss"><i class="pp-disp-box"></i>显示神煞</label>
31499
+ <label for="ppm-d-sbg"><i class="pp-disp-box"></i>三台八座恩光天贵</label>
31500
+ <label for="ppm-d-zha"><i class="pp-disp-box"></i>彩色箭头标识自化</label>
31501
+ <label for="ppm-d-ages"><i class="pp-disp-box"></i>流年虚岁年龄</label>
31502
+ <label for="ppm-d-sizhu"><i class="pp-disp-box"></i>中宫八字</label>
31503
+ <label for="ppm-d-rigan"><i class="pp-disp-box"></i>显示日干四化</label>
31504
+ <label for="ppm-d-njq"><i class="pp-disp-box"></i>显示非节气四柱</label>
31505
+ <label for="ppm-d-tjz"><i class="pp-disp-box"></i>显示太极点转换信息</label>
31506
+ </div>
31507
+ <div class="pp-disp-g"><span>四化派显示</span>
31508
+ <label for="ppm-d-small"><i class="pp-disp-box"></i>显示小星</label>
31509
+ <label for="ppm-d-shen"><i class="pp-disp-box"></i>显示身宫</label>
31510
+ <label for="ppm-d-hua"><i class="pp-disp-box"></i>显示命宫四化</label>
31511
+ <label for="ppm-d-sf"><i class="pp-disp-box"></i>显示三方四正</label>
31512
+ <label for="ppm-d-laiyin"><i class="pp-disp-box"></i>显示来因宫</label>
31513
+ </div>
31514
+ <div class="pp-disp-g"><span>限流盘显示</span>
31515
+ <label for="ppm-d-zha-bold"><i class="pp-disp-box"></i>自化箭头加粗</label>
31516
+ <label for="ppm-d-bad-ink"><i class="pp-disp-box"></i>六煞星黑字</label>
31517
+ <label for="ppm-d-bold"><i class="pp-disp-box"></i>主辅星加粗</label>
31518
+ <label for="ppm-d-hs"><i class="pp-disp-box"></i>显示运曜和流曜</label>
31519
+ </div>
31520
+ </details>
31166
31521
  <div class="pp-modes">
31167
31522
  <label for="ppm-ben">本命</label><label for="ppm-da">大限</label><label for="ppm-ln">流年</label>
31168
31523
  <span class="pp-soon">点任一宫位看详情</span>
@@ -31173,6 +31528,21 @@ window.__MP_VER = "0.64.0";
31173
31528
  ${body('ben', soulIdx, 'ben')}
31174
31529
  ${body('da', dxIdx, 'da')}
31175
31530
  ${body('ln', lnIdx, 'ln')}
31531
+ ${(() => {
31532
+ if (!riGanHits) return '';
31533
+ const CLS = { 禄: 'rl', 权: 'rq', 科: 'rk', 忌: 'rj' };
31534
+ const items = riGanHits.items
31535
+ .map((h) => `<i><em class="${CLS[h.type] || ''}">${h.type}</em>${esc(h.star)}<em>${esc(h.branch || '?')}${h.palace ? `·${esc(h.palace)}` : ''}</em></i>`)
31536
+ .join('');
31537
+ return `<div class="pp-rigan"><b>日干${esc(riGanHits.stem)}四化</b>${items}</div>`;
31538
+ })()} ${(() => {
31539
+ if (!riGanHits) return '';
31540
+ const CLS = { 禄: 'rl', 权: 'rq', 科: 'rk', 忌: 'rj' };
31541
+ const items = riGanHits.items
31542
+ .map((h) => `<i><em class="${CLS[h.type] || ''}">${h.type}</em>${esc(h.star)}<em>${esc(h.branch || '?')}${h.palace ? `·${esc(h.palace)}` : ''}</em></i>`)
31543
+ .join('');
31544
+ return `<div class="pp-rigan"><b>日干${esc(riGanHits.stem)}四化</b>${items}</div>`;
31545
+ })()}
31176
31546
  <div class="pp-zhlegend">自化图示 <span class="z-lu">${pp._zhaMark('禄', '本宫')}禄</span><span class="z-quan">${pp._zhaMark('权', '本宫')}权</span><span class="z-ke">${pp._zhaMark('科', '本宫')}科</span><span class="z-ji">${pp._zhaMark('忌', '本宫')}忌</span></div>
31177
31547
  <div class="pp-flywrap">${flyHTML}${flyCompositeHTML}</div>
31178
31548
  </div>${flowHTML}${chips}${pats}${dxs}${lnHit}${zyHTML}`;
@@ -31224,6 +31594,14 @@ window.__MP_VER = "0.64.0";
31224
31594
  ? starLine(mains)
31225
31595
  : `<span class="dt-empty">无主星</span><span class="dt-tri"> 借对宫 <b>${borrowStars.length ? borrowStars.map((s) => s.name).join('、') : '亦无主星'}</b></span>`;
31226
31596
  const row = (k, v) => `<div class="dt-dr"><span class="dt-k">${k}</span><div class="dt-v">${v}</div></div>`;
31597
+ // 太极点转换(文墨「显示太极点转换信息」):以本宫为新命宫重布十二宫名。
31598
+ // 宫序顺时针与本命同名序一致——新命宫=本宫,其后按本命十二宫顺序依次重排。
31599
+ const N = NAMES.length;
31600
+ const pivotOffset = fx(soulIdx - b); // 本宫在本命盘的宫名序
31601
+ const taiji = NAMES.map((_, i) => {
31602
+ const idx = fx(b + (i - pivotOffset + N) % N); // 从本宫起,按宫名序号推地支
31603
+ return `<span class="dt-st">${NAMES[i]}[${BR[idx]}]</span>`;
31604
+ }).join('');
31227
31605
 
31228
31606
  return `<div class="dt-dh">
31229
31607
  <b>${nm}</b><span>${p.branch}宫 · ${p.ganzhi}</span>
@@ -31239,6 +31617,7 @@ window.__MP_VER = "0.64.0";
31239
31617
  ${row('宫干四化', selfHua)}
31240
31618
  ${row('十二神', `<span class="dt-tri">长生 ${ss.changsheng || '—'} 博士 ${ss.boshi || '—'} 将前 ${ss.jiangqian || '—'} 岁前 ${ss.suiqi || '—'}</span>`)}
31241
31619
  ${row('三方四正', `<span class="dt-tri">${tri}</span>`)}
31620
+ ${row('太极转换', `<span class="dt-tri dt-taiji">以${nm}[${p.branch}]立太极${taiji}</span>`)}
31242
31621
  <div class="hint">三方四正在盘上已同步标出(浅红描边)。再点一次本宫可收起。</div>`;
31243
31622
  }
31244
31623