# Photo narrative anchors

Every photo in the Guesteria photo kit carries one narrative anchor: the compositional point a crop
of any aspect ratio must keep, as close to the crop's own centre as the frame allows. It is derived
by code from labelled subject boxes (faces, held objects, doors, still-life objects) and a named
rule - a model marks the boxes and never places the point itself, except for the `scene` rule.

Data for every photo this site serves: [anchors.json](https://brand.guesteria.com/assets/photos/anchors.json) - `file`, `url`, `width`,
`height` (of the web jpg), `rule`, `point` (the anchor, `[x, y]` fractions of the image, 0..1),
`object_position` (the same point as a CSS string), `note`, `subjects` (the labelled boxes), and
`crops` (a ready-made pixel box per standard ratio).

## Rule choice

| rule | when | anchor derivation (code) |
|---|---|---|
| face-chest | one person, face visible, no held object carries the story | x = face centre x; y = face bottom + 0.5 × face height (chest just below the face) |
| face-object | one person looking at / holding a phone, tablet, paper that carries the story | midpoint of face centre and the first HELD subject's centre (`phone`, `tablet`, `paper`, `hand-object` only - see below); no held subject present: falls back to `face-chest` |
| pair | two people carry the story | midpoint of their two face-chest points |
| group | three or more people | mean of their face-chest points |
| entrance | exterior or facade, lobby door as story | centre of the door / entrance box |
| object | still life, one object is the story | centre of the object box |
| scene | interiors/landscapes with no single subject | model-given `point` |

Precedence when ambiguous: face-object > pair > group > face-chest > entrance > object > scene.

**`face-object`'s held labels, and why `screen` and `object` are excluded.** A person HOLDS or
operates `phone`, `tablet`, `paper` or `hand-object`; `screen` is looked AT, never held (a desk
monitor, a wall display), and `object` is the still-life rule's own label, never a thing a person in
a `face-object` frame is holding. A `face-object` extraction naming only those two subjects beside
the face carries no held object at all, and the derivation falls back to `face-chest` on the face
alone. This was corrected after a review sheet showed desk monitors marked `screen` pulling the
anchor into empty wall behind the person, past the monitor's own edge.

## Cropping to a ratio

Two correct ways to get a crop box, both giving the same answer:

1. **Use `crops["<ratio>"]`** from anchors.json - `[x0, y0, x1, y1]` in integer pixels of that
   photo's web jpg, already computed to centre the anchor and keep the labelled `subjects` inside.
2. **Compute it**: take the largest box of the target ratio that fits inside the image; place it so
   `point` sits at the box's centre; clamp the box inside the frame. If the bounding box of
   `subjects[].box` is no larger than the crop box in either dimension, shift the box (never resize
   it) so that bounding box sits fully inside. This is `crop_box` in the framework's
   `photo_anchor.py` - the ratios above are exactly its `STANDARD_RATIOS`.

## CSS

For a frame shown uncropped (`object-fit: cover` filling a fixed box), set:

```css
img { object-fit: cover; object-position: <object_position>; }
```

using that photo's own `object_position` from anchors.json - already an `"x% y%"` string in
`object-fit: cover`'s own coordinate system.

## Data

https://brand.guesteria.com/assets/photos/anchors.json
