Skip to content

Commit 930b17a

Browse files
author
Lalit Sharma
committed
feat: enhance Photography Guide with sun/moon positioning utilities and update landscape composite logic; add tests for Gibraltar 2027 eclipse
1 parent ffd8ba4 commit 930b17a

7 files changed

Lines changed: 718 additions & 54 deletions

File tree

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.34] — 2026-02-26
9+
10+
### Added
11+
- Added a local sun/moon horizontal-position utility for mobile (`apps/mobile/src/utils/sunMoonPosition.ts`) that computes per-time azimuth, altitude, RA/Dec, distance, and apparent angular size for an observer.
12+
- Added regression tests validating Gibraltar 2027-08-02 sun/moon azimuth-altitude samples and angular-size ranges for 24mm framing.
13+
14+
### Fixed
15+
- Corrected `Photography Guide` landscape composite geometry to use real observer-based sun/moon alt-az offsets per scheduled shot instead of synthetic hourly drift.
16+
- Fixed composite horizon placement to derive from actual MAX sun altitude, preventing above-horizon shots from being rendered below the horizon for the tested Gibraltar scenario.
17+
- Fixed composite body sizing to use angular-size-to-frame scaling so sun/moon disks render smaller and more physically plausible for the 24mm simulation.
18+
- Fixed moon rendering in the composite to display only when the moon disk is actually occluding the sun at that shot.
19+
20+
### Changed
21+
- Updated landscape composite layout payload to carry per-shot sun radius and dynamic horizon line values consumed by `PhotographyGuideScreen`.
22+
- Updated total-eclipse landscape composite visuals to use a very dark-blue sky theme with a thin pink horizon glow, moon disk styled to match the sky, and a MAX-only corona ring; partial/annular visuals remain unchanged.
23+
- Bumped `apps/mobile` version to `1.1.34`.
24+
825
## [1.1.33] — 2026-02-26
926

1027
### Added

apps/mobile/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@eclipse-timer/mobile",
3-
"version": "1.1.33",
3+
"version": "1.1.34",
44
"private": true,
55
"main": "index.js",
66
"scripts": {

apps/mobile/src/screens/PhotographyGuideScreen.tsx

Lines changed: 125 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ import {
2828
const PHOTO_COUNT_OPTIONS: readonly PhotographyGuidePictureCount[] = [3, 5, 7, 9];
2929
const TABLE_THUMB_STAGE_SIZE = 40;
3030
const TABLE_THUMB_SUN_RADIUS = 18;
31+
const TOTALITY_SKY_COLOR = "#050d24";
32+
const TOTALITY_GROUND_COLOR = "#111827";
33+
const TOTALITY_MOON_COLOR = TOTALITY_SKY_COLOR;
34+
const TOTALITY_MOON_BORDER_COLOR = "#1f2c47";
35+
const TOTALITY_HORIZON_LINE_COLOR = "rgba(255, 174, 205, 0.75)";
36+
const TOTALITY_HORIZON_GLOW_COLOR = "rgba(255, 136, 182, 0.42)";
3137

3238
export type PhotographyGuidePayload = {
3339
eclipseId: string;
@@ -87,6 +93,7 @@ export default function PhotographyGuideScreen({
8793
width: 0,
8894
height: 0,
8995
});
96+
const isTotalCompositeTheme = payload.kindAtLocation === "total";
9097
const isWithinEclipseArea = payload.visible && payload.kindAtLocation !== "none";
9198
const scheduleResult = useMemo(
9299
() =>
@@ -151,6 +158,10 @@ export default function PhotographyGuideScreen({
151158
maxUtc: payload.maxUtc,
152159
frameWidth: compositeStageSize.width,
153160
frameHeight: compositeStageSize.height,
161+
observer: {
162+
latDeg: payload.observer.latDeg,
163+
lonDeg: payload.observer.lonDeg,
164+
},
154165
travelVector: previewTravelVector,
155166
});
156167
}, [
@@ -159,9 +170,20 @@ export default function PhotographyGuideScreen({
159170
payload.kindAtLocation,
160171
payload.magnitude,
161172
payload.maxUtc,
173+
payload.observer.latDeg,
174+
payload.observer.lonDeg,
162175
previewTravelVector,
163176
scheduleResult,
164177
]);
178+
const activeCompositeHorizonY = useMemo(() => {
179+
const fallback = compositeStageSize.height > 0 ? compositeStageSize.height * 0.76 : undefined;
180+
if (!compositeLayout) return fallback;
181+
return compositeLayout.horizonY;
182+
}, [compositeLayout, compositeStageSize.height]);
183+
const compositeGroundHeight = useMemo(() => {
184+
if (typeof activeCompositeHorizonY !== "number") return undefined;
185+
return Math.max(0, compositeStageSize.height - activeCompositeHorizonY);
186+
}, [activeCompositeHorizonY, compositeStageSize.height]);
165187
const handleCompositeStageLayout = (event: LayoutChangeEvent) => {
166188
const nextWidth = Math.round(event.nativeEvent.layout.width);
167189
const nextHeight = Math.round(event.nativeEvent.layout.height);
@@ -342,9 +364,44 @@ export default function PhotographyGuideScreen({
342364
<View style={styles.compositeModal}>
343365
<Text style={styles.compositeModalTitle}>Landscape composite</Text>
344366
<View style={styles.compositeFrame} onLayout={handleCompositeStageLayout}>
345-
<View style={styles.compositeSky} />
346-
<View style={styles.compositeGround} />
347-
<View style={styles.compositeHorizon} />
367+
<View
368+
style={[
369+
styles.compositeSky,
370+
isTotalCompositeTheme ? { backgroundColor: TOTALITY_SKY_COLOR } : null,
371+
]}
372+
/>
373+
<View
374+
style={[
375+
styles.compositeGround,
376+
isTotalCompositeTheme ? { backgroundColor: TOTALITY_GROUND_COLOR } : null,
377+
typeof activeCompositeHorizonY === "number" &&
378+
typeof compositeGroundHeight === "number"
379+
? {
380+
top: activeCompositeHorizonY,
381+
height: compositeGroundHeight,
382+
}
383+
: null,
384+
]}
385+
/>
386+
{isTotalCompositeTheme ? (
387+
<View
388+
style={[
389+
styles.compositeHorizonGlow,
390+
typeof activeCompositeHorizonY === "number"
391+
? { top: Math.max(0, activeCompositeHorizonY - 2.5) }
392+
: null,
393+
]}
394+
/>
395+
) : null}
396+
<View
397+
style={[
398+
styles.compositeHorizon,
399+
isTotalCompositeTheme ? { backgroundColor: TOTALITY_HORIZON_LINE_COLOR } : null,
400+
typeof activeCompositeHorizonY === "number"
401+
? { top: activeCompositeHorizonY }
402+
: null,
403+
]}
404+
/>
348405
{compositeLayout ? (
349406
<>
350407
<View
@@ -358,22 +415,59 @@ export default function PhotographyGuideScreen({
358415
/>
359416
{compositeLayout.placements.map((placement) => (
360417
<View key={placement.index}>
418+
{isTotalCompositeTheme &&
419+
placement.phaseBucket === "MAX" &&
420+
placement.showMoon &&
421+
placement.moon ? (
422+
<>
423+
<View
424+
style={[
425+
styles.compositeCoronaGlow,
426+
{
427+
width: Math.max(placement.sunRadius * 9, 16),
428+
height: Math.max(placement.sunRadius * 9, 16),
429+
borderRadius: Math.max(placement.sunRadius * 4.5, 8),
430+
left: placement.x - Math.max(placement.sunRadius * 4.5, 8),
431+
top: placement.y - Math.max(placement.sunRadius * 4.5, 8),
432+
},
433+
]}
434+
/>
435+
<View
436+
style={[
437+
styles.compositeCoronaRing,
438+
{
439+
width: Math.max(placement.sunRadius * 6, 10),
440+
height: Math.max(placement.sunRadius * 6, 10),
441+
borderRadius: Math.max(placement.sunRadius * 3, 5),
442+
left: placement.x - Math.max(placement.sunRadius * 3, 5),
443+
top: placement.y - Math.max(placement.sunRadius * 3, 5),
444+
},
445+
]}
446+
/>
447+
</>
448+
) : null}
361449
<View
362450
style={[
363451
styles.compositeSun,
364452
{
365-
width: compositeLayout.sunRadius * 2,
366-
height: compositeLayout.sunRadius * 2,
367-
borderRadius: compositeLayout.sunRadius,
368-
left: placement.x - compositeLayout.sunRadius,
369-
top: placement.y - compositeLayout.sunRadius,
453+
width: placement.sunRadius * 2,
454+
height: placement.sunRadius * 2,
455+
borderRadius: placement.sunRadius,
456+
left: placement.x - placement.sunRadius,
457+
top: placement.y - placement.sunRadius,
370458
},
371459
]}
372460
/>
373461
{placement.showMoon && placement.moon ? (
374462
<View
375463
style={[
376464
styles.compositeMoon,
465+
isTotalCompositeTheme
466+
? {
467+
backgroundColor: TOTALITY_MOON_COLOR,
468+
borderColor: TOTALITY_MOON_BORDER_COLOR,
469+
}
470+
: null,
377471
{
378472
width: placement.moon.radius * 2,
379473
height: placement.moon.radius * 2,
@@ -389,7 +483,7 @@ export default function PhotographyGuideScreen({
389483
styles.compositeShotIndexTag,
390484
{
391485
left: placement.x - 9,
392-
top: placement.y + compositeLayout.sunRadius + 3,
486+
top: placement.y + placement.sunRadius + 3,
393487
},
394488
placement.clamped ? styles.compositeShotIndexTagClamped : null,
395489
]}
@@ -401,8 +495,8 @@ export default function PhotographyGuideScreen({
401495
style={[
402496
styles.compositeClampIndicator,
403497
{
404-
left: placement.x + compositeLayout.sunRadius - 4,
405-
top: placement.y - compositeLayout.sunRadius - 4,
498+
left: placement.x + placement.sunRadius - 4,
499+
top: placement.y - placement.sunRadius - 4,
406500
},
407501
]}
408502
/>
@@ -725,7 +819,7 @@ function createStyles(colors: ReturnType<typeof useAppTheme>["colors"]) {
725819
position: "absolute",
726820
left: 0,
727821
right: 0,
728-
bottom: 0,
822+
top: "76%",
729823
height: "24%",
730824
backgroundColor: "#314451",
731825
},
@@ -737,6 +831,14 @@ function createStyles(colors: ReturnType<typeof useAppTheme>["colors"]) {
737831
height: 1,
738832
backgroundColor: "rgba(255,255,255,0.45)",
739833
},
834+
compositeHorizonGlow: {
835+
position: "absolute",
836+
left: 0,
837+
right: 0,
838+
height: 5,
839+
backgroundColor: TOTALITY_HORIZON_GLOW_COLOR,
840+
opacity: 0.95,
841+
},
740842
compositeMaxAnchor: {
741843
position: "absolute",
742844
width: 8,
@@ -758,6 +860,17 @@ function createStyles(colors: ReturnType<typeof useAppTheme>["colors"]) {
758860
borderWidth: 1,
759861
borderColor: "#3d4267",
760862
},
863+
compositeCoronaGlow: {
864+
position: "absolute",
865+
backgroundColor: "rgba(198, 228, 255, 0.20)",
866+
borderWidth: 0,
867+
},
868+
compositeCoronaRing: {
869+
position: "absolute",
870+
borderWidth: 1,
871+
borderColor: "rgba(236, 248, 255, 0.92)",
872+
backgroundColor: "transparent",
873+
},
761874
compositeShotIndexTag: {
762875
position: "absolute",
763876
minWidth: 18,

0 commit comments

Comments
 (0)