krz/moonrise

Night-sky companion for iPhone, Apple Watch and Vision Pro: what's up tonight, the Moon, planets, launches and missions, and a Library of the solar system. SwiftUI app with a Cloudflare Workers backend. astronomy cloudflare-workers ios night-sky space swiftui visionos watchos

Commit 98c962118c

98c962118c9453e90364859f18574e49dda11d80

parent: 97c255d2ba

Unsigned

cmc <hello@cleberg.net> · 2026-10-18 21:48 UTC

v3: Sky cultures (!36)

Settings › Display › Constellations: draw another culture's figures over the same stars instead of the IAU lines.

- Ten cultures from Stellarium's sky cultures, all CC BY-SA: Chinese (306 figures), Indian, Mongolian, Japanese moon stations, Hawaiian, Māori, Tongan, Boorong, Sámi, Norse. Credits screen lists each with its licence and source link; THIRD_PARTY.org updated.
- Not included: Arabic (all three sets CC BY-ND with permission only for Stellarium), Kamilaroi (CC BY-NC-ND), and the GPL v2 sets (Egyptian, Navajo, Korean, Inuit, Aztec).
- =scripts/make-skycultures.py= converts Hipparcos numbers to HR by position (nearest BSC star within 0.05°, Hipparcos V < 7.2 from VizieR I/239) and splits lines at stars fainter than the BSC. Chinese loses 12 of 318 figures and Indian 1 of 28 this way.
- Names are drawn at each figure's centre when the view is narrower than 110° (60° for Chinese).
- Credits: also adds CelesTrak, Mars raw images and Spaceflight News API, which were missing.
- Test: every figure uses catalogue stars, every culture is BY-SA, Norse Wolf's Mouth includes Aldebaran.

Review note: the Māori, Hawaiian and Boorong figures are Indigenous knowledge published by Stellarium with the communities' sources cited in each description.md; the app shows them with that credit.

Layout: unified · split

App/Sources/SettingsScreen.swift +22 −1
@@ -1,4 +1,5 @@
11import Library
2import SkyRenderer
23import SwiftUI
34import UserNotifications
45
@@ -13,6 +14,8 @@ enum SettingsKey {
1314 /// Whether the Sky tab is currently drawn in night mode (written by the Sky tab).
1415 static let nightActive = "nightActive"
1516 static let dailySummary = "dailySummary"
17 /// Sky culture id, or "western" for the IAU constellations.
18 static let skyCulture = "skyCulture"
1619 /// Minutes after local midnight.
1720 static let dailySummaryMinutes = "dailySummaryMinutes"
1821}
@@ -61,6 +64,7 @@ struct SettingsScreen: View {
6164 @AppStorage(SettingsKey.cityLatitude) private var cityLatitude = 41.878
6265 @AppStorage(SettingsKey.cityLongitude) private var cityLongitude = -87.630
6366 @AppStorage(SettingsKey.nightMode) private var nightMode = "auto"
67 @AppStorage(SettingsKey.skyCulture) private var skyCulture = "western"
6468 @Environment(\.dismiss) private var dismiss
6569 @State private var alerts = AuroraAlerts.shared
6670 @AppStorage(SettingsKey.dailySummary) private var dailySummary = false
@@ -117,6 +121,10 @@ struct SettingsScreen: View {
117121 Text("A note each day with the Moon, the planets up that night, the best satellite pass and any events. It is worked out on this device; nothing is sent to our server.")
118122 }
119123 Section {
124 Picker("Constellations", selection: $skyCulture) {
125 Text("Western (IAU)").tag("western")
126 ForEach(Catalog.skyCultures) { Text($0.name).tag($0.id) }
127 }
120128 Picker("Night mode", selection: $nightMode) {
121129 Text("Off").tag("off")
122130 Text("On").tag("on")
@@ -125,7 +133,7 @@ struct SettingsScreen: View {
125133 } header: {
126134 Text("Display")
127135 } footer: {
128 Text("Night mode draws the sky in red to keep your eyes adapted to the dark. After dark turns it on once the Sun is 12° below the horizon.")
136 Text("Constellations from other cultures come from Stellarium's sky cultures and are drawn over the same stars; figures with stars fainter than the app's catalogue are shortened. Night mode draws the sky in red to keep your eyes adapted to the dark. After dark turns it on once the Sun is 12° below the horizon.")
129137 }
130138 Section("About") {
131139 LabeledContent("Version", value: Bundle.main.versionString)
@@ -191,6 +199,9 @@ struct CreditsScreen: View {
191199 Credit(name: "Images of the Sun", detail: "Courtesy of NASA/SDO and the AIA, EVE, and HMI science teams."),
192200 Credit(name: "Launch schedule", detail: "The Space Devs, Launch Library 2."),
193201 Credit(name: "Deep Space Network status", detail: "NASA/JPL, DSN Now."),
202 Credit(name: "Satellite orbits", detail: "CelesTrak."),
203 Credit(name: "Mars rover raw images", detail: "NASA/JPL-Caltech, with MSSS and ASU for some cameras."),
204 Credit(name: "Space news headlines", detail: "Spaceflight News API, The Space Devs. Articles belong to their publishers."),
194205 ]
195206
196207 /// Every distinct image credit used by the Library, grouped by licence.
@@ -210,6 +221,16 @@ struct CreditsScreen: View {
210221 Section("Live data") {
211222 ForEach(feeds, id: \.self) { row($0) }
212223 }
224 Section("Sky cultures") {
225 ForEach(Catalog.skyCultures) { c in
226 Link(destination: c.source) {
227 VStack(alignment: .leading, spacing: 2) {
228 Text(c.name)
229 Text("Stellarium sky cultures. \(c.licence)").font(.footnote).foregroundStyle(.secondary)
230 }
231 }
232 }
233 }
213234 ForEach(imageCredits, id: \.licence) { group in
214235 Section("Library images: \(group.licence)") {
215236 ForEach(group.credits, id: \.self) { Text($0).font(.footnote) }
App/Sources/SkyScreen.swift +2 −1
@@ -11,6 +11,7 @@ struct SkyScreen: View {
1111 @State private var altitude = 45.0
1212 @State private var fieldOfView = 100.0
1313 @AppStorage(SettingsKey.nightMode) private var nightMode = "auto"
14 @AppStorage(SettingsKey.skyCulture) private var skyCulture = "western"
1415 @State private var showSettings = false
1516 @State private var showEvents = false
1617 @State private var showLog = false
@@ -37,7 +38,7 @@ struct SkyScreen: View {
3738 style.background.ignoresSafeArea()
3839 if let scene = model.scene {
3940 let view = current(width: geo.size.width)
40 SkyView(scene: scene, centerAzimuth: view.azimuth, centerAltitude: view.altitude, fieldOfView: view.fieldOfView, style: style) { [stats] d in
41 SkyView(scene: scene, centerAzimuth: view.azimuth, centerAltitude: view.altitude, fieldOfView: view.fieldOfView, style: style, culture: Catalog.skyCultures.first { $0.id == skyCulture }) { [stats] d in
4142 stats.record(d)
4243 }
4344 .ignoresSafeArea()
PLAN.org +3 −1
@@ -408,7 +408,9 @@ Sky, System, Sun, Launches, Library core (above).
408408
409409** v3: across time and cultures
410410- Sky cultures: Chinese, Polynesian, Arabic, Norse and other
411 constellations over the same stars.
411 constellations over the same stars. Done for the ten CC BY-SA cultures in
412 Stellarium's set; Arabic is not included (CC BY-ND, permission granted only
413 to Stellarium).
412414- Historical sky for any date and place, with precession. Done: 3000 BCE
413415 to 3000 CE, with BSC5 proper motions and the pole star of the year.
414416- 3D planets from USGS maps; immersive sky and orrery on Vision Pro.
Packages/MoonriseKit/Package.swift +1 −1
@@ -22,7 +22,7 @@ let package = Package(
2222 .target(
2323 name: "SkyRenderer",
2424 dependencies: ["SkyEngine"],
25 resources: [.copy("Resources/bsc5.json"), .copy("Resources/constellations.json"), .copy("Resources/coastline.json"), .copy("Resources/spacecraft.json")]
25 resources: [.copy("Resources/bsc5.json"), .copy("Resources/constellations.json"), .copy("Resources/coastline.json"), .copy("Resources/spacecraft.json"), .copy("Resources/skycultures.json")]
2626 ),
2727 .target(name: "Feeds"),
2828 .target(name: "ObservingLog"),
Packages/MoonriseKit/Sources/SkyRenderer/Resources/skycultures.json added +1
@@ -0,0 +1 @@
1[{"id":"chinese","name":"Chinese","region":"Asia","licence":"Su Song and Suzhou maps images: Public Domain Text and line: CC BY-SA","source":"https://github.com/Stellarium/stellarium-skycultures/tree/master/chinese","constellations":[{"name":"Net","lines":[[1409,1389,1373,1346],[1457,1411,1394,1346,1239],[1457,1479]],"native":"毕宿"},{"name":"Wall","lines":[[39,15]],"native":"壁宿"},{"name":"Three Stars","lines":[[2061,1948,1903,1852,1713],[1852,1790],[1948,2004]],"native":"参宿"},{"name":"Root","lines":[[5531,5652,5787,5685]],"native":"氐宿"},{"name":"Dipper","lines":[[6812,6913,7039,7121,7234,7194]],"native":"斗宿"},{"name":"Room","lines":[[5984,5953,5944,5928]],"native":"房宿"},{"name":"Ghosts","lines":[[3357,3366,3449,3461]],"native":"鬼宿"},{"name":"Winnowing Basket","lines":[[6746,6859,6879,6832]],"native":"箕宿"},{"name":"Horn","lines":[[5056,5107]],"native":"角宿"},{"name":"Well","lines":[[2763,2650,2529,2473],[2529,2343,2286],[2343,2421,2650],[2421,2484],[2286,2216]],"native":"井宿"},{"name":"Neck","lines":[[5315,5338,5409],[5315,5359]],"native":"亢宿"},{"name":"Legs","lines":[[271,215,231,163,165,154,226,269,337],[352,389,383,360,351,310,271]],"native":"奎宿"},{"name":"Willow","lines":[[3418,3454,3492,3482],[3410,3482],[3492,3547,3613,3665]],"native":"柳宿"},{"name":"Bond","lines":[[617,553,546]],"native":"娄宿"},{"name":"Hairy Head","lines":[[1142,1145,1151,1149],[1142,1156,1165,1178]],"native":"昴宿"},{"name":"Ox","lines":[[7776,7754,7715],[7776,7814,7830,7822],[7814,7822]],"native":"牛宿"},{"name":"Girl","lines":[[7950,7990,7982,7951]],"native":"女宿"},{"name":"Encampment","lines":[[8781,8775]],"native":"室宿"},{"name":"Supreme Palace Right Wall","lines":[[4540,4386,4399,4359,4357]],"native":"太微右垣"},{"name":"Supreme Palace Left Wall","lines":[[4689,4825,4910,4932,4968]],"native":"太微左垣"},{"name":"Heavenly Market Right Wall","lines":[[6148,6095,6008,5933,5867,5789,5854,5892,6056,6075,6175]],"native":"天市右垣"},{"name":"Heavenly Market Left Wall","lines":[[6410,6526,6623,6779,7113,7235,7141,6869,6698,6561,6378]],"native":"天市左垣"},{"name":"Rooftop","lines":[[8414,8450,8308]],"native":"危宿"},{"name":"Tail","lines":[[6241,6247,6262,6380,6553,6615,6580,6527,6508],[6247,6252]],"native":"尾宿"},{"name":"Stomach","lines":[[801,824,838]],"native":"胃宿"},{"name":"Heart","lines":[[6084,6134,6165]],"native":"心宿"},{"name":"Star","lines":[[3748,3759,3787,3845],[3748,3709,3706,3785],[3748,3785]]},{"name":"Emptiness","lines":[[8232,8131]],"native":"虚宿"},{"name":"Wings","lines":[[4287,4405],[4287,4395],[4287,4232],[4405,4514,4395],[4514,4567],[4405,4382,4488,4416,4402],[4402,4468,4529],[4395,4343,4314]],"native":"翼宿"},{"name":"Extended Net","lines":[[3903,3994,4094,3963],[3903,3963],[3903,3849],[4094,4171]],"native":"张宿"},{"name":"Chariot","lines":[[4786,4757,4662,4630],[4662,4696],[4757,4775],[4630,4623]],"native":"轸宿"},{"name":"Purple Forbidden Right Wall","lines":[[5291,4787,4434,3771,2511,1542,985]],"native":"紫微右垣"},{"name":"Purple Forbidden Left Wall","lines":[[5744,5986,6132,6396,7180,7879,8819,208]],"native":"紫微左垣"},{"name":"Turtle Beak","lines":[[1879,1876],[1879,1907]],"native":"觜宿"},{"name":"Eight Kinds of Crops","lines":[[2077,2029,1969,1678],[1969,1568],[1637,1622,2027]],"native":"八谷"},{"name":"Net for Catching Birds","lines":[[33,9098,9065],[33,9103],[33,88],[33,48]],"native":"八魁"},{"name":"Rotten Gourd","lines":[[7852,7858,7892,7883,7896]],"native":"败瓜"},{"name":"Decayed Mortar","lines":[[8353,8411,8695,8637]],"native":"败臼"},{"name":"Northern Dipper","lines":[[4301,4295,4554,4660,4905,5054,5191]],"native":"北斗"},{"name":"North River","lines":[[2990,2890,2852]],"native":"北河"},{"name":"Northern Pole","lines":[[5735,5563,5430,5321,4893]],"native":"北极"},{"name":"North Gate of the Military Camp","lines":[[8728,8728]],"native":"北落师门"},{"name":"River Turtle","lines":[[6897,7062,7188,7242,7259,7254,7226,7152,7129,6953,6951,6897]],"native":"鳖"},{"name":"Persia","lines":[[7869,7869]],"native":"波斯"},{"name":"Textile Ruler","lines":[[6730,6787]],"native":"帛度"},{"name":"Banner of Three Stars","lines":[[1556,1580,1569,1570,1544,1543,1552,1567,1601]],"native":"参旗"},{"name":"Toilet","lines":[[1865,1829,1983,2035]],"native":"厕"},{"name":"Whip","lines":[[264,264]],"native":"策"},{"name":"Royal Guards","lines":[[4915,4845,4811,4785,4728,4666,4594]],"native":"常陈"},{"name":"Big Yard for Chariots","lines":[[8699,8632,8523,8252,8047,8079,8266]],"native":"车府"},{"name":"Chariots and Cavalry","lines":[[5649,5453,5425]],"native":"车骑"},{"name":"Commodity Market","lines":[[6129,6243]],"native":"车肆"},{"name":"Hay","lines":[[708,752,666],[704,692,781]],"native":"刍藁"},{"name":"Pestle (In Winnowing Basket Mansion)","lines":[[6537,6510,6461]],"native":"杵 (箕宿)"},{"name":"Pestle (In Rooftop Mansion)","lines":[[8498,8454,8419]],"native":"杵 (危宿)"},{"name":"Changsha (Vassal of Chariot)","lines":[[4696,4696]],"native":"长沙 (附轸宿)"},{"name":"Guest House","lines":[[9013,137],[345,640,860,1035,1040,1046]],"native":"传舍"},{"name":"Retinue (In Room Mansion)","lines":[[5883,5839]],"native":"从官 (房宿)"},{"name":"Retinue (In Supreme Palace Enclosure)","lines":[[4495,4495]],"native":"从官 (太微垣)"},{"name":"Great Horn","lines":[[5340,5340]],"native":"大角"},{"name":"Chief Judge","lines":[[4646,4646]],"native":"大理"},{"name":"Mausoleum","lines":[[685,854,937,941,936,921,840,788]],"native":"大陵"},{"name":"Mattress of the Emperor","lines":[[5304,5263,5247]],"native":"帝席"},{"name":"Emperor's Seat","lines":[[6406,6406]],"native":"帝座"},{"name":"Eastern Door","lines":[[6147,6118,6104,6153]],"native":"东咸"},{"name":"Trials","lines":[[5660,5705]],"native":"顿顽"},{"name":"Send Armed Forces To Suppress (Vassal of Three Stars)","lines":[[1892,1897,1899],[1892,1903]],"native":"伐 (附参宿)"},{"name":"Punishment","lines":[[6060,6002,5954]],"native":"罚"},{"name":"Flying Fish","lines":[[3615,2736],[3615,3347],[3615,3301],[3615,2803],[3615,3024]],"native":"飞鱼"},{"name":"Tomb (Vassal of Rooftop)","lines":[[8558,8518],[8558,8597],[8558,8539],[8558,8414]],"native":"坟墓 (附危宿)"},{"name":"Axe","lines":[[8980,8998,9031]],"native":"鈇钺"},{"name":"Sickle","lines":[[433,585,565]],"native":"鈇锧"},{"name":"Basket for Mulberry Leaves","lines":[[7049,6978,6923,7125,7175,7218,7251]],"native":"扶筐"},{"name":"White Patched Nearby","lines":[[1208,872]],"native":"附白"},{"name":"Auxiliary Road","lines":[[153,153]],"native":"附路"},{"name":"Fu Yue","lines":[[6630,6630]],"native":"傅说"},{"name":"Roofing","lines":[[8402,8410]],"native":"盖屋"},{"name":"Canopy Support (Vassal of Canopy of the Emperor)","lines":[[1148,932,592],[575,480,427]],"native":"杠 (附华盖)"},{"name":"Flying Corridor","lines":[[707,542,403,343,223,193]],"native":"阁道"},{"name":"Celestial Lance","lines":[[5506,5447,5429]],"native":"梗河"},{"name":"Curved Array","lines":[[8748,285,424,6789,6322,5903]],"native":"勾陈"},{"name":"Lock (Vassal of Room)","lines":[[5993,5997],[5993,5984]],"native":"钩钤 (附房宿)"},{"name":"Dog","lines":[[7440,7362]],"native":"狗"},{"name":"Territory of Dog","lines":[[7597,7618,7650,7604,7597]],"native":"狗国"},{"name":"Coiled Thong","lines":[[5855,5778,5747,5793,5849,5889,5947,5971,5968]],"native":"贯索"},{"name":"Beacon Fire","lines":[[3191,3268,3304,3215]],"native":"爟"},{"name":"Tortoise","lines":[[6295,6462,6500,6229,6285]]},{"name":"Sea and Mountain","lines":[[4467,4520]],"native":"海山"},{"name":"Sea Rock","lines":[[3307,3699,3825,3884,3890]],"native":"海石"},{"name":"Drum at the River","lines":[[7602,7557,7525]],"native":"河鼓"},{"name":"Crane","lines":[[8425,8636,8675,8655,8848,8747,8636,8820],[8636,8787],[8636,8644,8552],[8636,8560,8486]],"native":"鹤"},{"name":"Railings","lines":[[5190,5193,5248,5285]],"native":"衡"},{"name":"Astrologer","lines":[[6556,6556]],"native":"候"},{"name":"Bow and Arrow","lines":[[2693,2827,3017,3113,3034,2949,2827,2618,2538,2773,3017]],"native":"弧矢"},{"name":"Dipper for Solids","lines":[[6281,6299,6250,6228]],"native":"斛"},{"name":"Emperor's Bodyguard","lines":[[4362,4362]],"native":"虎贲"},{"name":"Good Gourd","lines":[[7948,7906,7882,7928,7948],[7882,7871]],"native":"瓠瓜"},{"name":"Canopy of the Emperor","lines":[[427,456],[427,365],[427,336],[427,399],[427,478],[427,548]],"native":"华盖"},{"name":"Eunuch Official","lines":[[6337,6341,6355,6393]],"native":"宦者"},{"name":"Firebird","lines":[[8937,8949,8959,25,100,99,180,125,322,429]],"native":"火鸟"},{"name":"Heap of Corpses","lines":[[879,879]],"native":"积尸"},{"name":"Stored water","lines":[[1261,1261]],"native":"积水"},{"name":"Pile of Firewood","lines":[[2985,2985]],"native":"积薪"},{"name":"Group of Soldiers","lines":[[5987,5948]],"native":"积卒"},{"name":"White Patches Attached","lines":[[1744,1336]],"native":"夹白"},{"name":"Establishment","lines":[[7150,7217,7264,7304,7340,7342]],"native":"建"},{"name":"Clepsydra Terrace","lines":[[7139,7106,7178,7262]],"native":"渐台"},{"name":"Door Bolt","lines":[[6027,6027]],"native":"键闭"},{"name":"Goldfish","lines":[[1338,1465,1922,2015,2221]],"native":"金鱼"},{"name":"Recommending Virtuous Men","lines":[[4921,4921]],"native":"进贤"},{"name":"Accumulated Water","lines":[[2793,2793]],"native":"积水"},{"name":"Nine Water Wells","lines":[[8100,8100]],"native":"九坎"},{"name":"Nine Senior Officers","lines":[[4828,4847]],"native":"九卿"},{"name":"Imperial Military Flag","lines":[[1469,1520,1560,1608,1611,1549,1532,1496,1634]],"native":"九斿"},{"name":"Interpreters of Nine Dialects","lines":[[1318,1298,1383,1463,1508,1505]],"native":"九州殊口"},{"name":"Banner of Wine Shop","lines":[[3866,3782,3754]],"native":"酒旗"},{"name":"Mortar","lines":[[8522,8430,8315,8310]],"native":"臼"},{"name":"Rolled Tongue","lines":[[1135,1220,1228,1203,1131,1123]],"native":"卷舌"},{"name":"Military Well","lines":[[1696,1705,1756,1757]],"native":"军井"},{"name":"Southern Military Gate","lines":[[335,335]],"native":"军南门"},{"name":"Market for Soldiers","lines":[[2294,2443,2571,2588,2580,2387,2294]],"native":"军市"},{"name":"Chaff","lines":[[6492,6492]],"native":"糠"},{"name":"Boats and Lake","lines":[[5323,5365]],"native":"亢池"},{"name":"Peafowl","lines":[[6582,6745,6916,7074,7107,7665,7913,6982,7590,8181,7790]],"native":"孔雀"},{"name":"Crying","lines":[[8351,8452]],"native":"哭"},{"name":"Arsenal","lines":[[5231,5440,5288,5192,5089,4940,4819,4802]],"native":"库楼"},{"name":"Captain of the Bodyguards","lines":[[4883,4883]],"native":"郎将"},{"name":"Officers of the Imperial Guard","lines":[[4737,4733,4738,4752,4717,4707,4766,4753,4667,4789,4815,4756,4643,4602]],"native":"郎位"},{"name":"Old Man","lines":[[2326,2326]],"native":"老人"},{"name":"Thunder and Lightning","lines":[[8923,8893,8795,8697,8665,8634]],"native":"雷电"},{"name":"Line of Ramparts","lines":[[9087,9067,9089,3,9087],[9067,8834,8698,8573,8418,8322,8278,8260,8288,8322]],"native":"垒壁阵"},{"name":"Resting Palace (Vassal of Encampment)","lines":[[8667,8684],[8641,8650],[8880,8905],[8775,8684],[8775,8650],[8775,8880]],"native":"离宫 (附室宿)"},{"name":"Jade Ornament on Ladies' Wear","lines":[[8135,8214]],"native":"离瑜"},{"name":"Pearls on Ladies' Wear","lines":[[7897,7884,7873,7831]],"native":"离珠"},{"name":"Whetstone","lines":[[1269,1287,1369,1348]],"native":"砺石"},{"name":"Jewel Market","lines":[[6093,6149]],"native":"列肆"},{"name":"Astronomical Observatory","lines":[[4310,4294,4291]],"native":"灵台"},{"name":"Six Jia","lines":[[2401,2527,3082,2742,1523,1686]],"native":"六甲"},{"name":"Network of Dykes","lines":[[7889,7900,7937]],"native":"罗堰"},{"name":"Horse's Abdomen","lines":[[5267,5267]],"native":"马腹"},{"name":"Horse's Tail","lines":[[4732,4638,4621]],"native":"马尾"},{"name":"Bee","lines":[[4844,4798]],"native":"蜜蜂"},{"name":"The Hall of Glory","lines":[[4418,4471,4432]],"native":"明堂"},{"name":"Southern Boat","lines":[[4050,4140,4199,4037,3685]],"native":"南船"},{"name":"South River","lines":[[2828,2845,2943]],"native":"南河"},{"name":"Southern Gate","lines":[[5132,5460]],"native":"南门"},{"name":"Inner Kitchen","lines":[[4863,4916]],"native":"内厨"},{"name":"Inner Steps","lines":[[3323,3648,3531],[3757,3505,3660]],"native":"内阶"},{"name":"High Judge","lines":[[4014,3974,3857]],"native":"内平"},{"name":"Inner Screen","lines":[[4515,4517,4589,4608]],"native":"内屏"},{"name":"Imperial Passageway","lines":[[7157,7298,7314,7395,7534]],"native":"辇道"},{"name":"Bird's Beak","lines":[[8502,8540,9060,126,187,77,9076]],"native":"鸟喙"},{"name":"Peasant","lines":[[7029,7029]],"native":"农丈人"},{"name":"Woman's Bed","lines":[[6418,6436,6485]],"native":"女床"},{"name":"Female Protocol","lines":[[6725,6725]],"native":"女史"},{"name":"Thunderbolt","lines":[[8773,8852,8916,8969,9072]],"native":"霹雳"},{"name":"Judging","lines":[[5020,5287]]},{"name":"Flat Road","lines":[[4963,5150]],"native":"平道"},{"name":"Screen","lines":[[1702,1654]],"native":"屏"},{"name":"Seven Excellencies","lines":[[6200,6092,6023,5914,5763,5733,5681]],"native":"七公"},{"name":"Imperial Guards","lines":[[5776,5695,5576,5571,5626,5708,5683,5605,5528,5469]],"native":"骑官"},{"name":"Chariots and Cavalry General","lines":[[5646,5646]],"native":"骑阵将军"},{"name":"Weeping","lines":[[8512,8499]],"native":"泣"},{"name":"Green Hill","lines":[[4552,4565,4444,4449,4450,4458,4494]],"native":"青丘"},{"name":"Palace Gate","lines":[[2707,2506]],"native":"阙丘"},{"name":"Humans","lines":[[8225,8173,8313,8321]],"native":"人"},{"name":"Solar Star","lines":[[5838,5838]],"native":"日"},{"name":"Three Excellencies (In Supreme Palace Enclosure)","lines":[[4829,4858]],"native":"三公 (太微垣)"},{"name":"Three Excellencies (In Purple Forbidden Enclosure)","lines":[[5112,5023]],"native":"三公 (紫微垣)"},{"name":"Triangle","lines":[[5671,5897,6217,5671]],"native":"三角形"},{"name":"Three Top Instructors","lines":[[3576,3609]],"native":"三师"},{"name":"Three Steps","lines":[[3569,3594,4033,4069,4377]],"native":"三台"},{"name":"Royal Secretary","lines":[[6566,6161],[6566,6223],[6566,6126],[6566,6315]],"native":"尚书"},{"name":"Junior Officers","lines":[[4259,4192,4208]],"native":"少微"},{"name":"Snake's Abdomen","lines":[[837,806,705,570]],"native":"蛇腹"},{"name":"Snake's Head","lines":[[591,1175]],"native":"蛇首"},{"name":"Snake's Tail","lines":[[98,8471,8254,8021]],"native":"蛇尾"},{"name":"Changing Room (Vassal of Tail)","lines":[[6260,6260]],"native":"神宫 (附尾宿)"},{"name":"Twelve States","lines":[[8075,8137]],"native":"十二国"},{"name":"Cross","lines":[[4763,4730],[4853,4656]],"native":"十字架"},{"name":"Excrement","lines":[[1996,1996]],"native":"屎"},{"name":"Municipal Office","lines":[[6567,6581],[6734,6446],[6496,6601]],"native":"市楼"},{"name":"Eunuch","lines":[[4137,4124,4203,4247]],"native":"势"},{"name":"Official for Irrigation","lines":[[2159,2199,2223,2198]],"native":"水府"},{"name":"Crooked Running Water","lines":[[472,338,191]],"native":"水委"},{"name":"Water Level","lines":[[2864,3008,3163,3208]],"native":"水位"},{"name":"Deified Judge of Right and Wrong","lines":[[8097,8123]],"native":"司非"},{"name":"Deity in Charge of Monsters","lines":[[2084,2134,2135,2047]],"native":"司怪"},{"name":"Deified Judge of Rank","lines":[[8328,8277]],"native":"司禄"},{"name":"Deified Judge of Disaster and Good Fortune","lines":[[8178,8163]],"native":"司危"},{"name":"Four Channels","lines":[[2649,2503,2385,2298]],"native":"四渎"},{"name":"Four Advisors","lines":[[4084,4062]],"native":"四辅"},{"name":"Grandson","lines":[[2256,2177]],"native":"孙"},{"name":"Guard of the Sun","lines":[[4518,4518]],"native":"太阳守"},{"name":"First Great One","lines":[[5162,5162]],"native":"太乙"},{"name":"Crown Prince","lines":[[4527,4527]],"native":"太子"},{"name":"Royals","lines":[[4335,4335]],"native":"太尊"},{"name":"Flying Serpent","lines":[[8585,8541,8335,8301,8281,8371,8494,8538,9071,9045,9008,8926,8613,8780,8830,8860,8961,9003,8976,8965]],"native":"螣蛇"},{"name":"Celestial Concave","lines":[[1012,1012]],"native":"天阿"},{"name":"Celestial Flail","lines":[[6688,6555,6536,6705,6588]],"native":"天棓"},{"name":"Market Officer","lines":[[6973,7020,7032,7063,7149,7193,7236,7225,7209]],"native":"天弁"},{"name":"Square Celestial Granary","lines":[[74,334,402,539,509,583]],"native":"天仓"},{"name":"Celestial Slander","lines":[[1177,1177]],"native":"天谗"},{"name":"Celestial Kitchen","lines":[[7310,7462,7582,7685,7676,7371]],"native":"天厨"},{"name":"Celestial Boat","lines":[[834,915,1017,1087,1122,1273,1303,1330,1314]],"native":"天船"},{"name":"Celestial Bed","lines":[[5334,5691,5886],[6069,5589]],"native":"天床"},{"name":"Great General of Heaven","lines":[[603,496,464,430,469,458,477,557,622,664,660,603]],"native":"天大将军"},{"name":"Celestial Drumstick","lines":[[7710,7667,7596,7570]],"native":"天桴"},{"name":"Celestial Spokes","lines":[[5794,5812]],"native":"天辐"},{"name":"Materials for Making Tents","lines":[[8720,8720]],"native":"天纲"},{"name":"Celestial High Terrace","lines":[[1620,1547],[1739,1620]],"native":"天高"},{"name":"Celestial Hook","lines":[[7850,7957,8162,8417,8561,8694,8872]],"native":"天钩"},{"name":"Celestial Dog","lines":[[3426,3477,3438,3468,3518,3556]],"native":"天狗"},{"name":"Celestial Pass","lines":[[1910,1910]],"native":"天关"},{"name":"Great Emperor of Heaven","lines":[[8546,8546]],"native":"天皇大帝"},{"name":"Celestial Pier","lines":[[1740,1805],[1740,1773],[1740,1689],[1740,1706]],"native":"天潢"},{"name":"Celestial Pigsty","lines":[[255,267,203,194]],"native":"天溷"},{"name":"Celestial Cock","lines":[[7489,7515]],"native":"天鸡"},{"name":"Judge for Estimating the Age of Animals","lines":[[3634,3634]],"native":"天记"},{"name":"Celestial Discipline","lines":[[6103,6212,6324,6332,6346,6431,6570,6695]],"native":"天纪"},{"name":"Celestial River","lines":[[6402,6453,6486]],"native":"天江"},{"name":"Celestial Street","lines":[[1388,1329]],"native":"天街"},{"name":"Celestial Tally","lines":[[1396,1444],[1396,1351,1414,1473,1484,1458,1381]],"native":"天节"},{"name":"Celestial Ford","lines":[[8115,8146,8130,8028,7924,7730,7528,7796,7949,8115]],"native":"天津"},{"name":"Celestial Stable","lines":[[63,82,68]],"native":"天厩"},{"name":"Celestial Wolf","lines":[[2491,2491]],"native":"天狼"},{"name":"Celestial Prison","lines":[[4248,4422],[4277,4431],[4288,4392]],"native":"天牢"},{"name":"Celestial Ramparts","lines":[[8264,8311,8318,8319],[8187,8128],[8175,8195]],"native":"天垒城"},{"name":"Judge for Nobility","lines":[[4407,4566,4569]],"native":"天理"},{"name":"Celestial Foodstuff","lines":[[1066,1061,1038,1030]],"native":"天廪"},{"name":"Celestial Gate","lines":[[4981,5068]],"native":"天门"},{"name":"Celestial Money","lines":[[8405,8326,8305,8431,8447,8405]],"native":"天钱"},{"name":"Celestial Spear","lines":[[5328,5350,5404]],"native":"天枪"},{"name":"Circular Celestial Granary","lines":[[911,1007,896,813,649,718,754,804,779,739,691,639,650]],"native":"天囷"},{"name":"Celestial Milk","lines":[[5881,5881]],"native":"天乳"},{"name":"Celestial Earth God's Temple","lines":[[3207,3445,3485,3734,3803]],"native":"天社"},{"name":"Celestial Farmland (In Horn Mansion)","lines":[[5264,5105]],"native":"天田 (角宿)"},{"name":"Celestial Farmland (In Ox Mansion)","lines":[[8110,7980],[8110,8080,7936],[7980,7936]],"native":"天田 (牛宿)"},{"name":"Celestial Premier","lines":[[3989,4042]],"native":"天相"},{"name":"Celestial Great One","lines":[[5226,5226]],"native":"天乙"},{"name":"Celestial Yin Force","lines":[[1015,972,951]],"native":"天阴"},{"name":"Ricks of Grain","lines":[[749,749]],"native":"天庾"},{"name":"Celestial Spring","lines":[[7343,7337,7348]],"native":"天渊"},{"name":"Celestial Orchard","lines":[[440,566,674,721,789,897,1143,1190,1195,1347,1393,1464,1453]],"native":"天园"},{"name":"Celestial Meadows","lines":[[1231,1162,1136,1084,984,874,811,818,850,919,1003,1088,1173,1181,1213,1240]],"native":"天苑"},{"name":"Celestial Keyhole","lines":[[6672,6595],[6545,6519,6520,6616]],"native":"天籥"},{"name":"Celestial Pillar","lines":[[8002,8112,7686,7312,6809]],"native":"天柱"},{"name":"Celestial Wine Cup","lines":[[2808,2777,2630]],"native":"天樽"},{"name":"Butcher's Shops","lines":[[6895,6765]],"native":"屠肆"},{"name":"Official for Materials Supply","lines":[[8520,8562]],"native":"土公吏"},{"name":"Master of Constructions","lines":[[188,188]],"native":"土司空"},{"name":"Outer Kitchen","lines":[[3321,3459,3500]],"native":"外厨"},{"name":"Outer Fence","lines":[[595,549,489,434,361,294,224]],"native":"外屏"},{"name":"Wang Liang","lines":[[21,130,219,168,123]],"native":"王良"},{"name":"Administrative Center","lines":[[3888,3894,3775,3619,3662]],"native":"文昌"},{"name":"Five Chariots","lines":[[1577,1708,2088,2095,1791]],"native":"五车"},{"name":"Interior Seats of the Five Emperors","lines":[[881,581],[881,774],[881,961],[881,1230]],"native":"五帝内座"},{"name":"Seats of the Five Emperors","lines":[[4534,4535],[4534,4564],[4534,4543]],"native":"五帝座"},{"name":"Five Feudal Kings","lines":[[2540,2697,2821,2905,3067]],"native":"五诸侯"},{"name":"Five Lords","lines":[[4946,4920,4851,4663]],"native":"五诸侯"},{"name":"Western Door","lines":[[5941,5908,5848]],"native":"西咸"},{"name":"Xi Zhong","lines":[[7328,7420,7469,7503]],"native":"奚仲"},{"name":"Pool of Harmony","lines":[[1749,1825,1729]],"native":"咸池"},{"name":"Prime Minister","lines":[[4716,4716]],"native":"相"},{"name":"Little Dipper","lines":[[4674,4583,4174,4234,3860,3795,3543,3340,3000]],"native":"小斗"},{"name":"Temple","lines":[[8504,8533,8610,8727]],"native":"虚梁"},{"name":"Xuanyuan","lines":[[3579,3612,3690,3705],[3861,3731,3773,3873,3905,4031,4057,3975,3982,3852],[3982,4133],[3982,3980]],"native":"轩辕"},{"name":"Sombre Lance","lines":[[5351,5351]],"native":"玄戈"},{"name":"Battle Axe (Vassal of Well)","lines":[[2216,2216]],"native":"钺 (附井宿)"},{"name":"Gate of Yang","lines":[[5471,5485]],"native":"阳门"},{"name":"Wild Cockerel","lines":[[2429,2429]],"native":"野鸡"},{"name":"Usher to the Court","lines":[[4695,4695]],"native":"谒者"},{"name":"Exotic Bird","lines":[[6417,6411,6163,6102,5339,6020,5303],[6020,5470,5336]],"native":"异雀"},{"name":"Official in Charge of Pasturing","lines":[[413,437,463,510]],"native":"右更"},{"name":"Right Flag","lines":[[7429,7474,7377,7387,7447],[7460,7446,7584]],"native":"右旗"},{"name":"Right Conductor","lines":[[5235,5185,5200]],"native":"右摄提"},{"name":"Fish","lines":[[6662,6662]],"native":"鱼"},{"name":"Palace Guard","lines":[[8396,8439,8480],[8516,8529,8478],[8628,8693],[8592,8670],[8567,8534,8508],[8676,8704,8679],[8673,8709,8711],[8812,8817,8789],[8939,8932,8906],[8892,8890],[8865,8858,8841],[8850,8968,8988]],"native":"羽林军"},{"name":"Jade Well","lines":[[1679,1617,1666,1735]],"native":"玉井"},{"name":"Maids-in-waiting","lines":[[7352,7124],[7352,6927]],"native":"御女"},{"name":"Lunar Star","lines":[[1256,1256]],"native":"月"},{"name":"Whisper (Vassal of Net)","lines":[[1479,1479]],"native":"附耳 (附毕宿)"},{"name":"Cloud and Rain","lines":[[9022,8984]],"native":"云雨"},{"name":"Zaofu","lines":[[8571,8465,8469,8316,8334]],"native":"造父"},{"name":"Long Wall","lines":[[4127,4209,4227,4146]],"native":"长垣"},{"name":"Grandfather","lines":[[1956,1862]],"native":"丈人"},{"name":"Twinkling Indicator","lines":[[5435,5435]],"native":"招摇"},{"name":"Assistant (Vassal of Northern Dipper)","lines":[[5062,5062]],"native":"辅 (附北斗)"},{"name":"Executions","lines":[[5484,5548,5603]],"native":"折威"},{"name":"Battle Chariots","lines":[[5526,5591,5686]],"native":"阵车"},{"name":"Right linchpin (Vassal of Chariot)","lines":[[4623,4623]],"native":"右辖 (附轸宿)"},{"name":"Weaving Girl","lines":[[7051,7001,7056]],"native":"织女"},{"name":"Left linchpin (Vassal of Chariot)","lines":[[4775,4775]],"native":"左辖 (附轸宿)"},{"name":"Tripod of the Zhou","lines":[[4983,4924,4954]],"native":"周鼎"},{"name":"Feudal Kings","lines":[[2034,1928,1821,1659,1586,1497]],"native":"诸王"},{"name":"Pillars (In Net Mansion)","lines":[[1605,1612,1641,1605],[2011,2012,1995,2011],[1843,1914]],"native":"柱 (毕宿)"},{"name":"Pillars (In Horn Mansion)","lines":[[5378,5367],[5260,5249],[5354,5395],[5221,5210,5168],[5028,5028]],"native":"柱 (角宿)"},{"name":"Official of Royal Archives","lines":[[6920,6920]],"native":"柱史"},{"name":"Son","lines":[[2056,2040]],"native":"子"},{"name":"Patriarchal Clan","lines":[[7061,7069]],"native":"宗"},{"name":"Official of Religious Ceremonies","lines":[[6712,6714,6723,6752]],"native":"宗人"},{"name":"Official for the Royal Clan","lines":[[6603,6629]],"native":"宗正"},{"name":"Official in Charge of the Forest","lines":[[773,793,809,847,836]],"native":"左更"},{"name":"Left Flag","lines":[[7479,7488,7536,7546,7635,7645,7622,7664,7724]],"native":"左旗"},{"name":"Left Conductor","lines":[[5502,5475,5477]],"native":"左摄提"},{"name":"Seat Flags","lines":[[2487,2585,2459,2483,2427,2516,2420,2419,2539]],"native":"座旗"}]},{"id":"indian","name":"Indian (Vedic)","region":"Asia","licence":"CC BY-SA","source":"https://github.com/Stellarium/stellarium-skycultures/tree/master/indian","constellations":[{"name":"Twin physicians of Gods","lines":[[546,553]]},{"name":"She who bears","lines":[[801,824,838]]},{"name":"Nurses of kartiikeya","lines":[[1180,1178,1165,1156,1142,1145,1149,1151]]},{"name":"The spirited one","lines":[[1457,1457]]},{"name":"The deer's head","lines":[[1879,1876,1907]]},{"name":"The moist one","lines":[[2061,2061]]},{"name":"The restorers of goods","lines":[[2890,2990]]},{"name":"The nourisher","lines":[[3461,3357]]},{"name":"The embrace","lines":[[3482,3410,3418,3454,3492]]},{"name":"The bountiful one","lines":[[3982,3982]]},{"name":"The former red one","lines":[[4357,4359]]},{"name":"The latter red one","lines":[[4534,4534]]},{"name":"The hand","lines":[[4757,4786],[4757,4662,4630,4623],[4630,4786]]},{"name":"The bright one","lines":[[5056,5056]]},{"name":"The honest one","lines":[[5340,5340]]},{"name":"The gifted one","lines":[[5787,5685,5531],[5685,5652]]},{"name":"Followers of Radha","lines":[[5984,5953,5944]]},{"name":"The eldest one","lines":[[6084,6134,6165]]},{"name":"The root","lines":[[6241,6252,6271,6380,6553,6615,6580,6527,6508]]},{"name":"The former undefeated one","lines":[[6879,6859]]},{"name":"The latter undefeated one","lines":[[7121,7194]]},{"name":"The Ear","lines":[[7602,7557,7525]]},{"name":"The most famous one","lines":[[7928,7906]]},{"name":"hundred cures","lines":[[8518,8518]]},{"name":"The first of the blessed feet","lines":[[8775,8781]]},{"name":"The prosperous one","lines":[[361,361]]},{"name":"The invincible one","lines":[[7054,7001,7056]]}]},{"id":"mongolian","name":"Mongolian","region":"Asia","licence":"CC BY-SA","source":"https://github.com/Stellarium/stellarium-skycultures/tree/master/mongolian","constellations":[{"name":"The Bow and the Arrow","lines":[[7328,7420,7528,7796,7924],[7796,7949,8115,8310],[7796,7615,7417]]},{"name":"The Five Stars Woman","lines":[[542,403,264,168,21]]},{"name":"The Seven Buddhas","lines":[[5191,5054,4905,4660,4554,4295,4301,4660]]},{"name":"The Three Stags","lines":[[7924,7001,7557,7924]]}]},{"id":"japanese_moon_stations","name":"Japanese moon stations","region":"Asia","licence":"Text and data: CC BY-SA Yasui's Map detail[4] used with authorisation from Steven Renshaw","source":"https://github.com/Stellarium/stellarium-skycultures/tree/master/japanese_moon_stations","constellations":[{"name":"Horn","lines":[[5056,5107]]},{"name":"Neck","lines":[[5359,5315,5338,5409]]},{"name":"Root","lines":[[5652,5531,5685,5787,5652]]},{"name":"Chamber","lines":[[5984,5953,5944,5928]]},{"name":"Heart","lines":[[6084,6134,6165]]},{"name":"Tail","lines":[[6241,6247,6271,6380,6553,6615,6580,6527,6508]]},{"name":"Basket","lines":[[6859,6746,6832,6879,6859]]},{"name":"Dipper","lines":[[7234,7121,7039,7194]]},{"name":"Cow","lines":[[7754,7776,7822,7814]]},{"name":"Woman","lines":[[7950,7990,7985,7951,7950]]},{"name":"Emptiness","lines":[[8232,8131]]},{"name":"Roof Top","lines":[[8414,8308,8450,8414]]},{"name":"Room","lines":[[8781,8775]]},{"name":"Wall","lines":[[39,15]]},{"name":"Stride","lines":[[351,271,215,163,165,154,226,269,337,352,383,360,351]]},{"name":"Hill","lines":[[546,553,617]]},{"name":"Stomach","lines":[[838,801,824,838]]},{"name":"Stopping Place","lines":[[1142,1145,1165,1156,1142]]},{"name":"Net","lines":[[1409,1373],[1346,1412,1457]]},{"name":"Turtle Snout","lines":[[1907,1876,1879,1907]]},{"name":"Investigator","lines":[[2061,1790,1852,1903,1948],[1852,1713]]},{"name":"Well","lines":[[2286,2343,2421,2484],[2473,2529,2650,2763],[2529,2343],[2650,2421]]},{"name":"Ogre","lines":[[3461,3357,3366,3449,3461]]},{"name":"Willow","lines":[[3418,3410,3482,3547,3613,3665],[3482,3454]]},{"name":"Stars","lines":[[3845,3787,3759,3748,3709,3706]]},{"name":"Stretched Net","lines":[[3849,3903,3970,3994,4094,4171]]},{"name":"Wings","lines":[[4232,4287,4382,4468,4402,4305],[4314,4343,4514,4405]]},{"name":"Chariot Cross-Board","lines":[[4630,4662,4757,4786,4630]]}]},{"id":"hawaiian_starlines","name":"Hawaiian","region":"Oceania","licence":"CC BY-SA","source":"https://github.com/Stellarium/stellarium-skycultures/tree/master/hawaiian_starlines","constellations":[{"name":"The Canoe Bailer of Makali`i","lines":[[2491,2943,2990,2890,2088,2095,1791,1577,1708,2088],[2491,2294,2326]],"native":"Ke Ka o Makali’i"},{"name":"The Cat's Cradle","lines":[[2061,1948,2004,1713,1852,1790,2061],[1948,1903,1852]],"native":"Ka Hei-Hei o Na Keiki"},{"name":"The Chief's Eyes","lines":[[1142,1140]],"native":"Makali`i"},{"name":"Voice of Joy","lines":[[4757,4662,4630,4786,4757]],"native":"Me`e"},{"name":"The Seven","lines":[[5191,5054,4905,4660,4301,4295,4554,4660]],"native":"Na Hiku"},{"name":"The Backbone","lines":[[424,4301],[5191,5340,5056],[4757,5056],[4699,4763]],"native":"Ka Iwikuamo’o"},{"name":"The Chief's Fishline","lines":[[6527,6580,6615,6553,6380,6262,6247,6241,6165,6134,6084,5953],[5984,5953,5944]],"native":"Manaiakalani"},{"name":"Navigator's Triangle","lines":[[7924,7557,7001,7924],[7417,7528,7796,7949,7924,7796]]},{"name":"Kite of Kawelo","lines":[[15,8775,8781,39,15],[8728,8781],[21,15],[188,99],[39,188],[8775,8688]],"native":"Ka Lupe o Kawelo"},{"name":"Chief Frigate Bird","lines":[[542,403,264,168,21]],"native":"`Iwa Keli`i"},{"name":"Cared for by Moon","lines":[[4763,4730],[4853,4656]],"native":"Hanaiakamalama"},{"name":"The Pointers","lines":[[5460,5267]],"native":"Nakuhikuhi"},{"name":"Leo","lines":[[4534,4357,4359,3982,3975,4057,4031,3905,3873],[4534,4359]],"native":"Ka`ohiweliweli"}]},{"id":"maori","name":"Māori","region":"Oceania","licence":"Text and lines: CC BY-SA","source":"https://github.com/Stellarium/stellarium-skycultures/tree/master/maori","constellations":[{"name":"Taki-o-Autahi","lines":[[4763,4730],[4853,4656]]},{"name":"Te Taura-o-te-waka-o-tamarereti","lines":[[5267,5460]]},{"name":"Tau-toro","lines":[[1948,1903,1852]]},{"name":"The Great Boat of Tama Rereti","lines":[[6241,6247,6262,6380,6553,6615,6580,6527,6508]]},{"name":"Matakarehu","lines":[[1457,1412,1346,1373,1409]]},{"name":"The Sail of Tainui","lines":[[1457,1412,1346,1373,1409],[1457,1409],[1346,1852],[1142,1346],[1948,1903,1852]]}]},{"id":"tongan","name":"Tongan","region":"Oceania","licence":"CC BY-SA","source":"https://github.com/Stellarium/stellarium-skycultures/tree/master/tongan","constellations":[{"name":"Southern Wild Duck","lines":[[4763,4730],[4853,4656]],"native":"Toloatonga"},{"name":"Two Men","lines":[[2890,2990]],"native":"Lua tangata"},{"name":"Wild Duck","lines":[[1948,1903,1852]],"native":"Toloa"},{"name":"Pigeon Perch","lines":[[1457,1411,1346,1373,1409]],"native":"Tu'ulalupe"},{"name":"Big Wild Duck","lines":[[3485,3699],[3307,3734]],"native":"Toloalahi"},{"name":"Mound Top","lines":[[5460,5267]],"native":"Fungasia"},{"name":"String of fishes","lines":[[1788,1852,1903,1948,1931,1900,1892]],"native":"Tuinga ika"},{"name":"Wild Duck's Point of Land","lines":[[1903,3696,4739]],"native":"Houmatoloa"},{"name":"Two Carriers","lines":[[4737,4983,4968]],"native":"Fatanalua"},{"name":"Cloud of 'Uvea","lines":[[5971,5947,5889,5849,5793,5747,5778]],"native":"ʻAo ʻo ʻUvea"},{"name":"Wing of Tafahi","lines":[[542,403,264,168,21]],"native":"Kapakau'o'tafahi"}]},{"id":"boorong","name":"Boorong (Australia)","region":"Oceania","licence":"Data and illustrations: CC-BY SA","source":"https://github.com/Stellarium/stellarium-skycultures/tree/master/boorong","constellations":[{"name":"Long-necked tortoise","lines":[[2985,3067],[2985,2905],[3067,2973],[2905,2973,2857,2816]],"native":"Wanjel"},{"name":"Fan-tailed cockatoo","lines":[[2852,2890],[2896,2890,2924],[2890,3040],[2924,2930,2962,3013,3040]],"native":"Yurree"},{"name":"Two teenage boys","lines":[[1963,1955,1948],[1955,1988,2024,2037],[1852,1834],[1948,1931],[1873,1868,1861,1863]],"native":"Kulkunbulla"},{"name":"Girls","lines":[[1151,1145,1140,1142,1156,1165,1180,1178,1183,1172]],"native":"Lamankurrk"},{"name":"Red kangaroo","lines":[[1203,1228,1306,1454],[1605,1494,1306],[1494,1708],[1738,1729],[1641,1738,1729,1760],[1738,1760],[1641,1612,1454,1306],[1605,1824],[1760,1824]],"native":"Purra"},{"name":"Ring-tail possum","lines":[[4744,4730,4656,4763],[4754,4749,4702,4706,4739,4768,4823,4853,4897]],"native":"Bunya"},{"name":"Red-rumped parrot","lines":[[5984,5953,5944,5928],[6165,6134,6084,5824]],"native":"Djuit"},{"name":"Crow","lines":[[2515,2435,2326,2281,2290]],"native":"War"},{"name":"Female crow, wife of War","lines":[[4114,4177,4198],[4239,4257,4337]],"native":"Collowgulloric War"},{"name":"Owlet nightjar","lines":[[468,460,472]],"native":"Yerredetkurrk"},{"name":"Needlewood hakea and willie wagtails","lines":[[4983,4954,4883,4869,4738,4707],[4983,4984,4949,4792]],"native":"Tourtchinboiongerra"},{"name":"Red-kneed dotterel","lines":[[5593,5482,5463],[5482,5546],[5482,5349],[5482,5460]],"native":"Berm-Berm-Gle"},{"name":"Australian kestrel","lines":[[6527,6580],[6508,6580,6615],[6580,6523,6380],[6580,6832]],"native":"Karik Karik"},{"name":"Mallee fowl","lines":[[7001,7056],[7054,7056],[7054,7139,7140,7162,7178,7192,7102,7106,7043,7056]],"native":"Neilloan"},{"name":"Jacky lizard","lines":[[2580,2607,2616,2640],[2686,2704,2718,2745,2749,2750,2734,2724,2708,2688],[2614,2611],[2614,2567],[2611,2646,2637,2611]],"native":"Unurgunite"},{"name":"Female brolga","lines":[[98,98]],"native":"Kourt-chin"},{"name":"Male brolga","lines":[[1010,1083,1175,1744,2736,2662,2803],[1744,1922],[1744,1208]],"native":"Kourt-chin"},{"name":"Great fish","lines":[[7871,7918,7928,7948]],"native":"Otchocut"},{"name":"Wedge tailed eagle","lines":[[2294,2429,2491,2596,2657]],"native":"Warepil"},{"name":"Female eagle, wife of Warepil","lines":[[1560,1617,1679,1696,1705,1702],[1679,1713]],"native":"Collowgulloric Warepil"},{"name":"Emu","lines":[[5649,5649]],"native":"Tchingal"},{"name":"Purple crowned lorikeet","lines":[[7429,7519,7595,7648,7693],[7525,7557,7602]],"native":"Totyarguil"},{"name":"Meat ant","lines":[[5200,5185,5235,5340,5475,5477],[5340,5506],[5340,5429],[5506,5681],[5429,5602,5681]],"native":"Marpeankurrk"},{"name":"Galaxy","lines":[[6859,6859]],"native":"Warring"},{"name":"Singing bushlark","lines":[[5201,5201]],"native":"Weetkurrk"},{"name":"Pink cockatoo","lines":[[1457,1457]],"native":"Gellarlec"},{"name":"Species of ant","lines":[[7754,7754]],"native":"Collenbitchick"},{"name":"Boomerang","lines":[[7122,7188,7242,7259,7254,7226,7152,7021]],"native":"Won"},{"name":"The maned snake","lines":[[3634,3634]],"native":"Mindi"}]},{"id":"sami","name":"Sámi","region":"Europe","licence":"CC BY-SA","source":"https://github.com/Stellarium/stellarium-skycultures/tree/master/sami","constellations":[{"name":"Sarva the Elk","lines":[[542,403,264,168,21],[403,915,1017,936],[1017,1122,1220,1203],[1122,1708,1791],[1708,1641,1577]]},{"name":"Favdna's Bow and Arrow","lines":[[5191,5054,4905,4660,4295],[4301,4554]]},{"name":"Galla's Sons","lines":[[1948,1903,1852]]},{"name":"Sky Support","lines":[[424,424]]},{"name":"Favdna","lines":[[5340,5340]]},{"name":"The Runner","lines":[[7001,7001]]},{"name":"Morning Star","lines":[[7557,7557]]},{"name":"Pack of Dogs","lines":[[1165,1165]]},{"name":"Galla","lines":[[2943,2943]]},{"name":"The Ski Runners","lines":[[2890,2890],[2990,2990]]}]},{"id":"norse","name":"Norse","region":"Europe","licence":"CC BY-SA","source":"https://github.com/Stellarium/stellarium-skycultures/tree/master/norse","constellations":[{"name":"Aurvandil's Toe","lines":[[5778,5747,5793,5849,5889,5947,5971]]},{"name":"Wolf's Mouth","lines":[[1457,1412,1346,1373,1409]]},{"name":"The Fishermen","lines":[[1948,1903,1852]]},{"name":"Woman's Cart","lines":[[424,6789,6322,5903,6116,5735,5563,5903]]},{"name":"Man's Cart","lines":[[5191,5054,4905,4660,4301,4295,4554,4660]]},{"name":"The Asar Battlefield","lines":[[2095,2088,1708,1612,1577],[1791,1577],[1791,2095]]}]}]
\ No newline at end of file
Packages/MoonriseKit/Sources/SkyRenderer/SkyScene.swift +23
@@ -26,6 +26,23 @@ public struct Constellation: Sendable, Decodable {
2626 public var lines: [[Int]]
2727}
2828
29/// Another culture's figures over the same stars, from Stellarium's sky cultures (CC BY-SA).
30public struct SkyCulture: Sendable, Decodable, Identifiable {
31 public struct Figure: Sendable, Decodable {
32 public var name: String
33 public var native: String?
34 /// Polylines of HR numbers.
35 public var lines: [[Int]]
36 }
37
38 public var id: String
39 public var name: String
40 public var region: String
41 public var licence: String
42 public var source: URL
43 public var constellations: [Figure]
44}
45
2946public enum Catalog {
3047 /// Yale Bright Star Catalogue, 5th ed. (VizieR V/50): HR, RA and Dec (J2000, degrees), V, B−V,
3148 /// proper motion in RA (× cos dec) and Dec (arcsec/yr).
@@ -35,6 +52,12 @@ public enum Catalog {
3552 return rows.map { Star(hr: Int($0[0]), ra: $0[1], dec: $0[2], magnitude: $0[3], colorIndex: $0[4], pmRA: $0[5], pmDec: $0[6]) }
3653 }()
3754
55 /// Built by scripts/make-skycultures.py.
56 public static let skyCultures: [SkyCulture] = {
57 let url = Bundle.module.url(forResource: "skycultures", withExtension: "json")!
58 return try! JSONDecoder().decode([SkyCulture].self, from: Data(contentsOf: url))
59 }()
60
3861 public static let constellations: [Constellation] = {
3962 let url = Bundle.module.url(forResource: "constellations", withExtension: "json")!
4063 return try! JSONDecoder().decode([Constellation].self, from: Data(contentsOf: url))
Packages/MoonriseKit/Sources/SkyRenderer/SkyView.swift +33 −1
@@ -78,12 +78,15 @@ public struct SkyView: View {
7878 public var centerAltitude: Double
7979 public var fieldOfView: Double
8080 public var style: SkyStyle
81 /// Figures to draw instead of the IAU constellation lines.
82 public var culture: SkyCulture?
8183 /// Called after each draw with the time the draw took.
8284 public var onDraw: (@Sendable (Duration) -> Void)?
8385
84 public init(scene: SkyScene, centerAzimuth: Double = 180, centerAltitude: Double = 55, fieldOfView: Double = 110, style: SkyStyle = SkyStyle(), onDraw: (@Sendable (Duration) -> Void)? = nil) {
86 public init(scene: SkyScene, centerAzimuth: Double = 180, centerAltitude: Double = 55, fieldOfView: Double = 110, style: SkyStyle = SkyStyle(), culture: SkyCulture? = nil, onDraw: (@Sendable (Duration) -> Void)? = nil) {
8587 self.scene = scene
8688 self.style = style
89 self.culture = culture
8790 self.centerAzimuth = centerAzimuth
8891 self.centerAltitude = centerAltitude
8992 self.fieldOfView = fieldOfView
@@ -104,6 +107,10 @@ public struct SkyView: View {
104107 }
105108
106109 func drawConstellations(_ context: inout GraphicsContext, _ p: Projection) {
110 if let culture {
111 drawCulture(culture, &context, p)
112 return
113 }
107114 var path = Path()
108115 for c in Catalog.constellations {
109116 for line in c.lines {
@@ -119,6 +126,31 @@ public struct SkyView: View {
119126 context.stroke(path, with: .color(style.line), lineWidth: 0.6)
120127 }
121128
129 /// A culture's figures, named at the middle of their visible stars once zoomed in
130 /// (closer for cultures with many small figures).
131 func drawCulture(_ culture: SkyCulture, _ context: inout GraphicsContext, _ p: Projection) {
132 var path = Path()
133 let labelBelow = culture.constellations.count > 60 ? 60.0 : 110.0
134 for figure in culture.constellations {
135 var points: [CGPoint] = []
136 for line in figure.lines {
137 for (a, b) in zip(line, line.dropFirst()) {
138 guard let ha = scene.starsByHR[a], let hb = scene.starsByHR[b],
139 ha.altitude > -5 || hb.altitude > -5,
140 let pa = p.point(ha), let pb = p.point(hb) else { continue }
141 path.move(to: pa)
142 path.addLine(to: pb)
143 points += [pa, pb]
144 }
145 }
146 if fieldOfView <= labelBelow, points.count > 1 {
147 let c = CGPoint(x: points.map(\.x).reduce(0, +) / Double(points.count), y: points.map(\.y).reduce(0, +) / Double(points.count))
148 context.draw(Text(figure.name).font(.caption2).foregroundStyle(style.muted), at: c)
149 }
150 }
151 context.stroke(path, with: .color(style.line), lineWidth: 0.6)
152 }
153
122154 func drawStars(_ context: inout GraphicsContext, _ p: Projection) {
123155 for s in scene.stars where s.position.altitude > 0 {
124156 guard let pt = p.point(s.position) else { continue }
Packages/MoonriseKit/Tests/SkyRendererTests/SkyRenderTests.swift +15
@@ -62,3 +62,18 @@ let evening = Date(timeIntervalSince1970: 1_792_202_400) // 2026-10-17T02:00:00Z
6262 let renderer = ImageRenderer(content: SkyView(scene: scene, style: .night).frame(width: 393, height: 852))
6363 #expect(renderer.cgImage != nil)
6464}
65
66@Test func skyCulturesUseCatalogueStars() {
67 let cultures = Catalog.skyCultures
68 #expect(cultures.count == 10)
69 let known = Set(Catalog.stars.map(\.hr))
70 for c in cultures {
71 #expect(!c.constellations.isEmpty, "\(c.id)")
72 #expect(c.licence.contains("BY-SA") || c.licence.contains("BY SA"), "\(c.id)")
73 for f in c.constellations {
74 #expect(f.lines.allSatisfy { $0.count > 1 && $0.allSatisfy(known.contains) }, "\(c.id) \(f.name)")
75 }
76 }
77 // The Norse Wolf's Mouth is the Hyades and includes Aldebaran (HR 1457).
78 #expect(cultures.first { $0.id == "norse" }?.constellations.contains { $0.name == "Wolf's Mouth" && $0.lines.joined().contains(1457) } == true)
79}
THIRD_PARTY.org +3
@@ -4,6 +4,9 @@
44|-
55| Astronomy Engine v2.1.19, Copyright (c) 2019-2025 Don Cross | =Packages/MoonriseKit/Sources/CAstronomy= | MIT (=LICENSE= alongside) | https://github.com/cosinekitty/astronomy |
66| Yale Bright Star Catalogue, 5th rev. ed. (Hoffleit & Warren 1991) | =Packages/MoonriseKit/Sources/SkyRenderer/Resources/bsc5.json= | See VizieR policy; licence statement pending | https://cdsarc.cds.unistra.fr/viz-bin/cat/V/50 |
7| BSC5 proper motions (pmRA, pmDE) | same file, columns 6 and 7 | as above | https://cdsarc.cds.unistra.fr/viz-bin/cat/V/50 |
8| Stellarium sky cultures: Chinese, Indian, Mongolian, Japanese moon stations, Hawaiian starlines, Māori, Tongan, Boorong, Sámi, Norse (lines and names, converted to HR numbers by =scripts/make-skycultures.py=) | =Packages/MoonriseKit/Sources/SkyRenderer/Resources/skycultures.json= | CC BY-SA (per culture, stated in each culture's description.md); the converted file is under the same licence | https://github.com/Stellarium/stellarium-skycultures |
9| Hipparcos main catalogue positions (used only to match HIP to HR when building skycultures.json; not bundled) | — | ESA | https://cdsarc.cds.unistra.fr/viz-bin/cat/I/239 |
710| ConstellationLines v1.4, Copyright (c) 2005-2026 Marc van der Sluys | =Packages/MoonriseKit/Sources/SkyRenderer/Resources/constellations.json= | CC BY 4.0 | https://github.com/MarcvdSluys/ConstellationLines, doi:10.5281/zenodo.10397192 |
811| Natural Earth 1:110m coastline v5.1.2 | =Packages/MoonriseKit/Sources/SkyRenderer/Resources/coastline.json= | Public domain | https://www.naturalearthdata.com |
912| Launch Library 2 (The Space Devs) | fetched at runtime by =server/= | Free API; credit shown in the app | https://thespacedevs.com/llapi |
scripts/make-skycultures.py added +117
@@ -0,0 +1,117 @@
1#!/usr/bin/env python3
2"""Builds SkyRenderer/Resources/skycultures.json from Stellarium sky cultures (CC BY-SA only).
3
4Usage: make-skycultures.py HIP_TSV
5
6HIP_TSV is VizieR I/239/hip_main with columns HIP, RAICRS, DEICRS, Vmag (Vmag < 7.2):
7https://vizier.cds.unistra.fr/viz-bin/asu-tsv?-source=I/239/hip_main&-out=HIP,RAICRS,DEICRS,Vmag&Vmag=%3C7.2&-out.max=unlimited
8
9Stellarium lines use Hipparcos numbers; the app's catalogue is the Bright Star Catalogue (HR).
10Each HIP star is matched to the BSC star within 0.05 degrees. Lines are split where a star has no match
11(fainter than the BSC's limit), and segments with fewer than two stars are dropped.
12"""
13import json
14import math
15import sys
16import urllib.request
17from pathlib import Path
18
19ROOT = Path(__file__).resolve().parent.parent
20RES = ROOT / "Packages/MoonriseKit/Sources/SkyRenderer/Resources"
21BASE = "https://raw.githubusercontent.com/Stellarium/stellarium-skycultures/master"
22
23# id, display name. All CC BY-SA in their description.md as of 2026-10-18.
24CULTURES = [
25 ("chinese", "Chinese"),
26 ("indian", "Indian (Vedic)"),
27 ("mongolian", "Mongolian"),
28 ("japanese_moon_stations", "Japanese moon stations"),
29 ("hawaiian_starlines", "Hawaiian"),
30 ("maori", "Māori"),
31 ("tongan", "Tongan"),
32 ("boorong", "Boorong (Australia)"),
33 ("sami", "Sámi"),
34 ("norse", "Norse"),
35]
36
37
38def fetch(url):
39 with urllib.request.urlopen(url, timeout=60) as r:
40 return r.read().decode("utf-8")
41
42
43def license_section(md):
44 out, on = [], False
45 for line in md.splitlines():
46 if line.startswith("#"):
47 on = "licen" in line.lower()
48 continue
49 if on and line.strip():
50 out.append(line.strip())
51 return " ".join(out)
52
53
54def main():
55 hip = {}
56 for line in open(sys.argv[1]):
57 p = line.rstrip("\n").split("\t")
58 if len(p) == 4 and p[0].strip().isdigit() and p[1].strip() and p[2].strip():
59 hip[int(p[0])] = (float(p[1]), float(p[2]), float(p[3] or 99))
60
61 bsc = json.load(open(RES / "bsc5.json"))
62 cells = {}
63 for row in bsc:
64 cells.setdefault((int(row[2])), []).append(row)
65
66 def hr_for(h):
67 if h not in hip:
68 return None
69 ra, dec, _ = hip[h]
70 best = None
71 for d in (int(dec) - 1, int(dec), int(dec) + 1):
72 for row in cells.get(d, []):
73 dra = (row[1] - ra + 180) % 360 - 180
74 sep = math.hypot(dra * math.cos(math.radians(dec)), row[2] - dec)
75 if sep < 0.05 and (best is None or sep < best[0]):
76 best = (sep, int(row[0]))
77 return best[1] if best else None
78
79 out = []
80 for cid, name in CULTURES:
81 index = json.loads(fetch(f"{BASE}/{cid}/index.json"))
82 lic = license_section(fetch(f"{BASE}/{cid}/description.md"))
83 assert "BY-SA" in lic.replace("-BY SA", "BY-SA").replace("BY SA", "BY-SA"), (cid, lic)
84 constellations = []
85 for c in index.get("constellations", []):
86 segments = []
87 for line in c.get("lines", []):
88 current = []
89 for h in line:
90 hr = hr_for(h) if isinstance(h, int) else None
91 if hr is None:
92 if len(current) > 1:
93 segments.append(current)
94 current = []
95 else:
96 current.append(hr)
97 if len(current) > 1:
98 segments.append(current)
99 if not segments:
100 continue
101 cn = c.get("common_name", {})
102 entry = {"name": cn.get("english") or cn.get("native") or c["id"], "lines": segments}
103 if cn.get("native") and cn.get("native") != entry["name"]:
104 entry["native"] = cn["native"]
105 constellations.append(entry)
106 out.append({
107 "id": cid, "name": name, "region": index.get("region", ""),
108 "licence": lic, "source": f"https://github.com/Stellarium/stellarium-skycultures/tree/master/{cid}",
109 "constellations": constellations,
110 })
111 print(f"{cid}: {len(constellations)} of {len(index.get('constellations', []))} figures", file=sys.stderr)
112
113 (RES / "skycultures.json").write_text(json.dumps(out, ensure_ascii=False, separators=(",", ":")))
114
115
116if __name__ == "__main__":
117 main()