> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eigenpal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Figure Crops

> Crop and caption figure elements from a parsed PDF. Renders the source document, crops each kind=figure bbox from ai.parse output, and describes the crop with a vision model. Output is captions plus normalized bboxes for evidence viewers.

`ai.figure-crops` turns parser geometry into usable evidence: it renders the
source PDF, crops every `kind="figure"` element bbox from an
[`ai.parse`](/steps/ai/parse) result, and captions each crop with a vision
model. Pair it with `ai.parse` (openparser\@1 output) whenever downstream steps
need to see charts, diagrams, scanned tables, or photos — not just read text.

Point `input` at the same source PDF the parse step read, and pass the parse
output through (`{{ steps.parse.output }}`). Figure elements are read from its
`elements` array, so this step must run after a parse of the same document.

Captions describe what is visually depicted (chart type, axes and values,
objects, visible text). They are model-generated: treat them as association
hints for retrieval and review, not as verified facts. The normalized bboxes
are deterministic geometry from the parser and are safe to render as
highlights in evidence viewers.

Use `minAreaFrac` to skip tiny figures (page logos and decorations usually sit
well below 1% of page area). `includeCrops` embeds base64 JPEGs in the step
output — heavy, and off by default; prefer captions plus bboxes and re-render
crops at view time when you need pixels.

```yaml theme={null}
steps:
  - name: parse
    type: ai.parse
    with:
      file: "{{ input.document }}"

  - name: figures
    type: ai.figure-crops
    with:
      input: "{{ input.document }}"
      parseOutput: "{{ steps.parse.output }}"
      minAreaFrac: 0.005
```

Downstream steps can read:

```yaml theme={null}
# {{ steps.figures.output.figures }}
# {{ steps.figures.output._figureCrops }}
```

## Configuration

Configuration goes inside the step's `with:` block.

<ParamField path="input" type="string" required>
  Storage reference or template expression for the source PDF
</ParamField>

<ParamField path="parseOutput" type="unknown" required>
  ai.parse output object (template \{\{steps.\<parse>.output}}); figure elements are read from its `elements` array
</ParamField>

<ParamField path="model" type="string">
  Vision model for captions (defaults to workspace model)
</ParamField>

<ParamField path="figureInstructions" type="string">
  Custom caption instruction; applied per figure crop
</ParamField>

<ParamField path="maxFigures" type="integer" default="40">
  Cap on figures processed per document
</ParamField>

<ParamField path="minAreaFrac" type="number" default="0">
  Skip figures below this page-area fraction (logos/decorations)
</ParamField>

<ParamField path="includeCrops" type="boolean" default="false">
  Include base64 JPEG crops in output (heavy; default off, captions + bboxes only)
</ParamField>

<ParamField path="renderScale" type="number" default="1">
  Scale factor for rendering PDF pages before cropping
</ParamField>

<ParamField path="imageQuality" type="integer" default="85">
  JPEG quality for crops
</ParamField>

<ParamField path="llmReasoningEffort" type="&#x22;none&#x22; | &#x22;minimal&#x22; | &#x22;low&#x22; | &#x22;medium&#x22; | &#x22;high&#x22; | &#x22;xhigh&#x22; | &#x22;max&#x22;">
  Reasoning effort for models that support it. Omit to use the selected model's default.
</ParamField>

## Output

<ResponseField path="figures" type="array<object>" required>
  <Expandable title="figures properties">
    <ResponseField path="id" type="string" required />

    <ResponseField path="page" type="number" required />

    <ResponseField path="bboxNorm" type="array<number> | null" required />

    <ResponseField path="areaFrac" type="number" required />

    <ResponseField path="caption" type="string | null" required />

    <ResponseField path="cropJpegBase64" type="string" />
  </Expandable>
</ResponseField>

<ResponseField path="_figureCrops" type="object" required>
  <Expandable title="_figureCrops properties">
    <ResponseField path="pages" type="array<number>" required />

    <ResponseField path="model" type="string" />

    <ResponseField path="skippedSmall" type="number" required />
  </Expandable>
</ResponseField>
