@rr0/ufoathome 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -201,6 +201,48 @@ To regenerate it: download `hyg/CURRENT/hygdata_v41.csv` from that repo into `sc
201
201
  (gitignored — not checked in, ~34MB), then run `npm run build:stars`. The generated `.bin`/`.json` pair *is*
202
202
  checked in (~400KB) since it's small and doesn't need regenerating on every install.
203
203
 
204
+ **What else was in that sky.** Beside the Sun, Moon, planets and stars, the scene states — and where it can,
205
+ draws — the things that were genuinely up there and are genuinely mistaken for something else. Two so far, chosen
206
+ because their record is complete for every date this project can reconstruct, with no lookup, no key and no
207
+ coverage floor:
208
+
209
+ - **Meteor showers** (`src/engine/astronomy/MeteorShowers.ts`). A shower is a position in the Earth's own orbit,
210
+ so the Perseids of 1948 are the Perseids of today. Rates are corrected for the radiant's real altitude, and the
211
+ strongest statement is the negative one: a radiant below the horizon can have produced nothing.
212
+ - **Comets** (`src/engine/astronomy/Comets.ts`). Twenty-three naked-eye apparitions from Halley 1910 to
213
+ Tsuchinshan-ATLAS 2024, each with the orbit it was actually on that year. Positions come from a universal-variable
214
+ Kepler propagation (`Orbit.ts`) checked against JPL Horizons to about a thousandth of a degree; brightness is
215
+ modelled from magnitudes recorded at the time, and the tail is a real length in space, projected — so it
216
+ shortens when it points away from the observer instead of across their sky. Half the apparitions have no
217
+ recorded tail length and are drawn with no tail at all.
218
+
219
+ - **Satellites** (`src/engine/astronomy/Satellites.ts`). Not which one — historical orbital elements
220
+ cannot be obtained, and propagating today's back to 1965 would invent a precise, confident pass.
221
+ What is complete is the ILLUMINATION: `h = R(sec B - 1)` gives how high the Earth's shadow stood
222
+ above the witness, so deep in the night nothing in low orbit is lit and a light crossing the sky
223
+ then was not a satellite. Being lit and being seen are kept apart — everything in orbit is sunlit
224
+ by day, and an Iridium flare at magnitude -8 was genuinely watched at noon. Also complete, and
225
+ from CelesTrak's SATCAT: how many tracked objects were in orbit that month, and when each named
226
+ class existed (Echo balloons, Iridium flares, ISS, Starlink trains).
227
+
228
+ All three appear in the recorder's read-only "Sky:" line, with a button to turn the witness toward
229
+ the meteor or the comet.
230
+
231
+ **Regenerating the satellite catalog.** `src/engine/astronomy/satelliteCatalog.ts` is generated by
232
+ `npm run build:satellites` from [CelesTrak's SATCAT](https://celestrak.org/pub/satcat.csv) (CC BY
233
+ 4.0), cached under `scripts/data/` (gitignored). Only its LAUNCH_DATE and DECAY_DATE columns are
234
+ read: the orbital fields hold each object's *current* state, which for anything that has re-entered
235
+ is its state on the way down — Echo 1 is listed at 419 x 394 km and spent its life near 1500 — so
236
+ using them to describe a historical orbit would be quietly wrong. Which classes are worth naming,
237
+ and how bright they got, stay hand-entered in the script; every date is derived.
238
+
239
+ **Regenerating the comet catalog.** `src/engine/astronomy/cometCatalog.ts` is generated by
240
+ `npm run build:comets`, which asks [JPL Horizons](https://ssd.jpl.nasa.gov/horizons/) for osculating elements at
241
+ each apparition's own perihelion and caches the answers under `scripts/data/horizons/` (gitignored). The list of
242
+ apparitions, and the peak magnitudes and tail lengths recorded at the time, are hand-entered in
243
+ `scripts/build-comet-catalog.ts` — the orbits are looked up, the brightness is an observation, and the script's
244
+ own doc comment explains why the two cannot come from the same place. The generated file *is* checked in.
245
+
204
246
  The UFO shape itself deliberately stays a 2D overlay on top of the 3D decor, never "upgraded" to a 3D object: it's
205
247
  what the witness reported — possibly a misidentification or optical effect — not something to interpret as a real
206
248
  3D shape. Only the surrounding environment, independently computable from real astronomy, is rendered in 3D.
@@ -646,6 +688,8 @@ npm run build:embed-ufo # build dist-embed-ufo/rr0-ufo.mjs
646
688
  npm run build:embed-scene # build dist-embed-scene/rr0-scene.mjs
647
689
  npm run build:embed-eyewitness # build dist-embed-eyewitness/rr0-eyewitness.mjs
648
690
  npm run build:all # all four
691
+ npm run build:comets # regenerate the comet catalog from JPL Horizons
692
+ npm run build:satellites # regenerate the satellite catalog from CelesTrak's SATCAT
649
693
  ```
650
694
 
651
695
  ## License
@@ -1 +1 @@
1
- const e={oval:"Ovale",polygon:"Polygone",addVertex:"Ajouter un sommet",deleteVertex:"Supprimer le sommet",notAPolygon:"Sélectionnez une seule forme polygonale",tooFewVertices:"Une forme a besoin d'au moins 3 points",color:"Couleur",transparency:"Transparence",halo:"Halo",shape:"Forme",shapeTitle:"Nom",objectSize:"Essayer une taille",objectDistance:"à une distance de",apparentSize:"soit {deg}° — {moons}× la Lune",utcOffset:"Fuseau horaire",utcOffsetPlaceholder:"d'après la longitude",objectSizePlaceholder:"largeur supposée",objectDistancePlaceholder:"distance supposée",realSizeBetween:"Largeur réelle : entre {min} et {max} m, d'après ce qu'il croise",realSizeAtLeast:"Largeur réelle : au moins {min} m, d'après ce qu'il passe derrière",realSizeAtMost:"Largeur réelle : au plus {max} m, d'après ce qu'il passe devant",realSizeUnknown:"Largeur réelle indéterminée : rien dans la scène ne croise sa ligne de visée",realSizeContradiction:"Contradiction : les passages déclarés ne peuvent pas être vrais ensemble",realDistanceHere:" — soit ici entre {min} et {max} m",addShape:"Ajouter une forme",deleteShape:"Supprimer la forme",play:"Lecture",pause:"Pause",noDuration:"Aucune durée d'observation",autoReplay:"Lecture automatique",group:"Grouper",ungroup:"Dégrouper",bringToFront:"Placer devant",sendToBack:"Placer derrière",contextMenuDelete:"Supprimer",confirmDeleteShape:"Supprimer {name} ? Cette action est irréversible.",confirmDeleteShapes:"Supprimer {count} formes ? Cette action est irréversible.",onlyOneShape:"Il n'y a qu'une seule forme",alreadyAtFront:"Cette forme est déjà la plus en avant",alreadyAtBack:"Cette forme est déjà la plus en arrière",needTwoShapesToGroup:"Sélectionnez au moins deux formes pour les grouper",notGrouped:"Cette forme ne fait pas partie d'un groupe",multipleShapesSelected:"Plusieurs formes sélectionnées — sélectionnez-en une seule pour modifier ceci",cloudBase:"Base des nuages",elevation:"Altitude",samplingRate:"Échantillonnage",duration:"Durée",currentPosition:"Position actuelle",switchToElapsed:"cliquer pour afficher la durée écoulée",switchToClockTime:"cliquer pour afficher l'heure de l'observation",durationPlaceholder:"durée de l'observation",durationImprecise:"Ces dates ne permettent pas de déterminer précisément une durée — saisissez-la manuellement.",export:"Exporter le JSON",importFile:"Charger un fichier JSON",importUrl:"Ou charger depuis une URL",importUrlPlaceholder:"https://…/sighting.json",importButton:"Charger",importError:"Impossible de charger cet enregistrement — vérifiez le fichier ou l'URL et réessayez.",record:"Enregistrer",stop:"Arrêter",according:"selon",sourceElevation:"Relief",sourceImagery:"Imagerie",placeName:"Lieu",placeNamePlaceholder:"Valensole, France",searchPlace:"Localiser",placeMatch:"Correspondances",placeSearching:"Recherche du lieu…",placeMatchFound:"lieu trouvé",placeMatchesFound:"lieux trouvés",placeNotFound:"Aucun lieu de ce nom",placeSearchFailed:"Recherche de lieu momentanément indisponible",utcOffsetImplausible:"Ce fuseau ne correspond pas à la longitude saisie, dont l'heure solaire est UTC{solar} — la scène et le relevé météo obéissent pourtant à ce qui est déclaré ici. Videz le champ pour le déduire de la longitude.",timeZoneManual:"décalage saisi",altitudeAboveSeaLevel:"Altitude du témoin au-dessus du niveau de la mer — le sol du lieu saisi en fixe le minimum : un témoin dans les Alpes n'est pas à 0 m.",groundAt:"sol à {m} m",latitude:"Latitude",longitude:"Longitude",heading:"Orientation",headingPlaceholder:"inconnu",pitch:"Inclinaison",observationTime:"Début de l'observation",observationEndTime:"Fin de l'observation",edtfInvalid:"Date/heure EDTF invalide (ex. 1965-07-01T05:00, 2025-06?, 2025~).",edtfPlaceholder:"AAAA-MM-JJThh:mm[?~%] ou hh:mm",observationTimeHint:"EDTF — ex. 1965-07-01T05:00, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:00 si la date est inconnue",observationEndTimeHint:"EDTF — ex. 1965-07-01T05:10, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:10 si la date est inconnue",presetsGroupLabel:"Forme de l'ovni",witnessId:"ID témoin",witnessDirName:"Répertoire du témoin",witnessTitle:"Titre du témoin",witnessLastName:"Nom de famille du témoin",witnessFirstNames:"Prénoms du témoin",caseId:"ID de l'affaire",description:"Description",tags:"Mots-clés",tagsPlaceholder:"séparés par des virgules",weather:"Météo",shapeGroup:"Forme",soundGroup:"Son",temporalGroup:"Date et heure",locationGroup:"Lieu",observationGroup:"Observation",witnessGroup:"Témoin",circumstancesGroup:"Circonstances",weatherInferred:"D'après les relevés",weatherInferredTitle:"La météo n'est pas un témoignage : c'est un fait mesurable, relevé pour la date, l'heure et le lieu de l'observation. Décochez pour saisir les conditions rapportées par le témoin, qui priment alors sur le relevé.",weatherLookingUp:"Recherche du relevé…",weatherNeedsDateAndPlace:"Date complète et lieu requis pour retrouver le relevé",weatherNoRecord:"Aucun relevé pour cette date et ce lieu",weatherLookupFailed:"Relevés météo momentanément inaccessibles",cloudCover:"Couverture nuageuse",cloudDarkness:"Obscurité des nuages",precipitationType:"Précipitations",precipitationNone:"Aucune",precipitationRain:"Pluie",precipitationSnow:"Neige",precipitationHail:"Grêle",precipitationIntensity:"Intensité",windDirection:"Direction du vent",windSpeed:"Force du vent",storm:"Orage",soundKind:"Son",soundNone:"Aucun (silencieux)",soundHum:"Bourdonnement",soundWhistle:"Sifflement",soundRumble:"Grondement",soundCrackle:"Crépitement",soundVolume:"Intensité sonore",soundPitch:"Hauteur",soundSrc:"Enregistrement",soundSrcPlaceholder:"URL d'un enregistrement réel",lensFlareBrightness:"Intensité lumineuse",instrument:"Observé avec",decorAircraft:"Aéronef",skyShowerActive:"Ciel : {name} — radiant à {altitude}° de hauteur, au {bearing} — environ {rate}/h sous ce ciel",skyShowerBelowHorizon:"Ciel : {name} est actif, mais son radiant est sous l'horizon — il n'a rien pu produire",skyNothingActive:"Ciel : aucune pluie de météores active à cette date",showMeteor:"Montrer un météore",skyUnknown:"Ciel : indéterminable sans date ni lieu",decorAltitude:"Altitude",decorLights:"Feux",lookAtDecor:"Regarder cet élément",decorLightsNone:"aucun",cameraDevice:"Appareil photo/vidéo",decor:"Décor",decorBuilding:"Bâtiment",decorTree:"Arbre",decorStreetlight:"Lampadaire",decorVehicle:"Véhicule",decorWitness:"Autre témoin",addDecor:"Ajouter",deleteDecor:"Supprimer l'élément de décor",decorEast:"Distance à l'est",decorNorth:"Distance au nord",decorHeading:"Orientation",decorLit:"Allumé",decorTitle:"Nom",decorSightingUrl:"URL de l'enregistrement du témoin",viewTestimony:"Voir le témoignage",noWitnessRecording:"Aucune URL d'enregistrement définie pour ce témoin",masks:"Masque",addWitness:"Ajouter un témoin",decorFloors:"Étages",decorOccupiedFloor:"Étage occupé",decorWitnessSide:"Emplacement du témoin",decorWitnessSideNone:"Non présent",decorWindows:"Fenêtres",decorSideFront:"Avant",decorSideBehind:"Arrière",decorSideLeft:"Gauche",decorSideRight:"Droite",decorSideFrontLeft:"Avant-gauche",decorSideFrontRight:"Avant-droit",decorSideBehindLeft:"Arrière-gauche",decorSideBehindRight:"Arrière-droit"};export{e as ufoRecorderMessages_fr};
1
+ const e={oval:"Ovale",polygon:"Polygone",addVertex:"Ajouter un sommet",deleteVertex:"Supprimer le sommet",notAPolygon:"Sélectionnez une seule forme polygonale",tooFewVertices:"Une forme a besoin d'au moins 3 points",color:"Couleur",transparency:"Transparence",halo:"Halo",shape:"Forme",shapeTitle:"Nom",objectSize:"Essayer une taille",objectDistance:"à une distance de",apparentSize:"soit {deg}° — {moons}× la Lune",utcOffset:"Fuseau horaire",utcOffsetPlaceholder:"d'après la longitude",objectSizePlaceholder:"largeur supposée",objectDistancePlaceholder:"distance supposée",realSizeBetween:"Largeur réelle : entre {min} et {max} m, d'après ce qu'il croise",realSizeAtLeast:"Largeur réelle : au moins {min} m, d'après ce qu'il passe derrière",realSizeAtMost:"Largeur réelle : au plus {max} m, d'après ce qu'il passe devant",realSizeUnknown:"Largeur réelle indéterminée : rien dans la scène ne croise sa ligne de visée",realSizeContradiction:"Contradiction : les passages déclarés ne peuvent pas être vrais ensemble",realDistanceHere:" — soit ici entre {min} et {max} m",addShape:"Ajouter une forme",deleteShape:"Supprimer la forme",play:"Lecture",pause:"Pause",noDuration:"Aucune durée d'observation",autoReplay:"Lecture automatique",group:"Grouper",ungroup:"Dégrouper",bringToFront:"Placer devant",sendToBack:"Placer derrière",contextMenuDelete:"Supprimer",confirmDeleteShape:"Supprimer {name} ? Cette action est irréversible.",confirmDeleteShapes:"Supprimer {count} formes ? Cette action est irréversible.",onlyOneShape:"Il n'y a qu'une seule forme",alreadyAtFront:"Cette forme est déjà la plus en avant",alreadyAtBack:"Cette forme est déjà la plus en arrière",needTwoShapesToGroup:"Sélectionnez au moins deux formes pour les grouper",notGrouped:"Cette forme ne fait pas partie d'un groupe",multipleShapesSelected:"Plusieurs formes sélectionnées — sélectionnez-en une seule pour modifier ceci",cloudBase:"Base des nuages",elevation:"Altitude",samplingRate:"Échantillonnage",duration:"Durée",currentPosition:"Position actuelle",switchToElapsed:"cliquer pour afficher la durée écoulée",switchToClockTime:"cliquer pour afficher l'heure de l'observation",durationPlaceholder:"durée de l'observation",durationImprecise:"Ces dates ne permettent pas de déterminer précisément une durée — saisissez-la manuellement.",export:"Exporter le JSON",importFile:"Charger un fichier JSON",importUrl:"Ou charger depuis une URL",importUrlPlaceholder:"https://…/sighting.json",importButton:"Charger",importError:"Impossible de charger cet enregistrement — vérifiez le fichier ou l'URL et réessayez.",record:"Enregistrer",stop:"Arrêter",according:"selon",sourceElevation:"Relief",sourceImagery:"Imagerie",placeName:"Lieu",placeNamePlaceholder:"Valensole, France",searchPlace:"Localiser",placeMatch:"Correspondances",placeSearching:"Recherche du lieu…",placeMatchFound:"lieu trouvé",placeMatchesFound:"lieux trouvés",placeNotFound:"Aucun lieu de ce nom",placeSearchFailed:"Recherche de lieu momentanément indisponible",utcOffsetImplausible:"Ce fuseau ne correspond pas à la longitude saisie, dont l'heure solaire est UTC{solar} — la scène et le relevé météo obéissent pourtant à ce qui est déclaré ici. Videz le champ pour le déduire de la longitude.",timeZoneManual:"décalage saisi",altitudeAboveSeaLevel:"Altitude du témoin au-dessus du niveau de la mer — le sol du lieu saisi en fixe le minimum : un témoin dans les Alpes n'est pas à 0 m.",groundAt:"sol à {m} m",latitude:"Latitude",longitude:"Longitude",heading:"Orientation",headingPlaceholder:"inconnu",pitch:"Inclinaison",observationTime:"Début de l'observation",observationEndTime:"Fin de l'observation",edtfInvalid:"Date/heure EDTF invalide (ex. 1965-07-01T05:00, 2025-06?, 2025~).",edtfPlaceholder:"AAAA-MM-JJThh:mm[?~%] ou hh:mm",observationTimeHint:"EDTF — ex. 1965-07-01T05:00, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:00 si la date est inconnue",observationEndTimeHint:"EDTF — ex. 1965-07-01T05:10, 2025-06? (incertain), 2025~ (approximatif), ou juste 05:10 si la date est inconnue",presetsGroupLabel:"Forme de l'ovni",witnessId:"ID témoin",witnessDirName:"Répertoire du témoin",witnessTitle:"Titre du témoin",witnessLastName:"Nom de famille du témoin",witnessFirstNames:"Prénoms du témoin",caseId:"ID de l'affaire",description:"Description",tags:"Mots-clés",tagsPlaceholder:"séparés par des virgules",weather:"Météo",shapeGroup:"Forme",soundGroup:"Son",temporalGroup:"Date et heure",locationGroup:"Lieu",observationGroup:"Observation",witnessGroup:"Témoin",circumstancesGroup:"Circonstances",weatherInferred:"D'après les relevés",weatherInferredTitle:"La météo n'est pas un témoignage : c'est un fait mesurable, relevé pour la date, l'heure et le lieu de l'observation. Décochez pour saisir les conditions rapportées par le témoin, qui priment alors sur le relevé.",weatherLookingUp:"Recherche du relevé…",weatherNeedsDateAndPlace:"Date complète et lieu requis pour retrouver le relevé",weatherNoRecord:"Aucun relevé pour cette date et ce lieu",weatherLookupFailed:"Relevés météo momentanément inaccessibles",cloudCover:"Couverture nuageuse",highCloudCover:"Nuages de glace (cirrus)",cloudDarkness:"Obscurité des nuages",precipitationType:"Précipitations",precipitationNone:"Aucune",precipitationRain:"Pluie",precipitationSnow:"Neige",precipitationHail:"Grêle",precipitationIntensity:"Intensité",windDirection:"Direction du vent",windSpeed:"Force du vent",storm:"Orage",soundKind:"Son",soundNone:"Aucun (silencieux)",soundHum:"Bourdonnement",soundWhistle:"Sifflement",soundRumble:"Grondement",soundCrackle:"Crépitement",soundVolume:"Intensité sonore",soundPitch:"Hauteur",soundSrc:"Enregistrement",soundSrcPlaceholder:"URL d'un enregistrement réel",lensFlareBrightness:"Intensité lumineuse",instrument:"Observé avec",decorAircraft:"Aéronef",skyLine:"Ciel : {parts}",skyShowerActive:"{name} — radiant à {altitude}° de hauteur, {bearing} — environ {rate}/h sous ce ciel, sur un fond sporadique de {sporadic}/h",skyShowerBelowHorizon:"{name} est actif, mais son radiant est sous l'horizon — il n'a rien pu produire",skyNothingActive:"aucune pluie de météores active à cette date — un fond sporadique d'environ {sporadic}/h",showMeteor:"Montrer un météore",skyComet:"La {name}, magnitude {magnitude}, à {altitude}° de hauteur {bearing}, queue longue de {tail}°",skyCometNoTail:"La {name}, magnitude {magnitude}, à {altitude}° de hauteur {bearing}",skyCometBelowHorizon:"La {name} était là, magnitude {magnitude}, mais sous l'horizon — personne ici ne l'a vue",skyCometInDaylight:"La {name}, magnitude {magnitude}, à {altitude}° de hauteur {bearing} — mais à {elongation}° du Soleil seulement",showComet:"Montrer la comète",skyOpticsPossible:"nuages de glace suffisants pour un halo à 22°, avec des parhélies à {parhelia}° de part et d'autre {source}",skyOpticsHaloOnly:"nuages de glace suffisants pour un halo à 22° — l'astre est trop haut pour des parhélies",skyOpticsNoIce:"aucun nuage de glace : ni halo ni parhélie",skyOpticsHidden:"des nuages de glace en altitude, mais une couche plus basse les cache",skyOpticsSun:"du Soleil",skyOpticsMoon:"de la Lune",skySatellitesLit:"l'ombre de la Terre montait à {height} km au-dessus du témoin, l'orbite basse était donc encore éclairée — {count} objets suivis étaient en orbite ce mois-là",skySatellitesLitWith:"l'ombre de la Terre montait à {height} km au-dessus du témoin, l'orbite basse était donc encore éclairée — {count} objets suivis étaient en orbite ce mois-là, dont {eras}",skySatellitesShadowed:"l'ombre de la Terre montait à {height} km au-dessus du témoin : sur les {count} objets suivis en orbite ce mois-là, rien en orbite basse n'était éclairé",skySatellitesNotYet:"rien n'était encore en orbite",skySatellitesDaylight:"tout ce qui est en orbite était éclairé, comme toujours de jour, et {eras} pouvaient l'emporter même sur ce ciel",skySatellitesDaylightOne:"tout ce qui est en orbite était éclairé, comme toujours de jour, et {eras} pouvait l'emporter même sur ce ciel",skyUnknown:"indéterminable sans date ni lieu",decorAltitude:"Altitude",decorLights:"Feux",lookAtDecor:"Regarder cet élément",decorLightsNone:"aucun",cameraDevice:"Appareil photo/vidéo",decor:"Décor",decorBuilding:"Bâtiment",decorTree:"Arbre",decorStreetlight:"Lampadaire",decorVehicle:"Véhicule",decorWitness:"Autre témoin",addDecor:"Ajouter",deleteDecor:"Supprimer l'élément de décor",decorEast:"Distance à l'est",decorNorth:"Distance au nord",decorHeading:"Orientation",decorLit:"Allumé",decorTitle:"Nom",decorSightingUrl:"URL de l'enregistrement du témoin",viewTestimony:"Voir le témoignage",noWitnessRecording:"Aucune URL d'enregistrement définie pour ce témoin",masks:"Masque",addWitness:"Ajouter un témoin",decorFloors:"Étages",decorOccupiedFloor:"Étage occupé",decorWitnessSide:"Emplacement du témoin",decorWitnessSideNone:"Non présent",decorWindows:"Fenêtres",decorSideFront:"Avant",decorSideBehind:"Arrière",decorSideLeft:"Gauche",decorSideRight:"Droite",decorSideFrontLeft:"Avant-gauche",decorSideFrontRight:"Avant-droit",decorSideBehindLeft:"Arrière-gauche",decorSideBehindRight:"Arrière-droit"};export{e as ufoRecorderMessages_fr};