# zstarview 仕様書

最終更新: 2026-03-29

## 1. この文書の位置づけ

この文書は、`zstarview` の機能仕様を利用者視点でまとめたものである。  
README より詳細に、何ができるか、どう振る舞うか、どのような制約があるかを記述する。  
内部モジュール構成や実装手順は `docs/design.md` と `docs/implementation-history.md` に分離する。

## 2. 製品概要

`zstarview` は、指定した地点と時刻における空の見え方をデスクトップ上に表示するアプリケーションである。

主な目的は次の通り。

- 地点ごとの星空を視覚的に把握できること
- 昼間、薄明、曇天でも空の状態を把握しやすいこと
- 現在時刻だけでなく、任意時刻の空を確認できること
- 位置指定、表示方向変更、重ね合わせ表示を軽快に行えること

## 3. 想定利用者とユースケース

### 3.1 想定利用者

- 任意の都市や座標から見た星空を確認したいユーザー
- タワーや展望地点からの見え方を確認したいユーザー
- 観望前に雲の状態も含めて空の状況を把握したいユーザー
- 特定の星、惑星、アステリズム、DSO の位置関係を見たいユーザー

### 3.2 代表的なユースケース

1. 都市名を指定して現在の星空を表示する。
2. 緯度経度を直接指定して、その地点の空を表示する。
3. タワー名または山名を指定して、そのビューポイントからの見え方を表示する。
4. 視線方向を変えて、天頂から地平線付近まで任意方向を観察する。
5. 指定日時の空を表示して、過去または未来の見え方を確認する。
6. 雲表示や地形地平線を補助情報として重ねて観察する。
7. 星名検索や代表恒星ジャンプで目的の天体へ素早く移動する。

雲表示は観望補助用の近似表示であり、利用可能な衛星時刻、観測地点、部分欠損に応じて鮮度や見え方が変わってよい。
また、視線変更中は誤解を避けるため、旧視線条件で生成された雲画像を暫定表示せず、一時的に非表示としてよい。

## 4. 仕様範囲

### 4.1 対象機能

- 地点解決
  - 都市名
  - 国コード付き都市名
  - GeoNames ID
  - タワー名
  - Wikidata ID
  - 緯度経度
- 時刻指定
  - 現在時刻
  - 相対時間シフト
  - 絶対日時指定
- 星空表示
  - 恒星
  - 太陽、月、惑星
  - 地平線、天の赤道、黄道
  - 地平線下の地面ティント
  - 赤緯に基づく never-rises 領域の可視化
- 補助表示
  - DSO
  - アステリズム
  - 航空機オーバーレイ
  - 雲オーバーレイ
  - 地形地平線
- GUI 操作
  - キーボード操作
  - ハンバーガーメニュー
  - ホバー情報
- CLI 起動
- GNOME 向け `.desktop` ファイル生成

### 4.2 対象外

- 学術用途の厳密保証
- 小惑星や人工衛星などの網羅表示
- 複数ユーザー間での設定共有
- オフラインでの雲データ提供保証
- 衛星雲データの完全性、時刻厳密一致、全球一様な解像度保証

## 5. 入力仕様

### 5.1 起動引数

アプリケーションは `zstarview [options] [location]` 形式で起動する。

利用者が主要に指定する入力は次の通り。

- `location`
- `-p`, `--place`
- `--place-countrycode`
- `--place-lang`
- `--timezone`
- `--datetime`
- `--hours`
- `--days`
- `-Z`, `--view-center-az`
- `-A`, `--view-center-alt`
- `--content-fov-deg`
- `--observer-height-m`
- `--cloud-opacity`
- `--sky-opacity`
- `--terrain-horizon-opacity`
- `--urban-outline-opacity`
- `-r`, `--urban-outline-radius-km`
- `--urban-outline-skyscraper-radius-km`
  - 遠距離スカイスクレーパー補助レイヤーの外側半径を指定する。
  - `0` を指定した場合は、そのセッションでは skyscraper tile 探索を行わない。
  - `0` 以外の値は `--urban-outline-radius-km` 以上でなければならない。
  - 既定値は `60km`。
- `-b`, `--urban-outline-min-building-height-m`
- `--urban-outline-feature-type`
  - 都市アウトライン取得・キャッシュに使う Overture mode。
  - `both` または `building` を受け付ける。
  - 既定値は `both`。
  - `both` では `building` と `building_part` の両方を取得・利用する。
- `--urban-outline-skyscraper-only`
  - 確認用オプションとして、通常の近距離都市アウトラインを描かず、遠距離スカイスクレーパー補助レイヤーだけを表示する。
- `--clear-long-lived-cache`
  - 起動前に、長寿命キャッシュである `DEM` と都市アウトライン由来キャッシュを明示的に削除する。
  - 対象は `copernicus-dem`、`overture_buildings`、`overture_skyscrapers` とする。
  - このオプションはトラブルシュート用途であり、通常起動で常用しないことを前提とする。
  - 最後にこのオプションを実行してから `3日` 未満の場合は、再実行を拒否してよい。
  - 再実行拒否時は、通常ログだけでなく splash 上にも理由を表示し、そのまま終了してよい。
  - 利用者には、`zstarview-export-image --print-cache-dir` で cache root を確認し、その配下の `copernicus-dem`、`overture_buildings`、`overture_skyscrapers` を手動削除する方法を案内してよい。
- `--ground-tint-opacity`
- `-t`, `--theme`

詳細なオプション一覧は README を正本とし、本書では動作仕様を補足する。

#### 5.1.0 描画視野オプション

- `--content-fov-deg FLOAT`
  - 視野中心から `FLOAT` 度以内を、全レイヤー共通の描画対象として扱う。
  - このオプションは投影スケール自体を変えない。
  - ウィンドウ端は常に「視野中心から `90°` の位置」に対応する。
  - `FLOAT > 90` の場合、`90°` を超える要素はウィンドウ外へはみ出して描画されてよい。
  - これにより、ウィンドウ四隅の表示欠落領域を減らしてよい。
  - 対象レイヤーは、恒星、太陽、月、惑星、DSO、アステリズム、背景グラデーション、sky color disc、雲、航空機、地形地平線、都市アウトライン、地平線、天の赤道、黄道、方位線、ラベル候補を含む。
  - 既定値は `100` とする。
  - 許容範囲は `90 <= FLOAT <= 127` とする。
  - 暗い恒星だけを旧来の `90°` 背景境界で追加的に間引く特別扱いは行わない。
  - 背景は `FLOAT` まで連続的に伸ばし、その外側にはウィンドウ背景となじませるための短いフェード帯を置いてよい。

#### 5.1.1 地名・駅名検索オプション

- `--place QUERY`
  - OpenStreetMap Nominatim を使って地名、駅名、施設名などの自由入力文字列を検索し、その検索結果から観測地点を決める。
  - 位置引数 `location` とは相互排他とする。
  - 対話選択は行わず、正規化後の先頭候補を採用して通常起動する。
- `--place-countrycode CODE`
  - Nominatim の `countrycodes` パラメータとして検索対象国を ISO 3166-1 alpha-2 で制限する。
  - `--place` 指定時のみ意味を持つ。
- `--place-lang LANG`
  - Nominatim への `Accept-Language` として送る。
  - 既定値は `en` とする。
  - `--place` 指定時のみ意味を持つ。
- `--timezone TZ`
  - 地点から自動解決したタイムゾーンを上書きする。
  - `TZ` には IANA タイムゾーン名、UTC オフセット、またはサポート対象の略称を受け付けてよい。
  - 指定時は `location` / `--place` / coordinate URL の種類にかかわらず最優先で適用する。

`--place` 系オプションは、既存の `location` による offline-first 解決とは別経路で扱う。
`--place` が指定されていない通常起動では、GeoNames、viewpoint dataset、緯度経度解析による既存の地点解決規則を維持する。

### 5.1.2 ビューポイント dataset 一覧・詳細出力オプション

CLI には次のビューポイント dataset 参照専用オプションを持つ。

- `--list-viewpoints KIND`
  - `KIND` は `t` または `m` とする。
  - `t` は同梱タワー dataset、`m` は同梱 mountain viewpoint dataset の主表示名を 1 行 1 件で標準出力へ出し、終了する。
  - 各行は `t/NAME` または `m/NAME` 形式で出力する。
  - ASCII フォールバック名を算出できる項目では、`name` ではなくその ASCII フォールバック名を表示する。
- `--list-viewpoint-names KIND`
  - `KIND` は `t` または `m` とする。
  - `name`、`names`、`labels`、ASCII フォールバック名に含まれる名前を重複除去して 1 行 1 件で標準出力へ出し、終了する。
  - 各行は `t/NAME` または `m/NAME` 形式で出力する。
- `--show-viewpoint-json NAME`
  - `NAME` に `t/` または `m/` の prefix がある場合は、その kind だけを対象に 1 件解決して JSON で標準出力へ出し、終了する。
  - `NAME` に prefix がない場合は tower と mountain の両方を対象に解決を試みる。
  - prefix なしで tower と mountain の両方に exact match がある場合は、曖昧一致エラーとして終了する。
  - この場合、エラーメッセージには `t/...` / `m/...` 形式の候補名を列挙する。
  - JSON には、利用可能な場合 `ascii_name` を含める。

これらのオプションは相互排他とし、指定時は GUI を起動しない。
また、位置引数 `location` や描画・時刻調整オプションとは併用不可とする。
データは同梱 `tower_viewpoints.json` / `mountain_viewpoints.json` のみを参照し、GeoNames 読込や設定保存は行わない。
`mountain_viewpoints.json` は、Wikipedia を起点に候補収集し、Wikidata メタデータで正規化した同梱データである。

### 5.1.3 単発画像書き出し CLI

単発画像書き出し用に、GUI 常駐とは別の headless CLI を持つ。

- コマンド名は `zstarview-export-image` とする。
- この CLI は画像ファイルを 1 枚生成して終了し、GUI ウィンドウは常駐表示しない。
- 地点、時刻、視線方向、テーマ、各レイヤー opacity、`--enlarge-moon` など、通常の `zstarview` 起動引数の大半をそのまま受け付けてよい。
- 次の GUI 専用・即時終了専用オプションは受け付けない。
  - `--sky-update-interval`
  - `--window-geometry`
  - `--list-viewpoints`
  - `--list-viewpoint-names`
  - `--show-viewpoint-json`
- `--window-geometry` の代わりに、画像出力専用オプションとして次を持つ。
  - `-o`, `--output PATH`
    - 出力先ファイルパス。必須とする。
    - `PATH` に `-` を指定した場合は、PNG bytes を標準出力へ書き出してよい。
  - `--image-size WIDTH,HEIGHT`
    - 出力画像サイズ。
    - 既定値は通常 GUI の既定ウィンドウサイズと同等でよい。
  - `--layer-timeout-seconds FLOAT`
    - 雲、地形地平線、都市アウトライン、航空機などの外部依存レイヤー取得待ち時間の上限。
    - 既定値は `90` 秒とする。
    - 無限待ちは避ける。
  - `--allow-partial-data`
    - 有効なレイヤーの一部が取得失敗または timeout しても、取得できたレイヤーだけで画像を保存してよい。
    - このオプションがない既定動作では、部分データの画像は保存せず非 `0` で終了する。
  - `--sixel`
    - 生成した画像を端末へ SIXEL として出力してよい。
    - `--output` と併用可能とする。
    - `--output` 併用時は、まずファイル保存を行い、その後に SIXEL 出力を試みる。
    - SIXEL 変換は、一時ファイルではなく、生成済み画像を PNG bytes 化して `img2sixel -` の標準入力へ流す方式を前提としてよい。
    - `--sixel` 指定時は、処理開始前に `img2sixel` コマンドの存在を確認し、見つからなければ明示的なエラーで終了する。
    - `--output -` と `--sixel` の同時指定は、標準出力の用途が衝突するため受け付けない。
- 出力形式の初版は PNG を前提としてよい。
  - 拡張子による自動判定または `--output` の拡張子制約のどちらを採るかは実装側に委ねるが、少なくとも PNG は保証する。
- 既定では hover 情報、status line、jump highlight などの動的 HUD は含めない。
- 既定では `guide` は含めてよい。
- 既定では地点名、時刻、観測者高さなどの静的 overlay 情報も含めない。
- ただし、GUI 左上に表示される静的 overlay 情報のうち、地点名、地点高さ表示、観測者高さ、時刻、Alt/Az、`Vmag limit` は、画像には焼き込まず `stderr` へテキストで出力してよい。
  - 通常のファイル保存または PNG 標準出力では、レンダリング完了後に `stderr` へ出力する。
  - `--sixel` 指定時は、端末画像の直前に `stderr` へ出力する。
- `--content-fov-deg` の外側に置かれる GUI 向け背景グラデーションは export 画像には含めず、透明のままにしてよい。
- 雲レイヤーの見え方と部分欠損の扱いは、可能な限り通常 GUI の表示経路と一致させてよい。
- `--aircraft-opacity 0`、`--cloud-opacity 0`、`--terrain-horizon-opacity 0`、`--urban-outline-opacity 0` のときは、それぞれのレイヤー取得自体を省略してよい。
- `opacity 0` により取得自体を省略したレイヤーは、`--layer-timeout-seconds` の待機対象にも含めない。
- 既定では、要求された有効レイヤーがすべて揃った場合だけ画像保存成功とする。
- `--allow-partial-data` 指定時は、欠落レイヤーがあっても保存成功としてよい。
- `--sixel` 指定時に端末出力が失敗しても、`--output` によるファイル保存が成功していれば、警告を出して成功終了としてよい。
- `--sixel` のみ指定で端末出力に失敗した場合は、非 `0` で終了する。
- 正常終了時は `0`、引数不正、地点解決失敗、画像保存失敗、部分データ拒否条件違反時は非 `0` で終了する。

### 5.2 地点指定

`location` には次の形式を許容する。

- 都市名
  - 例: `Tokyo`
- 国コード付き都市名
  - 例: `JP/Tokyo`
- GeoNames ID
  - 数値のみ
- タワー名
  - 例: `Tokyo Skytree`
- 明示タワー名
  - 例: `t/Tokyo Skytree`
- 山名
  - 例: `Mount Fuji`
- 明示山名
  - 例: `m/Mount Fuji`
- Wikidata ID
  - 例: `wikidata:Q57965`
- 緯度経度
  - 例: `35.68;139.76`
  - 例: `N35.68;E139.76`
  - 例: `@35.68,139.76`
  - 例: `https://www.google.com/maps/@35.68,139.76,17z`
  - 例: `maps.google.com/maps/@35.68,139.76`
  - 例: `https://www.google.com/maps/place/...!3d35.68!4d139.76...`

地点が省略された場合は、前回起動時の地点を使用する。初回起動時の既定地点は `Tokyo` である。
ただし、`--place` 指定時は位置引数 `location` を受け付けない。

### 5.3 地点解決の挙動

- 都市名は GeoNames データに基づいて解決する。
- 都市候補が複数ある場合は、優先規則に従って 1 件を選ぶ。
- `--place QUERY` 指定時は Nominatim に対して free-form 検索を行う。
- `--place` に対する Nominatim 候補は `importance` 降順で正規化し、先頭候補を採用する。
- `--place` で複数候補が得られた場合は、採用した先頭候補を含め、候補一覧をターミナルへ出力してよい。
- `--place` の候補選択に対して起動時の対話入力は行わない。
- `--place` で採用した地点の GUI 表示名には、Nominatim が返す長い `display_name` を短縮せずそのまま使ってよい。
- `t/NAME` は tower viewpoint としてのみ解決する。
- `m/NAME` は mountain viewpoint としてのみ解決する。
- タワー名は内蔵の viewpoint データセットから解決する。
- 山名も内蔵の mountain viewpoint データセットから解決する。
- タワー名解決では、主表示名や別名に加えて ASCII フォールバック名も受け付ける。
- 山名解決でも、主表示名や別名に加えて ASCII フォールバック名も受け付ける。
- mountain viewpoint データセットは、Wikipedia 起点の候補選定と Wikidata メタデータ正規化に基づく。
- 直接座標入力として `lat;lon`、`@lat,lon`、および現在広く観測される Google Maps 共有 URL を受け付けてよい。
- Google Maps URL は、`maps.google.com/` または `www.google.com/maps/` で始まるものだけを受け付けてよい。各形式では先頭の `https://` を省略可とする。
- Google Maps URL に `!3dLAT!4dLON` が含まれる場合はその座標を優先して使う。これがない場合に限り、`@LAT,LON` を使ってよい。
- Google Maps URL では、採用した座標以外の zoom、高度、heading、pitch、query parameter、fragment などは地点解決に使わない。
- `@lat,lon` および Google Maps URL 内の `lat,lon` は、`lat;lon` と同様に緯度 `[-90, 90]`、経度 `[-180, 180]` の範囲チェックを行う。
- 緯度経度入力時は都市名文字列としての解釈を行わない。
- 解決された地点は次回起動用設定として保存する。
- `--place` で解決した地点は、次回起動時に再検索しないよう、採用済み候補の結果オブジェクトを設定へ保存してよい。
- この保存形式は、従来の文字列ベース地点保存とは異なる構造化オブジェクトであってよい。
- 構造化オブジェクトには、少なくとも「Nominatim 由来であることを判別できる情報」と「採用した候補の正規化済み JSON」を含める。
- `--place` で解決した地点のタイムゾーンは、tower / mountain と同様に最近傍の GeoNames 都市から補完してよい。
- `lat;lon`、`@lat,lon`、Google Maps URL から解決した地点のタイムゾーンも、`--place` と同じ規則で最近傍の GeoNames 都市から補完してよい。
- 地点からタイムゾーンを補完できない場合は UTC を用いる。

### 5.3.1 `--place` の失敗時挙動

- Nominatim 検索が 0 件だった場合は起動を中断する。
- HTTP エラー、レート制限、通信エラー、JSON 解析失敗、想定外レスポンスも起動を中断する。
- これらの失敗理由は、ターミナルとスプラッシュスクリーンの両方に表示してよい。
- 失敗メッセージには、少なくとも検索文字列と失敗理由を含める。
- `--place` を使わない通常起動時の地点解決失敗も、従来通りターミナルとスプラッシュスクリーンに表示してよい。

### 5.4 観測者高さ

- `--observer-height-m` は地面からの観測者高さをメートルで指定する。
- この値は、観測地点そのものの標高や構造物高ではなく、観測地点の足元から観測者の目線までの高さを表す。
- 既定値は入力種別にかかわらず `1.7m` とする。
- ユーザー指定値がある場合は、この既定の `1.7m` を置き換える。
- 都市名または緯度経度入力時は、観測点はその地点の地表とし、実効観測点は「地表 + 観測者高さ」とする。
- Google Maps URL に高度らしき数値が含まれていても、それは観測者高さとして使わない。
- 山名入力時は、観測点は mountain viewpoint dataset に登録された山頂ビューポイントとし、実効観測点は「山頂ビューポイント + 観測者高さ」とする。
- タワー名入力時は、観測点は tower viewpoint dataset に登録されたタワーのビューポイント高とし、実効観測点は「タワービューポイント高 + 観測者高さ」とする。

### 5.5 地点種別ごとの高さ情報

- 山ビューポイントでは、利用者向け表示として山頂の海抜標高を示してよい。
- この表示ラベルは `Elevation` を用い、観測者高さとは別概念として扱う。
- タワービューポイントでは、利用者向け表示として地表からのタワー高またはビューポイント高を示してよい。
- この表示ラベルは `Tower height` を用い、観測者高さとは別概念として扱う。
- 都市名または緯度経度入力では、既定の `1.7m` は情報価値が低いため、通常表示では観測者高さを省略してよい。
- 山やタワーの情報表示において、`Height` だけの曖昧なラベルは使わず、海抜標高は `Elevation`、構造物高は `Tower height` と明示する。

## 6. 時刻仕様

### 6.1 時刻モード

本アプリケーションは次の時刻モードを持つ。

- 実時間表示
  - 現在時刻を基準に表示する
- 相対時間シフト表示
  - `--hours` または `--days` によるオフセットを適用する
- 絶対日時表示
  - `--datetime` により日時を明示指定する

### 6.2 タイムゾーン

- 都市名、タワー名、山名から起動した場合は、その地点のタイムゾーンを用いる。
- `lat;lon`、`@lat,lon`、Google Maps URL から起動した場合も、地点座標から解決したタイムゾーンを用いる。
- `--timezone` が指定された場合は、地点種別にかかわらずそれを最優先で用いる。
- 地点からタイムゾーンを解決できない場合のみ UTC を基準とする。
- `--datetime` ではタイムゾーン略称、IANA タイムゾーン名、UTC オフセット形式を受け付ける。

### 6.3 時刻モードと補助レイヤーの関係

- 雲オーバーレイと航空機オーバーレイは、現在時刻近傍の観測実データに依存する補助レイヤーとして扱う。
- 人工衛星レイヤーは、軌道要素からのローカル計算で位置を再現できる補助レイヤーとして扱う。
- 地形地平線と都市アウトラインは地点依存レイヤーであり、時刻シフトの有無だけでは無効化しない。
- 実時間表示では、雲、航空機、人工衛星を表示してよい。
- 過去時刻表示では、雲と航空機は無効化し、人工衛星は表示してよい。
- 未来時刻表示では、雲、航空機、人工衛星をすべて無効化する。
- 恒星、太陽、月、惑星、DSO、アステリズム、sky color disc、ガイド線、地形地平線、都市アウトラインは、過去・現在・未来のいずれでも通常どおり表示してよい。

## 7. 表示仕様

### 7.1 表示対象

画面上には次を表示する。

- 恒星
- 太陽
- 月
- 惑星
- 地平線
- 天の赤道
- 黄道
- DSO
- アステリズム
- 航空機オーバーレイ
- 雲オーバーレイ
- 地形地平線
- 都市アウトライン
- ステータス表示、地点表示、時刻表示
- 山ビューポイントでは地点表示の補足情報として `Elevation` を表示してよい。
- タワービューポイントでは地点表示の補足情報として `Tower height` を表示してよい。
- `--observer-height-m` による観測者高さは、通常の地点表示では省略してよい。
- `--observer-height-m` が CLI で明示指定された場合は、地点種別にかかわらず地点表示の補足情報として `Observer height` を追加表示してよい。
- 山ビューポイントで `--observer-height-m` が指定された場合は、`Elevation` と `Observer height` を別行で併記してよい。
- タワービューポイントで `--observer-height-m` が指定された場合は、`Tower height` と `Observer height` を別行で併記してよい。

### 7.2 ビューの考え方

- 表示は円形の sky disc を基本とする。
- 視線中心は方位と高度で指定する。
- 高度は天頂方向が `90`、地平線方向が `0` である。
- 方位は度数または方位記号により解釈する。
- 投影スケール上、ウィンドウ端は常に視野中心から `90°` の位置に対応する。
- `--content-fov-deg` は投影スケール変更ではなく、描画対象として保持する角距離上限を制御する。
- `--content-fov-deg > 90` の場合、`90°` を超える要素はウィンドウ外へはみ出して描画されてよい。
- その結果、四隅付近の「何も表示されない領域」は減少してよい。
- `--content-fov-deg` は全レイヤー共通で適用し、特定レイヤーだけが狭い視野のまま残らないこと。
- 背景グラデーション、sky disc、雲合成、地面ティントも同じ `--content-fov-deg` に追従すること。
- 横長ウィンドウかつ低仰角のレイアウトでも、sky disc と雲レイヤーは `radius*2` の固定正方形ではなく実ウィンドウ形状に追従して overscan を表現すること。
- `--content-fov-deg` 外側には、表示の打ち切りを急に見せないための短いフェード帯を置いてよい。

### 7.3 星と天体の見え方

- 恒星は等級に応じて明るさとサイズを変えて表示する。
- 色のある恒星は色指数を反映した見た目を持つ。
- 月は位相を反映して表示する。
- `Enlarge Moon` が有効なときは、月を通常時の見た目半径に対して `5x` で表示してよい。
- 惑星は恒星とは異なるスタイルで識別しやすく描画する。
- 太陽、月、惑星は恒星とは別レイヤーの重要天体として扱う。
- 恒星は明るさにかかわらず、`--content-fov-deg` 以内であれば描画してよい。
- 同梱の分割星カタログは `stars_base` が `vmag <= 6`、`stars_extra7/8/9/10` がそれぞれ `6-7/7-8/8-9/9-10`、`stars_extra_faint` が `10 < vmag <= 10.5` を保持する。
- そのため、同梱データをそのまま使う標準配布では、CLI の `-V` / `--vmag-limit` は `10.5` を超える指定を受けても `10.5` に丸めてよい。
- 旧来の「暗い星だけ背景境界外で描かない」ような特別扱いは行わない。
- 視線変更またはウィンドウリサイズの直後は、短時間の簡易描画モードに入り、`vmag <= 4.0` の明るい星のみを即時再投影して表示する。

### 7.4 地平線と地面表示

- 地平線上と地平線下が視覚的に区別されること。
- 地平線下の領域には地面色のティントを適用する。
- 地形地平線が有効な場合、地面/空の境界には地形地平線を用いる。
- 地形地平線が無効な場合、幾何学的地平線を用いる。
- 視線変更またはウィンドウリサイズ直後の簡易描画モードでも、天の赤道、黄道、地平線、地形地平線、方位ラベル、天頂マーカーは即時に追随表示する。

### 7.5 DSO 表示

- 対象 DSO は名称付きの主要天体に限定する。
- DSO は恒星とは異なる柔らかい強調表示で描画する。
- DSO の表示有無は GUI から切り替えられる。

### 7.6 アステリズム表示

- IAU 星座境界ではなく、一般的な線パターンとしてのアステリズムを表示する。
- 通常時は淡い補助線として表示する。
- 線分は、少なくとも片端がアステリズム表示境界内にある場合に表示し、境界外へはみ出す部分は描画しない。
- 構成恒星へホバーしたときは、そのアステリズムを強調表示する。
- 同じ恒星が複数のアステリズムに属する場合は、一定間隔で表示対象を切り替える。
- 表示有無は GUI から切り替えられる。

### 7.7 雲オーバーレイ

- 利用可能な衛星データに基づく雲表示を重畳する。
- 雲は観望の補助情報として扱う。
- 雲表示は透明度を調整できる。
- 雲レイヤーの可視範囲とハッチ描画範囲も `--content-fov-deg` に追従すること。
- 雲投影の可視下限は幾何学的地平線ちょうどではなく、既定で `alt >= 3.0°` としてよい。
- これにより、地平線ぎりぎりの遠距離雲を抑え、観測補助として意味の薄い領域の取得・表示を減らしてよい。
- データ欠損領域は、通常領域と区別できるよう薄いティントで示す。
- 雲取得中、失敗時、部分欠損時には状態が利用者に分かるよう表示する。
- 視線変更またはリサイズにより現在の雲画像が新しい視線条件と一致しなくなった場合、古い視線条件の雲画像をそのまま表示し続けてはならない。
- 視線変更中の簡易表示では、雲を一時的に非表示としてよい。停止後に新しい視線条件で再生成された雲画像へ切り替えること。

### 7.8 地形地平線

- DEM から推定した地形地平線を補助線として表示できる。
- 地形地平線は地点依存であり、時刻依存ではない。
- 表示は透明度で制御する。
- `opacity == 0` の場合、DEM 取得、計算、描画をすべて行わない。
- CLI で `0` を指定して起動した場合、そのセッションでは GUI から再有効化できない。
- DEM タイルはローカルキャッシュとして保持してよく、保存期限の既定値は `90日` とする。
- DEM タイルのキャッシュが保存期限を超えている場合、次回そのタイルが必要になった時点で再取得を試みてよい。
- DEM タイルの再取得に失敗した場合は、期限切れ後であっても既存キャッシュを警告付きでフォールバック利用してよい。
- DEM タイルの保存期限は削除期限ではなく再取得を試みる目安であり、一度取得済みのタイルはオフライン時でも継続利用できてよい。

### 7.9 都市アウトライン

- 都市アウトラインは、観測地点周辺の Overture `building` / `building_part` data から生成した建物上端の輪郭を白線で表示する。
- 既定 mode `both` では、`building` と `building_part` を併用する。
- `building_part` が親 `building` を参照している場合、その親 `building` の外形より `building_part` の輪郭を優先して表示する。
- `building_part` が存在しない建物については、`building` の輪郭をそのまま表示してよい。
- 都市アウトラインは、通常レイヤーと遠距離スカイスクレーパー補助レイヤーの合成結果として表示してよい。
- 通常レイヤーは、観測地点 `lat/lon` を中心とする半径 `2.5km` の範囲を既定対象とする。
- 遠距離スカイスクレーパー補助レイヤーは、既定では観測地点から `2.5km` を超え `60km` 以下の範囲を対象とし、`150m` 以上の高層 `building` のみを扱う。
- 遠距離スカイスクレーパー補助レイヤーは、アプリ同梱の seed tile list を参照して必要 tile だけを選び、必要時に `overturemaps download --bbox=...` で取得してよい。
- 遠距離スカイスクレーパー補助レイヤーは通常レイヤーと同じ更新タイミングで取得・反映してよい。
- 遠距離スカイスクレーパー補助レイヤーの取得に失敗しても、通常レイヤーの表示は継続してよい。
- 表示は透明度で制御する。既定値は `0.2` である。
- CLI で指定した都市アウトライン不透明度は、高さ `50m` 以上の建物に対する基準値として扱う。
- 建物高さ `0m` の場合は基準不透明度の `1/4`、`0m` から `50m` の間は線形補間で不透明度を下げてよい。
- `opacity > 0` の場合、起動時にバックグラウンドで都市アウトライン取得またはキャッシュ読込を開始し、完了後に表示してよい。
- 取得結果は、地点、半径、最小建物高さ、mode をキーとするローカルキャッシュとして保持してよい。
- `both` では `building` 用と `building_part` 用のキャッシュを別々に保持してよい。
- 遠距離スカイスクレーパー補助レイヤーは、通常レイヤーとは別 root の tile 単位キャッシュとして保持してよい。
- Overture 建物由来の derived dataset / tile cache の保存期限の既定値は `30日` とする。
- Overture 建物キャッシュが保存期限を超えている場合、次回その dataset / tile が必要になった時点で再取得を試みてよい。
- Overture 建物キャッシュの再取得に失敗した場合は、期限切れ後であっても既存キャッシュを警告付きでフォールバック利用してよい。
- Overture 建物キャッシュの保存期限は削除期限ではなく再取得を試みる目安であり、一度取得済みの dataset / tile はオフライン時でも継続利用できてよい。
- `overturemaps` CLI が利用できない場合、または取得に失敗した場合、そのセッションでは都市アウトラインを表示しなくてよい。
- `-r`, `--urban-outline-radius-km` で取得半径を変更してよい。
- `--urban-outline-skyscraper-radius-km` で遠距離スカイスクレーパー補助レイヤーの外側半径を変更してよい。
- `--urban-outline-skyscraper-radius-km 0` を指定した場合、そのセッションでは skyscraper tile 探索と遠距離スカイスクレーパー補助レイヤー解決をスキップしてよい。
- `--urban-outline-skyscraper-radius-km` の `0` 以外の値は `--urban-outline-radius-km` 以上でなければならない。
- `-b`, `--urban-outline-min-building-height-m` で取得対象の最小建物高さを変更してよい。
- `--urban-outline-feature-type` で取得対象 mode を切り替えてよい。既定値は `both` とする。
- `--urban-outline-feature-type building` を指定した場合は `building_part` を取得せず、`building` のみで都市アウトラインを構成してよい。
- `--urban-outline-skyscraper-only` を指定した場合は、通常近距離レイヤーを描かず、遠距離スカイスクレーパー補助レイヤーだけを描画してよい。
- 取得中、キャッシュ読込中、失敗時には状態が利用者に分かるよう表示する。
- `opacity == 0` を CLI で指定して起動した場合、そのセッションでは GUI から再有効化できない。
- 都市アウトライン描画時には、キャッシュ済み derived tile に保持されている建物を runtime 側で追加の高さ再フィルタなしに利用してよい。
- 遠距離スカイスクレーパー補助レイヤーでは、runtime 側で「通常レイヤー半径より外側かつ `60km` 以下」を満たす建物だけを採用してよい。
- 遠距離スカイスクレーパー補助レイヤーでは、cache 取得時の `150m` 下限は固定のままとし、`-b`, `--urban-outline-min-building-height-m` が `150m` を超える場合に限り runtime 描画時の追加高さフィルタとして使ってよい。
- runtime の都市アウトライン内部表現は、各輪郭ごとに `height_m` を保持する前提でよい。
- 見かけの方位幅が `0.5°` 未満の細い屋根線分は、細かい輪郭ではなく、太い水平線として簡略表示する。

### 7.10 航空機オーバーレイ

- 航空機オーバーレイは、観測地点周辺の民間航空機を「空に動きがある補助表示」として重畳してよい。
- 航空機オーバーレイは、航空管制用途の厳密表示ではなく、視覚的な位置関係の把握を目的とする。
- 航空機オーバーレイは現在時刻近傍の実データ表示のみを対象とし、過去時刻および未来時刻では無効化してよい。
- 表示対象データは OpenSky Network の `states/all` を前提としてよい。
- 取得要求には観測地点由来の `bbox` を必ず付与し、広域全件取得は行わない。
- `bbox` は観測地点の緯度経度を中心に決め、現在の視線方向ではなく観測地点を基準に選定する。
- `bbox` の大きさは、観測地点周辺を安定してカバーしつつ無料枠を超えにくい範囲に抑えること。
- 航空機データ取得の既定更新間隔は `5分` とする。
- `5分` の更新間隔は、無料枠での継続利用と一時的な取得失敗吸収を優先した設定として扱う。
- CLI には航空機レイヤー不透明度 `--aircraft-opacity` を持たせてよい。
- `--aircraft-opacity` には短縮形 `-a` を割り当ててよい。
- `--aircraft-opacity 0.0` のときは、航空機データ取得を起動時から行わない。
- `--aircraft-opacity` が `0.0` より大きいときだけ、GUI メニューから航空機レイヤーを表示・非表示トグルしてよい。
- GUI からの航空機レイヤートグルには `I` ショートカットを割り当ててよい。
- 観測地点由来 `bbox` の既定範囲は、南北方向では中心から `±1.0°` とする。
- 東西方向の `bbox` は緯度に応じて調整し、少なくとも約 `90km` の east-west coverage を確保してよい。
- ただし bbox 面積は OpenSky `/states/all` の `1 credit` 帯を超えないよう `25 square degrees` 以下へクリップしてよい。
- 航空機データは OpenSky の単一取得元を前提に、観測地点由来 `bbox` ごとの短寿命永続キャッシュを持ってよい。
- 永続キャッシュは GOES/Himawari のような時刻別ディレクトリ列ではなく、航空機専用 root 配下に `bbox` 単位の少数ファイルを保持する方式でよい。
- `bbox` が同じなら、観測地点の `lat/lon` が完全一致しなくても同じ航空機キャッシュを再利用してよい。
- fresh cache が存在し、取得時刻から一定時間以内であれば、OpenSky API を再問い合わせせずそのキャッシュを使ってよい。
- fresh cache の TTL は、短時間の連続起動で API 回数を抑えつつ位置ずれを増やしすぎない値にすること。現在の実装では既存の航空機更新間隔と同じ `5分` を使ってよい。
- fresh TTL を超えた場合は再取得を試みてよい。
- 再取得に失敗した場合は、同じ `bbox` の stale cache を一定時間まで警告付きで再利用してよい。
- stale fallback の上限は、表示の近似性を損ねすぎない範囲に抑えること。初期案では `10分` 程度を想定してよい。
- 観測地点由来 `bbox` が変わった場合は、別キャッシュとして扱ってよい。
- `zstarview-export-image` を短時間に連続実行する場合でも、fresh cache がある間は OpenSky API の再問い合わせを省略してよい。
- 更新間隔が粗いため、表示位置はリアルタイムの厳密位置ではなく近似表示であることを前提にしてよい。
- 各航空機は少なくとも `icao24`、`callsign`、`latitude`、`longitude`、`baro_altitude`、`velocity`、`heading`、`vertical_rate`、`on_ground`、`last_contact` を保持してよい。
- runtime の航空機状態は、少なくとも緯度、経度、高度、速度、進行方位、上昇下降率、最終更新時刻を持つ前提でよい。
- API 応答更新の間は、最後に取得したスナップショットから短時間の前進予測を行い、予想位置へ表示を動かしてよい。
- 予想位置の再投影は `2秒` ごとに更新してよい。
- `latitude` または `longitude` が欠損している機体は表示しない。
- `on_ground == true` の機体は表示しない。
- `velocity` が低すぎる機体は、離着陸直後や地上機の混入を避けるため表示しなくてよい。
- 機体位置は、予想した緯度経度高度を既存の天球変換と同じ経路で高度・方位へ変換してよい。
- 地平線上かつ視野内に入る機体だけを描画してよい。
- 表示は `4秒前 -> 現在 -> 4秒後` を `2秒` 刻みでたどる細いオレンジの折れ線を基本とする。
- 折れ線と `callsign` ラベルの描画 alpha には、航空機レイヤー不透明度を乗算してよい。
- 線幅は観測地点に近い機体ほど太く、遠い機体ほど細くしてよい。ただし上限を設けてよい。
- 表示対象は観測地点から `50km` 以内の機体に限定してよい。
- `callsign` は観測地点から `10km` 以内の近距離機体にだけ表示してよい。
- 取得時刻から `90秒` を超えた機体は、予想位置の不確かさが増すものとして徐々に薄くしてよい。
- `90秒` から次回更新時刻までの退色は段階的なグラデーションで表現してよい。
- GUI で航空機レイヤーを一時的に非表示にしても、保持済みの最新スナップショットと取得時刻は捨てなくてよい。
- 航空機レイヤーを再表示するときは、保持済みデータが `5分` 未満なら API を再問い合わせせず、そのスナップショットを再投影してよい。
- 保持済みデータが `5分` を超えて古い場合にだけ、再表示時の即時再取得を行ってよい。
- 取得失敗時は直前に保持していた航空機状態を一定時間まで再利用してよい。
- 航空機データ取得に失敗しても、星空表示や他の補助表示は継続する。
- 取得中、取得失敗時、データが空だった場合には、状態が利用者に分かるよう表示してよい。
- `--aircraft-opacity 0.0` のセッションでは、航空機 API 問い合わせと航空機キャッシュ読込のどちらも省略してよい。

### 7.11 人工衛星レイヤー

- 人工衛星レイヤーは、観測地点から見える人工衛星を「空にある人工物の補助表示」として重畳してよい。
- 人工衛星レイヤーは、追尾用途の厳密表示ではなく、視覚的な位置関係の把握を目的とする。
- 人工衛星レイヤーは現在時刻だけで表示してよく、過去時刻と未来時刻では無効化してよい。
- 現在の表示対象は `ISS` のみとしてよい。
- 初期実装の GUI では人工衛星レイヤー全体をまとめて表示・非表示してよく、個別 sublayer toggle は必須としない。
- 人工衛星の軌道計算には Skyfield の `EarthSatellite` を使ってよい。
- 人工衛星の軌道要素は、外部ソースから取得した TLE または OMM 相当データをローカルキャッシュしてよい。
- current 用の人工衛星 cache には、少なくとも `element_epoch_utc`、`fetched_at_utc`、データ取得元、直近取得試行時刻、直近失敗有無、失敗理由、次回再試行可能時刻を保持してよい。
- 人工衛星データの主取得先は `wheretheiss.at` としてよく、ISS 用 TLE を取得できなかった場合だけ `CelesTrak stations` を fallback として試してよい。
- current 用の軌道要素 cache の fresh 判定は `element_epoch_utc` 基準としてよい。現在の実装では `ISS` に `24時間` を使ってよい。
- current 用の軌道要素 cache が fresh 範囲を超えて古い場合は、起動時または次回更新時に再取得を試みてよい。
- 直近の取得失敗で `failure_backoff_until_utc` が未来の場合は、アプリ再起動後であっても再取得を抑止してよい。
- タイムシフト表示では人工衛星データの取得も表示も行わなくてよい。
- 再取得に失敗した場合は、失敗状態を表示しつつ `2時間` の backoff を設定してよい。
- stale cache が残っている場合は、その backoff 期間中に stale cache を使って表示継続してよい。
- 表示位置の再計算はネットワーク取得とは分離し、保持済み軌道要素からローカル計算してよい。
- 表示位置の再計算更新間隔は `2秒` に統一してよい。
- 人工衛星と航空機は、表示上の動きがずれないよう同じ描画再投影 tick で更新してよい。
- 視野内に入る人工衛星は、地平線下であっても描画してよい。
- 人工衛星は、航空機と同系統の紫色で、惑星マーカーに似た小型クロス記号として描画してよい。
- 人工衛星マーカーは、惑星や月のクロス記号より一段小さくしてよい。
- `ISS` にはラベルを付けてよい。
- 人工衛星は、描画順として惑星・月より後、航空機より前に置いてよい。
- この描画順は、「人工衛星は惑星や月より近く、航空機よりは遠い」という視覚的な層順を優先したものとして扱ってよい。
- 人工衛星が惑星や月の近くを通過して一時的に重なることはありうるが、長時間同じ天体に重なり続ける前提ではなくてよい。
- 初期実装では、人工衛星が月や惑星に近接した場合でも特別な隠蔽処理や減光処理を必須としなくてよい。
- 人工衛星レイヤーを一時的に非表示にしても、保持済み軌道要素と最終更新時刻は捨てなくてよい。
- 軌道要素がまだ fresh な間は、人工衛星レイヤー再表示時に外部データを再取得せず、そのまま位置再計算だけで即時復帰してよい。
- 軌道要素が stale な場合は、レイヤー再表示時にも再取得を優先してよい。ただし失敗 backoff 中は stale cache を優先してよい。
- 軌道要素取得に失敗しても、既存の星空表示、惑星表示、航空機表示など他のレイヤーは継続してよい。
- 取得中、取得失敗時、データが空だった場合には、状態が利用者に分かるよう表示してよい。

## 8. GUI 操作仕様

### 8.1 基本操作

- 矢印キーで表示方向を変更できる。
- 矢印キーによる連続操作中は、最後の入力から約 0.7 秒間、明るい星とガイドライン中心の簡易描画モードを維持する。
- `M` で月の拡大表示を切り替える。
- `D` で DSO 表示を切り替える。
- `A` でアステリズム表示を切り替える。
- `S` で sky color disc 表示を切り替える。
- `C` で雲表示を切り替える。
- `T` で地形地平線表示を切り替える。
- `U` で都市アウトライン表示を切り替える。
- `F11` で fullscreen を切り替える。
- `Q` で終了する。

### 8.2 メニュー操作

ハンバーガーメニューから次を実行できる。

- 代表恒星ジャンプ
- 星とアステリズムの検索
- place 検索
- 各種表示トグル
- fullscreen
- 終了

### 8.2.1 GUI place 検索

- GUI は恒星・アステリズム検索とは別に、Nominatim を使った place 検索ダイアログを提供してよい。
- place 検索は GUI 内機能としてのみ提供し、CLI オプションは追加しない。
- place 検索は専用ダイアログで自由文字列クエリを受け付け、利用者が明示的に検索を実行したときだけ Nominatim の候補一覧を取得してよい。
- place 検索のメニュー項目にはキーボードショートカットを必須としない。
- 候補が複数ある場合は、利用者が候補を選べる一覧を表示してよい。
- 候補一覧には少なくとも place 名を含め、必要に応じて種別や長い表示名を併記してよい。
- 選択した place は、その緯度経度を現在の観測地点から見た方位角・仰角へ変換して扱う。
- place を選択した場合は、恒星検索と同様に、その対象方向へ視界中心を移してよい。
- place のハイライト表示には、恒星検索と同じ通常の白丸マーカーを使ってよい。
- place の仰角が `0°` 付近または `0°未満` であっても、特別な記号や別モードに切り替えず、通常どおり対象方向へ向けて白丸で示してよい。
- place の検索結果は固定地表点として扱い、時間変化で位置更新される対象としては扱わない。
- place のラベルには候補の表示名を使ってよい。
- place 検索の失敗、候補なし、通信失敗、レート制限時は、検索 UI 内またはステータス表示で簡潔に通知してよい。
- 初期仕様では、地形遮蔽、建物遮蔽、地球曲率による可視・不可視の UI 分岐は行わなくてよい。
- 初期仕様では、選択した place の保存、履歴、再検索最適化は必須としない。

### 8.3 ホバーとハイライト

- 恒星ホバー時は名称などの情報を表示する。
- DSO ホバーは恒星ホバーと独立して扱う。
- 月をホバーしたときは、通常の月描画を残したまま、拡大表示を後段で上書きしてよい。
- DSO ホバー情報は、地形地平線や方位・天頂ガイドとは別の後段オーバーレイとして表示してよい。
- 方位ラベルと天頂マーカーは、空色・雲合成の上に見える独立ガイドとして表示してよい。
- ジャンプや検索で選択した対象は一時的にハイライトする。
- place 検索で選択した対象も、恒星検索と同じ白丸マーカーで一時的にハイライトしてよい。

### 8.4 ビューポート操作中の簡易描画

- 視線変更またはウィンドウリサイズの直後は `viewport interaction mode` に入る。
- このモードは最後の入力またはリサイズから約 0.7 秒で終了する。
- このモード中に表示するのは、`vmag <= 4.0` の恒星、天の赤道、黄道、地平線、地形地平線、方位ラベル、天頂マーカーである。
- このモード中は惑星、全星等の星空、sky color disc、雲、DSO、アステリズムは表示しない。
- このモード中は、直前の視線条件で生成された雲画像を暫定表示してはならない。
- 都市アウトラインは、このモード中は描画しない。
- 航空機オーバーレイは、このモード中は描画しなくてよい。
- モード終了後に通常の星空、sky color disc、雲、地形地平線、都市アウトラインの更新を行う。

## 9. 設定保持仕様

- 最後に使用した地点を保存する。
- ウィンドウ位置やサイズなどの GUI 状態を保存する。
- ローカル設定ファイルはユーザー環境下に保存し、リポジトリには含めない。

## 10. エラー時の利用者向け挙動

### 10.1 起動不能なエラー

- 星データや必須初期化に失敗した場合は、起動を中断する。
- 起動失敗時は原因が分かる形でログまたはメッセージを残す。

### 10.2 継続可能なエラー

- 雲取得失敗時でも星空表示は継続する。
- 地形地平線取得失敗時でも本体表示は継続する。
- 航空機データ取得失敗時でも本体表示は継続する。
- 一時的なネットワーク不調で全体が異常終了しないこと。

### 10.3 ステータス表示

- 雲の取得状態や失敗状態を利用者が確認できること。
- 地形地平線の読み込みや失敗状態を利用者が確認できること。
- 航空機データの取得状態や失敗状態を利用者が確認できること。
- ステータス表示は画面操作を妨げない補助情報として提供する。

## 11. 非機能仕様

### 11.1 応答性

- UI は操作に対して即応すること。
- 重い処理は利用者操作を長時間ブロックしないこと。

### 11.2 耐障害性

- 外部データ取得失敗が発生しても、本体表示機能はできるだけ維持すること。

### 11.3 保守性

- 利用者向け仕様、内部設計、実装履歴を別文書として維持すること。

## 12. 既知の制約

- 雲表示は外部の衛星データ供給状況に依存する。
- 航空機表示は OpenSky Network の提供状況、認証条件、利用枠に依存する。
- 航空機表示は `5分` 更新の観測値とその間の短時間予想に基づく近似表示であり、実際の飛行位置と一致しない場合がある。
- オフライン環境では雲表示は利用できない。
- 高密度な表示設定では計算量と描画負荷が増える。
- 表示精度は利用ライブラリ、元データ品質、地点解決結果に依存する。
