Quick answer: When you use render_mode skip_vertex_transform, you must manually apply MODEL_MATRIX, CANVAS_MATRIX, and SCREEN_MATRIX. Otherwise vertices land at raw object-space positions.

A custom water shader needs raw vertex positions for a swirl effect. You add render_mode skip_vertex_transform. The sprite now renders at the top-left of the screen at unit size regardless of where it’s placed — because no transform is being applied.

Default vs Skipped Transform

Normal canvas_item vertex shader (simplified):

void vertex() {
    // Engine implicitly does:
    // VERTEX = (CANVAS_MATRIX * MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy
}

With render_mode skip_vertex_transform:

render_mode skip_vertex_transform;

void vertex() {
    // You write transform yourself
    VERTEX = (CANVAS_MATRIX * MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
}

That restores the default transform; now you can add your own perturbation on top of it.

Adding a Custom Effect

render_mode skip_vertex_transform;

uniform float swirl_strength = 10.0;

void vertex() {
    vec2 v = VERTEX;
    // Add swirl in object space
    float r = length(v);
    float theta = atan(v.y, v.x) + r * swirl_strength * sin(TIME);
    v = vec2(cos(theta), sin(theta)) * r;
    // Reapply standard transform
    VERTEX = (CANVAS_MATRIX * MODEL_MATRIX * vec4(v, 0.0, 1.0)).xy;
}

The custom math operates on object-space vertices first, then the transform brings them into canvas space.

Do You Actually Need to Skip?

If your custom effect is offset-based rather than full-position-based, you can usually leave the default transform on:

void vertex() {
    // Add offset to VERTEX before engine’s implicit transform
    VERTEX.x += sin(TIME + VERTEX.y * 0.1) * 10.0;
}

The engine still applies the transform after your offset. Simpler.

Verifying

Place the sprite somewhere in the scene. Check it renders at the placed position with the expected effect. If the sprite is at world origin regardless of placement, you forgot to reapply MODEL_MATRIX.

“Skip transform = you control the transform. Don’t skip unless you have a real reason; if you do, reapply the matrices.”

Most “skip transform” usage is unnecessary — try the offset approach first, only escalate if you need raw object-space access.