Kind: Service
Source: atloria-monorepo/apps/screenshot-worker/src/app/screenshot/services/annotation-emitter.service.ts
TS port of the atlorix Python annotation producer (tools/capture_annotations.py + tools/emit_annotations.py).
Locates a step's target element on the LIVE page, converts it to percent-of-
natural-image coordinates, and builds the non-destructive overlay payload +
the #atloria-annotations= URL fragment the web viewer consumes. Coordinates
only — the screenshot pixels are never touched (moat intact).
AnnotationEmitterService locates a screenshot step’s target element on the live page and converts its bounding box into percentage coordinates relative to the natural screenshot image. It produces non-destructive annotation overlay data and the #atloria-annotations= URL fragment consumed by the web viewer, without modifying screenshot pixels.
Methods
| Method | Signature | Returns | Description |
|---|---|---|---|
recomputeTargetBoxPct | recomputeTargetBoxPct(page: Page, selector: string, opts: { fullPage: boolean }) | `Promise<BoxPct | null>` |
buildStepAnnotations | buildStepAnnotations(boxPct: BoxPct, stepIndex: number) | Annotation[] | Turn a located box into a highlight box + a numbered marker at the box center. |
toFragment | toFragment(annotations: Annotation[]) | string | Build the #atloria-annotations=<url-encoded JSON> fragment for a set of annotations. |
Where it refuses work
AnnotationEmitterServicestops the work with an early return when!box.AnnotationEmitterServicestops the work with an early return whenbox.w < 0.5 || box.h < 0.5.AnnotationEmitterServicestops the work with an early return whenbox.x < 0 || box.y < 0 || box.x > 100 || box.y > 100 || box.x + box.w > 100 || box.y + bo….AnnotationEmitterServicestops the work with an early return when!annotations || annotations.length === 0.
When something fails
AnnotationEmitterServicehandles failure in 1 place: it turns it into a return value in all 1.
Diagram
mermaidsequenceDiagram participant Caller as Screenshot Workflow participant Service as AnnotationEmitterService participant Page as Live Browser Page participant Viewer as Web Viewer Caller->>Service: recomputeTargetBoxPct() Service->>Page: Locate target element Page-->>Service: Element bounding box Service->>Page: Read natural image/page dimensions Page-->>Service: Dimensions Service-->>Caller: BoxPct | null Caller->>Service: buildStepAnnotations() Service-->>Caller: Annotation[] Caller->>Service: toFragment() Service-->>Caller: #atloria-annotations=... Caller->>Viewer: Open screenshot URL with fragment Viewer->>Viewer: Render overlay annotations
Usage
tsimport { AnnotationEmitterService } from './annotation-emitter.service';
// Typically injected by NestJS with the current step/page context.
const annotationEmitter = new AnnotationEmitterService(/* dependencies */);
// Resolve the step target against the currently loaded live page.
const targetBox = await annotationEmitter.recomputeTargetBoxPct();
if (targetBox) {
const annotations = annotationEmitter.buildStepAnnotations();
const annotationFragment = annotationEmitter.toFragment();
const viewerUrl =
`https://viewer.example/screenshots/step-42.png${annotationFragment}`;
console.log({ targetBox, annotations, viewerUrl });
}
AI Coding Instructions
- Keep annotations non-destructive: generate coordinate metadata and URL fragments only; never draw or alter screenshot pixels.
- Call
recomputeTargetBoxPct()after the live page and target element are available, and handlenullwhen an element cannot be found or measured. - Preserve percentage-of-natural-image coordinates so annotations remain aligned when the viewer scales the screenshot.
- Use
buildStepAnnotations()as the canonical overlay payload source, then passtoFragment()output directly to the viewer URL. - Maintain compatibility with the existing Python producer behavior in
capture_annotations.pyandemit_annotations.pywhen changing coordinate or fragment serialization logic.
Referenced By
ScreenshotModule(MODULE_PROVIDES)FlowReplayService(DEPENDS_ON)
Was this page helpful?