<div id="container"></div>
html {
	overflow: hidden;
}

body {
	margin: 0;
	padding: 0;
	overflow: hidden;
	color: #fff;
	background: #4831ab;
}
View Compiled

var container = document.getElementById( 'container' );

var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );

var camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, .1, 1000 );
camera.position.set( 0, 0, 4 );

var scene = new THREE.Scene();
scene.background = new THREE.Color( 0x4831ab );

// lights
var aLight = new THREE.AmbientLight( 0x7f46ab );
scene.add( aLight );

// ---------------------------------------------------------------
// ---------------------------------------------------------------

// clouds

var cloudsSize = new THREE.Vector3( 15, 4, 6 );
var cloudsBox = new THREE.Box3();
cloudsBox.setFromCenterAndSize( new THREE.Vector3(), cloudsSize );

// -----------------------------------------------------------------

var sphereGeo = new THREE.SphereBufferGeometry( 0.2, 32, 16 );
var cloudMat = new THREE.MeshPhongMaterial({
	color: 0xffffff,
	shininess: 0
});

var Cloud = function() {

	THREE.Group.call( this );

	this.spheres = [];

	// fill in 3 boxes with a random number of
	// randomly positioned and randomly scaled spheres

	// large base
	var center1 = new THREE.Vector3();
	var size1 = new THREE.Vector3( 1, 0.25, 0.6 );
	var number1 = THREE.Math.randInt( 10, 25 );
	var scaleRange1 = new THREE.Vector2( 0.2, 1 );
	this.fillBox( center1, size1, number1, scaleRange1 );

	// top of cloud
	var center2 = new THREE.Vector3( 0, size1.y, 0 );
	var size2 = new THREE.Vector3( 0.5, 0.25, 0.5 );
	var number2 = THREE.Math.randInt( 5, 15 );
	var scaleRange2 = new THREE.Vector2( 0.2, 1 );
	this.fillBox( center2, size2, number2, scaleRange2 );

	// small tail
	var center3 = new THREE.Vector3( -0.7, 0, 0 );
	var size3 = new THREE.Vector3( 0.4, 0.2, 0.25 );
	var number3 = THREE.Math.randInt( 3, 7 );
	var scaleRange3 = new THREE.Vector2( 0.1, 0.5 );
	this.fillBox( center3, size3, number3, scaleRange3 );

	this.userData.velocity = THREE.Math.randFloat( 0.003, 0.007 );

};

Cloud.prototype = Object.create( THREE.Group.prototype );
Cloud.prototype.constructor = Cloud;

Cloud.prototype.fillBox = function( center, size, number, scale ){

	var box = new THREE.Box3();
	box.setFromCenterAndSize( center, size );

	var boxGroup = new THREE.Group();
	boxGroup.position.copy( center );
	this.add( boxGroup );

	for ( var i = 0; i < number; i++ ) {

		var sphere = new THREE.Mesh( sphereGeo, cloudMat );

		sphere.position.set(
			THREE.Math.randFloatSpread( size.x ),
			THREE.Math.randFloatSpread( size.y ),
			THREE.Math.randFloatSpread( size.z )
		);

		sphere.userData.scale = THREE.Math.randFloat( scale.x, scale.y );
		sphere.scale.setScalar( sphere.userData.scale );

		sphere.userData.velocity = THREE.Math.randFloat( 0.001, 0.002 );

		boxGroup.add( sphere );
		this.spheres.push( sphere );

	}

	return boxGroup;

};

Cloud.prototype.update = function( t ){

	// scale individual spheres
	for ( var i = 0; i < this.spheres.length; i++ ) {
		var sphere = this.spheres[i];
		var scaleOffset = Math.sin( t + ( i + 1 ) ) * 0.4 + 1;
		sphere.scale.setScalar( sphere.userData.scale * scaleOffset );
	}

	// move entire cloud forward
	this.position.x += this.userData.velocity;

	// reset cloud position
	if ( this.position.x > cloudsBox.max.x ) {
		this.position.x = cloudsBox.min.x;
	}

};

// -----------------------------------------------------------------

// fill clouds box with clouds

var clouds = [];

for ( var i = 0; i < 40; i++ ) {

	var cloud = new Cloud();

	cloud.position.set(
		THREE.Math.randFloatSpread( cloudsSize.x ),
		THREE.Math.randFloatSpread( cloudsSize.y ),
		THREE.Math.randFloatSpread( cloudsSize.z )
	);

	scene.add( cloud );
	clouds.push( cloud );

}

// -----------------------------------------------------------------
// -----------------------------------------------------------------

// moon

var MoonShader = {

	uniforms: {

		colorA: { type: 'v3', value: scene.background },
		colorB: { type: 'v3', value: new THREE.Color('#fff') },

	},

	vertexShader: [

		"varying vec2 vUv;",
		"void main() {",
		"	vUv = uv;",
		"	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
		"}"

	].join('\n'),

	fragmentShader: [

		"varying vec2 vUv;",
		"uniform vec3 colorA;",
		"uniform vec3 colorB;",

		"void main() {",
		" float pct = smoothstep( 0.39, 0.44, vUv.y );",
		"	vec3 col = mix( colorA, colorB, pct );",
		"	gl_FragColor = vec4( col, 1.0 );",
		"}"

	].join('\n')

};

var moonGeo = new THREE.SphereBufferGeometry( 2, 32, 32 );
var moonMat = new THREE.ShaderMaterial({
	uniforms: THREE.UniformsUtils.clone( MoonShader.uniforms ),
	vertexShader: MoonShader.vertexShader,
	fragmentShader: MoonShader.fragmentShader,
});
var moon = new THREE.Mesh( moonGeo, moonMat );
moon.position.set( -3, 4, -20 );
moon.rotation.set(
	- Math.PI / 2,
	- Math.PI / 6,
	Math.PI / 4,
);
scene.add( moon );

var moonLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
moonLight.position.copy( moon.position );
scene.add( moonLight );

//

// key light

var dLight = new THREE.DirectionalLight( 0xffffff, 0.2 );
dLight.position.set( 1, 1, 1 );
scene.add( dLight );

// ---------------------------------------------------------------
// ---------------------------------------------------------------

// stars

StarShader = {

	uniforms: {

		color:   { type: 'v3', value: new THREE.Color( 0xffffff ) },
		texture: { type: 't', value: null },
		time:    { type: 'f', value: 0 },
		size:    { type: 'f', value: 500.0 }

	},

	vertexShader: [

		'uniform float time;',
		'uniform float size;',
		'attribute float alphaOffset;',
		'varying float vAlpha;',
		'uniform vec4 origin;',

		'void main() {',

			'vAlpha = 0.5 * ( 1.0 + sin( alphaOffset + time ) );',

			'vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
			'float cameraDist = distance( mvPosition, origin );',
			'gl_PointSize = size / cameraDist;',
			'gl_Position = projectionMatrix * mvPosition;',

		'}'

	].join('\n'),

	fragmentShader: [

		'uniform float time;',
		'uniform vec3 color;',
		'uniform sampler2D texture;',

		'varying float vAlpha;',

		'void main() {',
		'  gl_FragColor = vec4( color, vAlpha );',
		'  gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord );',
		'}'

	].join('\n')
};

var Stars = function( options ) {

	var color = this.color = options.color || 0x333333;
	var size = this.size = options.size || 0.4;

	var pointCount = this.pointCount = options.pointCount || 40;
	var range = this.range = options.range || new THREE.Vector3( 2, 2, 2 );

	THREE.Group.call( this );

	// circle texture

	var canvas = document.createElement('canvas');
	canvas.width = canvas.height = 128;
	var ctx = canvas.getContext( '2d' );

	var centerX = canvas.width / 2;
	var centerY = canvas.height / 2;
	var radius = canvas.width / 3;

	ctx.beginPath();
	ctx.arc( centerX, centerY, radius, 0, 2 * Math.PI, false );
	ctx.fillStyle = '#fff';
	ctx.fill();

	var texture = new THREE.Texture( canvas );
	texture.premultiplyAlpha = true;
	texture.needsUpdate = true;

	//

	StarShader.uniforms.texture.value = texture;
	StarShader.uniforms.size.value = size;

	var pointsMat = new THREE.ShaderMaterial( {
		uniforms:       StarShader.uniforms,
		vertexShader:   StarShader.vertexShader,
		fragmentShader: StarShader.fragmentShader,
		blending:       THREE.AdditiveBlending,
		depthWrite: false,
		transparent:    true
	});

	var pointsGeo = new THREE.BufferGeometry();

	var positions = new Float32Array( pointCount * 3 );
	var alphas = new Float32Array( pointCount );

	for ( var i = 0; i < pointCount; i++ ) {

		positions[ i*3 + 0 ] = THREE.Math.randFloatSpread( range.x );
		positions[ i*3 + 1 ] = THREE.Math.randFloatSpread( range.y );
		positions[ i*3 + 2 ] = THREE.Math.randFloatSpread( range.z );

		alphas[ i ] = i;

	}

	pointsGeo.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
	pointsGeo.addAttribute( 'alphaOffset', new THREE.BufferAttribute( alphas, 1 ) );

	var points = this.points = new THREE.Points( pointsGeo, pointsMat );
	points.sortParticles = true;
	points.renderOrder = 1;

	this.add( points );

}

Stars.prototype = Object.create( THREE.Group.prototype );
Stars.prototype.constructor = Stars;

// ---------------------------------------------------------------

var stars = new Stars({
	color: 0xffffff,
	range: new THREE.Vector3( 110, 60, 30 ),
	pointCount: 400,
	size: 400,
	speed: 0.1
});

scene.add( stars );

stars.position.z = -50;

// ---------------------------------------------------------------
// ---------------------------------------------------------------

window.addEventListener( 'resize', resize, false );
function resize() {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize( window.innerWidth, window.innerHeight );
}

var clock = new THREE.Clock();

renderer.setAnimationLoop( loop );

function loop() {

	var time = clock.getElapsedTime();

	for ( var i = 0; i < clouds.length; i++ ) {
		clouds[i].update( time );
	}

	stars.points.material.uniforms.time.value = time;

	renderer.render( scene, camera );
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

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