사진·카메라

밤하늘 촬영 플래너

은하수·달·별궤적·유성우·행성·도시 야경을 찍으려는 사람에게 그날 밤의 하늘, 카메라 방향, 카메라 설정을 한 화면에 보여 주는 촬영 플래너입니다.

분야사진·카메라플랫폼Web (PWA)기술Vanilla JS (ES 모듈) · Astronomy Engine · Canvas · SVG · DeviceOrientation API · Open-Meteo API · Service Worker(PWA) · node:test · GitHub Actions → Pages
오늘 밤 은하수 촬영 가능 시간, 하늘 지도, 시간대별 고도 흐름.
오늘 밤 은하수 촬영 가능 시간, 하늘 지도, 시간대별 고도 흐름.
모바일 화면: 현장에서 휴대폰으로 확인합니다.
모바일 화면: 현장에서 휴대폰으로 확인합니다.

왜 만들었나

밤하늘 촬영은 달·박명·광해·은하수 고도를 따로 찾아보고 셔터·ISO를 감으로 정해야 해서 어렵습니다. 위치와 날짜, 장비 정보만 넣으면 시각별 하늘 상태로 설정값을 계산해 줍니다.

주요 기능

  • 대상 6가지별 ISO·조리개·셔터 추천과 대안 설정
  • NPF 규칙·500 법칙으로 별이 점으로 남는 최대 노출 계산
  • 하늘 지도(파노라마/전천 돔)와 화각 사각형, 밤 고도 차트
  • 휴대폰 나침반으로 방향 안내(자기 편각 보정)
  • Open-Meteo 구름량 예보, 적색 모드, 오프라인 PWA

숫자로 보면

촬영 대상 6가지
밝은 별 145개 · 유성우 10개 · 은하수 영역 6곳 데이터
단위 테스트 25개

어떻게 동작하나

  1. 밤 단위 계산

    computeNight()가 일몰·박명·월출/월몰 시각을 찾고, 하룻밤을 5분 간격으로 나눠 해·달·행성·은하 중심·은하수 영역의 고도/방위를 샘플링합니다.

    js/astro.js
  2. 어두운 시간 구간

    intervals()로 해 고도 -18° 이하이면서 달빛 영향이 없는 구간을 뽑고, 천문박명이 없는 날은 -12° 기준으로 낮춥니다.

    js/astro.js
  3. 대상별 분석

    analyzeMilkyWay()가 샘플마다 영역 가중치 × 고도 점수 × 달빛 계수를 매겨 오늘 밤 가장 좋은 은하수 영역과 시각을 고릅니다.

    js/astro.js
  4. 장면 밝기

    sceneEV()가 보틀 등급별 어두운 하늘 EV에 달빛 EV와 박명 EV를 빛의 양(2^EV)으로 더해 목표 노출을 구합니다.

    js/camera.js
  5. 카메라 설정

    starfieldBase()가 화소 피치로 NPF 최대 셔터를 구하고, ISO = 100·N²/(t·2^EV) 식으로 ISO를 정해 표준 단계로 반올림합니다.

    js/camera.js
  6. 화면 갱신

    시간 막대를 움직이면 그 시각의 snapshot으로 설정·방향·하늘 지도를 다시 그립니다.

    js/app.js

핵심 코드

/** NPF 규칙 (간이식): 별이 점으로 남는 최대 노출 시간 */
export function npfSeconds(aperture, pitchUm, focal) {
  return (35 * aperture + 30 * pitchUm) / focal;
}
// …
function starfieldBase(ctx, { evShift = 0, maxT = 30, minT = 0 } = {}) {
  const sensor = sensorOf(ctx.gear.sensor);
  const pitch = pixelPitch(sensor, ctx.gear.mp);
  const n = wideAperture(ctx.gear.maxAperture);
  const npf = npfSeconds(n, pitch, ctx.gear.focal);
  const r500 = rule500(ctx.gear.focal, sensor.crop);
  const t = floorShutter(Math.max(minT, Math.min(npf, maxT)));
  const ev = sceneEV(ctx);
  const target = ev.value + evShift;
  const rawIso = isoFor(n, t, target);
  return { sensor, pitch, n, npf, r500, t, ev, target, rawIso, iso: roundISO(rawIso) };
}

NPF 규칙으로 별이 점으로 남는 최대 셔터를 정하고, 장면 EV에서 필요한 ISO를 역산하는 핵심 계산입니다.

어려웠던 점

달빛·박명·광해는 밝기 단위가 EV(로그)라 그냥 더할 수 없어서, 각각 2^EV로 바꿔 더한 뒤 다시 log2를 취해 합칩니다. 그 위에 밝은 렌즈는 코마 수차를 줄이려 한 스톱 조이고, NPF 결과를 30초 이하 표준 셔터 단계로 내림해 현장에서 바로 쓸 수 있는 값으로 만듭니다.