2
0

Expand portrait progression

This commit is contained in:
kingOfSoySauce
2026-08-14 22:48:03 +08:00
parent ed342f0aa4
commit a0b8a636af
13 changed files with 105 additions and 32 deletions

View File

@@ -2,6 +2,14 @@
把 Harness 的推理等级改为紧凑滑块,并用滑动变祖原项目的 0–30 强度映射同步人物、背景与界面配色。 把 Harness 的推理等级改为紧凑滑块,并用滑动变祖原项目的 0–30 强度映射同步人物、背景与界面配色。
## 效果预览
![滑动变祖皮肤效果](docs/preview.png)
拖动推理等级滑块时,人物形态与界面配色会同步变化:
![滑动变祖交互演示](docs/demo.gif)
## 交互规则 ## 交互规则
- 档位直接读取当前模型的 `reasoning.efforts`,不写死数量或名称。 - 档位直接读取当前模型的 `reasoning.efforts`,不写死数量或名称。
@@ -24,7 +32,7 @@
需要先安装 DeepSeek Harness CLI。发布到独立 GitHub 仓库后,可以直接从 Git 安装: 需要先安装 DeepSeek Harness CLI。发布到独立 GitHub 仓库后,可以直接从 Git 安装:
```sh ```sh
dsh plugin --profile web add 'github:kingOfSoySauce/dsh-liang-skin#v0.1.0' dsh plugin --profile web add 'github:kingOfSoySauce/dsh-liang-skin#v0.1.1'
dsh --profile web --dump-config dsh --profile web --dump-config
dsh --profile web dsh --profile web
``` ```
@@ -73,4 +81,4 @@ npm run build
## 素材 ## 素材
插件包含运行时所需的图片和视频素材,安装后不需要额外下载。 插件包含运行时所需的图片和视频素材,安装后不需要额外下载。0–30 强度轴当前接入 24 张经过审核的人像锚点,滑动时直接切换最近锚点,不做图片交叉渐变。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -27,10 +27,12 @@ final result: passed
- Tooltip may extend beyond the slider box at either endpoint so its center remains aligned with the thumb - Tooltip may extend beyond the slider box at either endpoint so its center remains aligned with the thumb
- Tooltip now follows the active skin surface: light surface with dark text in the light shell, dark surface with light text in the dark shell - Tooltip now follows the active skin surface: light surface with dark text in the light shell, dark surface with light text in the dark shell
- Light mode retains Harness blue accents and a black badge with light lettering - Light mode retains Harness blue accents and a black badge with light lettering
- Dark mode uses the calibrator's `#c19a49` / `#d5b56e` gold for the badge, hero glow, effort label, slider, and send action - Dark mode uses the calibrator's `#c19a49` / `#d5b56e` gold for the badge, hero glow, effort label, and send action
- Slider thumb, rail, and ticks use one subdued accent family; the send arrow is dark on gold - Slider thumb, rail, and ticks always use the subdued secondary text color; the send arrow is dark on gold
- Light mode slider, rail, and ticks use the secondary text color; the send arrow remains white on blue - Light mode slider, rail, and ticks use the secondary text color; the send arrow remains white on blue
- Portraits render without brightness, contrast, or saturation filters; source artwork supplies the intended tonal grade - Portraits render without brightness, contrast, or saturation filters; source artwork supplies the intended tonal grade
- All 24 approved portrait anchors are registered by the host and selected by the client; no image crossfade is used
- The custom rail starts and ends at the endpoint ticks, producing terminal T caps instead of crossing past them
- Side-by-side reference comparison: `design-qa-comparison.png` - Side-by-side reference comparison: `design-qa-comparison.png`
- Final implementation capture: `design-qa-final.png` - Final implementation capture: `design-qa-final.png`

BIN
docs/demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

BIN
docs/preview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "dsh-client-liang-intensity-skin", "name": "dsh-client-liang-intensity-skin",
"version": "0.1.0", "version": "0.1.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "dsh-client-liang-intensity-skin", "name": "dsh-client-liang-intensity-skin",
"version": "0.1.0", "version": "0.1.1",
"devDependencies": { "devDependencies": {
"@types/react": "~18.3.1", "@types/react": "~18.3.1",
"esbuild": "^0.25.0", "esbuild": "^0.25.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "dsh-client-liang-intensity-skin", "name": "dsh-client-liang-intensity-skin",
"version": "0.1.0", "version": "0.1.1",
"private": true, "private": true,
"description": "滑动变祖:an opt-in adaptive reasoning slider skin for DeepSeek Harness", "description": "滑动变祖:an opt-in adaptive reasoning slider skin for DeepSeek Harness",
"repository": { "repository": {
@@ -21,12 +21,28 @@
"assets/liang-evolution.webm", "assets/liang-evolution.webm",
"assets/liang-poster.png", "assets/liang-poster.png",
"assets/portrait-source-v2/stage-00.png", "assets/portrait-source-v2/stage-00.png",
"assets/portrait-source-v2/level-01.png",
"assets/portrait-source-v2/level-03.png",
"assets/portrait-source-v2/level-04.png",
"assets/portrait-source-v2/stage-06.png", "assets/portrait-source-v2/stage-06.png",
"assets/portrait-source-v2/level-07.png",
"assets/portrait-source-v2/level-09.png",
"assets/portrait-source-v2/level-10.png",
"assets/portrait-source-v2/stage-12.png", "assets/portrait-source-v2/stage-12.png",
"assets/portrait-source-v2/level-13.png",
"assets/portrait-source-v2/level-14.png",
"assets/portrait-source-v2/bridge-15.png", "assets/portrait-source-v2/bridge-15.png",
"assets/portrait-source-v2/level-16.png",
"assets/portrait-source-v2/level-17.png",
"assets/portrait-source-v2/stage-18.png", "assets/portrait-source-v2/stage-18.png",
"assets/portrait-source-v2/level-19.png",
"assets/portrait-source-v2/level-21.png",
"assets/portrait-source-v2/level-22.png",
"assets/portrait-source-v2/stage-24.png", "assets/portrait-source-v2/stage-24.png",
"assets/portrait-source-v2/level-25.png",
"assets/portrait-source-v2/bridge-27.png", "assets/portrait-source-v2/bridge-27.png",
"assets/portrait-source-v2/level-28.png",
"assets/portrait-source-v2/level-29.png",
"assets/portrait-source-v2/stage-30.png", "assets/portrait-source-v2/stage-30.png",
"cordis.patch.yml", "cordis.patch.yml",
"lib/client.js", "lib/client.js",

View File

@@ -29,12 +29,28 @@ const PREFERENCE_KEY = "dsh-liang-intensity-skin.enabled";
const PORTRAIT_ANCHORS = [ const PORTRAIT_ANCHORS = [
{ level: 0, file: "stage-00.png" }, { level: 0, file: "stage-00.png" },
{ level: 1, file: "level-01.png" },
{ level: 3, file: "level-03.png" },
{ level: 4, file: "level-04.png" },
{ level: 6, file: "stage-06.png" }, { level: 6, file: "stage-06.png" },
{ level: 7, file: "level-07.png" },
{ level: 9, file: "level-09.png" },
{ level: 10, file: "level-10.png" },
{ level: 12, file: "stage-12.png" }, { level: 12, file: "stage-12.png" },
{ level: 13, file: "level-13.png" },
{ level: 14, file: "level-14.png" },
{ level: 15, file: "bridge-15.png" }, { level: 15, file: "bridge-15.png" },
{ level: 16, file: "level-16.png" },
{ level: 17, file: "level-17.png" },
{ level: 18, file: "stage-18.png" }, { level: 18, file: "stage-18.png" },
{ level: 19, file: "level-19.png" },
{ level: 21, file: "level-21.png" },
{ level: 22, file: "level-22.png" },
{ level: 24, file: "stage-24.png" }, { level: 24, file: "stage-24.png" },
{ level: 25, file: "level-25.png" },
{ level: 27, file: "bridge-27.png" }, { level: 27, file: "bridge-27.png" },
{ level: 28, file: "level-28.png" },
{ level: 29, file: "level-29.png" },
{ level: 30, file: "stage-30.png" }, { level: 30, file: "stage-30.png" },
] as const; ] as const;
@@ -347,7 +363,7 @@ function LiangEffortSlider({ directory, load, select, presenter, scope }: Slider
const previewIndex = nearestEffortIndex(frame, efforts); const previewIndex = nearestEffortIndex(frame, efforts);
const previewEffort = efforts[previewIndex]; const previewEffort = efforts[previewIndex];
const progress = `${(frame / PREVIEW_MAX_FRAME) * 100}%`; const progressRatio = frame / PREVIEW_MAX_FRAME;
const commit = async (rawFrame: number) => { const commit = async (rawFrame: number) => {
const targetIndex = nearestEffortIndex(rawFrame, efforts); const targetIndex = nearestEffortIndex(rawFrame, efforts);
@@ -383,7 +399,7 @@ function LiangEffortSlider({ directory, load, select, presenter, scope }: Slider
{interacting && ( {interacting && (
<output <output
className="liang-effort-control__tooltip" className="liang-effort-control__tooltip"
style={{ "--liang-tooltip-position": progress } as React.CSSProperties} style={{ "--liang-slider-ratio": progressRatio } as React.CSSProperties}
> >
{indicatorLabel(frame, efforts)} {indicatorLabel(frame, efforts)}
</output> </output>
@@ -407,7 +423,6 @@ function LiangEffortSlider({ directory, load, select, presenter, scope }: Slider
disabled={pending || state.status === "selecting"} disabled={pending || state.status === "selecting"}
aria-label="思考等级" aria-label="思考等级"
aria-valuetext={previewEffort?.name ?? ""} aria-valuetext={previewEffort?.name ?? ""}
style={{ "--liang-slider-progress": progress } as React.CSSProperties}
onPointerDown={() => { onPointerDown={() => {
dragging.current = true; dragging.current = true;
setInteracting(true); setInteracting(true);

View File

@@ -267,16 +267,6 @@ body[data-liang-skin="on"]:is(
} }
body[data-liang-skin="on"] .liang-effort-control { body[data-liang-skin="on"] .liang-effort-control {
--liang-control-accent: var(--liang-accent);
--liang-control-rail: color-mix(in srgb, var(--liang-accent) 34%, transparent);
}
body[data-liang-skin="on"]:is(
[data-liang-stage="0"],
[data-liang-stage="1"],
[data-liang-stage="2"],
[data-liang-stage="3"]
) .liang-effort-control {
--liang-control-accent: var(--liang-secondary); --liang-control-accent: var(--liang-secondary);
--liang-control-rail: color-mix(in srgb, var(--liang-secondary) 28%, transparent); --liang-control-rail: color-mix(in srgb, var(--liang-secondary) 28%, transparent);
} }
@@ -288,11 +278,22 @@ body[data-liang-skin="on"]:is(
pointer-events: none; pointer-events: none;
} }
.liang-effort-control__ticks::before {
position: absolute;
top: 50%;
right: 0;
left: 0;
height: 1px;
content: "";
background: var(--liang-control-rail);
transform: translateY(-50%);
}
.liang-effort-control__tooltip { .liang-effort-control__tooltip {
position: absolute; position: absolute;
z-index: 4; z-index: 4;
bottom: calc(100% + 7px); bottom: calc(100% + 7px);
left: var(--liang-tooltip-position); left: calc(10px + (100% - 20px) * var(--liang-slider-ratio));
min-width: max-content; min-width: max-content;
padding: 5px 8px; padding: 5px 8px;
border: 1px solid var(--liang-border, rgb(0 0 0 / 12%)); border: 1px solid var(--liang-border, rgb(0 0 0 / 12%));
@@ -333,9 +334,9 @@ body[data-liang-skin="on"]:is(
.liang-effort-control__range { .liang-effort-control__range {
position: relative; position: relative;
z-index: 1; z-index: 1;
width: 100%; width: calc(100% - 7px);
height: 28px; height: 28px;
margin: 0; margin: 0 3.5px;
cursor: ew-resize; cursor: ew-resize;
appearance: none; appearance: none;
background: transparent; background: transparent;
@@ -350,7 +351,7 @@ body[data-liang-skin="on"]:is(
.liang-effort-control__range::-webkit-slider-runnable-track { .liang-effort-control__range::-webkit-slider-runnable-track {
height: 1px; height: 1px;
border-radius: 1px; border-radius: 1px;
background: linear-gradient(90deg, var(--liang-control-accent) 0 var(--liang-slider-progress), var(--liang-control-rail) var(--liang-slider-progress) 100%); background: transparent;
} }
.liang-effort-control__range::-webkit-slider-thumb { .liang-effort-control__range::-webkit-slider-thumb {
@@ -374,12 +375,12 @@ body[data-liang-skin="on"] .liang-effort-control__range::-webkit-slider-thumb {
.liang-effort-control__range::-moz-range-track { .liang-effort-control__range::-moz-range-track {
height: 1px; height: 1px;
background: var(--liang-control-rail); background: transparent;
} }
.liang-effort-control__range::-moz-range-progress { .liang-effort-control__range::-moz-range-progress {
height: 1px; height: 1px;
background: var(--liang-control-accent); background: transparent;
} }
.liang-effort-control__range::-moz-range-thumb { .liang-effort-control__range::-moz-range-thumb {

View File

@@ -13,12 +13,28 @@ const ASSET_SPECS = [
["liang-evolution.mp4", "video/mp4"], ["liang-evolution.mp4", "video/mp4"],
["liang-poster.png", "image/png"], ["liang-poster.png", "image/png"],
["portrait-source-v2/stage-00.png", "image/png"], ["portrait-source-v2/stage-00.png", "image/png"],
["portrait-source-v2/level-01.png", "image/png"],
["portrait-source-v2/level-03.png", "image/png"],
["portrait-source-v2/level-04.png", "image/png"],
["portrait-source-v2/stage-06.png", "image/png"], ["portrait-source-v2/stage-06.png", "image/png"],
["portrait-source-v2/level-07.png", "image/png"],
["portrait-source-v2/level-09.png", "image/png"],
["portrait-source-v2/level-10.png", "image/png"],
["portrait-source-v2/stage-12.png", "image/png"], ["portrait-source-v2/stage-12.png", "image/png"],
["portrait-source-v2/level-13.png", "image/png"],
["portrait-source-v2/level-14.png", "image/png"],
["portrait-source-v2/bridge-15.png", "image/png"], ["portrait-source-v2/bridge-15.png", "image/png"],
["portrait-source-v2/level-16.png", "image/png"],
["portrait-source-v2/level-17.png", "image/png"],
["portrait-source-v2/stage-18.png", "image/png"], ["portrait-source-v2/stage-18.png", "image/png"],
["portrait-source-v2/level-19.png", "image/png"],
["portrait-source-v2/level-21.png", "image/png"],
["portrait-source-v2/level-22.png", "image/png"],
["portrait-source-v2/stage-24.png", "image/png"], ["portrait-source-v2/stage-24.png", "image/png"],
["portrait-source-v2/level-25.png", "image/png"],
["portrait-source-v2/bridge-27.png", "image/png"], ["portrait-source-v2/bridge-27.png", "image/png"],
["portrait-source-v2/level-28.png", "image/png"],
["portrait-source-v2/level-29.png", "image/png"],
["portrait-source-v2/stage-30.png", "image/png"], ["portrait-source-v2/stage-30.png", "image/png"],
]; ];