// ==UserScript== // @name DigDig.IO Effects // @namespace http://tampermonkey.net/ // @version 0.1.5 // @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 // @downloadURL none // ==/UserScript== ( function () { 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 ) { const height = ctx.getTransform().d; if ( height < 10 && particlesEnabled() ) { ctx.globalAlpha = 1; ctx.fillStyle = particleColor; } } return Reflect.apply( ...arguments ); } } ); 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( { alpha: 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( Math.PI / 3 ); 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 material = new THREE.RawShaderMaterial( { vertexShader: ` precision mediump float; attribute vec3 position; attribute vec2 uv; uniform mat4 projectionMatrix; uniform mat4 modelViewMatrix; uniform sampler2D texture; uniform float groundDepth; varying vec2 vUv; varying float vDepth; void main() { vec4 p = vec4( position, 1.0 ); vec3 texColor = texture2D( texture, uv ).rgb; if ( length( ${ground} - texColor ) < 0.05 ) p.z -= groundDepth; vDepth = - p.z; gl_Position = projectionMatrix * modelViewMatrix * p; vUv = uv; } `, fragmentShader: ` precision mediump float; uniform sampler2D texture; uniform float groundDepth; varying vec2 vUv; varying float vDepth; void main() { if ( vDepth > 0.0 && vDepth < groundDepth ) { gl_FragColor = vec4( ${ground} * 0.8, 1.0 ); } else { gl_FragColor = texture2D( texture, vUv ); } } `, uniforms: { texture: { value: texture }, groundDepth: { value: 0.10 } } } ); const tessellation = new THREE.Mesh( new THREE.PlaneGeometry( 1, 1, 500, 500 ), material ); scene.add( tessellation ); const rtt = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight ); 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 && value <= 1.0 ) { gl_FragColor = vec4( 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 = parseInt( color.slice( 1, 3 ), 16 ) / 255; const g = parseInt( color.slice( 3, 5 ), 16 ) / 255; const b = parseInt( color.slice( 5, 7 ), 16 ) / 255; return 'vec3(' + r + ', ' + g + ', ' + b + ')'; } } 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(); } } )();