@rr0/ufoathome 0.31.0 → 0.33.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
@@ -160,6 +160,30 @@ nested element's `fullscreenTarget` to its own outer stage for this.
160
160
  <rr0-scene src="sighting.json"></rr0-scene>
161
161
  ```
162
162
 
163
+ **What the sighting was made through.** An eye and a camera are not the same claim, and the difference
164
+ is geometric: a lens maps a direction as `tan θ` (a building 33 degrees off-centre comes out 42% wider
165
+ than the angle it subtends), while an eye perceives an angle as an angle wherever it falls — so the
166
+ scene renders a naked-eye sighting through an equidistant resampling pass and a photographed one
167
+ through the ordinary pinhole projection (`src/engine/instrument/`, `src/render3d/EquidistantProjectionPass.ts`).
168
+ A camera also has a FORMAT, which is part of what a photograph carries as evidence: an instrument
169
+ states the image it exposes and the lens in front of it, in millimetres, so the ratio is the shape of
170
+ the picture (a square 126 frame, a phone held upright) and `2·atan(h/2f)` is the field it takes in.
171
+ And it has SETTINGS, each kept on the pose beside the heading and the pitch, each read-only where the
172
+ device fixed it (an Instamatic's owner had one aperture, one shutter speed and one focal length):
173
+ the focal length, which is the field written the way a photographer writes it; the aperture, which
174
+ decides both the depth of field and whether the diaphragm's blades throw a star at all; the shutter,
175
+ which accumulates a moving light into a STREAK and a blinking one into a dashed streak; and where the
176
+ lens was focused. Two of them are drawn rather than merely stated — the blur (`DepthOfFieldPass.ts`,
177
+ from the thin-lens geometry in `DepthOfField.ts`) and the streak — because that is what makes them
178
+ evidence a reader can compare against a photograph: a sharp object bounds its own distance, and a
179
+ blurred one in a sharp frame was close.
180
+ The frame is letterboxed inside the widget's own box rather than resizing it, and the field it
181
+ implies becomes the recording's default — a recording that states its own (a zoom, binoculars) keeps
182
+ it. An eye has no rectangle and no format, and neither has a camera nobody identified: both fall back
183
+ to the scene's own 16:9 at the 60° vertical field this project draws an unaided witness through
184
+ (about the middle half of a real human field, which is where acuity actually is). The catalogue is
185
+ dated, so the picker offers what existed: no telephone in 1964.
186
+
163
187
  **Real astronomy for misidentification spotting.** A recurring cause of UFO reports is a mundane astronomical
164
188
  object or atmospheric optical effect — Venus (by far the most commonly misreported "UFO"), other planets, the
165
189
  Moon, lens flare, or halo phenomena like sun dogs/moon dogs. `<rr0-scene>` renders the sky astronomically: real
@@ -171,10 +195,12 @@ darkness/color follows the sun's altitude (day/twilight bands/night), and its da
171
195
  sun's real compass direction, not spread uniformly around the horizon — see `src/render3d/skyColors.ts`.
172
196
 
173
197
  The witness's own pose — geographic position, elevation, and viewing heading/pitch/field of view — can vary over
174
- the sighting's timeline via `observerTrack` in the sighting JSON (a keyframe array alongside `timeline`, same
198
+ the sighting's timeline via `witnessTrack` in the sighting JSON (a keyframe array of `{ t, pose }` alongside
199
+ `timeline` — the model class is `ObserverTrack`, but the serialized key is `witnessTrack`, and writing the class's
200
+ name into a file is a mistake that costs an afternoon; same
175
201
  hold-last/interpolated-lookup shape — see `src/engine/model/ObserverTrack.ts`), driving both the camera's own
176
202
  orientation and which real-world instant the astronomy is computed for as playback advances. Older recordings
177
- with no `observerTrack` fall back to the legacy static `place[0]` (see `resolveObserverPoseAt` in
203
+ with no `witnessTrack` fall back to the legacy static `place[0]` (see `resolveObserverPoseAt` in
178
204
  `src/engine/model/Sighting.ts`) — usable for sky darkness/color and camera pitch/fov, but with no compass heading
179
205
  to orient the camera by.
180
206
 
@@ -184,12 +210,13 @@ the live rendering path now uses `astronomy-engine` for the Sun too, for a singl
184
210
  Sun's azimuth from the same call used for the sky's directional glow.
185
211
 
186
212
  `<rr0-ufo-recorder>` has editor fields for the witness's latitude/longitude/heading and the observation's start
187
- date/time (all optional) — filling in lat+lng writes both the legacy `place` and a single t=0 `observerTrack`
213
+ date/time (all optional) — filling in lat+lng writes both the legacy `place` and a single t=0 `witnessTrack`
188
214
  keyframe (elevation/pitch/field of view stay at neutral defaults; there's no UI yet for authoring the observer
189
215
  *moving* over time, only a single static pose per recording).
190
216
 
191
- Not yet done: sun dog/moon dog/halo rendering, a real (non-flat) ground/terrain, precipitation and other optical
192
- effects (lens flare, mirage), and a multi-keyframe `observerTrack` authoring UI (today the recorder can only set
217
+ Not yet done: a mirage, the supernumerary arcs crowded inside a bright rainbow and the corona round a Sun seen
218
+ through a thin water cloud (all three are interference, and nothing here models the wave see `WaterDrop.ts`),
219
+ and a multi-keyframe `witnessTrack` authoring UI (today the recorder can only set
193
220
  one static pose; an observer that moves/re-orients mid-recording still needs hand-authored or scripted JSON). The
194
221
  Moon's phase currently only dims/brightens its disc's overall
195
222
  color rather than rendering a geometrically accurate crescent shape — a natural follow-up.
@@ -202,8 +229,8 @@ To regenerate it: download `hyg/CURRENT/hygdata_v41.csv` from that repo into `sc
202
229
  checked in (~400KB) since it's small and doesn't need regenerating on every install.
203
230
 
204
231
  **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
232
+ draws — the things that were genuinely up there and are genuinely mistaken for something else. Each is here
233
+ because its record is complete for every date this project can reconstruct, with no lookup, no key and no
207
234
  coverage floor:
208
235
 
209
236
  - **Meteor showers** (`src/engine/astronomy/MeteorShowers.ts`). A shower is a position in the Earth's own orbit,
@@ -225,8 +252,23 @@ coverage floor:
225
252
  from CelesTrak's SATCAT: how many tracked objects were in orbit that month, and when each named
226
253
  class existed (Echo balloons, Iridium flares, ISS, Starlink trains).
227
254
 
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.
255
+ - **What the air itself did to the light** (`src/engine/atmosphere/`). Two families, and neither is drawn form by
256
+ form. The ICE one traces sunlight through hexagonal prisms in a cirrus deck (`IceCrystal.ts`, `HaloSky.ts`) and
257
+ the 22° ring, the 46° ring, the sundogs, the tangent arc, the parhelic circle, the circumzenithal arc and the
258
+ pillar come out of the answer at whatever brightness the physics gives each — the one thing no record holds is
259
+ how steadily the crystals were falling, so that stays a stated condition (`Weather.iceCrystalAlignment`). The
260
+ WATER one sweeps a ray across a raindrop (`WaterDrop.ts`, `RainbowSky.ts`) and the primary bow at 42°, the
261
+ reversed secondary at 51°, Alexander's dark band between them and the bright sky inside the first come out the
262
+ same way. Nothing about a rainbow has to be assumed: a drop is a sphere, so there is no orientation to state,
263
+ and both of its ingredients — falling water, and a source that reaches it — are in the weather record. Each
264
+ family keeps a second, independent derivation in closed form (`IceHalos.ts`, `Rainbows.ts`) whose only job is to
265
+ disagree with the trace; that check has already caught one shipped error.
266
+
267
+ All of them appear in the recorder's read-only "Sky:" line, with a button to turn the witness toward
268
+ the meteor or the comet. The bow line is said only when rain was reported — everybody knows whether it was
269
+ raining, so the interesting answers are the negative ones: a Sun higher than 42° puts every bow below a ground
270
+ witness's horizon, and an unbroken deck between the Sun and the rain is the missing half of the famous
271
+ condition.
230
272
 
231
273
  **Regenerating the satellite catalog.** `src/engine/astronomy/satelliteCatalog.ts` is generated by
232
274
  `npm run build:satellites` from [CelesTrak's SATCAT](https://celestrak.org/pub/satcat.csv) (CC BY
@@ -0,0 +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:"Enregistrer",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)",instrumentOutOfPeriod:"{name} — hors de son époque",focalLength:"Focale",fieldOfView:"Champ de vision",aperture:"Diaphragme",exposure:"Temps de pose",focusDistance:"Mise au point à",unitMillimetres:"mm",unitDegrees:"°",iceCrystalAlignment:"Alignement des cristaux",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",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, autour {source}, pour {forms}",skyOpticsAlignment:" — tout sauf les halos exige des cristaux tombant à plat, ici supposés alignés à {alignment} %, qu'aucun relevé ne donne",skyOpticsHalo22:"un halo à {angle}°",skyOpticsHalo46:"un halo à {angle}°",skyOpticsParhelia:"des parhélies à {angle}° de part et d'autre",skyOpticsTangentArc:"un arc tangent au sommet",skyOpticsParhelicCircle:"un cercle parhélique blanc faisant le tour du ciel à sa hauteur",skyOpticsCircumzenithal:"un arc circumzénithal à {angle}° de hauteur",skyOpticsCircumhorizontal:"un arc circumhorizontal très au-dessous",skyOpticsPillar:"un pilier dressé au-dessus",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",skyBowPossible:"pluie et soleil suffisants pour {forms}",skyBowMoon:"pluie sous une Lune éclairée à {lit} %, de quoi former {forms} — un arc-en-ciel lunaire, que l'œil voit blanc",skyBowPrimary:"un arc de {radius}° de rayon, dont le sommet montait à {top}°",skyBowSecondary:"un second, plus pâle, à {radius}°, aux couleurs inversées",skyBowSourceTooHigh:"pluie, mais l'astre à {altitude}° de hauteur : aucun arc ne pouvait dépasser l'horizon, ils se tiennent à {radius}° du point opposé",skyBowHidden:"pluie, mais une couche continue entre elle et la lumière : aucun arc",skyBowNoSource:"pluie, et rien d'allumé pour en tirer un arc",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",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};