Frontend Forever App
We have a mobile app for you to download and use. And you can unlock many features in the app.
Get it now
Intall Later
Run
HTML
CSS
Javascript
Output
Document
@charset "UTF-8"; @import url(https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,600,700,800); *, :after, :before { box-sizing: border-box; padding: 0; margin: 0; } body{ overflow: hidden; margin: 0; }
console.log("Event Fired") import * as THREE from "three"; import { OrbitControls } from "three/addons/controls/OrbitControls.js"; import { mergeGeometries } from "three/addons/utils/BufferGeometryUtils.js"; import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js"; import { RenderPass } from "three/addons/postprocessing/RenderPass.js"; import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js"; import { OutputPass } from "three/addons/postprocessing/OutputPass.js"; import { RoomEnvironment } from "three/addons/environments/RoomEnvironment.js"; console.clear(); // load fonts await (async function () { async function loadFont(fontface) { await fontface.load(); document.fonts.add(fontface); } let fonts = [ new FontFace( "KodeMono", "url(https://fonts.gstatic.com/s/kodemono/v1/A2BYn5pb0QgtVEPFnlYOnYLw.woff2) format('woff2')" ) ]; for (let font in fonts) { //console.log(fonts[font]); await loadFont(fonts[font]); } })(); class GlowLayer extends EffectComposer { constructor(renderer) { const target = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { type: THREE.HalfFloatType, format: THREE.RGBAFormat, colorSpace: THREE.SRGBColorSpace, samples: 8 } ); super(renderer, target); const renderScene = new RenderPass(scene, camera); const bloomPass = new UnrealBloomPass( new THREE.Vector2(window.innerWidth, window.innerHeight), 0.1, 0, 5 ); const outputPass = new OutputPass(); this.uniforms = { aspect: { value: camera.aspect } }; outputPass.material.onBeforeCompile = (shader) => { shader.uniforms.aspect = this.uniforms.aspect; shader.uniforms.watermark = {value: (function () { let c = document.createElement("canvas"); c.width = 1024; c.height = 128; let $ = c.getContext("2d"); $.clearRect(0, 0, c.width, c.height); $.font = `bold ${c.height * 0.5}px KodeMono`; $.textAlign = "left"; $.textBaseline = "middle"; $.fillStyle = "#fff"; $.fillText("849 # Die Digitaluhr", c.width * 0.01, c.height * 0.5); let cTex = new THREE.CanvasTexture(c); cTex.colorSpace = THREE.SRGBColorSpace; return cTex; })() } shader.fragmentShader = ` ${shader.fragmentShader} ` .replace( `precision highp float;`, `precision highp float; uniform float aspect; uniform sampler2D watermark; ` ) .replace( `}`, ` // signature vec2 sUv = vUv * 14. * vec2(aspect / 8., 1.); sUv -= vec2(0.05, 0.05); float sig = texture2D(watermark, sUv).r; vec3 sigColor = vec3(0.75); //////////// gl_FragColor.rgb = mix(gl_FragColor.rgb, sigColor, sig); } ` ); //console.log(shader.fragmentShader) }; this.addPass(renderScene); this.addPass(bloomPass); this.addPass(outputPass); //console.log(outputPass); } } class Logo extends THREE.BufferGeometry { constructor() { super(); let baseVector = new THREE.Vector2(0, 1); let center = new THREE.Vector2(); let shift = new THREE.Vector2(0, -0.25); let a = 3 / Math.sqrt(3); let hA = a * 0.5; let hStep = 1.5; let hHeight = 0.75; let steps = 4; let scale = 0.85; let baseTri = [ baseVector.clone().multiplyScalar(scale).add(shift), baseVector .clone() .rotateAround(center, (-Math.PI * 2) / 3) .multiplyScalar(scale) .add(shift), baseVector .clone() .rotateAround(center, (Math.PI * 2) / 3) .multiplyScalar(scale) .add(shift) ]; let baseTriFlip = [ baseVector .clone() .rotateAround(center, Math.PI) .multiplyScalar(scale) .sub(shift), baseVector .clone() .rotateAround(center, Math.PI / 3) .multiplyScalar(scale) .sub(shift), baseVector .clone() .rotateAround(center, -Math.PI / 3) .multiplyScalar(scale) .sub(shift) ]; let holes = []; for (let rows = 0; rows < steps; rows++) { let items = 1 + rows * 2; // arithmetic progression let h = hStep * 1.5 - rows * hStep; console.log(h); let w = -((items - 1) / 2) * hA; for (let item = 0; item < items; item++) { let shiftX = w + hA * item; let shiftY = h; let tri = (item % 2 == 0 ? baseTri : baseTriFlip).map((p) => { let pt = p.clone(); pt.x += shiftX; pt.y += shiftY; return pt; }); let hole = new THREE.Path(tri); holes.push(hole); } } let contourShift = new THREE.Vector2(0, -1); let contour = [ baseVector.clone().multiplyScalar(4.1).add(contourShift), baseVector .clone() .rotateAround(center, (Math.PI * 2) / 3) .multiplyScalar(4.1) .add(contourShift), baseVector .clone() .rotateAround(center, (-Math.PI * 2) / 3) .multiplyScalar(4.1) .add(contourShift) ]; let shape = new THREE.Shape(contour); shape.holes = holes; let shapeGeom = new THREE.ExtrudeGeometry(shape, { depth: 0.1, bevelEnabled: true, bevelThickness: 0.1, bevelSize: 0.1, bevelSegments: 5 }); shapeGeom.rotateZ(Math.PI * 0.25); shapeGeom.center(); this.copy(shapeGeom); } } class Display extends THREE.InstancedMesh { constructor(thickness) { let g = new THREE.PlaneGeometry(5, 7.5); let m = new THREE.MeshBasicMaterial({ color: new THREE.Color(0x0088ff), map: null, side: THREE.DoubleSide, forceSinglePass: true, transparent: true }); super(g, m, 10); this.thickness = thickness; console.log(this); this.init(); } init() { let dummy = new THREE.Object3D(); for (let i = 0; i < this.count; i++) { dummy.position.z = i * (this.thickness / (this.count - 1)); dummy.updateMatrix(); this.setMatrixAt(i, dummy.matrix); } let canvas = document.createElement("canvas"); canvas.width = 1000; canvas.height = 1400; this.context = canvas.getContext("2d"); this.days = [ "SONNTAG", "MONTAG", "DIENSTAG", "MITTWOCH", "DONNERSTAG", "FREITAG", "SAMSTAG" ]; this.displayTexture = new THREE.CanvasTexture(canvas); this.material.map = this.displayTexture; this.material.onBeforeCompile = (shader) => { shader.vertexShader = ` varying float viID; ${shader.vertexShader} `.replace( `#include
`, `#include
float iID = float(gl_InstanceID); viID = iID; ` ); //console.log(shader.vertexShader); shader.fragmentShader = ` varying float viID; ${shader.fragmentShader} `.replace( `vec4 diffuseColor = vec4( diffuse, opacity );`, `vec4 diffuseColor = vec4( diffuse, opacity ); float aa = viID / ${this.count - 1}.; aa *= aa * aa * aa; diffuseColor.a = aa; float iID = floor(viID + 0.1); diffuseColor.rgb *= iID == ${this.count - 1}. ? 20. : 1.; if ((!gl_FrontFacing) && (iID < ${this.count - 1}.)) discard; ` ); //console.log(shader.fragmentShader); }; //this.material.needsUpdate = true; } update() { let date = new Date(); //console.log(date); let ctx = this.context; ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.fillStyle = "rgba(255, 255, 255, 1)"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; let DoW = this.days[date.getDay()]; ctx.font = "bold 75px KodeMono"; ctx.fillText(DoW, ctx.canvas.width * 0.5, ctx.canvas.height * 0.3); let days = ("0" + date.getDate()).slice(-2); let month = ("0" + (date.getMonth() + 1)).slice(-2); let year = date.getFullYear(); let fullDate = days + "." + month + "." + year; ctx.font = "bold 100px KodeMono"; ctx.fillText(fullDate, ctx.canvas.width * 0.5, ctx.canvas.height * 0.4); let hours = ("0" + date.getHours()).slice(-2); let minutes = ("0" + date.getMinutes()).slice(-2); let milliseconds = date.getMilliseconds(); let time = hours + (milliseconds < 500 ? ":" : " ") + minutes; ctx.font = "bold 300px KodeMono"; ctx.fillText(time, ctx.canvas.width * 0.5, ctx.canvas.height * 0.6); /* ctx.strokeStyle = "rgba(255, 255, 255, 1)"; ctx.lineWidth = 5; ctx.strokeRect(0, 0, ctx.canvas.width, ctx.canvas.height); */ this.displayTexture.needsUpdate = true; } } class Digitaluhr extends THREE.Mesh { constructor() { let axis = new THREE.Vector3(0, 0, 1); let baseContour = [ [0.1, 2], [1, 0], [0, -1], [-1, 0], [-0.1, 2] ].map((p) => { return new THREE.Vector3(p[0], p[1], 0).multiplyScalar(5); //.applyAxisAngle(axis, Math.PI * 0.25); }); let thickness = 1.25; // extrusion let shapeCurve = new THREE.CatmullRomCurve3([...baseContour], true); let holeCurve = new THREE.CatmullRomCurve3( [...baseContour].map((p) => { return p.clone().multiplyScalar(0.5); }), true ); let shape = new THREE.Shape(shapeCurve.getSpacedPoints(1000)); shape.holes.push(new THREE.Path(holeCurve.getSpacedPoints(1000).reverse())); let gExtrude = new THREE.ExtrudeGeometry(shape, { depth: thickness, steps: 1, bevelEnabled: false }); let mExtrude = new THREE.MeshLambertMaterial({ color: new THREE.Color().setHSL(0.33, 1, 1) }); let goldMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000, metalness: 1, roughness: 0.25 }); super(gExtrude, [mExtrude, goldMaterial]); this.position.y = 5.2; this.position.z = -thickness * 0.5; //this.rotation.x = Math.PI * -0.5; this.castShadow = true; this.receiveShadow = true; let gOutline = mergeGeometries([ new THREE.TubeGeometry(shapeCurve, 1000, 0.2, 16, true), new THREE.TubeGeometry(shapeCurve, 1000, 0.2, 16, true).translate( 0, 0, thickness ), new THREE.TubeGeometry(holeCurve, 1000, 0.2, 16, true), new THREE.TubeGeometry(holeCurve, 1000, 0.2, 16, true).translate( 0, 0, thickness ) ]); let outline = new THREE.Mesh(gOutline, goldMaterial); outline.castShadow = true; outline.receiveShadow = true; this.add(outline); let logo = new THREE.Mesh(new Logo(), goldMaterial); logo.scale.setScalar(0.4); logo.position.set(0, 7, thickness); logo.castShadow = true; this.add(logo); this.display = new Display(thickness); this.display.position.y = 1.125; this.add(this.display); //display.update(); } } class Background extends THREE.Mesh { constructor(backcolor) { let g = new THREE.SphereGeometry(900, 64, 32); let m = new THREE.MeshBasicMaterial({ color: backcolor, side: THREE.BackSide }); m.defines = { USE_UV: "" }; super(g, m); this.uniforms = { time: { value: 0 } }; this.material.onBeforeCompile = (shader) => { shader.uniforms.time = this.uniforms.time; shader.fragmentShader = ` uniform float time; ${snoise2d} ${shader.fragmentShader} `.replace( `vec4 diffuseColor = vec4( diffuse, opacity );`, ` float t = time * 0.1; vec2 uv = vUv; uv -= 0.5; vec2 uvMult = vec2(40., 4.); uv *= uvMult; uv.y += 0.33; uv.y = abs(uv.y); vec2 cId = floor(uv); vec2 cUv = fract(uv); cUv.x -= 0.5; cUv.x /= 5.; float rnd = snoise(cId + vec2(0., t)) * 0.5 + 0.5; float baseVal = 0.1; float baseRand = baseVal + rnd * 0.5; float rounding = 0.1; vec2 a = vec2(0., baseVal); vec2 b = vec2(0., baseRand); float f = udSegment(cUv, a, b) - rounding; vec2 fw = fwidth(cUv); float mf = min(fw.x, fw.y); float df = smoothstep(mf, -mf, f); float circf = length(vec2(0., baseRand + 0.3) - cUv) - rounding * 0.5; float circ = smoothstep(mf, -mf, circf); df = max(df, circ); df *= step(0., cId.y) - step(1., cId.y); // first row only vec3 col = mix(diffuse, diffuse + 0.005, df); vec4 diffuseColor = vec4( col, opacity ); ` ); //console.log(shader.fragmentShader) }; } update(t) { this.uniforms.time.value = t; } } let scene = new THREE.Scene(); scene.background = new THREE.Color(0x111111); let camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 1, 1000); camera.position.set(-5, 2, 8).setLength(20); let renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(innerWidth, innerHeight); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; document.body.appendChild(renderer.domElement); let cameraShift = new THREE.Vector3(0, 8, 0); let glowLayer = new GlowLayer(renderer); window.addEventListener("resize", (event) => { camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); renderer.setSize(innerWidth, innerHeight); glowLayer.setSize(innerWidth, innerHeight); glowLayer.uniforms.aspect.value = camera.aspect; }); let controls = new OrbitControls(camera, renderer.domElement); controls.enablePan = false; controls.enableDamping = true; controls.minDistance = 10; controls.maxDistance = 25; controls.maxPolarAngle = Math.PI * 0.5; controls.target.copy(cameraShift); controls.object.position.add(cameraShift); controls.update(); const pmremGenerator = new THREE.PMREMGenerator(renderer); scene.environment = pmremGenerator.fromScene( new RoomEnvironment(), 0.04 ).texture; let light = new THREE.DirectionalLight(0xffffff, Math.PI); light.castShadow = true; light.shadow.mapSize.width = 2048; light.shadow.mapSize.height = 2048; light.shadow.camera.near = 0.5; light.shadow.camera.far = 100; let hSize = 7; light.shadow.camera.top = hSize; light.shadow.camera.bottom = -hSize; light.shadow.camera.left = -hSize; light.shadow.camera.right = hSize; light.position.setScalar(20).add(cameraShift); let lightTarget = new THREE.Object3D(); scene.add(lightTarget); lightTarget.position.copy(cameraShift); light.target = lightTarget; scene.add(light, new THREE.AmbientLight(0xffffff, 0.5)); //let grid = new THREE.GridHelper(10, 10); //grid.rotation.x = Math.PI * 0.5; //scene.add(grid); let digitaluhr = new Digitaluhr(); scene.add(digitaluhr); let surface = new THREE.Mesh( new THREE.CircleGeometry(20, 72).rotateX(-Math.PI * 0.5), new THREE.MeshLambertMaterial({ color: 0x404040, transparent: true, onBeforeCompile: (shader) => { shader.uniforms.outerShade = { value: scene.background }; shader.fragmentShader = ` uniform vec3 outerShade; ${shader.fragmentShader} `.replace( `#include
`, `#include
float os = smoothstep(0.3, 0.5, length(vUv - 0.5)); gl_FragColor.a = 1. - os; //mix(gl_FragColor.rgb, outerShade, os); ` ); //console.log(shader.fragmentShader); } }) ); surface.material.defines = { USE_UV: "" }; surface.receiveShadow = true; scene.add(surface); let background = new Background(scene.background); scene.add(background); let clock = new THREE.Clock(); let t = 0; renderer.setAnimationLoop(() => { let dt = clock.getDelta(); t += dt; controls.update(); digitaluhr.display.update(); background.update(t); glowLayer.render(); //renderer.render(scene, camera); });