feat(companion): render Sagi 50% larger and crop the artwork's empty padding
SAGI_SIZE (the draggable button's real footprint) and SagiAvatar's default `size` both go 60 -> 90, and the viewBox drops the exporter's padded `0 0 1280 1280` canvas for a tight window on the art: the measured bbox over every path is x 331..1114 / y 173..1044, padded out to a square and raised to y 106 so the zzz / bang / sparkle mood overlays stay inside and the box keeps the 1:1 aspect of the square width/height. Path data is not rescaled, so MAX_PUPIL_SHIFT and the eye/mood transform-origins in sagi.css stay valid in the original 1280-unit space.
This commit is contained in:
@@ -45,7 +45,18 @@ interface SagiAvatarProps {
|
||||
size?: number;
|
||||
}
|
||||
|
||||
const MAX_PUPIL_SHIFT = 36; // px in the 0-1280 viewBox (scaled from the old 100x100 art)
|
||||
const MAX_PUPIL_SHIFT = 36; // px in the 1280-unit path coordinate space
|
||||
|
||||
// Tight window on the artwork instead of the exporter's `0 0 1280 1280` canvas,
|
||||
// which padded the mascot with ~330 units of empty space on the left and
|
||||
// ~170-240 on the other three sides. Measured bbox over every path is
|
||||
// x 331..1114 / y 173..1044; the top is raised to 106 and the width padded out
|
||||
// to a square so the mood overlays (zzz / bang / sparkle, which sit above and
|
||||
// to the right of the body) stay inside and the box keeps the 1:1 aspect of the
|
||||
// square width/height below. Path data and every coordinate constant that
|
||||
// references it (MAX_PUPIL_SHIFT above, the eye/mood transform-origins in
|
||||
// sagi.css) are untouched — only the window moved.
|
||||
const VIEW_BOX = "253.5 106 938 938";
|
||||
|
||||
// Module-level last-known cursor position, tracked from the moment this module
|
||||
// first loads (well before any avatar mounts). This is what makes eye tracking
|
||||
@@ -65,7 +76,7 @@ if (typeof window !== "undefined") {
|
||||
});
|
||||
}
|
||||
|
||||
export function SagiAvatar({ mood, reducedMotion, size = 60 }: SagiAvatarProps) {
|
||||
export function SagiAvatar({ mood, reducedMotion, size = 90 }: SagiAvatarProps) {
|
||||
const rootRef = useRef<SVGSVGElement | null>(null);
|
||||
const rafRef = useRef<number>();
|
||||
const [pupil, setPupil] = useState({ x: 0, y: 0 });
|
||||
@@ -129,7 +140,7 @@ export function SagiAvatar({ mood, reducedMotion, size = 60 }: SagiAvatarProps)
|
||||
data-reduced={reducedMotion ? "1" : "0"}
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 1280 1280"
|
||||
viewBox={VIEW_BOX}
|
||||
role="img"
|
||||
aria-label={`Sagi (${mood})`}
|
||||
>
|
||||
|
||||
@@ -74,7 +74,7 @@ import { sagiPrefs, type SagiPos } from "./prefs";
|
||||
import type { PointerEvent as ReactPointerEvent } from "react";
|
||||
|
||||
// Avatar footprint + edge gap, in px. SIZE matches SagiAvatar's default size.
|
||||
export const SAGI_SIZE = 60;
|
||||
export const SAGI_SIZE = 90;
|
||||
export const SAGI_MARGIN = 16;
|
||||
const DRAG_THRESHOLD = 5;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user