Annotate a video
An annotation in Fovea is a sequence of keyframe bounding boxes
plus a label. The label resolves either to a typeId from the
persona's ontology (a "type" annotation, e.g. player) or to a
world-state object id (an "object" annotation, e.g. a specific
worldEntity representing a named player). Frames between
keyframes are interpolated linearly at render time.
This chapter draws the first annotation against the persona created in the previous chapter.
Add a video
Drop an .mp4 into the videos/ directory mounted by the
backend, then trigger the sync:
cp ~/match.mp4 ./videos/match.mp4
curl -s -X POST http://localhost:3001/api/videos/sync \
--cookie cookies.txt
# {"added":1,"updated":0,"removed":0}
The video is now listed at GET /api/videos. Save its
id as VIDEO_ID. The frontend's video browser refreshes on
its own.
Draw a type annotation
Open the video in the annotation workspace
(/annotate/<videoId>?personaId=<personaId>). The keyboard model
is documented in Reference > Keyboard shortcuts;
the relevant ones for this chapter:
n start drawing a new annotation
space play / pause
right next frame
k add a keyframe at the current frame
enter confirm the annotation in progress
To annotate a player across frames 0-60: press n, draw a box
around the player at frame 0, advance to frame 60, draw the box
again, press enter. The frame range in between gets interpolated.
The equivalent API call:
curl -s -X POST http://localhost:3001/api/annotations \
-H 'Content-Type: application/json' \
--cookie cookies.txt \
-d "{
\"videoId\": \"$VIDEO_ID\",
\"personaId\": \"$PERSONA_ID\",
\"type\": \"type\",
\"label\": \"player\",
\"frames\": [
{\"frame\":0, \"box\":{\"x\":120,\"y\":80,\"width\":60,\"height\":140}},
{\"frame\":60, \"box\":{\"x\":150,\"y\":85,\"width\":60,\"height\":140}}
]
}"
The response carries the assigned id and a server-rendered
linkType of null (this is a type annotation, not an object
annotation, so no linkType applies).
Draw an object annotation
An object annotation is a bounding-box sequence whose label is the
id of a world entity, event, time, or location. The persona's
world state holds those objects. To attach a box to the named
player "Player 9" (a worldEntity of type player):
- Create the world entity through the world editor or
PUT /api/world. - Draw the bounding-box sequence as in the previous section, but
set
typetoobject,labelto the entity id, andlinkTypetoentity.
curl -s -X POST http://localhost:3001/api/annotations \
-H 'Content-Type: application/json' \
--cookie cookies.txt \
-d "{
\"videoId\": \"$VIDEO_ID\",
\"type\": \"object\",
\"label\": \"$PLAYER_9_ENTITY_ID\",
\"linkType\": \"entity\",
\"frames\": [
{\"frame\":0, \"box\":{\"x\":120,\"y\":80,\"width\":60,\"height\":140}},
{\"frame\":60, \"box\":{\"x\":150,\"y\":85,\"width\":60,\"height\":140}}
]
}"
Object annotations linked to events, times, or locations use
linkType values event, time, location respectively. The
column was added in v0.1.8 so these annotations round-trip through
export and import without flattening to entity-linked. See
Guide > Annotations for the full state
machine.
Next
Continue to Summary and claims to generate a VLM summary against the persona and pull claims out of it.