# Confirmation of XCS File Format (xTool F2) - VANTAGE-ALPHA Baseline
(LOCKED 2026-03-18)

This document defines the strictly required structure for `.xcs` files to ensure full compatibility with xTool Creative Space and the F2 system.

---

## 1. Top-Level Node Hierarchy

1.  **Project Root**: Contains metadata and links trees via `canvasId`.
    *   **CRITICAL Root Fields**:
        *   `extId`: `"GS006"` (Mandatory for F2 recognition).
        *   `extName`: `"F2"` (Mandatory for F2 recognition).
        *   `version`: `"1.5.8"` (Matches current stable).
        *   `minRequiredVersion`: `"2.6.0"`.
2.  **Canvas Tree (`canvas[]`)**:
    *   `layerData`: A manifest registering every unique layer color.
    *   `displays[]`: Visual shape definitions.
3.  **Device Tree (`device`)**:
    *   `id`: `"GS006"` (F2 Identifier).
    *   `power`: `[5, 15]` (Laser wattages).
    *   `data`: The **Processing Tree** (Map keyed by `canvasId`).
        *   `displays`: The **Parameter Tree** (Map keyed by **Shape ID**).

---

## 2. Shape-to-Parameter Mapping Logic

XCS links geometry to settings using a strict **Three-Point Sync**:
1.  **Point A**: `project.canvasId`
2.  **Point B**: `canvas[0].id`
3.  **Point C**: `device.data.value[0][0]` (The Map key)

Individual shapes are linked via:
1.  **Point D**: `canvas[0].displays[i].id`
2.  **Point E**: `device.data.value[0][1].displays.value[j][0]` (The Map key)

---

## 3. Mandatory Processing Node Structure (Per Shape)

**CRITICAL:** For the F2 UI to show sliders, every shape configuration in the `device` tree MUST include all four operation nodes, regardless of which one is active.

### The Operation Keys:
*   `COLOR_FILL_ENGRAVE`: CONFIRMED primary type for **FILL**. Uses **1:1 LPCM mapping** (1000 in JSON = 1000 LPCM in UI).
*   `FILL_VECTOR_ENGRAVING`: Alternative fill type. Note: Some versions may scale density by 10x in this mode.
*   `VECTOR_ENGRAVING`: Used for **SCORE** (Outlines).
*   `VECTOR_CUTTING`: Used for **CUT**.
*   `INTAGLIO`: Used for 3D/relief.

### Internal Parameter Mapping:
Inside each operation node (e.g., `FILL_VECTOR_ENGRAVING`), the path to settings is:
`data` → `[OP_NAME]` → `parameter` → `customize` → `[power|speed|density|repeat]`

---

## 4. Text Object Structure

TEXT objects in XCS are complex as they often include baked glyph paths for offline processing.

### Root TEXT Fields:
*   `type`: `"TEXT"`
*   `text`: The actual string content.
*   `width`/`height`: Dimensions in mm of the bounding box.
*   `charJSONs`: **MANDATORY FOR F2**. An array of `PATH` objects, one per character, containing baked SVG `dPath` data. Without this, text remains invisible in XCS.
*   `fontData`: **MANDATORY FOR F2**. Contains `fontInfo` (metrics) and `glyphData` (dictionary of paths/advances).
*   `fillRule`: `"nonzero"`.
*   `style`: Object containing formatting:
    *   `fontSize`: Size in points (pt). **CRITICAL:** XCS uses a ratio of approx **0.275 mm per point** for the visual height of built-in fonts like Lato.
        *   Example: `fontSize: 72` pt results in `height: 19.85` mm.
        *   Formula: `height (mm) ≈ fontSize (pt) * 0.2757`.
        *   Formula: `fontSize (pt) ≈ height (mm) * 3.626`.
    *   `align`: `"center"`, `"left"`, or `"right"`. **CRITICAL:** `align` is often metadata only; the exporter must manually calculate the anchor shift.

### Coordinate & Scaling Logic for TEXT:
1.  **Anchor Point**: The `x` and `y` properties of the parent `TEXT` object define the **baseline anchor of the first character**.
2.  **Manual Centering**: XCS does NOT automatically center the bounding box based on the `align` property. The exporter must:
    *   Calculate `totalWidth = sum(glyph.advanceWidth) * scale`.
    *   **Horizontal Centering**: Set parent `x = targetX - totalWidth / 2`.
    *   **Vertical Centering (-90°)**: Set parent `y = targetY + totalWidth / 2`. (Note: Rotated text expands "down" from the anchor).
3.  **Character Synchronization**: The first character's `x` and `y` in `charJSONs` MUST match the parent's `x` and `y`. Subsequent characters are offset by the `advanceWidth * scale`.

---

## 5. Processing Order & Layer Sequencing

XCS determines the execution sequence of shapes based on a combination of layer metadata and device path planning settings.

### Layer-Based Ordering
Each layer defined in `canvas.layerData` contains an `order` integer.
*   **Property**: `canvas[0].layerData[HEX_COLOR].order`
*   **Behavior**: When custom ordering is active, XCS processes layers based on these values. 
*   **Note**: Observed behavior shows processing from **Highest Order value to Lowest Order value** (e.g., Order 3 processes before Order 1).

### Path Planning Settings
The logic switch for sequencing is found in the `device` tree:
`device` → `data` → `value[canvasId]` → `data` → `LASER_PLANE`

| Property | Value | Description |
| :--- | :--- | :--- |
| `pathPlanning` | `"auto"` | **Automatic Sequencing**: XCS optimizes for travel time, ignoring layer sequence. |
| `pathPlanning` | `"custom"` | **User Sequencing**: XCS respects the layer order and physical sequence. |
| `isProcessByLayer`| `true/false` | **Layer Grouping**: If true, all shapes in a layer are completed before moving to the next. |

### Implementation for Forced Order:
To ensure a file renders in a specific order (e.g., Layer A then Layer B):
1.  Set `"pathPlanning": "custom"`.
2.  Set `"isProcessByLayer": true`.
3.  Assign higher `order` values to the layers that should process first.

---

## 6. Mandatory Integrity Checks (Validation)

Every exported file must pass these two structural tests:

1.  **Canvas-to-Device Join**: The GUID in the root `canvasId` field MUST exist as a key in the `device.data.value` Map, and MUST match the `id` field of the corresponding object in the `canvas[]` array.
2.  **Shape-to-Parameter Join**: For every shape in `canvas[n].displays[]`, its `id` (GUID) MUST exist as a key within the `device.data.value[n][1].displays.value` Map.

---

## 7. Exporter Implementation Rules

1.  **IDs**: Generate standard 36-character UUIDs.
2.  **Layers**: Every unique `layerColor` used in `displays` MUST have a matching entry in `canvas.layerData`.
3.  **Maps**: Every Map-like structure MUST be wrapped in `{"dataType": "Map", "value": [...]}`.
4.  **Boilerplate**: Include all four operation nodes (`VECTOR_CUTTING`, `VECTOR_ENGRAVING`, `FILL_VECTOR_ENGRAVING`, `INTAGLIO`) in the shape's processing config.
5.  **Alignment**: Coordinates are mm from top-left (0,0). Mandala center is (50, 50) for 100x100 area.
6.  **Root Metadata**: Include `extId: "GS006"` and `extName: "F2"` at the root level.

---

## 9. XCS Reference Files (`xcs-references/`)

Authoritative samples exported directly from xTool Creative Space.

### `XCSFONTEXAMPLE1.xcs` (Scribe/Score Text)
*   **Purpose**: Shows "Lato Regular" text set to **Score** (Scribe) for 304 Stainless Steel.
*   **Geometry (`displays`)**:
    *   `type`: `"TEXT"`
    *   `isFill`: `false` (Required for Score/Scribe).
    *   `scale`: Uses non-uniform/non-identity scaling (e.g., `0.155`).
    *   **CRITICAL**: Includes a `fontData` block with `glyphData` (baked SVG paths). This may be required for F2 offline processing.
*   **Processing (`device`)**:
    *   `processingType`: `"VECTOR_ENGRAVING"` (Score).
    *   `isWhiteModel`: `true`.
    *   `planType`: `"red"` (for IR Laser).
    *   **Settings (Official 304 Score)**:
        *   Power: `90`
        *   Speed: `500`
        *   Repeat: `1`
        *   ProcessingLightSource: `"red"` (IR).

---

## 10. Summary of Findings (Scribe vs Fill)
| Feature | Fill (Engrave) | Scribe (Score) |
| :--- | :--- | :--- |
| `processingType` | `COLOR_FILL_ENGRAVE` | `VECTOR_ENGRAVING` |
| `isFill` (Root) | `true` | `false` |
| `isWhiteModel` | `false` | `true` |
| `charJSONs` | Required | Required |
| `fontSize` | Ratio ~0.275 | Ratio ~0.275 |
| `anchor` | Left-Baseline | Left-Baseline |

---

## 11. Glyph Baking & Layout (Galvo/F2 Specific)

To ensure text renders on Galvo-based machines (F2), the exporter must act as a mini-typesetter.

1.  **Glyph Cache**: Store a dictionary of characters mapped to their SVG `dPath` and `advanceWidth` (metric in pts/mm at 72pt).
2.  **Layout Pass**: 
    *   Iterate through characters.
    *   Accumulate `advanceWidth` to find the string's length.
    *   Factor in `scale = fontSize / 72`.
3.  **Hydration**: Every `TEXT` object must contain a redundant array of `PATH` objects (`charJSONs`) representing the "baked" visual representation of the string.

---

## 12. Anchoring & Rotation Facts

| Scenario | Anchor Point (x, y) | Growth Direction |
| :--- | :--- | :--- |
| **Horizontal (0°)** | Left-edge Baseline | Grows Right (+X) |
| **Vertical (-90°)** | Top-edge Baseline | Grows Down (+Y) |
| **Centering (Horiz)** | `targetX - (width/2)` | Centered on targetX |
| **Centering (Vert)** | `targetY + (width/2)` | Centered on targetY |

---

## 13. Positioning & Coordinate Systems

XCS Studio separates **Object Origin** from **Geometric Data**. Failure to respect this hierarchy results in double-offsetting (shapes ending up at 0,0 or misaligned).

### Relative Geometry Rule (MANDATORY)
1.  **`dPath` Content**: All coordinates within an SVG path string (`M`, `L`, etc.) MUST be relative to the object's Top-Left corner (`0,0`).
2.  **Explicit Origin**: The machine-bed position MUST be defined exclusively by the `x` and `y` properties of the parent object.
3.  **Offsets**: The `offsetX` and `offsetY` properties must represent the distance from the `x,y` anchor to the geometric center of the shape (usually `width/2` and `height/2`).

### Why my "Position 0,0" error happened:
I was generating `dPath` data using absolute machine coordinates (e.g., `M 50 50`) while simultaneously setting the object's `x` and `y` to those same coordinates. XCS interpreted this as: "Go to 50,50 on the bed, and then draw a line 50mm away from that anchor," resulting in shapes rendering far outside the work area or defaulting to 0,0.

### Implementation Mandate:
*   **Generate** technical paths (spirals, loops) centered around `(width/2, height/2)`.
*   **Set** `x` and `y` to the desired Top-Left position in the grid.
*   **Result**: 1:1 parity between our Viewer and XCS Studio's layout.
