cynarAI ba89574c83
Align Oo avatar eye spacing with evoo-logo (#173)
* Align Oo avatar eye spacing with evoo-logo overlap ratio

Derive small-eye placement from evoo-logo.svg center spacing (~0.94 of
r_big + r_small) for the shared rig, EvooMascot brand lock, and face crops.

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>

* Format brand-lock spacing test for Biome

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>

* Align mobile Expo packages for install --check in CI

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>

* ci: retrigger after flaky chart-links E2E

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
2026-10-06 18:56:40 +02:00

83 lines
3.3 KiB
TypeScript

import {
OO_EYE_ASYMMETRY_MIN_RATIO,
OO_EYE_CENTER_SPACING_RATIO,
ooEyeCentersFromLogoRatio,
} from "@rakazo/core";
/**
* evOo brand lock — non-negotiable (Ingo).
*
* Oo trademark = asymmetric Kulleraugen + size difference.
*
* All mascot surfaces (EvooMascot, BotAvatar, Wordmark) MUST keep:
* 1. Consistent size asymmetry between the two eyes (big O vs small o).
* 2. Kulleraugen — big, round, glossy googly/cute sclera + pupils.
* 3. Eye center spacing matched to `evoo-logo.svg` (close / slight overlap).
*
* Personality (mouth, hands, accessories, poses) builds ON TOP of this signature.
* Never symmetrize the eyes. Never use Grok-style emoji faces. Never equal eye radii.
*/
/** Canonical trademark string — cite in reviews and design docs. */
export const EVOO_OO_TRADEMARK = "Oo trademark = asymmetric Kulleraugen + size difference" as const;
/** Big eye (capital O) — outer sclera radius in mascot viewBox units. */
export const EVOO_EYE_BIG_R = 30;
/** Small eye (lowercase o) — ~φ⁻¹ of big eye; trademark size gap. */
export const EVOO_EYE_SMALL_R = 18.54;
/** Big sclera anchor in the mascot viewBox (capital O). */
export const EVOO_EYE_BIG_CX = 44;
export const EVOO_EYE_BIG_CY = 54;
const _mascotSmallCenter = ooEyeCentersFromLogoRatio(
{ cx: EVOO_EYE_BIG_CX, cy: EVOO_EYE_BIG_CY, r: EVOO_EYE_BIG_R },
EVOO_EYE_SMALL_R,
);
/** Small sclera anchor derived from the logo spacing ratio. */
export const EVOO_EYE_SMALL_CX = _mascotSmallCenter.cx;
export const EVOO_EYE_SMALL_CY = _mascotSmallCenter.cy;
/** Logo-matched center distance ÷ sum of sclera radii (re-export for docs/tests). */
export const EVOO_EYE_CENTER_SPACING_RATIO = OO_EYE_CENTER_SPACING_RATIO;
/** Pupil radii scale with sclera; golden-ratio proportion preserved. */
export const EVOO_PUPIL_BIG_R = 14.2;
export const EVOO_PUPIL_SMALL_R = EVOO_PUPIL_BIG_R * 0.618034;
/** Pupil anchors track sclera; offsets unchanged from the original mascot art. */
export const EVOO_PUPIL_BIG_CX = EVOO_EYE_BIG_CX + 4;
export const EVOO_PUPIL_BIG_CY = EVOO_EYE_BIG_CY + 3;
export const EVOO_PUPIL_SMALL_CX = EVOO_EYE_SMALL_CX + 0.37;
export const EVOO_PUPIL_SMALL_CY = EVOO_EYE_SMALL_CY + 0.94;
/** Minimum big÷small ratio — catches accidental symmetrization in tests/CI. */
export const EVOO_EYE_ASYMMETRY_MIN_RATIO = OO_EYE_ASYMMETRY_MIN_RATIO;
export const EVOO_BRAND_LOCK_RULES = [
"Two eyes only: one big O, one small o — never equal radii.",
"Kulleraugen: round white sclera, dark glossy pupil, primary + secondary catchlights.",
"Eye spacing follows evoo-logo.svg — centers closer than r_big + r_small (slight overlap).",
"Poses may change gaze, blink, squint (eyeOpen), brows, mouth, hands, accessories — not eye size parity.",
"No Grok-bot emoji face replacement; no symmetric sticker eyes.",
] as const;
/** Dev/test guard — throws if constants violate the trademark asymmetry. */
export function assertEvooEyeBrandLock(bigR = EVOO_EYE_BIG_R, smallR = EVOO_EYE_SMALL_R): void {
if (!(bigR > smallR)) {
throw new Error(
`${EVOO_OO_TRADEMARK}: big eye radius must exceed small (${bigR} vs ${smallR})`,
);
}
const ratio = bigR / smallR;
if (ratio < EVOO_EYE_ASYMMETRY_MIN_RATIO) {
throw new Error(
`${EVOO_OO_TRADEMARK}: asymmetry ratio ${ratio.toFixed(3)} below minimum ${EVOO_EYE_ASYMMETRY_MIN_RATIO}`,
);
}
}
assertEvooEyeBrandLock();