@rr0/ufoathome 0.19.5 → 0.20.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
@@ -320,7 +320,7 @@ interface SightingRecordingJson {
320
320
  selected: boolean
321
321
  title?: string // shown as an on-canvas tooltip when hovered
322
322
  behindCloud?: boolean // the witness reported it behind cloud at this instant — stated, never deduced (see below)
323
- physical?: { sizeM: number, distanceM: number } // what the witness reported — see Apparent size
323
+ angular?: { widthDeg: number, heightDeg: number } // how big it LOOKEDthe only size a testimony holds, see Apparent size
324
324
  points?: { x: number, y: number }[] // "polygon" shapes only
325
325
  }
326
326
  }>
@@ -504,20 +504,49 @@ diff shows the weather and nothing else.
504
504
  appearance field, and held rather than blended. It is *stated*, for the same reason
505
505
  `DecorObject.occludesSourceIds` is: this format describes a 2D appearance on the witness's own field
506
506
  of view, not where an object was in space, so nothing in it can deduce whether cloud came between
507
- them. A reported distance (`physical`) is an occasional, often shaky extra, and the sky's own gaps
508
- are procedural noise — leaving the question to geometry means tuning the weather until the reported
509
- disappearance happens to occur. The witness's account outranks both; where a recording states a
510
- distance and makes no claim about cloud, the renderer falls back to the geometric test (is the deck
511
- crossed before the object, on the right side, with actual cloud in that direction).
512
-
513
- ### Apparent size
514
-
515
- `physical` is the witness's own reported size and distance, and the on-screen `bounds.width` is derived from it
516
- rather than drawn by eye: on the 640x360 canvas at the default 60° vertical field of view, one degree is about
517
- 5.4px and the full Moon about 2.8px, so an object of 3.5m at 90m is 12px wide — not the 90px an author reaches for
518
- unaided. `ApparentSize` (`src/engine/shape/ApparentSize.ts`) does the conversion both ways, and the editor's own
519
- **Real size** / **Distance** fields apply it and read back what the current drawing actually spans, in degrees and
520
- in full Moons.
507
+ them. A recording holds no distance at all (see *Apparent size* below), and the sky's own gaps are
508
+ procedural noise — leaving the question to geometry means tuning the weather until the reported
509
+ disappearance happens to occur. So the witness's account is the whole answer: no `behindCloud`, no
510
+ cloud.
511
+
512
+ There used to be a geometric fallback here, for a recording that stated a real distance and made no
513
+ claim about cloud. It went when stated distances did, and it had earned it: the one case it fired on
514
+ was Chiles-Whitted, where "it disappeared into the cloud deck" turned out to be an interrogator's
515
+ reconstruction that Whitted himself denied to McDonald in 1968.
516
+
517
+ ### Apparent size and why there is no real one
518
+
519
+ A witness never perceives meters. They perceive an angle: the thing covered a thumbnail at arm's length, or a fifth
520
+ of the windshield, or two full Moons. "About thirty meters long" is a conclusion they drew from a distance they
521
+ could not perceive either, and the two errors multiply. So a recording stores `angular` — how wide and how tall the
522
+ object *looked*, in degrees — and stores no real size and no real distance anywhere.
523
+
524
+ `bounds` is that angle projected onto the fixed 640x360 canvas at the pose's own field of view, which is what every
525
+ editing gesture, hit-test and renderer keeps working on. The angle is authoritative: `SightingShapes`
526
+ (`src/engine/persistence/SightingShapes.ts`) re-derives `bounds` from it on load and reads it back from `bounds` on
527
+ save, so a file survives a change of canvas or of field of view, and if the two ever disagree the angle wins.
528
+
529
+ At 60° across 360px, one degree is about 5.4px and the full Moon about 2.8px — so an object of 3.5m at 90m is 12px
530
+ wide, not the 90px an author reaches for unaided. That is why the editor's **Try a size** / **at a distance of**
531
+ fields exist: type a hypothesis, get the angle it implies on the canvas, and the meters are forgotten the moment
532
+ they have been applied. They are an authoring aid, never testimony.
533
+
534
+ #### Where meters do come back
535
+
536
+ The only real distance a testimony can support is an **inequality**, and only where the witness saw the object
537
+ cross something whose position is known: it passed *behind* that hangar (at least that far), or *in front of* that
538
+ tree (at most that far). `DecorObject.eastM/northM` give the decor its real position, `occludesSourceIds` says
539
+ which side of it the object was on, and `SceneRenderer.decorDistancesAt` raycasts the exact line of sight to
540
+ measure the crossing.
541
+
542
+ An angle plus a distance is a size, and a size does not change as the object flies — so every crossing narrows the
543
+ object's real width from one side, for the whole recording, and the narrowed width reads back as a distance at
544
+ every other instant. `SizeEstimate` (`src/engine/shape/SizeEstimate.ts`) accumulates that, reports a contradiction
545
+ rather than clamping one, and the editor prints the result under the apparent size.
546
+
547
+ Most sightings constrain nothing at all — a light in an empty night sky crosses nothing — and the readout then says
548
+ so. "Unknown" is the honest answer for a majority of cases, and saying it out loud is the entire point of not
549
+ storing a number instead.
521
550
 
522
551
  This format is deliberately independent of [`@rr0/data`](https://github.com/RR0/data)'s `RR0Event`/`@rr0/time`'s
523
552
  `Level2Date`/`@rr0/place`'s `Place` classes, even though its `time`/`place` fields are structurally aligned with
@@ -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",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",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};