dsh-prime-memory 0.26.33 → 0.26.35
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.
- package/CHANGELOG.md +19 -0
- package/dist/client.js +234 -121
- package/dsh.plugin.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# 更新日志(Changelog)
|
|
2
2
|
|
|
3
|
+
## [0.26.33] — 2026-11-04
|
|
4
|
+
|
|
5
|
+
- **根治 3D 记忆海「闪一下变暗」:不是掉帧,是 `resize()` 清空 canvas 位图后,空帧被合成器取样**
|
|
6
|
+
|
|
7
|
+
> 先说结论:前一轮「每帧重绘太贵 → 掉帧 → 分层缓存 + 空闲停摆」的修复方向是错的,`0.26.33-local.1..4` 的四次本地迭代都治的是另一个病。真正的机制是——给 `canvas.width` 赋值这个动作本身会清空整张位图(规范行为),而 `ResizeObserver` 回调落在渲染步骤的 **layout 之后、paint 之前**:此刻清空、本帧就 paint,擦白的那一帧必然上屏,下一 rAF 才补画回来。所以观感是「闪一下」,且只在外部尺寸事件触发时出现,与单帧耗时无关。
|
|
8
|
+
|
|
9
|
+
- **像素级取证(推翻多模态观察)**:多模态逐帧描述前后三轮互相矛盾(有说 t=7s 黑屏的、有说全片无黑屏的),改用 `ffmpeg signalstats` 拉全片 **324 帧(30fps / 10.8s)** 客观统计——整片 YAVG 只有 **两个离散值**:`49.20` 与 `40.46`;**22 张暗帧完全同参**(YAVG=40.46 / SATAVG=7.29 / SATMAX=75),说明它们是**同一张图反复出现**,不是渐进掉元素。
|
|
10
|
+
- **定位到「位图透明」而非「元素缺失」**:暗帧下画布三个区域全部塌到同一个纯色——黄簇 `28.69→22.00`、青簇 `26.13→22.00`、空白星空区 `30.95→22.89`,饱和全落到 `≈4.00`。Y=22 是 limited-range,换全范围 luma ≈ 7,而 canvas 元素 L779 的 inline background `#04070f` 实测 luma = **6.99**——对上了:看到的是 canvas 自己的背景色透出来,不是背景层或点层画了一半。
|
|
11
|
+
- **排除合成器/GPU/整窗级问题**:同帧内左侧栏 `61.94→61.81`(-0.2%)、顶部图例条 `100.52→100.52`(**像素零差异**)。窗体重排、resize 抖动、掉驱动都会被这一条否掉。
|
|
12
|
+
- **修复一(幂等 resize)**:`resize()` 改成返回布尔——尺寸与 DPR 都未变时整段跳过,不碰 `canvas.width`。RO 在布局抖动/滚动条出现时的重复触发从此是零成本,不再反复擦白。
|
|
13
|
+
- **修复二(RO 内同步出帧)**:新增 `presentNow()`,RO 里 `if (resize()) presentNow()`——真擦了就**当场画完上屏**,把「清空 → paint 空帧 → 下一 rAF 补画」压成同一渲染步骤内的原子操作。原来那句 `wake()` 只排下一 rAF,本帧照旧 paint 空位图,这是闪烁的直接成因。
|
|
14
|
+
- **修复三(帧句柄自清)**:`frame()` 入口 `raf = 0`。它现在会被 `presentNow()` 同步调用,留着旧句柄会让后续 `wake()` 以为还有链在跑而漏排帧。
|
|
15
|
+
- **附带(非闪烁,每帧税)**:`getComputedStyle` 解色从「每帧 4 次」改为脏标记缓存(`refreshColors()`,仅 resize 与本 effect 重建时置脏)。原实现每帧强制同步样式重算,是纯白交的开销;语义不变——令牌解析时机仍是「主题/尺寸变化」。
|
|
16
|
+
|
|
17
|
+
- **为什么分层缓存没能解决**:那套改动只降低单帧重绘成本、减少 rAF 次数,但闪烁发生在「可见 canvas 被清空」这条独立通路上,三层缓存(edgeCv / nodeCv / buffer)再快也救不了本帧已经 paint 出去的空位图。反过来说,分层缓存本身是有效的性能优化,保留。
|
|
18
|
+
- **未改任何对外契约**:无新配置键、无端点变化、无默认值变化;仅 `client/src/explorer/Scene3D.tsx` 内部渲染调度。
|
|
19
|
+
- **验证口径(可复现)**:重录 30s 后跑 `ffmpeg -i <rec> -vf "signalstats,metadata=print:file=signalstats.txt" -f null NUL`,**暗帧计数必须为 0**(修复前同一口径为 22/324 帧)。本机已核对:`desktop` profile 装的是 `v0.26.33-local.4`,`dist/client.js` 哈希 `A6879304…` 与源码构建一致——闪烁不是「没装上新代码」,是代码里还在。
|
|
20
|
+
- **测试**:全量 **2048 passed / 1 skipped**(200 文件);client typecheck 0、`eslint client/src/explorer/Scene3D.tsx` 0 error;`npm run build` 0。产物核对:`dist/client.js` 新哈希 `98DD1061…`,与装入 `desktop` profile 的副本逐字节一致(`v0.26.33-local.5`)。
|
|
21
|
+
|
|
3
22
|
## [0.26.31] — 2026-11-03
|
|
4
23
|
|
|
5
24
|
- **回填 0.26.30 的测试缺口 + 让 npm 产物与 main 对齐(无运行时行为变更)**
|
package/dist/client.js
CHANGED
|
@@ -42800,9 +42800,13 @@ var __create = Object.create;
|
|
|
42800
42800
|
// v5 实名 animation(v4 的 animated 在这儿不生效);true = 逐 tick 迭代过渡
|
|
42801
42801
|
animation: true,
|
|
42802
42802
|
iterations: 300,
|
|
42803
|
-
//
|
|
42804
|
-
|
|
42805
|
-
alphaDecay
|
|
42803
|
+
// 分散够了就停摆:旧版故意把 alphaMin 调小维持“漂浮感”,但 manyBody 与
|
|
42804
|
+
// collide 的残余能量每 tick 都给节点重新加速,观感是随机摆动(用户裁定限制它)。
|
|
42805
|
+
// alphaMin 抬到停摆线、alphaDecay 稍快冷却、velocityDecay 加强阻尼(d3 默认 0.4)
|
|
42806
|
+
// ——前半段扩散行为不变,后半段残差速度快速衰减到静。
|
|
42807
|
+
alphaMin: 0.012,
|
|
42808
|
+
alphaDecay: 0.028,
|
|
42809
|
+
velocityDecay: 0.55,
|
|
42806
42810
|
link: { distance: 90, strength: 0.6 },
|
|
42807
42811
|
collide: { radius: 14, strength: 0.8 },
|
|
42808
42812
|
manyBody: { strength: -60 },
|
|
@@ -44864,6 +44868,7 @@ var __create = Object.create;
|
|
|
44864
44868
|
|
|
44865
44869
|
// client/src/explorer/projection.ts
|
|
44866
44870
|
var FOCAL = 1100;
|
|
44871
|
+
var LABEL_SKIP_DIST = 2600;
|
|
44867
44872
|
var CAM_DEFAULT = { yaw: 0.45, pitch: -0.3, dist: 1200, panX: 0, panY: 0 };
|
|
44868
44873
|
var DIST_MIN = 380;
|
|
44869
44874
|
var DIST_MAX = 3200;
|
|
@@ -45023,6 +45028,10 @@ var __create = Object.create;
|
|
|
45023
45028
|
}
|
|
45024
45029
|
return null;
|
|
45025
45030
|
}
|
|
45031
|
+
var BREATH_PERIOD_MS = 260;
|
|
45032
|
+
function phaseOf(id) {
|
|
45033
|
+
return hash322(id) % 6283 / 1e3;
|
|
45034
|
+
}
|
|
45026
45035
|
function easeInOut(p) {
|
|
45027
45036
|
const k = Math.min(1, Math.max(0, p));
|
|
45028
45037
|
return k < 0.5 ? 2 * k * k : 1 - Math.pow(-2 * k + 2, 2) / 2;
|
|
@@ -45074,6 +45083,7 @@ var __create = Object.create;
|
|
|
45074
45083
|
const [pointSize, setPointSize] = (0, import_react32.useState)(2.2);
|
|
45075
45084
|
const [driftOn, setDriftOn] = (0, import_react32.useState)(false);
|
|
45076
45085
|
const [starry, setStarry] = (0, import_react32.useState)(true);
|
|
45086
|
+
const [twinkleOn, setTwinkleOn] = (0, import_react32.useState)(true);
|
|
45077
45087
|
const camRef = (0, import_react32.useRef)({ ...CAM_DEFAULT });
|
|
45078
45088
|
const modeRef = (0, import_react32.useRef)("cluster");
|
|
45079
45089
|
const focusRef = (0, import_react32.useRef)(null);
|
|
@@ -45084,7 +45094,7 @@ var __create = Object.create;
|
|
|
45084
45094
|
const clickRef = (0, import_react32.useRef)(null);
|
|
45085
45095
|
const emphasisRef = (0, import_react32.useRef)(emphasisId);
|
|
45086
45096
|
emphasisRef.current = emphasisId;
|
|
45087
|
-
const
|
|
45097
|
+
const wakeRef = (0, import_react32.useRef)(null);
|
|
45088
45098
|
const degree = (0, import_react32.useMemo)(() => degreeMapOf(full), [full]);
|
|
45089
45099
|
const edgeList = (0, import_react32.useMemo)(
|
|
45090
45100
|
() => full.edges.map((e) => ({ from: e.from, to: e.to, relation: e.relation, causal: e.causal })),
|
|
@@ -45126,6 +45136,7 @@ var __create = Object.create;
|
|
|
45126
45136
|
camRef.current.dist = Math.min(3200, Math.max(380, EGO_HOPS_MAX2 * 300 * 1.55));
|
|
45127
45137
|
camRef.current.panX = 0;
|
|
45128
45138
|
camRef.current.panY = 0;
|
|
45139
|
+
wakeRef.current?.();
|
|
45129
45140
|
}, [emphasisId, adj, clusterLayout]);
|
|
45130
45141
|
const metasRef = (0, import_react32.useRef)(/* @__PURE__ */ new Map());
|
|
45131
45142
|
const spritesRef = (0, import_react32.useRef)(/* @__PURE__ */ new Map());
|
|
@@ -45168,14 +45179,33 @@ var __create = Object.create;
|
|
|
45168
45179
|
if (!host || !canvas) return;
|
|
45169
45180
|
const ctx = canvas.getContext("2d");
|
|
45170
45181
|
if (!ctx) return;
|
|
45171
|
-
dirtyRef.current = true;
|
|
45172
45182
|
const buffer = document.createElement("canvas");
|
|
45173
45183
|
const bctx = buffer.getContext("2d");
|
|
45184
|
+
const edgeCv = document.createElement("canvas");
|
|
45185
|
+
const ectx = edgeCv.getContext("2d");
|
|
45186
|
+
const nodeCv = document.createElement("canvas");
|
|
45187
|
+
const nctx = nodeCv.getContext("2d");
|
|
45188
|
+
let edgeDirty = true;
|
|
45189
|
+
let nodeDirty = true;
|
|
45190
|
+
let needsPresent = true;
|
|
45191
|
+
let lastActiveKey = "";
|
|
45174
45192
|
let raf = 0;
|
|
45193
|
+
let running = false;
|
|
45175
45194
|
let disposed = false;
|
|
45176
45195
|
let vw = 0;
|
|
45177
45196
|
let vh = 0;
|
|
45178
45197
|
const dprRef = { current: 1 };
|
|
45198
|
+
let colEdge = "";
|
|
45199
|
+
let colCausal = "";
|
|
45200
|
+
let colText = "";
|
|
45201
|
+
let colStale = true;
|
|
45202
|
+
const refreshColors = () => {
|
|
45203
|
+
if (!colStale) return;
|
|
45204
|
+
colEdge = resolveColor2(host, "--dsh-mem-border-strong");
|
|
45205
|
+
colCausal = resolveColor2(host, "--dsh-mem-accent");
|
|
45206
|
+
colText = resolveColor2(host, "--dsh-mem-text-2");
|
|
45207
|
+
colStale = false;
|
|
45208
|
+
};
|
|
45179
45209
|
const spriteFor = (color) => {
|
|
45180
45210
|
const hit = spritesRef.current.get(color);
|
|
45181
45211
|
if (hit) return hit;
|
|
@@ -45247,23 +45277,41 @@ var __create = Object.create;
|
|
|
45247
45277
|
}
|
|
45248
45278
|
return cv;
|
|
45249
45279
|
};
|
|
45280
|
+
let sized = false;
|
|
45250
45281
|
const resize = () => {
|
|
45251
45282
|
const dpr = Math.min(2, window.devicePixelRatio || 1);
|
|
45283
|
+
const nextW = host.clientWidth || 640;
|
|
45284
|
+
const nextH = host.clientHeight || host.offsetHeight || height;
|
|
45285
|
+
if (sized && nextW === vw && nextH === vh && dpr === dprRef.current) return false;
|
|
45286
|
+
sized = true;
|
|
45252
45287
|
dprRef.current = dpr;
|
|
45253
|
-
vw =
|
|
45254
|
-
vh =
|
|
45288
|
+
vw = nextW;
|
|
45289
|
+
vh = nextH;
|
|
45255
45290
|
canvas.width = Math.round(vw * dpr);
|
|
45256
45291
|
canvas.height = Math.round(vh * dpr);
|
|
45257
45292
|
canvas.style.width = `${vw}px`;
|
|
45258
45293
|
canvas.style.height = `${vh}px`;
|
|
45259
45294
|
buffer.width = canvas.width;
|
|
45260
45295
|
buffer.height = canvas.height;
|
|
45296
|
+
edgeCv.width = canvas.width;
|
|
45297
|
+
edgeCv.height = canvas.height;
|
|
45298
|
+
nodeCv.width = canvas.width;
|
|
45299
|
+
nodeCv.height = canvas.height;
|
|
45300
|
+
ectx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
45301
|
+
nctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
45261
45302
|
bctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
45262
45303
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
45263
45304
|
bgCache = null;
|
|
45305
|
+
edgeDirty = true;
|
|
45306
|
+
nodeDirty = true;
|
|
45307
|
+
colStale = true;
|
|
45308
|
+
needsPresent = true;
|
|
45309
|
+
return true;
|
|
45264
45310
|
};
|
|
45265
45311
|
resize();
|
|
45266
|
-
const ro = new ResizeObserver(
|
|
45312
|
+
const ro = new ResizeObserver(() => {
|
|
45313
|
+
if (resize()) presentNow();
|
|
45314
|
+
});
|
|
45267
45315
|
ro.observe(host);
|
|
45268
45316
|
const activeLayout = (now) => {
|
|
45269
45317
|
const tr = transRef.current;
|
|
@@ -45278,133 +45326,192 @@ var __create = Object.create;
|
|
|
45278
45326
|
};
|
|
45279
45327
|
let lastProjected = [];
|
|
45280
45328
|
const frame = (now) => {
|
|
45329
|
+
raf = 0;
|
|
45281
45330
|
if (disposed) return;
|
|
45331
|
+
refreshColors();
|
|
45282
45332
|
const cam = camRef.current;
|
|
45283
45333
|
const layout = activeLayout(now);
|
|
45284
45334
|
const ego = modeRef.current === "ego";
|
|
45285
45335
|
const metas = metasRef.current;
|
|
45286
45336
|
const hover = hoverRef.current;
|
|
45287
45337
|
const focus = focusRef.current;
|
|
45288
|
-
|
|
45289
|
-
if (
|
|
45290
|
-
|
|
45291
|
-
|
|
45338
|
+
const emph = emphasisRef.current;
|
|
45339
|
+
if (transRef.current !== null || driftOn && !ego) {
|
|
45340
|
+
edgeDirty = true;
|
|
45341
|
+
nodeDirty = true;
|
|
45292
45342
|
}
|
|
45293
45343
|
const projected = projectAll(layout, cam, { w: vw, h: vh }, void 0, now, driftOn && !ego);
|
|
45294
45344
|
lastProjected = projected;
|
|
45295
|
-
const
|
|
45296
|
-
|
|
45297
|
-
|
|
45298
|
-
|
|
45299
|
-
|
|
45300
|
-
|
|
45301
|
-
|
|
45302
|
-
|
|
45303
|
-
|
|
45345
|
+
const activeKey = `${hover ?? ""}|${focus ?? ""}|${emph ?? ""}`;
|
|
45346
|
+
if (activeKey !== lastActiveKey) {
|
|
45347
|
+
lastActiveKey = activeKey;
|
|
45348
|
+
nodeDirty = true;
|
|
45349
|
+
}
|
|
45350
|
+
const activeIds = /* @__PURE__ */ new Set();
|
|
45351
|
+
if (hover) activeIds.add(hover);
|
|
45352
|
+
if (focus) activeIds.add(focus);
|
|
45353
|
+
if (emph) activeIds.add(emph);
|
|
45304
45354
|
const pos = new Map(projected.map((p) => [p.id, p]));
|
|
45305
|
-
|
|
45306
|
-
|
|
45307
|
-
|
|
45308
|
-
c
|
|
45309
|
-
|
|
45310
|
-
|
|
45311
|
-
|
|
45312
|
-
|
|
45313
|
-
|
|
45314
|
-
|
|
45315
|
-
|
|
45316
|
-
|
|
45317
|
-
|
|
45318
|
-
c.
|
|
45319
|
-
|
|
45355
|
+
const edgeBase = colEdge;
|
|
45356
|
+
const causalC = colCausal;
|
|
45357
|
+
if (edgeDirty) {
|
|
45358
|
+
const c = ectx;
|
|
45359
|
+
c.clearRect(0, 0, vw, vh);
|
|
45360
|
+
if (!bgCache || bgCacheW !== vw || bgCacheH !== vh || bgCacheStarry !== starry) {
|
|
45361
|
+
bgCache = bakeBg(vw, vh, starry, nodeKeySeed);
|
|
45362
|
+
bgCacheW = vw;
|
|
45363
|
+
bgCacheH = vh;
|
|
45364
|
+
bgCacheStarry = starry;
|
|
45365
|
+
}
|
|
45366
|
+
c.drawImage(bgCache, 0, 0);
|
|
45367
|
+
if (edgesOn) {
|
|
45368
|
+
c.globalCompositeOperation = "source-over";
|
|
45369
|
+
for (const e of edgeList) {
|
|
45370
|
+
const a = pos.get(e.from);
|
|
45371
|
+
const b = pos.get(e.to);
|
|
45372
|
+
if (!a || !b) continue;
|
|
45373
|
+
const avgF = (a.f + b.f) / 2;
|
|
45374
|
+
c.strokeStyle = e.causal ? causalC : edgeBase;
|
|
45375
|
+
c.globalAlpha = Math.min(0.9, Math.max(0.05, avgF * 0.34));
|
|
45376
|
+
c.lineWidth = e.causal ? 1.2 : 0.7;
|
|
45377
|
+
c.beginPath();
|
|
45378
|
+
c.moveTo(a.x, a.y);
|
|
45379
|
+
c.lineTo(b.x, b.y);
|
|
45380
|
+
c.stroke();
|
|
45381
|
+
}
|
|
45382
|
+
c.globalAlpha = 1;
|
|
45383
|
+
}
|
|
45384
|
+
edgeDirty = false;
|
|
45385
|
+
needsPresent = true;
|
|
45386
|
+
}
|
|
45387
|
+
if (nodeDirty) {
|
|
45388
|
+
const c = nctx;
|
|
45389
|
+
c.clearRect(0, 0, vw, vh);
|
|
45390
|
+
for (const p of projected) {
|
|
45391
|
+
if (activeIds.has(p.id)) continue;
|
|
45392
|
+
const m = metas.get(p.id);
|
|
45393
|
+
if (!m) continue;
|
|
45394
|
+
const alpha = brightnessFor(p.f, agingOn ? m.aging : null, true);
|
|
45395
|
+
const r = Math.max(0.8, m.base * p.f * 1.75);
|
|
45396
|
+
if (glowOn) {
|
|
45397
|
+
c.globalCompositeOperation = "lighter";
|
|
45398
|
+
c.globalAlpha = alpha * 0.5;
|
|
45399
|
+
const sp = spriteFor(m.color);
|
|
45400
|
+
const gr = r * 3.4;
|
|
45401
|
+
c.drawImage(sp, p.x - gr, p.y - gr, gr * 2, gr * 2);
|
|
45402
|
+
}
|
|
45403
|
+
c.globalCompositeOperation = "source-over";
|
|
45404
|
+
c.globalAlpha = Math.min(1, alpha + 0.15);
|
|
45405
|
+
c.fillStyle = m.color;
|
|
45320
45406
|
c.beginPath();
|
|
45321
|
-
c.
|
|
45322
|
-
c.
|
|
45323
|
-
c.stroke();
|
|
45407
|
+
c.arc(p.x, p.y, r, 0, Math.PI * 2);
|
|
45408
|
+
c.fill();
|
|
45324
45409
|
}
|
|
45325
45410
|
c.globalAlpha = 1;
|
|
45326
|
-
|
|
45327
|
-
|
|
45328
|
-
|
|
45329
|
-
|
|
45330
|
-
|
|
45331
|
-
|
|
45332
|
-
|
|
45333
|
-
|
|
45334
|
-
|
|
45335
|
-
const r = Math.max(0.8, m.base * p.f * 1.75 * (isFocus || isHover ? 1.9 : 1));
|
|
45336
|
-
if (glowOn) {
|
|
45337
|
-
c.globalCompositeOperation = "lighter";
|
|
45338
|
-
c.globalAlpha = alpha * 0.5;
|
|
45339
|
-
const sp = spriteFor(m.color);
|
|
45340
|
-
const gr = r * 3.4;
|
|
45341
|
-
c.drawImage(sp, p.x - gr, p.y - gr, gr * 2, gr * 2);
|
|
45342
|
-
}
|
|
45343
|
-
c.globalCompositeOperation = "source-over";
|
|
45344
|
-
c.globalAlpha = Math.min(1, alpha + 0.15);
|
|
45345
|
-
c.fillStyle = m.color;
|
|
45346
|
-
c.beginPath();
|
|
45347
|
-
c.arc(p.x, p.y, r, 0, Math.PI * 2);
|
|
45348
|
-
c.fill();
|
|
45349
|
-
}
|
|
45350
|
-
c.globalAlpha = 1;
|
|
45351
|
-
if (labelsOn) {
|
|
45352
|
-
const textColor = resolveColor2(host, "--dsh-mem-text-2");
|
|
45353
|
-
const inSet = /* @__PURE__ */ new Set();
|
|
45354
|
-
const cand = projected.filter((p) => metas.has(p.id)).map((p) => {
|
|
45355
|
-
const m = metas.get(p.id);
|
|
45356
|
-
const hot = p.id === focus || p.id === hover || p.id === emphasisRef.current;
|
|
45357
|
-
if (hot) inSet.add(p.id);
|
|
45358
|
-
return {
|
|
45359
|
-
id: p.id,
|
|
45360
|
-
x: p.x,
|
|
45361
|
-
y: p.y,
|
|
45362
|
-
f: p.f,
|
|
45363
|
-
rank: (hot ? 1e6 : 0) + m.degree * 10 + (m.aging ?? 1) * 5 + hash322(p.id) % 7
|
|
45411
|
+
if (labelsOn && cam.dist <= LABEL_SKIP_DIST) {
|
|
45412
|
+
const textColor = colText;
|
|
45413
|
+
const cand = projected.filter((p) => metas.has(p.id) && !activeIds.has(p.id)).map((p) => {
|
|
45414
|
+
const m = metas.get(p.id);
|
|
45415
|
+
return { id: p.id, x: p.x, y: p.y, f: p.f, rank: m.degree * 10 + (m.aging ?? 1) * 5 + hash322(p.id) % 7 };
|
|
45416
|
+
});
|
|
45417
|
+
const widthOf = (id) => {
|
|
45418
|
+
const m = metas.get(id);
|
|
45419
|
+
return m ? clipByWidth(m.name).length * 6.4 : 0;
|
|
45364
45420
|
};
|
|
45365
|
-
|
|
45366
|
-
|
|
45421
|
+
const picked = new Set(pickLabels(cand, labelBudget(cam.dist), widthOf, vw));
|
|
45422
|
+
c.globalCompositeOperation = "source-over";
|
|
45423
|
+
c.fillStyle = textColor;
|
|
45424
|
+
c.font = '11px system-ui, "Microsoft YaHei", sans-serif';
|
|
45425
|
+
for (const p of projected) {
|
|
45426
|
+
if (!picked.has(p.id)) continue;
|
|
45427
|
+
c.globalAlpha = Math.min(1, Math.max(0.35, p.f));
|
|
45428
|
+
c.fillText(clipByWidth(metas.get(p.id).name), p.x + 7, p.y - 5);
|
|
45429
|
+
}
|
|
45430
|
+
c.globalAlpha = 1;
|
|
45431
|
+
}
|
|
45432
|
+
nodeDirty = false;
|
|
45433
|
+
needsPresent = true;
|
|
45434
|
+
}
|
|
45435
|
+
const breathing = twinkleOn && activeIds.size > 0;
|
|
45436
|
+
if (breathing) {
|
|
45437
|
+
const c = bctx;
|
|
45438
|
+
c.setTransform(1, 0, 0, 1, 0, 0);
|
|
45439
|
+
c.drawImage(edgeCv, 0, 0);
|
|
45440
|
+
c.drawImage(nodeCv, 0, 0);
|
|
45441
|
+
c.setTransform(dprRef.current, 0, 0, dprRef.current, 0, 0);
|
|
45442
|
+
for (const id of activeIds) {
|
|
45443
|
+
const p = pos.get(id);
|
|
45367
45444
|
const m = metas.get(id);
|
|
45368
|
-
|
|
45369
|
-
|
|
45370
|
-
|
|
45371
|
-
|
|
45372
|
-
|
|
45373
|
-
|
|
45374
|
-
|
|
45375
|
-
|
|
45376
|
-
|
|
45377
|
-
|
|
45378
|
-
|
|
45379
|
-
c.
|
|
45380
|
-
|
|
45381
|
-
|
|
45382
|
-
|
|
45383
|
-
|
|
45384
|
-
|
|
45385
|
-
|
|
45386
|
-
|
|
45387
|
-
|
|
45388
|
-
|
|
45389
|
-
|
|
45390
|
-
|
|
45391
|
-
|
|
45392
|
-
|
|
45393
|
-
|
|
45394
|
-
const
|
|
45395
|
-
|
|
45396
|
-
|
|
45397
|
-
|
|
45398
|
-
|
|
45399
|
-
|
|
45400
|
-
|
|
45401
|
-
|
|
45445
|
+
if (!p || !m) continue;
|
|
45446
|
+
const tw = 0.5 + 0.5 * Math.sin(now / BREATH_PERIOD_MS + phaseOf(id));
|
|
45447
|
+
const alpha = brightnessFor(p.f, agingOn ? m.aging : null, true);
|
|
45448
|
+
const r = Math.max(0.8, m.base * p.f * 1.75 * 1.9);
|
|
45449
|
+
if (glowOn) {
|
|
45450
|
+
c.globalCompositeOperation = "lighter";
|
|
45451
|
+
c.globalAlpha = Math.min(1, alpha * 0.5 + tw * 0.4);
|
|
45452
|
+
const sp = spriteFor(m.color);
|
|
45453
|
+
const gr = r * 3.4 * (1 + tw * 0.45);
|
|
45454
|
+
c.drawImage(sp, p.x - gr, p.y - gr, gr * 2, gr * 2);
|
|
45455
|
+
}
|
|
45456
|
+
c.globalCompositeOperation = "source-over";
|
|
45457
|
+
c.globalAlpha = Math.min(1, alpha + 0.15 + tw * 0.25);
|
|
45458
|
+
c.fillStyle = m.color;
|
|
45459
|
+
c.beginPath();
|
|
45460
|
+
c.arc(p.x, p.y, r, 0, Math.PI * 2);
|
|
45461
|
+
c.fill();
|
|
45462
|
+
if (labelsOn) {
|
|
45463
|
+
c.globalAlpha = 1;
|
|
45464
|
+
c.fillStyle = colText;
|
|
45465
|
+
c.font = '11px system-ui, "Microsoft YaHei", sans-serif';
|
|
45466
|
+
c.fillText(clipByWidth(m.name), p.x + 7, p.y - 5);
|
|
45467
|
+
}
|
|
45468
|
+
}
|
|
45469
|
+
if (hover && edgesOn) {
|
|
45470
|
+
c.font = '10px system-ui, "Microsoft YaHei", sans-serif';
|
|
45471
|
+
const used = /* @__PURE__ */ new Set();
|
|
45472
|
+
const related = edgeList.filter((e) => (e.from === hover || e.to === hover) && pos.has(e.from) && pos.has(e.to)).sort((a, b) => Number(b.causal) - Number(a.causal));
|
|
45473
|
+
for (const e of related.slice(0, 12)) {
|
|
45474
|
+
const a = pos.get(e.from);
|
|
45475
|
+
const b = pos.get(e.to);
|
|
45476
|
+
const mx = (a.x + b.x) / 2;
|
|
45477
|
+
const my = (a.y + b.y) / 2;
|
|
45478
|
+
const cell = Math.floor(mx / 72) * 1e3 + Math.floor(my / 13);
|
|
45479
|
+
if (used.has(cell)) continue;
|
|
45480
|
+
used.add(cell);
|
|
45481
|
+
c.fillStyle = e.causal ? causalC : edgeBase;
|
|
45482
|
+
c.globalAlpha = 0.92;
|
|
45483
|
+
c.fillText(e.relation, mx, my);
|
|
45484
|
+
}
|
|
45485
|
+
c.globalAlpha = 1;
|
|
45486
|
+
}
|
|
45487
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
45488
|
+
ctx.drawImage(buffer, 0, 0);
|
|
45489
|
+
ctx.setTransform(dprRef.current, 0, 0, dprRef.current, 0, 0);
|
|
45490
|
+
needsPresent = false;
|
|
45491
|
+
} else if (needsPresent) {
|
|
45492
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
45493
|
+
ctx.drawImage(edgeCv, 0, 0);
|
|
45494
|
+
ctx.drawImage(nodeCv, 0, 0);
|
|
45495
|
+
ctx.setTransform(dprRef.current, 0, 0, dprRef.current, 0, 0);
|
|
45496
|
+
needsPresent = false;
|
|
45497
|
+
}
|
|
45498
|
+
running = edgeDirty || nodeDirty || needsPresent || breathing || transRef.current !== null || driftOn && !ego;
|
|
45499
|
+
if (running) raf = requestAnimationFrame(frame);
|
|
45500
|
+
};
|
|
45501
|
+
const presentNow = () => {
|
|
45502
|
+
if (disposed) return;
|
|
45503
|
+
if (raf) cancelAnimationFrame(raf);
|
|
45504
|
+
raf = 0;
|
|
45505
|
+
running = false;
|
|
45506
|
+
frame(performance.now());
|
|
45507
|
+
};
|
|
45508
|
+
const wake = () => {
|
|
45509
|
+
if (!running && !disposed) {
|
|
45510
|
+
running = true;
|
|
45511
|
+
raf = requestAnimationFrame(frame);
|
|
45402
45512
|
}
|
|
45403
|
-
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
45404
|
-
ctx.drawImage(buffer, 0, 0);
|
|
45405
|
-
ctx.setTransform(dprRef.current, 0, 0, dprRef.current, 0, 0);
|
|
45406
|
-
raf = requestAnimationFrame(frame);
|
|
45407
45513
|
};
|
|
45514
|
+
wakeRef.current = wake;
|
|
45408
45515
|
frame(performance.now());
|
|
45409
45516
|
const toLocal = (ev) => {
|
|
45410
45517
|
const rect = canvas.getBoundingClientRect();
|
|
@@ -45428,13 +45535,15 @@ var __create = Object.create;
|
|
|
45428
45535
|
}
|
|
45429
45536
|
drag.x = pt.x;
|
|
45430
45537
|
drag.y = pt.y;
|
|
45431
|
-
|
|
45538
|
+
edgeDirty = true;
|
|
45539
|
+
nodeDirty = true;
|
|
45540
|
+
wake();
|
|
45432
45541
|
return;
|
|
45433
45542
|
}
|
|
45434
45543
|
const hit = pickNearest(lastProjected, pt.x, pt.y, PICK_PX);
|
|
45435
45544
|
if (hit !== hoverRef.current) {
|
|
45436
45545
|
hoverRef.current = hit;
|
|
45437
|
-
|
|
45546
|
+
wake();
|
|
45438
45547
|
setHoverInfo(hit ? { id: hit, x: pt.x, y: pt.y } : null);
|
|
45439
45548
|
} else if (hit) {
|
|
45440
45549
|
setHoverInfo({ id: hit, x: pt.x, y: pt.y });
|
|
@@ -45487,7 +45596,9 @@ var __create = Object.create;
|
|
|
45487
45596
|
const onWheel = (ev) => {
|
|
45488
45597
|
ev.preventDefault();
|
|
45489
45598
|
camRef.current.dist = zoomBy(camRef.current.dist, ev.deltaY);
|
|
45490
|
-
|
|
45599
|
+
edgeDirty = true;
|
|
45600
|
+
nodeDirty = true;
|
|
45601
|
+
wake();
|
|
45491
45602
|
};
|
|
45492
45603
|
const onKey = (ev) => {
|
|
45493
45604
|
if (ev.key === "Enter" && hoverRef.current) onPick(hoverRef.current);
|
|
@@ -45513,6 +45624,7 @@ var __create = Object.create;
|
|
|
45513
45624
|
return () => {
|
|
45514
45625
|
disposed = true;
|
|
45515
45626
|
cancelAnimationFrame(raf);
|
|
45627
|
+
wakeRef.current = null;
|
|
45516
45628
|
ro.disconnect();
|
|
45517
45629
|
canvas.removeEventListener("mousedown", onDown);
|
|
45518
45630
|
window.removeEventListener("mousemove", onMove);
|
|
@@ -45521,7 +45633,7 @@ var __create = Object.create;
|
|
|
45521
45633
|
canvas.removeEventListener("mouseleave", onLeave);
|
|
45522
45634
|
window.removeEventListener("keydown", onKey);
|
|
45523
45635
|
};
|
|
45524
|
-
}, [full, edgeList, adj, clusterLayout, glowOn, edgesOn, labelsOn, agingOn, driftOn, starry, nodeKeySeed, height, onPick]);
|
|
45636
|
+
}, [full, edgeList, adj, clusterLayout, glowOn, edgesOn, labelsOn, agingOn, driftOn, twinkleOn, starry, nodeKeySeed, pointSize, height, onPick]);
|
|
45525
45637
|
const hoverMeta = hoverInfo ? metasRef.current.get(hoverInfo.id) : null;
|
|
45526
45638
|
const ui = starry ? {
|
|
45527
45639
|
barBg: "rgba(10, 13, 22, 0.72)",
|
|
@@ -45602,6 +45714,7 @@ var __create = Object.create;
|
|
|
45602
45714
|
toggle("边", edgesOn, setEdgesOn),
|
|
45603
45715
|
toggle("标签", labelsOn, setLabelsOn),
|
|
45604
45716
|
toggle("老化亮度", agingOn, setAgingOn),
|
|
45717
|
+
toggle("呼吸", twinkleOn, setTwinkleOn),
|
|
45605
45718
|
toggle("漂移", driftOn, setDriftOn),
|
|
45606
45719
|
toggle(starry ? "星空底" : "白底", starry, setStarry),
|
|
45607
45720
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("label", { style: { fontSize: 11, color: ui.dim, display: "inline-flex", alignItems: "center", gap: 4 }, children: [
|
package/dsh.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-prime-memory",
|
|
3
3
|
"name": "dsh-prime-memory",
|
|
4
|
-
"version": "0.26.
|
|
4
|
+
"version": "0.26.35",
|
|
5
5
|
"description": {
|
|
6
6
|
"en": "Layered distilled memory plugin (L0 capture → L1 atomic memory → L2 scenes → L3 persona) with automatic recall injection before each model step.",
|
|
7
7
|
"zh": "L0~L3 分层蒸馏记忆插件:自动捕获对话、抽取原子记忆、整合场景块、蒸馏核心画像,并在模型步骤前自动召回注入。"
|