I am here today to ask for some guidance/help with a personal goal to learn to recreate one of Szenia Zadvornykh animations link below. I have been on a learn binge for a handful of days now trying to get a deeper understanding of ReactJS 17.0.2. Now by all means no expert using React. My goal was to have this animation appear as a splash screen then to the create-react-app default landing page. I been slowly trying to come up with ways to get it to run, sadly all i have manage is a white screen for set timeout time i placed then sent to react landing page with no animation. Any positive advice would be greatly appreciated thank you.
**NPM Links:**
[Three.js NPM][1]
[PNLTRI NPM][2]
[GSAP NPM][3]
[BAS-Three NPM][4]
**IMG LINKS**
[IMG of Dev Tools][5]
[IMG of AppJS][6]
[IMG of indexHTML][7]
**Szenia Zadvornykh Example**
[Szenia Zadvornykh Animation][1]
SPA JS script is below too long for one IMG
import * as THREE from 'three';
import * as PNLTRI from 'pnltri';
import * as BAS from 'three-bas';
import {
OrbitControls
} from 'three/examples/jsm/controls/OrbitControls';
import {
TextGeometry
} from 'three/src/geometries/TextGeometry';
import {
TweenMax,
Power1
} from 'gsap';
import {
Matrix4
} from 'three/src/math/Matrix4';
window.onload = init;
var utils = {
extend: function(dst, src) {
for (var key in src) {
dst[key] = src[key];
}
return dst;
}
};
function init() {
var root = new THREERoot({
createCameraControls: false,
fov: 10
});
root.renderer.setClearColor(0xffffff);
root.renderer.setPixelRatio(window.devicePixelRatio || 1);
root.camera.position.set(0, 0, 1400);
var textAnimation = createTextAnimation();
root.scene.add(textAnimation);
var tween = TweenMax.fromTo(textAnimation, 4, {
animationProgress: 0
}, {
animationProgress: 1,
ease: Power1.easeInOut,
repeat: -1,
yoyo: true
});
createTweenScrubber(tween);
}
function createTweenScrubber(tween, seekSpeed) {
seekSpeed = seekSpeed || 0.001;
function stop() {
TweenMax.to(tween, 2, {
timeScale: 0
});
}
function resume() {
TweenMax.to(tween, 2, {
timeScale: 1
});
}
function seek(dx) {
var progress = tween.progress();
var p = THREE.Math.clamp((progress + (dx * seekSpeed)), 0, 1);
tween.progress(p);
}
var _cx = 0;
// desktop
var mouseDown = false;
document.body.style.cursor = 'pointer';
window.addEventListener('mousedown', function(e) {
mouseDown = true;
document.body.style.cursor = 'ew-resize';
_cx = e.clientX;
stop();
});
window.addEventListener('mouseup', function(e) {
mouseDown = false;
document.body.style.cursor = 'pointer';
resume();
});
window.addEventListener('mousemove', function(e) {
if (mouseDown === true) {
var cx = e.clientX;
var dx = cx - _cx;
_cx = cx;
seek(dx);
}
});
// mobile
window.addEventListener('touchstart', function(e) {
_cx = e.touches[0].clientX;
stop();
e.preventDefault();
});
window.addEventListener('touchend', function(e) {
resume();
e.preventDefault();
});
window.addEventListener('touchmove', function(e) {
var cx = e.touches[0].clientX;
var dx = cx - _cx;
_cx = cx;
seek(dx);
e.preventDefault();
});
}
function createTextAnimation() {
var geometry = generateTextGeometry('Evan Jancy', {
size: 14,
height: 0,
font: 'droid sans',
weight: 'bold',
style: 'normal',
bevelSize: 0.75,
bevelThickness: 0.50,
bevelEnabled: true,
anchor: {
x: 0.5,
y: 0.5,
z: 0.5
}
});
BAS.Utils.separateFaces(geometry);
return new TextAnimation(geometry);
}
function generateTextGeometry(text, params) {
var geometry = new TextGeometry(text, params);
geometry.computeBoundingBox();
geometry.userData = {};
geometry.userData.size = {
width: geometry.boundingBox.max.x - geometry.boundingBox.min.x,
height: geometry.boundingBox.max.y - geometry.boundingBox.min.y,
depth: geometry.boundingBox.max.z - geometry.boundingBox.min.z
};
var anchorX = geometry.userData.size.width * -params.anchor.x;
var anchorY = geometry.userData.size.height * -params.anchor.y;
var anchorZ = geometry.userData.size.depth * -params.anchor.z;
var matrix = new Matrix4().makeTranslation(anchorX, anchorY, anchorZ);
geometry.applyMatrix(matrix);
return geometry;
}
////////////////////
// CLASSES
////////////////////
function TextAnimation(textGeometry) {
var bufferGeometry = new BAS.ModelBufferGeometry(textGeometry);
var aAnimation = bufferGeometry.createAttribute('aAnimation', 2);
var aControl0 = bufferGeometry.createAttribute('aControl0', 3);
var aControl1 = bufferGeometry.createAttribute('aControl1', 3);
var aEndPosition = bufferGeometry.createAttribute('aEndPosition', 3);
var faceCount = bufferGeometry.faceCount;
var i, i2, i3, i4, v;
var size = textGeometry.userData.size;
var length = new THREE.Vector3(size.width, size.height,
size.depth).multiplyScalar(0.5).length();
var maxDelay = length * 0.06;
this.animationDuration = maxDelay + 4 + 1;
this._animationProgress = 0;
for (i = 0, i2 = 0, i3 = 0, i4 = 0; i < faceCount; i++, i2 += 6, i3 += 9, i4 += 12) {
var face = textGeometry.faces[i];
var centroid = BAS.Utils.computeCentroid(textGeometry, face);
var dirX = centroid.x > 0 ? 1 : -1;
var dirY = centroid.y > 0 ? 1 : -1;
// animation
var delay = centroid.length() * THREE.Math.randFloat(0.03, 0.06);
var duration = THREE.Math.randFloat(2, 4);
for (v = 0; v < 6; v += 2) {
aAnimation.array[i2 + v] = delay + Math.random();
aAnimation.array[i2 + v + 1] = duration;
}
// ctrl
var c0x = THREE.Math.randFloat(0, 30) * dirX;
var c0y = THREE.Math.randFloat(60, 120) * dirY;
var c0z = THREE.Math.randFloat(-20, 20);
var c1x = THREE.Math.randFloat(30, 60) * dirX;
var c1y = THREE.Math.randFloat(0, 60) * dirY;
var c1z = THREE.Math.randFloat(-20, 20);
for (v = 0; v < 9; v += 3) {
aControl0.array[i3 + v] = c0x;
aControl0.array[i3 + v + 1] = c0y;
aControl0.array[i3 + v + 2] = c0z;
aControl1.array[i3 + v] = c1x;
aControl1.array[i3 + v + 1] = c1y;
aControl1.array[i3 + v + 2] = c1z;
}
}
var material = new BAS.BasicAnimationMaterial({
shading: THREE.FlatShading,
side: THREE.DoubleSide,
uniforms: {
uTime: {
type: 'f',
value: 0
}
},
shaderFunctions: [
BAS.ShaderChunk['cubic_bezier']
],
shaderParameters: [
'uniform float uTime;',
'attribute vec2 aAnimation;',
'attribute vec3 aControl0;',
'attribute vec3 aControl1;',
'attribute vec3 aEndPosition;'
],
shaderVertexInit: [
'float tDelay = aAnimation.x;',
'float tDuration = aAnimation.y;',
'float tTime = clamp(uTime - tDelay, 0.0, tDuration);',
'float tProgress = tTime / tDuration;'
],
shaderTransformPosition: [
'vec3 tPosition = transformed;',
'tPosition *= 1.0 - tProgress;',
'tPosition += cubicBezier(transformed, aControl0, aControl1, aEndPosition,
tProgress);',
'transformed = tPosition;'
]
}, {
diffuse: 0x000000
});
THREE.Mesh.call(this, bufferGeometry, material);
this.frustumCulled = false;
}
TextAnimation.prototype = Object.create(THREE.Mesh.prototype);
TextAnimation.prototype.constructor = TextAnimation;
Object.defineProperty(TextAnimation.prototype, 'animationProgress', {
get: function() {
return this._animationProgress;
},
set: function(v) {
this._animationProgress = v;
this.material.uniforms['uTime'].value = this.animationDuration * v;
}
});
function THREERoot(params) {
params = utils.extend({
antialias: false,
fov: 60,
zNear: 1,
zFar: 10000,
createCameraControls: true
}, params);
this.renderer = new THREE.WebGLRenderer({
antialias: params.antialias
});
document.getElementById('rootr').appendChild(this.renderer.domElement);
this.camera = new THREE.PerspectiveCamera(
params.fov,
window.innerWidth / window.innerHeight,
params.zNear,
params.zfar
);
this.scene = new THREE.Scene();
if (params.createCameraControls) {
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
}
// this.resize = this.resize.bind(this);
this.tick = this.tick.bind(this);
this.resize();
this.tick();
window.addEventListener('resize', this.resize, false);
}
THREERoot.prototype = {
tick: function() {
this.update();
this.render();
requestAnimationFrame(this.tick);
},
update: function() {
this.controls && this.controls.update();
},
render: function() {
this.renderer.render(this.scene, this.camera);
},
resize: function() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
};
<script
src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js">.
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-
dom.production.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See
https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!-- div with id="rootr" is where I was hoping the splash screen will show -->
<div id="rootr"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
import React, { useEffect, useState} from 'react';
import './App.css';
import logo from './logo.svg'
import SplashScreenContainer from './components/SplashScreenContainer';
import * as THREE from 'three';
import * as PNLTRI from 'pnltri';
import SPA from './components/SPA'
function App() {
const [loading, setLoading] = useState(false);
useEffect(()=>{
THREE.ShapeUtils.triangulateShape = (function () {
var pnlTriangulator = new PNLTRI.Triangulator();
return function triangulateShape(contour, holes) {
return pnlTriangulator.triangulate_polygon([contour].concat(holes));
};
})();
setLoading(true)
setTimeout(() => {
setLoading(false)
}, 6000)
},[])
return (
<div className="App">
{
loading ? (
<SplashScreenContainer>
HELLO SPLASH SCREEN HERE
<div type="text/javascript" src="./SPA.js" async/>
</SplashScreenContainer>
)
:
(
<header className="App-header" >
<img src ={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrrer"
>Learn React</a>
</header>
)
}
</div>
);
}
export default App;
[1]: https://www.npmjs.com/package/three
[2]: https://www.npmjs.com/package/pnltri
[3]: https://www.npmjs.com/package/gsap
[4]: https://www.npmjs.com/package/three-bas
[5]: https://i.stack.imgur.com/R8LcW.png
[6]: https://i.stack.imgur.com/MPABk.png
[7]: https://i.stack.imgur.com/kM9j2.png