fix: smooth persona hover transitions

Preserve the original reflection material while adding pointer inertia and a short exit hold. Retain the Rive pointer constraint through the fade and blend rapid re-entry to avoid abrupt changes.

Cover timing, re-entry, cancellation, renderer disposal and native Rive frames. The fade regression fails with the previous resource and passes with the updated resource.
This commit is contained in:
2026-10-28 11:46:14 +08:00
parent 4f0f34f460
commit e57e0f099f
12 changed files with 325 additions and 31 deletions
+10 -2
View File
@@ -121,7 +121,7 @@ test("renders original Obsidian, caches across reloads and releases offscreen re
});
});
test("pointer coordinates reach the native hover listener in the launcher and header", async ({ page }) => {
test("pointer coordinates reach the native hover listener in the launcher and header", async ({ page }, testInfo) => {
await page.addInitScript(() => {
const addListener = HTMLCanvasElement.prototype.addEventListener;
HTMLCanvasElement.prototype.addEventListener = function (type, listener, options) {
@@ -144,7 +144,8 @@ test("pointer coordinates reach the native hover listener in the launcher and he
await page.goto("/", { waitUntil: "domcontentloaded" });
const launcher = page.getByLabel("Agent 折叠栏");
const panel = page.getByRole("complementary", { name: "Agent 命令面板" });
for (const orb of [launcher.locator("[data-agent-orb]"), panel.locator("header [data-agent-orb]")]) {
const orbs = [launcher.locator("[data-agent-orb]"), panel.locator("header [data-agent-orb]")];
for (const [index, orb] of orbs.entries()) {
await ready(orb);
const bounds = (await orb.boundingBox())!;
for (const x of [0.25, 0.75, 0.5]) {
@@ -154,6 +155,13 @@ test("pointer coordinates reach the native hover listener in the launcher and he
return point ? JSON.parse(point) : null;
}).toEqual({ x, y: 0.5 });
}
await testInfo.attach(`original-hover-${index === 0 ? "launcher" : "header"}`, {
body: await page.screenshot({
path: `/tmp/nexttjwater-persona-hover-${index}.png`,
clip: { x: Math.max(0, bounds.x - 12), y: Math.max(0, bounds.y - 12), width: 240, height: 104 }
}),
contentType: "image/png"
});
await page.mouse.move(600, 600);
await expect(orb).toHaveAttribute("data-hovered", "false");
if (!(await panel.isVisible())) await launcher.getByRole("button").click();