body {
	width: 100vw;
	height: 100vh;
	margin: 0;
	background: black;
	overflow: hidden;
}
let scene,
	camera,
	renderer,
	cloudParticles = [],
	rainParticles = [],
	flash,
	rain,
	rainGeo,
	rainCount = 15000;
function init() {
	scene = new THREE.Scene();
	camera = new THREE.PerspectiveCamera(
		60,
		window.innerWidth / window.innerHeight,
		1,
		1000
	);
	camera.position.z = 1;
	camera.rotation.x = 1.16;
	camera.rotation.y = -0.12;
	camera.rotation.z = 0.27;

	ambient = new THREE.AmbientLight(0x555555);
	scene.add(ambient);

	directionalLight = new THREE.DirectionalLight(0xffeedd);
	directionalLight.position.set(0, 0, 1);
	scene.add(directionalLight);

	flash = new THREE.PointLight(0x062d89, 30, 500, 1.7);
	flash.position.set(200, 300, 100);
	scene.add(flash);

	renderer = new THREE.WebGLRenderer();

	scene.fog = new THREE.FogExp2(0x11111f, 0.002);
	renderer.setClearColor(scene.fog.color);

	renderer.setSize(window.innerWidth, window.innerHeight);
	document.body.appendChild(renderer.domElement);

	let positions = [];
	let sizes = [];
	rainGeo = new THREE.BufferGeometry();
	for (let i = 0; i < rainCount; i++) {
		rainDrop = new THREE.Vector3(
			Math.random() * 400 - 200,
			Math.random() * 500 - 250,
			Math.random() * 400 - 200
		);
		positions.push(Math.random() * 400 - 200);
		positions.push(Math.random() * 500 - 250);
		positions.push(Math.random() * 400 - 200);
		sizes.push(30);
	}
	rainGeo.setAttribute(
		"position",
		new THREE.BufferAttribute(new Float32Array(positions), 3)
	);
	rainGeo.setAttribute(
		"size",
		new THREE.BufferAttribute(new Float32Array(sizes), 1)
	);
	rainMaterial = new THREE.PointsMaterial({
		color: 0xaaaaaa,
		size: 0.1,
		transparent: true
	});
	rain = new THREE.Points(rainGeo, rainMaterial);
	scene.add(rain);

	let loader = new THREE.TextureLoader();
	loader.load(
		"https://static.vecteezy.com/system/resources/previews/010/884/548/original/dense-fluffy-puffs-of-white-smoke-and-fog-on-transparent-background-abstract-smoke-clouds-movement-blurred-out-of-focus-smoking-blows-from-machine-dry-ice-fly-fluttering-in-air-effect-texture-png.png",
		function (texture) {
			cloudGeo = new THREE.PlaneBufferGeometry(500, 500);
			cloudMaterial = new THREE.MeshLambertMaterial({
				map: texture,
				transparent: true
			});

			for (let p = 0; p < 25; p++) {
				let cloud = new THREE.Mesh(cloudGeo, cloudMaterial);
				cloud.position.set(
					Math.random() * 800 - 400,
					500,
					Math.random() * 500 - 450
				);
				cloud.rotation.x = 1.16;
				cloud.rotation.y = -0.12;
				cloud.rotation.z = Math.random() * 360;
				cloud.material.opacity = 0.6;
				cloudParticles.push(cloud);
				scene.add(cloud);
			}
			animate();
			window.addEventListener("resize", onWindowResize);
		}
	);
}
function animate() {
	cloudParticles.forEach((p) => {
		p.rotation.z -= 0.002;
	});
	rainGeo.attributes.size.array.forEach((r, i) => {
		r += 0.3;
	});
	const time = Date.now() * 0.005;

	rainGeo.verticesNeedUpdate = true;

	rain.position.z -= 0.222;
	if (rain.position.z < -200) {
		rain.position.z = 0;
	}

	if (Math.random() > 0.93 || flash.power > 100) {
		if (flash.power < 100)
			flash.position.set(Math.random() * 400, 300 + Math.random() * 200, 100);
		flash.power = 50 + Math.random() * 500;
	}
	renderer.render(scene, camera);
	requestAnimationFrame(animate);
}

init();

function onWindowResize() {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();

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

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/three.js/0.147.0/three.min.js