JSFiddle - React, Tailwind, and code Playground
by tfoller
HTML
<link type="text/css" rel="stylesheet" href="https://alikim.com/_v1_jsm/css/controls.css">
<script type="x-shader/x-vertex" id="vs">
varying vec2 vuv;
void main() {
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * mvPosition;
vuv = uv;
}
</script>
<script type='x-shader/x-fragment' id='fs'>
varying vec2 vuv;
uniform float time;
uniform sampler2D map;
void main() {
vec2 uv = vuv;
float amp = 0.3;
float freq = 3.0;
uv.x = 0.5 * (1.0 + amp * sin(freq * vuv.y + time)) + (1.0 - amp) * (uv.x - 0.5);
vec3 clr = texture2D(map, uv).rgb;
gl_FragColor = vec4(clr, 1.0);
}
</script>
CSS
body {
margin: 0;
}
JavaScript
import * as THREE from 'https://alikim.com/_v1_jsm/three.module.js';
import * as CONTROLS from 'https://alikim.com/_v1_jsm/controls.js'
const get = id => document.getElementById(id);
const cont = document.documentElement;
const [w, h] = [cont.clientWidth - 20, cont.clientHeight - 20];
const renderer = new THREE.WebGLRenderer();
renderer.setSize(w, h);
document.body.appendChild(renderer.domElement);
const [near, far] = [0.1, 100];
const mid = (near - far) / 2;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(50, w / h, near, far);
camera.position.set(10, 10, 10);
const hlp = new THREE.AxesHelper(3);
scene.add(hlp);
const render = () => {
renderer.render(scene, camera);
};
const map = new THREE.TextureLoader().load(
'https://source.unsplash.com/random/200x200',
render,
);
const geo = new THREE.PlaneBufferGeometry(10, 10, 1, 1);
const msh = new THREE.Mesh(
geo,
new THREE.ShaderMaterial({
vertexShader: get('vs').textContent,
fragmentShader: get('fs').textContent,
uniforms: {
map: { value: map },
time: { get value() { return 0.001 * performance.now() }},
},
})
);
scene.add(msh);
const state = { play: true };
const maybeRender = () => { if (!state.play) render() };
const framerate = 60;
const fpsint = 1000 / framerate;
let elapsed, now, then;
const renderFrame = newtime => {
if (!state.play) return;
requestAnimationFrame(renderFrame);
if (!newtime) then = newtime = window.performance.now();
now = newtime;
elapsed = now - then;
if (!fpsint || elapsed > fpsint) {
then = now - (elapsed % fpsint);
render();
}
};
CONTROLS.create({
cont: renderer.domElement,
cam: camera,
type: 'Orbital',
overlay: true,
lookAt: [0, 0, 0],
callback: render
});
renderFrame();