DigDig.IO/DigWorm.IO Effects

3D, particles and glow effect for DigDig.IO and DigWorm.IO. Use num keys from 1 to 3 to toggle effects

// ==UserScript==
// @name         DigDig.IO/DigWorm.IO Effects
// @namespace    http://tampermonkey.net/
// @version      0.2.5
// @description  3D, particles and glow effect for DigDig.IO and DigWorm.IO. Use num keys from 1 to 3 to toggle effects
// @author       Zertalious (Zert)
// @match        *://digdig.io/*
// @match        *://digworm.io/*
// @icon         https://www.google.com/s2/favicons?domain=digdig.io
// @grant        none
// @require      https://unpkg.com/three@0.120.0/build/three.min.js
// @require      https://unpkg.com/three@0.120.0/examples/js/postprocessing/EffectComposer.js
// @require      https://unpkg.com/three@0.120.0/examples/js/postprocessing/RenderPass.js
// @require      https://unpkg.com/three@0.120.0/examples/js/postprocessing/UnrealBloomPass.js
// @require      https://unpkg.com/three@0.120.0/examples/js/postprocessing/ShaderPass.js
// @require      https://unpkg.com/three@0.120.0/examples/js/shaders/LuminosityHighPassShader.js
// @require      https://unpkg.com/three@0.120.0/examples/js/shaders/CopyShader.js
// ==/UserScript==

window.enable3d = true;

window.enableParticles = function ( bool ) {

	if ( bool === undefined ) {

		bool = ! particlesEnabled();

	}

	maskMaterial.uniforms.enableParticles.value = bool;

}

window.enableGlow = function ( bool ) {

	if ( bool === undefined ) {

		bool = ! glowEnabled();

	}

	maskMaterial.uniforms.enableGlow.value = bool;

}

window.addEventListener( 'keyup', function ( event ) {

	const key = String.fromCharCode( event.keyCode );

	switch ( key ) {

		case '1' : enable3d = ! enable3d; break;
		case '2' : enableGlow(); break;
		case '3' : enableParticles(); break;

	}

} );

const canvas = document.getElementById( 'canvas' );
canvas.style.opacity = '0';

const particleColor = '#0000ff';

CanvasRenderingContext2D.prototype.fillRect = new Proxy( CanvasRenderingContext2D.prototype.fillRect, {
	apply( target, ctx, args ) {

		if ( ctx.globalAlpha <= 1 ) {

			if ( ctx.fillStyle === '#000000' ) {

				return;

			} if ( particlesEnabled() ) {

				if ( ctx.getTransform().d < 20 ) {

					ctx.fillStyle = '#00' + Math.floor( ctx.globalAlpha * 256 ).toString( 16 ).padStart( 2, '0' ) + 'ff';
					ctx.globalAlpha = 1;

				}

			}

		}

		return Reflect.apply( ...arguments );

	}
} );

const Canvas = window.OffscreenCanvas ? OffscreenCanvas.prototype : HTMLCanvasElement.prototype;

Canvas.getContext = new Proxy( Canvas.getContext, {
	apply( target, canvas, args ) {

		const ctx = Reflect.apply( ...arguments );

		ctx.fillRect = new Proxy( ctx.fillRect, {
			apply( target, thisArgs, args ) {

				if ( ctx.globalAlpha < 1 ) {

					if ( ctx.fillStyle === '#000000' ) {

						return;

					}

				}

				return Reflect.apply( ...arguments );

			}
		} );

		return ctx;

	}
} );

window.Image = new Proxy( window.Image, {
	construct( target, thisArgs, args ) {

		const image = Reflect.construct( ...arguments );

		image.crossOrigin = 'anonymous';

		return image;

	}
} );

const renderer = new THREE.WebGLRenderer( { antialias: true, preserveDrawingBuffer: true } );

renderer.domElement.style.position = 'absolute';
renderer.domElement.style.left = '0';
renderer.domElement.style.top = '0';
renderer.domElement.style.pointerEvents = 'none';

renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );

canvas.parentNode.insertBefore( renderer.domElement, canvas );

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 60, 1, 0.1, 1000 );

camera.position.z = Math.sin( camera.fov * Math.PI / 180 ) * 2;

const texture = new THREE.CanvasTexture( canvas );
texture.minFilter = texture.magFilter = THREE.NearestFilter;

scene.background = new THREE.Color( '#522e00' );

const ground = toVec3( scene.background );
const diamond = toVec3( '#31a59e' );
const gold = toVec3( '#a59e15' );
const lava = toVec3( '#a61906' );
const uranium = toVec3( '#32a430' );
const particle = toVec3( particleColor );
const grid = toVec3( '#4e2c00' );
const amethyst = toVec3( '#b332b5' );

const material = new THREE.RawShaderMaterial( {
    vertexShader: `

		attribute vec3 position;

		varying vec3 vPosition;

		void main() {

			vPosition = position;

			gl_Position = vec4( position, 1.0 );

		}

		`,
    fragmentShader: `

		precision mediump float;

		uniform sampler2D map;
		uniform float depth;

		uniform mat4 modelViewMatrix;
		uniform mat4 projectionMatrix;

		varying vec3 vPosition;

		void main() {

			vec4 a;

			const int count = 20;

			for ( int i = 0; i <= count; i ++ ) {

				vec4 p = projectionMatrix * modelViewMatrix * vec4( vec3( vPosition.xy, float( i ) / float( count ) * depth ), 1.0 );

				vec4 b = texture2D( map, p.xy / p.w * 0.5 + 0.5 );

				if ( length( b.rgb - ${ground} ) < 0.1 || length( b.rgb - ${grid} ) < 0.1 ) {

					if ( i != count ) {

						b.a = 0.0;

					}

				} else if ( i != 0 ) {

					b.rgb = ${ground} * 0.8;

				}

				a.rgb = a.rgb * a.a + b.rgb * b.a * ( 1.0 - a.a );
				a.a = a.a + b.a * ( 1.0 - a.a );

			}

			gl_FragColor = a;

		}

		`,
    uniforms: {
        map: {
            value: texture
        },
        depth: {
            value: 0.20
        }
    }
} );

const tessellation = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), material );
scene.add( tessellation );

const rtt = new THREE.WebGLRenderTarget( window.innerWidth * window.devicePixelRatio, window.innerHeight * window.devicePixelRatio );

const array = [ diamond, gold, lava, uranium, amethyst ];

let text = '';

for ( let i = 0; i < array.length; i ++ ) {

	text += 'length( ' + array[ i ] + ' - gl_FragColor.rgb ) > 0.1';

	if ( i < array.length - 1 ) {

		text += ' && ';

	}

}

const maskMaterial = new THREE.RawShaderMaterial( {
	vertexShader: `

	precision mediump float;

	attribute vec3 position;
	attribute vec2 uv;

	uniform mat4 projectionMatrix;
	uniform mat4 modelViewMatrix;

	varying vec2 vUv;

	void main() {

		gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
		vUv = uv;

	}

	`,
	fragmentShader: `

	precision mediump float;

	uniform sampler2D texture;
	uniform bool enableParticles;
	uniform bool enableGlow;

	varying vec2 vUv;

	void main() {

		gl_FragColor = texture2D( texture, vUv );

		float value = length( ${particle} - gl_FragColor.rgb ) / 0.2;

		if ( enableParticles && gl_FragColor.r == 0.0 && gl_FragColor.b == 1.0 ) {

			gl_FragColor = vec4( 1.0, 1.0 - gl_FragColor.g, gl_FragColor.g * 0.5 + 0.5, 1.0 );

		} else if ( ! enableGlow || ${text} ) {

			gl_FragColor = vec4( 0.0 );

		}

	}

	`,
	uniforms: {
		texture: { value: undefined },
		enableParticles: { value: true },
		enableGlow: { value: true }
	}
} );

function toVec3( color ) {

	if ( color.isColor ) {

		return 'vec3(' + color.r + ', ' + color.g + ', ' + color.b + ')';

	} else {

		const [ r, g, b ] = toRGB( color );

		return 'vec3(' + r + ', ' + g + ', ' + b + ')';

	}

}

function toRGB( hex ) {

	return [
		parseInt( hex.slice( 1, 3 ), 16 ) / 255,
		parseInt( hex.slice( 3, 5 ), 16 ) / 255,
		parseInt( hex.slice( 5, 7 ), 16 ) / 255
	]

}

const bloomScene = new THREE.Scene();
bloomScene.background = null;

const bloomCamera = new THREE.OrthographicCamera();

bloomCamera.position.z = 5;

const mask = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), maskMaterial );
bloomScene.add( mask );

const finalPass = new THREE.ShaderPass(
	new THREE.ShaderMaterial( {
		uniforms: {
			baseTexture: { value: null },
			originalTexture: { value: undefined }
		},
		vertexShader: `

		varying vec2 vUv;

		void main() {

			vUv = uv;

			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

		}

		`,
		fragmentShader: `

		uniform sampler2D baseTexture;
		uniform sampler2D originalTexture;

		varying vec2 vUv;

		void main() {

			gl_FragColor = texture2D( originalTexture, vUv ) + texture2D( baseTexture, vUv );

		}

		`,
		defines: {}
	} ), 'baseTexture'
);

const params = {
	exposure: 1,
	bloomStrength: 0.5,
	bloomThreshold: 0,
	bloomRadius: 0
};

const bloomPass = new THREE.UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
bloomPass.threshold = params.bloomThreshold;
bloomPass.strength = params.bloomStrength;
bloomPass.radius = params.bloomRadius;

const renderPass = new THREE.RenderPass( bloomScene, bloomCamera );

const composer = new THREE.EffectComposer( renderer );
composer.addPass( renderPass );
composer.addPass( bloomPass );
composer.addPass( finalPass );

window.addEventListener( 'resize', function () {

	composer.setSize( window.innerWidth, window.innerHeight );

	renderer.setSize( window.innerWidth, window.innerHeight );

	rtt.setSize( window.innerWidth, window.innerHeight );

	render();

} );

window.requestAnimationFrame = new Proxy( window.requestAnimationFrame, {
	apply( target, thisArgs, args ) {

		args[ 0 ] = new Proxy( args[ 0 ], {
			apply() {

				Reflect.apply( ...arguments );

				render();

			}
		} )

		Reflect.apply( ...arguments );

	}
} );

function particlesEnabled() {

	return maskMaterial.uniforms.enableParticles.value === true;

}

function glowEnabled() {

	return maskMaterial.uniforms.enableGlow.value === true;

}

function render() {

	if ( ! ( enable3d || glowEnabled() || particlesEnabled() ) ) {

		if ( canvas.style.opacity === '0' ) {

			canvas.style.opacity = '1';
			renderer.domElement.style.display = 'none';

		}

		return;

	} else {

		if ( canvas.style.opacity === '1' ) {

			canvas.style.opacity = '0';
			renderer.domElement.style.display = '';

		}

	}

	texture.needsUpdate = true;

	bloomPass.strength = ( Math.sin( Date.now() / 150 ) * 0.5 + 0.5 ) * 0.75 + 0.5;

	if ( enable3d ) {

		finalPass.material.uniforms.originalTexture.value = maskMaterial.uniforms.texture.value = rtt.texture;

		renderer.setRenderTarget( rtt );
		renderer.render( scene, camera );

		renderer.setRenderTarget( null );

	} else {

		finalPass.material.uniforms.originalTexture.value = maskMaterial.uniforms.texture.value = texture;

	}

	composer.render();

}