Build and inspect Video Sequence Editor timelines from Python: SequenceEditor.strips vs the removed .sequences, new_effect length vs frame_end, strip transforms, and the 5.2 COLOR strip width/height bake from scene resolution. Use when the user scripts the sequencer, hits AttributeError on sequence_editor.sequences in 5.x or a TypeError on new_effect keyword arguments, or renders COLOR strips that ignore transform scale after a resolution change. Targets 5.2 LTS with 4.5 LTS fallback.
Installs into .claude/skills of the current project.
Are you the author of Vse Python?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tmhsdigital-vse-python)
---
name: vse-python
description: "Build and inspect Video Sequence Editor timelines from Python: SequenceEditor.strips vs the removed .sequences, new_effect length vs frame_end, strip transforms, and the 5.2 COLOR strip width/height bake from scene resolution. Use when the user scripts the sequencer, hits AttributeError on sequence_editor.sequences in 5.x or a TypeError on new_effect keyword arguments, or renders COLOR strips that ignore transform scale after a resolution change. Targets 5.2 LTS with 4.5 LTS fallback."
standards-version: 1.10.0
---
# Video Sequence Editor in Python
## Trigger
Use this skill when the user:
- Builds or inspects a VSE / sequencer timeline from a script
- Mentions `sequence_editor`, `strips`, `sequences`, `new_effect`, COLOR strips, or `StripTransform`
- Hits `AttributeError: 'SequenceEditor' object has no attribute 'sequences'` on 5.x
- Hits `TypeError` on `new_effect` kwargs (`frame_end` vs `length`)
- Renders a sequencer composite whose COLOR cells ignore `transform.scale_*` after a resolution change
## High-level shape
```python
import bpy
scene = bpy.context.scene
se = scene.sequence_editor or scene.sequence_editor_create()
coll = se.strips if hasattr(se, "strips") else se.sequences
if bpy.app.version >= (5, 0, 0):
strip = coll.new_effect(
name="A", type="COLOR", channel=1,
frame_start=1, length=10,
)
else:
strip = coll.new_effect(
name="A", type="COLOR", channel=1,
frame_start=1, frame_end=11,
)
strip.color = (0.85, 0.10, 0.22)
```
Branch on the `bpy.app.version` tuple for known API boundaries (such as the 5.2 COLOR strip `width`/`height` bake), never on `bpy.app.version_string`. Pick the `.strips` vs `.sequences` accessor with `hasattr`, not version: an empty `bpy_prop_collection` is falsy, so `se.strips or se.sequences` silently falls through to the legacy accessor on an empty timeline.
## Accessor: `.strips` vs `.sequences`
| | 4.5 LTS | 5.1 / 5.2+ |
| --- | --- | --- |
| Canonical collection | `.strips` (`.sequences` is a bridge to the same strips) | `.strips` only |
| `.sequences` | Present, same contents as `.strips` | `AttributeError` |
```python
def strips_coll(se):
return se.strips if hasattr(se, "strips") else se.sequences
```
Do not write `se.sequences` in new code. On 5.x it is gone; on 4.5 `.strips` already exists.
## `new_effect` end kwarg
`strips.new_effect(...)` ends a strip with **one** accepted end argument. The other raises `TypeError`.
```python
span = (1, 33) # end-exclusive [start, end)
if bpy.app.version >= (5, 0, 0):
strip = coll.new_effect(
name="A", type="COLOR", channel=1,
frame_start=span[0], length=span[1] - span[0],
)
else:
strip = coll.new_effect(
name="A", type="COLOR", channel=1,
frame_start=span[0], frame_end=span[1],
)
```
Timeline bounds: `frame_final_start` / `frame_final_end` / `frame_final_duration` on 4.5. On 5.x those names are deprecated aliases (removal announced for 6.0); canonical accessors are `left_handle` / `right_handle` / `duration`. Scene strips take four args — `new_scene(name, scene, channel, frame_start)` — with no `length` / `frame_end` kwarg on either version.
The `TRANSFORM` effect type is removed on 5.x. Place strips with per-strip `strip.transform` (`StripTransform`) on both versions. Effect inputs are `input_1` / `input_2` (creation kwargs `input1` / `input2`).
## COLOR strip intrinsic size (5.2)
4.5 LTS and 5.1 COLOR strips have **no** intrinsic size. `transform.scale_*` is a fraction of the **output frame**. Creating at factory resolution then rendering a tiny buffer is fine.
5.2 and later bake readonly `width` / `height` from **scene render resolution at `new_effect` time**. Scale and offset are then in that **media** space, not a later output size. Set scene resolution **before** building strips.
This split is **not** in the 5.2 `python_api` release notes. Witnessed by [`examples/vse-cut-list/`](https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/examples/vse-cut-list) `--check-pixels`.
```python
width, height = 96, 54
scene.render.resolution_x = width
scene.render.resolution_y = height
se = scene.sequence_editor or scene.sequence_editor_create()
coll = se.strips if hasattr(se, "strips") else se.sequences
if bpy.app.version >= (5, 0, 0):
strip = coll.new_effect(
name="A", type="COLOR", channel=1,
frame_start=1, length=10,
)
else:
strip = coll.new_effect(
name="A", type="COLOR", channel=1,
frame_start=1, frame_end=11,
)
if bpy.app.version >= (5, 2, 0):
# 5.2+: readonly width/height baked at new_effect from scene.render
assert (strip.width, strip.height) == (width, height)
# strip.width = 64 # TypeError — readonly
else:
# 4.5 / 5.1: no intrinsic size; hasattr(strip, "width") is False
pass
strip.transform.scale_x = 0.36
strip.transform.scale_y = 0.36
```
Creating at factory 1920×1080 then dropping the scene to 96×54 for a check render makes a 0.36-scaled COLOR cell larger than the output. On 5.2 the long-runner covers the frame; pixel samples read the wrong strip.
A lone COLOR strip **does** honor `transform.scale_*` on 5.2. The break is media size vs a later output size, not "transform is ignored."
## Common AI mistakes
1. **`sequence_editor.sequences` on 5.x.** `AttributeError`. Use `.strips` (with `hasattr` only as a 4.5 bridge).
2. **Wrong `new_effect` end kwarg.** `frame_end=` on 5.x and `length=` on 4.5 both raise `TypeError`.
3. **Creating COLOR strips, then changing render size** (the 5.2 trap):
```python
a = coll.new_effect(...) # bakes 1920×1080 on 5.2
scene.render.resolution_x = 96 # output changed; media size did not
```
Set `scene.render.resolution_*` **before** `new_effect`.
4. **`se.strips or se.sequences`.** An empty collection is falsy, so this falls through to `.sequences` on a fresh editor.
5. **`TRANSFORM` effect type on 5.x.** Gone. Use `strip.transform`.
6. **Scene strip pointing at its own scene.** Feedback loop; renders transparent. Source a **separate** scene.
7. **Effect strips consume their inputs** only when stacked on a channel **above** those inputs. Below, the inputs keep compositing independently. A `GAMMA_CROSS` asked to outlast its inputs' overlap is silently clamped to the overlap.
## See also
- Example [`examples/vse-cut-list/`](https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/examples/vse-cut-list) — accessor rename, `new_effect` kwargs, save/reload, and the 5.2 COLOR size bake (`--check-pixels` asserts `A.width, A.height == render size` on 5.2+).
- Example [`examples/vse-gamma-cross/`](https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/examples/vse-gamma-cross) — `GAMMA_CROSS` blend curve.
- Audit log: [`docs/technical-audit.md`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/docs/technical-audit.md) § Findings the release notes did not list.
<!-- examples:begin (generated by scripts/build_examples_index.py from examples/skills.json; do not edit) -->
## Runnable examples
Each example runs headless, asserts the contract, and exits non-zero when it breaks. Run one with `blender --background --python <script> --`; pass a falsifier flag to watch the check fail.
- [`vse-cut-list`](https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/examples/vse-cut-list): The sequencer API rename from 4.5 LTS to 5.x — strips (never .sequences), new_effect ending in length= vs frame_end=, and left_handle/right_handle/duration replacing the deprecated frame_final_*. Falsify: `--swap-inputs` (exit 7).
- [`vse-gamma-cross`](https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/examples/vse-gamma-cross): The GAMMA_CROSS fade is not the naive linear mix: it blends in a gamma-0.5 space, so the mid-cross dips below the sRGB lerp. Falsify: `--swap-inputs` (exit 4).
- [`vse-linear-modifiers`](https://github.com/TMHSDigital/Blender-Developer-Tools/tree/main/examples/vse-linear-modifiers): Pathology witness for the 5.2 removal of `Strip.use_linear_modifiers`. Falsify: `--assume-present` (exit 4).
<!-- examples:end -->
## References
- `bpy.types.SequenceEditor`: https://docs.blender.org/api/current/bpy.types.SequenceEditor.html
- `bpy.types.Strip` (5.x name of `Sequence`): https://docs.blender.org/api/current/bpy.types.Strip.html
- 4.5 LTS `Sequence`: https://docs.blender.org/api/4.5/bpy.types.Sequence.html
- 4.5 LTS `SequenceEditor`: https://docs.blender.org/api/4.5/bpy.types.SequenceEditor.html
- 5.1 `SequenceEditor`: https://docs.blender.org/api/5.1/bpy.types.SequenceEditor.html