Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
OpenPets Dev
be21907030 fix(pet): render scale handle and add keyboard arrow nudges
- Add a visible scale handle inside the pet shell with proper CSS sizing,
  pointer-events, and focus styles so it is grabbable.
- Add keyboard arrow nudges (up/down/left/right) to adjust pet scale when
  the pet window is focused, with a debounced commit.
2026-06-14 03:14:40 +00:00
2 changed files with 30 additions and 0 deletions

View file

@ -494,6 +494,31 @@ const installMouseInterop = () => {
if (!dragging && !scaling) setInteractiveHit(false);
}, { passive: true });
const scaleNudgeStep = 0.02;
let scaleNudgeCommitTimer = null;
const commitScaleNudge = () => {
if (scaleNudgeCommitTimer) {
clearTimeout(scaleNudgeCommitTimer);
scaleNudgeCommitTimer = null;
}
const finalScale = getCurrentSpriteScale();
ipcRenderer.send("openpets:pet-scale-end", { scale: finalScale });
};
window.addEventListener("keydown", (event) => {
if (event.ctrlKey || event.metaKey || event.altKey) return;
const target = event.target;
if (target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable)) return;
if (event.key !== "ArrowUp" && event.key !== "ArrowDown" && event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
event.preventDefault();
const current = getCurrentSpriteScale();
const delta = event.key === "ArrowUp" || event.key === "ArrowRight" ? scaleNudgeStep : -scaleNudgeStep;
const next = applyScalePreview(current + delta);
ipcRenderer.send("openpets:pet-scale-preview", { scale: next });
if (scaleNudgeCommitTimer) clearTimeout(scaleNudgeCommitTimer);
scaleNudgeCommitTimer = setTimeout(commitScaleNudge, 250);
});
setInteractiveHit(false, "ready");
ipcRenderer.send("openpets:pet-ready");
};

View file

@ -986,6 +986,7 @@ function createPetBodyMarkup(stageLabel: string, bubble: string, spriteMarkup: s
<div class="pet-hitbox" aria-hidden="true">
<div class="pet-shell">
${spriteMarkup}
<div class="scale-handle" role="slider" aria-label="Resize pet" aria-orientation="vertical" aria-valuemin="0.16" aria-valuemax="3" tabindex="0" title="Drag up/down to scale; use Arrow keys to nudge"></div>
</div>
</div>
</div>`;
@ -1018,6 +1019,10 @@ function createPetWindowCss(paused: boolean, scale: PetScaleValue, layout?: Part
.stage { width: 100%; height: 100%; position: relative; box-sizing: border-box; overflow: visible; }
.pet-hitbox { position: absolute; left: 50%; bottom: ${Math.max(0, petBottom - hitPadding)}px; z-index: 1; width: ${scaledWidth + hitPadding * 2}px; height: ${scaledHeight + hitPadding * 2}px; display: grid; place-items: center; transform: translateX(-50%); pointer-events: auto; -webkit-app-region: no-drag; cursor: grab; }
.pet-shell { position: relative; width: ${scaledWidth}px; height: ${scaledHeight}px; display: block; opacity: var(--pet-opacity); filter: ${petShellFilter}; transition-property: opacity, filter; transition-duration: 180ms; transition-timing-function: cubic-bezier(0.2, 0, 0, 1); pointer-events: auto; -webkit-app-region: no-drag; cursor: grab; }
.scale-handle { position: absolute; right: -7px; bottom: -7px; width: 18px; height: 18px; border-radius: 50%; background: rgba(255, 255, 255, 0.92); border: 1px solid rgba(30, 58, 138, 0.28); box-shadow: 0 2px 6px rgba(15, 23, 42, 0.18); cursor: ns-resize; pointer-events: auto; -webkit-app-region: no-drag; z-index: 5; display: grid; place-items: center; font-size: 10px; line-height: 1; color: #475569; }
.scale-handle::after { content: "↕"; }
.scale-handle:hover { background: #ffffff; border-color: rgba(37, 99, 235, 0.5); color: #2563eb; transform: scale(1.08); }
.scale-handle:focus-visible { outline: 2px solid rgba(37, 99, 235, 0.6); outline-offset: 1px; }
.bubble { position: absolute; left: 50%; bottom: ${bubbleBottom}px; z-index: 4; box-sizing: border-box; display: inline-flex; flex-direction: column; width: fit-content; min-width: 92px; max-width: min(340px, calc(100vw - 24px)); max-height: var(--bubble-max-height); padding: 10px 12px; background: linear-gradient(135deg, rgba(239, 246, 255, 0.97), rgba(237, 233, 254, 0.96)); color: #172033; font: 760 11px/14px Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; text-align: left; border: 1px solid rgba(255, 255, 255, 0.78); border-radius: 14px; box-shadow: 0 12px 24px rgba(15, 23, 42, 0.16), 0 2px 5px rgba(15, 23, 42, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.82); white-space: normal; overflow-wrap: break-word; word-break: normal; overflow: visible; pointer-events: auto; -webkit-app-region: no-drag; opacity: 1; backdrop-filter: ${bubbleBackdropFilter}; transform: translateX(-50%); transform-origin: 64% 100%; animation: bubble-in 180ms cubic-bezier(0.2, 0, 0, 1); }
.bubble.is-below { bottom: auto; top: ${bubbleTop}px; transform-origin: 64% 0; }
.bubble.is-below::after { top: -7px; bottom: auto; border: none; border-top: 1px solid rgba(255, 255, 255, 0.56); border-left: 1px solid rgba(255, 255, 255, 0.56); border-bottom-right-radius: 0; border-top-left-radius: 3px; transform: translateX(-50%) rotate(45deg); }