diff --git a/examples/files.json b/examples/files.json
index 7bac8861c4693a..10094900b055a7 100644
--- a/examples/files.json
+++ b/examples/files.json
@@ -467,6 +467,7 @@
"webgpu_tsl_galaxy",
"webgpu_tsl_halftone",
"webgpu_tsl_interoperability",
+ "webgpu_tsl_override_context",
"webgpu_tsl_procedural_terrain",
"webgpu_tsl_raging_sea",
"webgpu_tsl_transpiler",
diff --git a/examples/screenshots/webgpu_tsl_override_context.jpg b/examples/screenshots/webgpu_tsl_override_context.jpg
new file mode 100644
index 00000000000000..da440263035c30
Binary files /dev/null and b/examples/screenshots/webgpu_tsl_override_context.jpg differ
diff --git a/examples/webgpu_tsl_override_context.html b/examples/webgpu_tsl_override_context.html
new file mode 100644
index 00000000000000..e4894115386e6c
--- /dev/null
+++ b/examples/webgpu_tsl_override_context.html
@@ -0,0 +1,136 @@
+
+
+
+
+ Three.js webgpu - tsl override context
+
+
+
+
+
+
+
three.js - WebGPU - TSL Override Context
+ Left: Default Normals | Right: Overridden Normals (Rotated via Context)
+
+
+
+
+
+
+
+
diff --git a/src/Three.TSL.js b/src/Three.TSL.js
index 0ea6849fbe2758..9e1d85ab8a8a2c 100644
--- a/src/Three.TSL.js
+++ b/src/Three.TSL.js
@@ -133,6 +133,7 @@ export const compute = TSL.compute;
export const computeKernel = TSL.computeKernel;
export const computeSkinning = TSL.computeSkinning;
export const context = TSL.context;
+export const overrideContext = TSL.overrideContext;
export const convert = TSL.convert;
export const convertColorSpace = TSL.convertColorSpace;
export const convertToTexture = TSL.convertToTexture;
diff --git a/src/nodes/core/ContextNode.js b/src/nodes/core/ContextNode.js
index da770f8e3252fc..5824e42fe3ac77 100644
--- a/src/nodes/core/ContextNode.js
+++ b/src/nodes/core/ContextNode.js
@@ -220,7 +220,26 @@ export function label( node, name ) {
}
+/**
+ * TSL function for overriding a context for a given node.
+ *
+ * @tsl
+ * @function
+ * @param {Node} node - The node whose context should be modified.
+ * @param {Node} targetNode - The node that will be replaced.
+ * @param {Node} sourceNode - The node that will replace the targetNode.
+ * @returns {ContextNode}
+ */
+export const overrideContext = ( node, targetNode, sourceNode ) => {
+
+ const cleanSource = context( sourceNode, { [ targetNode.uuid ]: undefined } );
+
+ return context( node, { [ targetNode.uuid ]: cleanSource } );
+
+};
+
addMethodChaining( 'context', context );
addMethodChaining( 'label', label );
addMethodChaining( 'uniformFlow', uniformFlow );
addMethodChaining( 'setName', setName );
+addMethodChaining( 'overrideContext', overrideContext );
diff --git a/src/nodes/core/Node.js b/src/nodes/core/Node.js
index 241ec9d2c4adf1..f8cd4bcd8f8957 100644
--- a/src/nodes/core/Node.js
+++ b/src/nodes/core/Node.js
@@ -720,6 +720,16 @@ class Node extends EventDispatcher {
*/
build( builder, output = null ) {
+ const nodeFromContext = builder.context[ this.uuid ];
+
+ if ( nodeFromContext !== undefined ) {
+
+ return nodeFromContext.build( builder, output );
+
+ }
+
+ //
+
const refNode = this.getShared( builder );
if ( this !== refNode ) {
diff --git a/src/nodes/core/VarNode.js b/src/nodes/core/VarNode.js
index 3727a0234d0a5e..70e9238f093cb4 100644
--- a/src/nodes/core/VarNode.js
+++ b/src/nodes/core/VarNode.js
@@ -181,6 +181,14 @@ class VarNode extends Node {
const builder = params[ 0 ];
+ const nodeFromContext = builder.context[ this.uuid ];
+
+ if ( nodeFromContext !== undefined ) {
+
+ return nodeFromContext.build( ...params );
+
+ }
+
if ( this._hasStack( builder ) === false && builder.buildStage === 'setup' ) {
if ( builder.context.nodeLoop || builder.context.nodeBlock ) {