diff --git a/examples/files.json b/examples/files.json
index 39389c773481a0..abbc2ef8da3108 100644
--- a/examples/files.json
+++ b/examples/files.json
@@ -379,6 +379,7 @@
"webgpu_postprocessing_pixel",
"webgpu_postprocessing_fxaa",
"webgpu_postprocessing_sobel",
+ "webgpu_postprocessing_transition",
"webgpu_postprocessing",
"webgpu_procedural_texture",
"webgpu_reflection",
diff --git a/examples/screenshots/webgpu_postprocessing_transition.jpg b/examples/screenshots/webgpu_postprocessing_transition.jpg
new file mode 100644
index 00000000000000..1e0cccd8471033
Binary files /dev/null and b/examples/screenshots/webgpu_postprocessing_transition.jpg differ
diff --git a/examples/webgpu_postprocessing_transition.html b/examples/webgpu_postprocessing_transition.html
new file mode 100644
index 00000000000000..1a23923f68b1b3
--- /dev/null
+++ b/examples/webgpu_postprocessing_transition.html
@@ -0,0 +1,265 @@
+
+
+
+ three.js webgpu - scenes transition
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/nodes/Nodes.js b/src/nodes/Nodes.js
index 348ce958598285..b7439ab67a7bce 100644
--- a/src/nodes/Nodes.js
+++ b/src/nodes/Nodes.js
@@ -138,6 +138,7 @@ export { default as GTAONode, ao } from './display/GTAONode.js';
export { default as DenoiseNode, denoise } from './display/DenoiseNode.js';
export { default as FXAANode, fxaa } from './display/FXAANode.js';
export { default as BloomNode, bloom } from './display/BloomNode.js';
+export { default as TransitionNode, transition } from './display/TransitionNode.js';
export { default as RenderOutputNode, renderOutput } from './display/RenderOutputNode.js';
export { default as PixelationPassNode, pixelationPass } from './display/PixelationPassNode.js';
diff --git a/src/nodes/display/TransitionNode.js b/src/nodes/display/TransitionNode.js
new file mode 100644
index 00000000000000..e911d85b28b459
--- /dev/null
+++ b/src/nodes/display/TransitionNode.js
@@ -0,0 +1,76 @@
+import TempNode from '../core/TempNode.js';
+import { uv } from '../accessors/UVNode.js';
+import { addNodeElement, tslFn, nodeObject, float, int, vec4, If } from '../shadernode/ShaderNode.js';
+import { clamp, mix } from '../math/MathNode.js';
+import { sub } from '../math/OperatorNode.js';
+
+class TransitionNode extends TempNode {
+
+ constructor( textureNodeA, textureNodeB, mixTextureNode, mixRatioNode, thresholdNode, useTextureNode ) {
+
+ super();
+
+ // Input textures
+
+ this.textureNodeA = textureNodeA;
+ this.textureNodeB = textureNodeB;
+ this.mixTextureNode = mixTextureNode;
+
+ // Uniforms
+
+ this.mixRatioNode = mixRatioNode;
+ this.thresholdNode = thresholdNode;
+ this.useTextureNode = useTextureNode;
+
+ }
+
+ setup() {
+
+ const { textureNodeA, textureNodeB, mixTextureNode, mixRatioNode, thresholdNode, useTextureNode } = this;
+
+ const sampleTexture = ( textureNode ) => {
+
+ const uvNodeTexture = textureNode.uvNode || uv();
+ return textureNode.uv( uvNodeTexture );
+
+ };
+
+ const transition = tslFn( () => {
+
+ const texelOne = sampleTexture( textureNodeA );
+ const texelTwo = sampleTexture( textureNodeB );
+
+ const color = vec4().toVar();
+
+ If( useTextureNode.equal( int( 1 ) ), () => {
+
+ const transitionTexel = sampleTexture( mixTextureNode );
+ const r = mixRatioNode.mul( thresholdNode.mul( 2.0 ).add( 1.0 ) ).sub( thresholdNode );
+ const mixf = clamp( sub( transitionTexel.r, r ).mul( float( 1.0 ).div( thresholdNode ) ), 0.0, 1.0 );
+
+ color.assign( mix( texelOne, texelTwo, mixf ) );
+
+ } ).else( () => {
+
+ color.assign( mix( texelTwo, texelOne, mixRatioNode ) );
+
+ } );
+
+ return color;
+
+ } );
+
+ const outputNode = transition();
+
+ return outputNode;
+
+ }
+
+}
+
+export const transition = ( nodeA, nodeB, mixTexture, mixRatio = 0.0, threshold = 0.1, useTexture = 0 ) => nodeObject( new TransitionNode( nodeObject( nodeA ).toTexture(), nodeObject( nodeB ).toTexture(), nodeObject( mixTexture ).toTexture(), nodeObject( mixRatio ), nodeObject( threshold ), nodeObject( useTexture ) ) );
+
+addNodeElement( 'transition', transition );
+
+export default TransitionNode;
+