DigDig.IO Effects

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

As of 2021-09-01. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         DigDig.IO Effects
// @namespace    http://tampermonkey.net/
// @version      0.2.1
// @description  3D, particles and glow effect for DigDig.IO. Use num keys from 1 to 3 to toggle effects
// @author       Zertalious (Zert)
// @match        *://digdig.io/*
// @icon         https://www.google.com/s2/favicons?domain=digdig.io
// @grant        none
// @require      https://unpkg.com/three@latest/build/three.min.js
// @require      https://unpkg.com/three@latest/examples/js/postprocessing/EffectComposer.js
// @require      https://unpkg.com/three@latest/examples/js/postprocessing/RenderPass.js
// @require      https://unpkg.com/three@latest/examples/js/postprocessing/UnrealBloomPass.js
// @require      https://unpkg.com/three@latest/examples/js/postprocessing/ShaderPass.js
// @require      https://unpkg.com/three@latest/examples/js/shaders/LuminosityHighPassShader.js
// @require      https://unpkg.com/three@latest/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 < 13 ) {

					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 );

document.body.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 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 ];

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();

}