Now I have everything I need. Let me compose the section content.

# Section 1: BUILD_SCENE -- Grid Offset

## Background

The `build_scene` tool creates multiple nodes in a Godot scene using high-level patterns (grid, line, scatter, nodes). Currently, all placement starts at the world origin `[0, 0, 0]` (or the grid's `origin` parameter). There is no way to shift an entire pattern by an arbitrary offset vector.

This section adds an `offset: [x, y, z]` parameter to `build_scene()` that shifts ALL placement modes -- grid, scatter, and line. The offset is applied on the GDScript side after the normal position calculation, and is validated on the Python side before being sent to the bridge.

## Files to Modify

- `/Users/salvatorefarruggio/Desktop/godotiq/src/godotiq/tools/bridge/build_scene.py` -- Add `offset` parameter to `build_scene()` and validation to `validate_build_params()`
- `/Users/salvatorefarruggio/Desktop/godotiq/src/godotiq/tools/bridge/__init__.py` -- Add `offset` parameter to the MCP wrapper `godotiq_build_scene()` and pass it through to `_build_scene()`
- `/Users/salvatorefarruggio/Desktop/godotiq/godot-addon/addons/godotiq/godotiq_server.gd` -- Apply offset in `_expand_build_grid()`, `_expand_build_line()`, and scatter handling within `_expand_build_pattern()`
- `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_tools/test_build_scene.py` -- Add new test class for offset validation

## Tests First

All tests go in `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_tools/test_build_scene.py`. Add a new test class `TestOffsetValidation` after the existing classes.

```python
class TestOffsetValidation:
    """Offset parameter validation for build_scene."""

    # Test: validate_build_params accepts grid with valid offset [10, 0, 5]
    # - Call validate_build_params with a valid grid and offset=[10, 0, 5]
    # - Assert no error, params returned successfully

    # Test: validate_build_params accepts grid with no offset (backward compat)
    # - Call validate_build_params with a valid grid and no offset argument
    # - Assert no error, params returned (offset defaults gracefully)

    # Test: validate_build_params rejects offset with wrong length [1, 2]
    # - Call validate_build_params with offset=[1, 2]
    # - Assert error dict returned mentioning "3" (must be 3 elements)

    # Test: validate_build_params rejects offset with non-numeric values ["a", 0, 0]
    # - Call validate_build_params with offset=["a", 0, 0]
    # - Assert error dict returned

    # Test: build_scene passes offset through to bridge request params
    # - Mock get_bridge, call build_scene with offset=[10, 0, 5]
    # - Assert bridge.request was called with params containing "offset": [10, 0, 5]

    # Test: build_scene defaults offset to [0, 0, 0] when not provided
    # - Mock get_bridge, call build_scene without offset
    # - Assert bridge.request was called with params containing "offset": [0, 0, 0]
```

### Validation function signature change

`validate_build_params` must accept an additional `offset` parameter:

```python
def validate_build_params(
    grid: dict | None,
    line: dict | None,
    scatter: dict | None,
    nodes: list[dict] | None,
    offset: list[float] | None = None,
) -> tuple[dict | None, dict | None]:
```

The offset validation logic should be:
- If `offset` is `None`, treat as `[0, 0, 0]` (no error).
- If provided, it must be a `list` (or `tuple`) of exactly 3 elements, each numeric (`int` or `float`). Otherwise return an error dict.
- Offset validation runs independently of mode validation -- it should be checked before or after the mode checks but should not short-circuit them. A reasonable approach: validate offset first, then validate mode. If offset is invalid, return the offset error immediately.
- On success, include `"offset"` in the returned params dict alongside the mode key (e.g., `{"grid": {...}, "offset": [10, 0, 5]}`).

## Python Implementation Details

### `build_scene.py` changes

1. Add `offset: list[float] | None = None` parameter to `validate_build_params()`.

2. Add offset validation at the top of the function (before mode selection). If `offset is not None`:
   - Check `isinstance(offset, (list, tuple))` and `len(offset) == 3`.
   - Check each element is `isinstance(el, (int, float))`.
   - On failure, return `(None, {"error": "offset must be a list of exactly 3 numbers [x, y, z]"})`.

3. In the success return paths of each `_validate_*` helper (or more cleanly, after the helper returns), merge `"offset"` into the params dict. The cleanest approach: after calling the per-mode validator, if `offset` is not None, add it to the params dict; if None, add `[0, 0, 0]`.

4. Add `offset: list[float] | None = None` parameter to `async def build_scene()`.

5. Update the `validate_build_params` call site inside `build_scene()` to pass `offset`.

6. In the `bridge.request()` call, include offset in params: `{**params, "parent": parent, "target_scene": target_scene}` already spreads params -- since offset is now in the params dict, it will be included automatically.

### `__init__.py` MCP wrapper changes

1. Add `offset: list[float] | None = None` parameter to `godotiq_build_scene()` function signature, between `nodes` and `ctx`.

2. Update the docstring to document the new parameter:
   - Under Args: `offset: Shift entire pattern by [x, y, z] (default [0, 0, 0]).`
   - Under Modes descriptions, mention that offset applies to all modes.

3. Pass `offset=offset` to the `_build_scene()` call.

## GDScript Implementation Details

### `godotiq_server.gd` changes

All changes are in the `_expand_build_pattern` function and the three expansion helpers.

**In `_expand_build_pattern()`:**
- Read offset from the top-level params: `var offset: Array = params.get("offset", [0, 0, 0])`
- Pass it to `_expand_build_grid()` and `_expand_build_line()` as a second argument.
- For scatter mode: after getting the items array, iterate and add offset to each item's `"position"` array (if present). Items without a `position` key are left unchanged.

**In `_expand_build_grid(grid, offset)`:**
- Accept the `offset` array parameter (default `[0, 0, 0]`).
- Parse offset components: `var off_x = float(offset[0])`, etc.
- After calculating each node's position, add the offset. The position line changes from:
  - `[ox + col * spacing, oy, oz + row * spacing]` to
  - `[ox + col * spacing + off_x, oy + off_y, oz + row * spacing + off_z]`
- This applies to both `xz` and `xy` axis modes.
- For override tiles that already have a `position` key, also add offset to their position values, since override positions are relative to the pattern origin.

**In `_expand_build_line(line, offset)`:**
- Accept the `offset` array parameter (default `[0, 0, 0]`).
- Parse offset components.
- After computing each interpolated position along the path, add offset to the `[x, y, z]` array before appending to the spec.
- This includes the first point (start of line) and all interpolated points.

**In scatter handling (inside `_expand_build_pattern`):**
- After getting `scatter.get("items", [])`, iterate over each item dict.
- If the item has a `"position"` key (an array), create a new position array with offset added: `[pos[0] + off_x, pos[1] + off_y, pos[2] + off_z]`.
- If the item has no `"position"` key, skip it (scatter items require explicit positions but the system tolerates missing ones).
- Return the modified items array.

## Backward Compatibility

- When `offset` is not provided (or is `None`), Python defaults it to `[0, 0, 0]`.
- GDScript reads `params.get("offset", [0, 0, 0])`, so older Python versions that do not send offset will still work.
- All existing tests should pass unchanged since they do not provide offset and the default `[0, 0, 0]` produces identical positions.

## Dependencies

None. This section is fully independent and can be implemented in isolation.

## Implementation Notes (Post-Build)

### Files Modified
- `src/godotiq/tools/bridge/build_scene.py` — Added `offset` param to `validate_build_params()` and `build_scene()`
- `src/godotiq/tools/bridge/__init__.py` — Added `offset` param to MCP wrapper `godotiq_build_scene()`
- `godot-addon/addons/godotiq/godotiq_server.gd` — Applied offset in `_expand_build_pattern()`, `_expand_build_grid()`, `_expand_build_line()`, and scatter handling
- `tests/test_tools/test_build_scene.py` — Added `TestOffsetValidation` class (6 tests) + updated signature test

### Deviations from Plan
- **Line endpoint deduplication fix:** Code review caught that `final_pos` in `_expand_build_line` was constructed without offset, causing duplicate endpoint nodes when offset is non-zero. Fixed by applying offset to `final_pos` before the distance comparison.
- **Grid override positions:** Added offset application to override tiles that already have a `position` key (plan mentioned this but implementation confirmed it works).
- **`nodes` mode:** Does NOT apply offset — kept as-is since nodes mode uses explicit positions and offset is primarily for pattern-based placement.

### Test Results
- 38 tests pass in `test_build_scene.py` (6 new + 32 existing)
- No regressions in full suite (1181 pass)