@rr0/ufoathome 0.28.0 → 0.29.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,30 @@ 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
+ Both appear in the recorder's read-only "Sky:" line, with a button to turn the witness toward one.
220
+
221
+ **Regenerating the comet catalog.** `src/engine/astronomy/cometCatalog.ts` is generated by
222
+ `npm run build:comets`, which asks [JPL Horizons](https://ssd.jpl.nasa.gov/horizons/) for osculating elements at
223
+ each apparition's own perihelion and caches the answers under `scripts/data/horizons/` (gitignored). The list of
224
+ apparitions, and the peak magnitudes and tail lengths recorded at the time, are hand-entered in
225
+ `scripts/build-comet-catalog.ts` — the orbits are looked up, the brightness is an observation, and the script's
226
+ own doc comment explains why the two cannot come from the same place. The generated file *is* checked in.
227
+
204
228
  The UFO shape itself deliberately stays a 2D overlay on top of the 3D decor, never "upgraded" to a 3D object: it's
205
229
  what the witness reported — possibly a misidentification or optical effect — not something to interpret as a real
206
230
  3D shape. Only the surrounding environment, independently computable from real astronomy, is rendered in 3D.
@@ -646,6 +670,7 @@ npm run build:embed-ufo # build dist-embed-ufo/rr0-ufo.mjs
646
670
  npm run build:embed-scene # build dist-embed-scene/rr0-scene.mjs
647
671
  npm run build:embed-eyewitness # build dist-embed-eyewitness/rr0-eyewitness.mjs
648
672
  npm run build:all # all four
673
+ npm run build:comets # regenerate the comet catalog from JPL Horizons
649
674
  ```
650
675
 
651
676
  ## 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",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, au {bearing} — environ {rate}/h sous ce ciel",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",showMeteor:"Montrer un météore",skyComet:"La {name}, magnitude {magnitude}, à {altitude}° de hauteur au {bearing}, queue longue de {tail}°",skyCometNoTail:"La {name}, magnitude {magnitude}, à {altitude}° de hauteur au {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 au {bearing} — mais à {elongation}° du Soleil seulement",showComet:"Montrer la comète",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};