*Epic CLI Manual — [index](../MANUAL.md)*

# 7. `--compile=REQUEST`

```
java -jar java-epic-cli.jar --compile=design.json
java -jar java-epic-cli.jar --aws=aws.ini --compile=s3://bucket/requests/design.json
```

Compiles an Artwork Designer layer-JSON canvas description into one print-ready PDF with
genuine spot-color separations. Standalone: the request carries its own destination; only
`--aws=FILE`, `--fonts-dir=DIR` and `--quiet` are accepted alongside. Prints exactly one JSON
result object on stdout **even under `--quiet`**.

## Request schema (`schema_version: 1`)

```json
{
  "schema_version": 1,
  "destination": "/path/out.pdf | s3://bucket/key",
  "design": {
    "artboard": { "width_in": 13.0, "height_in": 9.2 },
    "colors":   [ { "ref": "c1", "pms": "PANTONE 186 C", "c": 0, "m": 100, "y": 81, "k": 4 } ],
    "fonts":    [ { "ref": "f1", "font": "Bungee-Regular" } ],
    "live_text": false,
    "layers":   [ ... ]
  },
  "variables_xml": "<variables>...</variables>",
  "ai_private": false
}
```

(`ai_private` defaults to **true**; the example shows the opt-out — see below.)

- `colors[].pms` is the **literal output separation name** — whatever string you put there is
  the plate name in the PDF. CMYK values are 0–100 (note: different scale from
  `--swap-spot-colors`).
- `fonts[].font` is `{Family}-{Style}`, resolved to `{fonts-dir}/{font}.ttf` (see [§3](03-configuration-aws-mysql-fonts.md)).
  TrueType only.
- Unknown top-level keys are ignored (schema headroom); an absent or unsupported
  `schema_version` is a hard error, never a guess.

## Layers

Layers draw in array order (index 0 = bottom). Every layer requires a unique `id` string —
it names the layer in error results. Geometry is in **inches from the artboard top-left**;
`rotation` is degrees clockwise about the layer center.

**`artwork`** — place an external PDF: `file` (local or `s3://`), `x`/`y`/`w`/`h` box the
artwork's CropBox is scaled onto, optional `recolor` map of
`{ original separation name → palette ref }`. An incomplete recolor — any source separation
left unmapped — fails the layer. No silent pass-through of foreign inks.

**`shape`** — `shape`: `rect` | `ellipse` | `star` | `polygon`; `fill` and/or `stroke`
palette refs; `stroke_width_pt`. Stars take `points` + `inner_ratio`; polygons take `sides`.
Star/polygon vertices sit on the box's inscribed ellipse starting at 12 o'clock.

**`text`** — single line. `x`/`y` = top-left of the **post-warp ink bounding box**; `size_pt`
drives scale; `tracking` in thousandths of an em per slot (spaces included); `warp` =
`{ "style": "none"|"arc", "bend": -100..100 }` in percent, negative = arch down.

Text is rendered as filled outline paths by default. Two opt-in systems change that:

### Live text (`live_text`)

`design.live_text: true` sets the design-wide default; a per-layer boolean `live_text`
overrides it (absent/null inherits). With live text on, an **unwarped** text layer is emitted
as real live PDF text: the face is fully embedded (unsubsetted — editable in Illustrator),
tracking becomes `Tc` and kern pairs become `TJ` adjustments, at the exact geometry of the
outlined rendering. Warped layers **always stay outlined**. `live_text` + `stroke` on an
unwarped layer fails the layer — live text cannot stroke.

With live text on, every live text layer (warped or not) is recorded in a **mapping sidecar**
written next to the output as `<name>.mapping.json` (S3 destinations upload it as
`<key>.mapping.json`):

- `schema_version: 2`
- one entry per layer: `id`, `text`, `font`, `size_pt`, `tracking`, `live` (true = real live
  text in the PDF; false = outlined ink), `anchor_in {x,y}` and `bbox_in {x,y,w,h}` — the
  post-warp ink box in artboard inches, top-left y-down.
- warped entries add `warp {style, bend}` plus the outlined `d` path (M/L/Z commands,
  inches) so a caller can rebuild them as editable warped text.
- a live warped layer with a non-integer bend raises a result warning — Illustrator's warp
  UI only accepts whole percents, and the bend is never silently rounded.

### `variables_xml`

Optional raw Adobe variable-library XML (the same dialect as the batch sidecars), embedded
verbatim as the PDF's XMP metadata packet (standard `x:xmpmeta`/`xpacket` wrapper added).
Absent/blank writes no metadata and the output is unchanged. EXPERIMENTAL: Illustrator's
Variables panel may additionally require native AI private data.

### `ai_private` (native Illustrator live editing)

**Default: on.** Every compiled PDF additionally authors **native Illustrator private
data** unless the request opts out with `"ai_private": false`. `"ai_private": true`
asks for it explicitly — same output, stricter failure mode (see limits below). The
private data is
(AIPDFPrivateData PieceInfo) so the compiled PDF opens in Illustrator as fully **live
editable text**: real ATE stories, straight layers as area frames (vertical Align:Center,
fixed width/height, centered padding), and a live Warp: Arc envelope for the warped layer.
The file opens with no prompts, no click-shift, and survives editing and re-saving in
Illustrator 30.x. The PDF also carries the matching save identity (XMP CreatorTool + Info
dictionary) Illustrator writes on its own saves.

`"ai_private": false` restores the bare-PDF output (byte-identical to the pre-B5
compile). When the flag is **absent** and the design uses something the forge cannot
author (an artwork/raster layer, a stroke, transforms on text), the compile **degrades
softly**: the PDF ships without private data and the result carries a `warnings[]`
entry saying why. When `"ai_private": true` was explicit, the same conditions are
**hard errors** — never a silent downgrade.

**Limits — each one is a hard error, never a silent downgrade:** text, shape, and
path layers (artwork/raster layers cannot be authored as native AI art); no stroke;
no rotation/shear/flip on text layers (shape and path transforms are baked into the
transcribed geometry). Any number of layers may be warped (style `arc`, positive
bend). Shape and path layers become native spot-filled compound paths in z-order. Any TTF
face works: the ATE font signature is synthesized from the font's own name table, and
layout metrics (ascent/descent/cap height) come from its hhea/head/OS-2 tables. Multiple
spot colors are supported: each text layer's fill becomes its own named spot ink with its
own document swatch, art style, and ATE paint.

## Output and result

The output PDF is exact-trim: MediaBox = CropBox = TrimBox = ArtBox = BleedBox = the
artboard. No colorbar, no registration marks — those are sheet-run concerns.

Exactly one JSON object on stdout:

```json
{"status":"ok","destination":"...","colors_used":["PANTONE 186 C"]}          // exit 0
{"status":"error","layer_id":"l2","reason":"..."}                            // exit 1
```

`ok` results add `"mapping": "<path>"` when a live-text sidecar was written and
`"warnings": [...]` when non-fatal advisories were raised; both fields are absent otherwise.
`layer_id` is absent for request-level errors. **There are no silent skips**: unknown
refs/types/styles/shapes and incomplete recolors all fail loudly.
