Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.19] — 2026-02-23

### Fixed
- Corrected Timer screen compact `MAX View` moon/sun sizing so moon-size ratios now match the full preview geometry instead of using oversized fixed moon radii.

### Changed
- Bumped `apps/mobile` version to `1.1.19`.

### Tests
- Added regression tests to verify compact-stage moon/sun ratio scaling and C1/C4 tangency distance in the Timer screen `MAX View` size profile.

## [1.1.18] — 2026-02-23

### Added
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@eclipse-timer/mobile",
"version": "1.1.18",
"version": "1.1.19",
"private": true,
"main": "index.js",
"scripts": {
Expand Down
5 changes: 4 additions & 1 deletion apps/mobile/src/screens/TimerScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { eclipseCenterForRecord, kindCodeForRecord } from "../utils/eclipse";
import {
calculatePreviewMoonGeometry,
determinePreviewTravelVector,
PREVIEW_STAGE_SIZE,
PREVIEW_SUN_RADIUS,
} from "../utils/previewGeometry";

const VISIBLE_PATH_COLOR = "rgba(79, 195, 247, 0.22)";
Expand All @@ -36,7 +38,8 @@ const FAVORITE_COORD_EPSILON = 0.0001;
const DEG2RAD = Math.PI / 180;
const RAD2DEG = 180 / Math.PI;
const TIMER_HERO_PREVIEW_STAGE_SIZE = 84;
const TIMER_HERO_PREVIEW_SUN_RADIUS = 19;
const TIMER_HERO_PREVIEW_SUN_RADIUS =
(TIMER_HERO_PREVIEW_STAGE_SIZE * PREVIEW_SUN_RADIUS) / PREVIEW_STAGE_SIZE;
const TIMER_HERO_PREVIEW_GLOW_SIZE = 118;

function localKindLabel(kind: "none" | "partial" | "total" | "annular") {
Expand Down
25 changes: 17 additions & 8 deletions apps/mobile/src/utils/previewGeometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import type { EclipseKindAtLocation } from "@eclipse-timer/shared";

export const PREVIEW_SUN_RADIUS = 72;
export const PREVIEW_STAGE_SIZE = 300;
const ANNULAR_RADIUS_RATIO = 58 / PREVIEW_SUN_RADIUS;
const TOTAL_RADIUS_RATIO = 76 / PREVIEW_SUN_RADIUS;
const PARTIAL_RADIUS_RATIO = 68 / PREVIEW_SUN_RADIUS;
const NONE_RADIUS_RATIO = 66 / PREVIEW_SUN_RADIUS;
const NONE_GAP_RATIO = 14 / PREVIEW_SUN_RADIUS;
const PARTIAL_INTERNAL_MARGIN_RATIO = 6 / PREVIEW_SUN_RADIUS;

export type PreviewMotionContacts = {
c1?: number;
Expand Down Expand Up @@ -98,11 +104,14 @@ export function describePreviewTravelDirection(vector: PreviewTravelVector): str
return `${vertical}, ${horizontal}`;
}

export function determineMoonRadius(kindAtLocation: EclipseKindAtLocation) {
if (kindAtLocation === "annular") return 58;
if (kindAtLocation === "total") return 76;
if (kindAtLocation === "partial") return 68;
return 66;
export function determineMoonRadius(
kindAtLocation: EclipseKindAtLocation,
sunRadius = PREVIEW_SUN_RADIUS,
) {
if (kindAtLocation === "annular") return sunRadius * ANNULAR_RADIUS_RATIO;
if (kindAtLocation === "total") return sunRadius * TOTAL_RADIUS_RATIO;
if (kindAtLocation === "partial") return sunRadius * PARTIAL_RADIUS_RATIO;
return sunRadius * NONE_RADIUS_RATIO;
}

export function determineApproachOffset(
Expand All @@ -112,13 +121,13 @@ export function determineApproachOffset(
sunRadius = PREVIEW_SUN_RADIUS,
) {
if (kindAtLocation === "none") {
return sunRadius + moonRadius + 14;
return sunRadius + moonRadius + sunRadius * NONE_GAP_RATIO;
}

if (kindAtLocation === "partial") {
const safeMag =
typeof magnitude === "number" && Number.isFinite(magnitude) ? clamp01(magnitude) : 0.6;
return (1 - safeMag) * (sunRadius + moonRadius - 6);
return (1 - safeMag) * (sunRadius + moonRadius - sunRadius * PARTIAL_INTERNAL_MARGIN_RATIO);
}

return 0;
Expand Down Expand Up @@ -196,7 +205,7 @@ export function calculatePreviewMoonGeometry(params: {
}): PreviewMoonGeometry {
const stageSize = params.stageSize ?? PREVIEW_STAGE_SIZE;
const sunRadius = params.sunRadius ?? PREVIEW_SUN_RADIUS;
const moonRadius = determineMoonRadius(params.kindAtLocation);
const moonRadius = determineMoonRadius(params.kindAtLocation, sunRadius);
const moonClosestOffset = determineApproachOffset(
params.kindAtLocation,
params.magnitude,
Expand Down
51 changes: 51 additions & 0 deletions apps/mobile/tests/preview-geometry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
calculatePreviewMoonGeometry,
describePreviewTravelDirection,
determinePreviewTravelVector,
PREVIEW_STAGE_SIZE,
PREVIEW_SUN_RADIUS,
} from "../src/utils/previewGeometry";

Expand Down Expand Up @@ -130,4 +131,54 @@ describe("preview moon geometry", () => {
expect(c1Distance).toBeCloseTo(PREVIEW_SUN_RADIUS + c1Geometry.moonRadius, 6);
expect(c4Distance).toBeCloseTo(PREVIEW_SUN_RADIUS + c4Geometry.moonRadius, 6);
});

it("keeps moon-size ratio consistent when rendered in compact max-view stage", () => {
const compactStageSize = 84;
const compactSunRadius = (compactStageSize * PREVIEW_SUN_RADIUS) / PREVIEW_STAGE_SIZE;
const fullGeometry = calculatePreviewMoonGeometry({
progress: 0.5,
kindAtLocation: "total",
contacts: { c1: 0, c2: 0.25, max: 0.5, c3: 0.75, c4: 1 },
});
const compactGeometry = calculatePreviewMoonGeometry({
progress: 0.5,
kindAtLocation: "total",
contacts: { c1: 0, c2: 0.25, max: 0.5, c3: 0.75, c4: 1 },
stageSize: compactStageSize,
sunRadius: compactSunRadius,
});

const fullRatio = fullGeometry.moonRadius / PREVIEW_SUN_RADIUS;
const compactRatio = compactGeometry.moonRadius / compactSunRadius;
expect(compactRatio).toBeCloseTo(fullRatio, 10);
});

it("preserves C1/C4 tangency distance in compact max-view stage", () => {
const compactStageSize = 84;
const compactSunRadius = (compactStageSize * PREVIEW_SUN_RADIUS) / PREVIEW_STAGE_SIZE;
const stageCenter = compactStageSize / 2;
const contacts = { c1: 0, c2: 0.25, max: 0.5, c3: 0.75, c4: 1 };

const c1Geometry = calculatePreviewMoonGeometry({
progress: 0,
kindAtLocation: "annular",
contacts,
stageSize: compactStageSize,
sunRadius: compactSunRadius,
});
const c4Geometry = calculatePreviewMoonGeometry({
progress: 1,
kindAtLocation: "annular",
contacts,
stageSize: compactStageSize,
sunRadius: compactSunRadius,
});

const c1Distance = Math.abs(c1Geometry.moonCenterX - stageCenter);
const c4Distance = Math.abs(c4Geometry.moonCenterX - stageCenter);
const expectedDistance = compactSunRadius + c1Geometry.moonRadius;

expect(c1Distance).toBeCloseTo(expectedDistance, 6);
expect(c4Distance).toBeCloseTo(expectedDistance, 6);
});
});