{"id":1691,"date":"2023-08-07T15:05:00","date_gmt":"2023-08-07T12:05:00","guid":{"rendered":"https:\/\/notes.profidev.online\/?p=1691"},"modified":"2023-08-07T15:05:02","modified_gmt":"2023-08-07T12:05:02","slug":"text-effect-2","status":"publish","type":"post","link":"https:\/\/notes.profidev.online\/ru\/effect\/1691\/","title":{"rendered":"Text Effect"},"content":{"rendered":"\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe title=\"Text Effect with TweenMax\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/xUh2L9lAdQw?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;htmlmixed&quot;,&quot;mime&quot;:&quot;text\/html&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;HTML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;html&quot;}\">&lt;div id=&quot;three-container&quot;&gt;&lt;\/div&gt;\n\n  &lt;script src='http:\/\/cdnjs.cloudflare.com\/ajax\/libs\/three.js\/r75\/three.min.js'&gt;&lt;\/script&gt;\n  &lt;script src='https:\/\/s3-us-west-2.amazonaws.com\/s.cdpn.io\/175711\/bas.js'&gt;&lt;\/script&gt;\n  &lt;script src='https:\/\/s3-us-west-2.amazonaws.com\/s.cdpn.io\/175711\/TextGeometry.js'&gt;&lt;\/script&gt;\n  &lt;script src='https:\/\/s3-us-west-2.amazonaws.com\/s.cdpn.io\/175711\/FontUtils.js'&gt;&lt;\/script&gt;\n  &lt;script src='https:\/\/s3-us-west-2.amazonaws.com\/s.cdpn.io\/175711\/pnltri.min.js'&gt;&lt;\/script&gt;\n  &lt;script src='https:\/\/s3-us-west-2.amazonaws.com\/s.cdpn.io\/175711\/droid_sans_bold.typeface.js'&gt;&lt;\/script&gt;\n  &lt;script src='http:\/\/cdnjs.cloudflare.com\/ajax\/libs\/gsap\/1.18.0\/TweenMax.min.js'&gt;&lt;\/script&gt;<\/pre><\/div>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;css&quot;,&quot;mime&quot;:&quot;text\/css&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;CSS&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;css&quot;}\">body {\n\tmargin: 0;\n\toverflow: hidden;\n}<\/pre><\/div>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;javascript&quot;,&quot;mime&quot;:&quot;text\/javascript&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;JavaScript&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;js&quot;}\">\/\/capture the window loading\nwindow.onload = init;\n\nfunction init() {\n  var root = new THREERoot({\n    createCameraControls:false,\n\t\tantialias: true,\n    fov:60\n  });\n    \n\/\/setup the scene\n    \n  root.renderer.setClearColor(0x3AAFA9); \n  root.renderer.setPixelRatio(window.devicePixelRatio || 1);\n  root.camera.position.set(0, 0, 400);\n\n\n\/\/create the text animation variable\n    \n  var textAnimation = createTextAnimation();\n  textAnimation.position.y = -10; \n  root.scene.add(textAnimation);\n\n \/\/set the timeline aspects of the animation\n    \n  var tl = new TimelineMax({\n    repeat:-1, \/\/-1 loop\n    repeatDelay:0.25,\n    yoyo:true\n  });\n  tl.fromTo(textAnimation, 4, \/\/4\n    {animationProgress:0.0},\n    {animationProgress:1.0, ease:Power1.easeInOut},\n    0\n  );\n\n  createTweenScrubber(tl);\n}\n\n\/\/create the text to be animated\n\nfunction createTextAnimation() {\n  var geometry = generateTextGeometry('Profidev_JS', {\n    size:14,\n    height:0,\n    font:'droid sans',\n    weight:'bold',\n    style:'normal',\n    anchor:{x:0.5, y:0.5, z:0.0}\n  });\n\n  THREE.BAS.Utils.separateFaces(geometry);\n\n  return new TextAnimation(geometry);\n}\n\n\/\/mathematical details of the animation\n\nfunction generateTextGeometry(text, params) {\n  var geometry = new THREE.TextGeometry(text, params);\n\n  geometry.computeBoundingBox();\n\n  geometry.userData = {};\n  geometry.userData.size = {\n    width: geometry.boundingBox.max.x - geometry.boundingBox.min.x,\n    height: geometry.boundingBox.max.y - geometry.boundingBox.min.y,\n    depth: geometry.boundingBox.max.z - geometry.boundingBox.min.z\n  };\n\n  var anchorX = geometry.userData.size.width * -params.anchor.x;\n  var anchorY = geometry.userData.size.height * -params.anchor.y;\n  var anchorZ = geometry.userData.size.depth * -params.anchor.z;\n  var matrix = new THREE.Matrix4().makeTranslation(anchorX, anchorY, anchorZ);\n\n  geometry.applyMatrix(matrix);\n\n  return geometry;\n} \n\n\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n\/\/ CLASSES\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n\nfunction TextAnimation(textGeometry) {\n  var bufferGeometry = new THREE.BAS.ModelBufferGeometry(textGeometry);\n\n  var aAnimation = bufferGeometry.createAttribute('aAnimation', 2);\n  var aCentroid = bufferGeometry.createAttribute('aCentroid', 3);\n  var aControl0 = bufferGeometry.createAttribute('aControl0', 3);\n  var aControl1 = bufferGeometry.createAttribute('aControl1', 3);\n  var aEndPosition = bufferGeometry.createAttribute('aEndPosition', 3);\n\n  var faceCount = bufferGeometry.faceCount;\n  var i, i2, i3, i4, v;\n\n  var size = textGeometry.userData.size;\n\n  var maxDelayX = 2.0;\n  var maxDelayY = 0.25;\n  var minDuration = 2;\n  var maxDuration = 8;\n  var stretch = 0.25;\n\n  this.animationDuration = maxDelayX + maxDelayY + maxDuration - 3;\n  this._animationProgress = 0;\n\n  for (i = 0, i2 = 0, i3 = 0, i4 = 0; i &lt; faceCount; i++, i2 += 6, i3 += 9, i4 += 12) {\n    var face = textGeometry.faces[i];\n    var centroid = THREE.BAS.Utils.computeCentroid(textGeometry, face);\n\n    \/\/ animation\n    var delayX = Math.max(0, (centroid.x \/ size.width) * maxDelayX);\n    var delayY = Math.max(0, (1.0 - (centroid.y \/ size.height)) * maxDelayY);\n    var duration = THREE.Math.randFloat(minDuration, maxDuration);\n\n    for (v = 0; v &lt; 6; v += 2) {\n      aAnimation.array[i2 + v    ] = delayX + delayY + Math.random() * stretch;\n      aAnimation.array[i2 + v + 1] = duration;\n    }\n\n    \/\/ centroid\n    for (v = 0; v &lt; 9; v += 3) {\n      aCentroid.array[i3 + v    ] = centroid.x;\n      aCentroid.array[i3 + v + 1] = centroid.y;\n      aCentroid.array[i3 + v + 2] = centroid.z;\n    }\n\n    \/\/ ctrl\n    var c0x = centroid.x + THREE.Math.randFloat(40, 120);\n    var c0y = centroid.y + size.height * THREE.Math.randFloat(0.0, 12.0);\n    var c0z = THREE.Math.randFloatSpread(120);\n\n    var c1x = centroid.x + THREE.Math.randFloat(80, 120) * -1;\n    var c1y = centroid.y + size.height * THREE.Math.randFloat(0.0, 12.0);\n    var c1z = THREE.Math.randFloatSpread(120);\n\n    for (v = 0; v &lt; 9; v += 3) {\n      aControl0.array[i3 + v    ] = c0x;\n      aControl0.array[i3 + v + 1] = c0y;\n      aControl0.array[i3 + v + 2] = c0z;\n\n      aControl1.array[i3 + v    ] = c1x;\n      aControl1.array[i3 + v + 1] = c1y;\n      aControl1.array[i3 + v + 2] = c1z;\n    }\n\n    \/\/ end position\n    var x, y, z;\n\n    x = centroid.x + THREE.Math.randFloatSpread(120);\n    y = centroid.y + size.height * THREE.Math.randFloat(0.0, 12.0);\n    z = THREE.Math.randFloat(-20, 20);\n\n    for (v = 0; v &lt; 9; v += 3) {\n      aEndPosition.array[i3 + v    ] = x;\n      aEndPosition.array[i3 + v + 1] = y;\n      aEndPosition.array[i3 + v + 2] = z;\n    }\n  }\n\n  var material = new THREE.BAS.BasicAnimationMaterial({\n      shading: THREE.FlatShading,\n      side: THREE.DoubleSide,\n      transparent: true,\n      uniforms: {\n        uTime: {type: 'f', value: 0}\n      },\n      shaderFunctions: [\n        THREE.BAS.ShaderChunk['cubic_bezier'],\n        THREE.BAS.ShaderChunk['ease_out_cubic']\n      ],\n      shaderParameters: [\n        'uniform float uTime;',\n        'attribute vec2 aAnimation;',\n        'attribute vec3 aCentroid;',\n        'attribute vec3 aControl0;',\n        'attribute vec3 aControl1;',\n        'attribute vec3 aEndPosition;'\n      ],\n      shaderVertexInit: [\n        'float tDelay = aAnimation.x;',\n        'float tDuration = aAnimation.y;',\n        'float tTime = clamp(uTime - tDelay, 0.0, tDuration);',\n        'float tProgress =  ease(tTime, 0.0, 1.0, tDuration);'\n         \/\/'float tProgress = tTime \/ tDuration;'\n      ],\n      shaderTransformPosition: [\n        'vec3 tPosition = transformed - aCentroid;',\n        'tPosition *= 1.0 - tProgress;',\n        'tPosition += aCentroid;',\n        'tPosition += cubicBezier(tPosition, aControl0, aControl1, aEndPosition, tProgress);',\n        'transformed = tPosition;'\n\n        \/\/ 'vec3 tPosition = transformed;',\n        \/\/ 'tPosition *= 1.0 - tProgress;',\n        \/\/ 'tPosition += cubicBezier(transformed, aControl0, aControl1, aEndPosition, tProgress);',\n        \/\/ 'tPosition += mix(transformed, aEndPosition, tProgress);',\n        \/\/ 'transformed = tPosition;'\n      ]\n    },\n    {\n      diffuse: 0xffffff \/\/0000\n    }\n  );\n\n  THREE.Mesh.call(this, bufferGeometry, material);\n\n  this.frustumCulled = false;\n}\nTextAnimation.prototype = Object.create(THREE.Mesh.prototype);\nTextAnimation.prototype.constructor = TextAnimation;\n\nObject.defineProperty(TextAnimation.prototype, 'animationProgress', {\n  get: function() {\n    return this._animationProgress;\n  },\n  set: function(v) {\n    this._animationProgress = v;\n    this.material.uniforms['uTime'].value = this.animationDuration * v;\n  }\n});\n\nfunction THREERoot(params) {\n  params = utils.extend({\n    antialias:false,\n\n    fov:60,\n    zNear:1,\n    zFar:10000,\n\n    createCameraControls:true\n  }, params);\n\n  this.renderer = new THREE.WebGLRenderer({\n    antialias:params.antialias\n  });\n  document.getElementById('three-container').appendChild(this.renderer.domElement);\n\n  this.camera = new THREE.PerspectiveCamera(\n    params.fov,\n    window.innerWidth \/ window.innerHeight,\n    params.zNear,\n    params.zfar\n  );\n\n  this.scene = new THREE.Scene();\n\n  if (params.createCameraControls) {\n    this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);\n  }\n\n  this.resize = this.resize.bind(this);\n  this.tick = this.tick.bind(this);\n\n  this.resize();\n  this.tick();\n\n  window.addEventListener('resize', this.resize, false);\n}\nTHREERoot.prototype = {\n  tick: function() {\n    this.update();\n    this.render();\n    requestAnimationFrame(this.tick);\n  },\n  update: function() {\n    this.controls &amp;&amp; this.controls.update();\n  },\n  render: function() {\n    this.renderer.render(this.scene, this.camera);\n  },\n  resize: function() {\n    this.camera.aspect = window.innerWidth \/ window.innerHeight;\n    this.camera.updateProjectionMatrix();\n\n    this.renderer.setSize(window.innerWidth, window.innerHeight);\n  }\n};\n\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n\/\/ UTILS\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n\nvar utils = {\n  extend:function(dst, src) {\n    for (var key in src) {\n      dst[key] = src[key];\n    }\n\n    return dst;\n  },\n  randSign: function() {\n    return Math.random() &gt; 0.5 ? 1 : -1;\n  }\n};\n\nfunction createTweenScrubber(tween, seekSpeed) {\n  seekSpeed = seekSpeed || 0.001;\n\n  function stop() {\n    TweenMax.to(tween, 2, {timeScale:0});\n  }\n\n  function resume() {\n    TweenMax.to(tween, 2, {timeScale:1});\n  }\n\n  function seek(dx) {\n    var progress = tween.progress();\n    var p = THREE.Math.clamp((progress + (dx * seekSpeed)), 0, 1);\n\n    tween.progress(p);\n  }\n\n  var _cx = 0;\n\n  \/\/ desktop\n  var mouseDown = false;\n  document.body.style.cursor = 'pointer';\n\n  window.addEventListener('mousedown', function(e) {\n    mouseDown = true;\n    document.body.style.cursor = 'ew-resize';\n    _cx = e.clientX;\n    stop();\n  });\n  window.addEventListener('mouseup', function(e) {\n    mouseDown = false;\n    document.body.style.cursor = 'pointer';\n    resume();\n  });\n  window.addEventListener('mousemove', function(e) {\n    if (mouseDown === true) {\n      var cx = e.clientX;\n      var dx = cx - _cx;\n      _cx = cx;\n\n      seek(dx);\n    }\n  });\n  \/\/ mobile\n  window.addEventListener('touchstart', function(e) {\n    _cx = e.touches[0].clientX;\n    stop();\n    e.preventDefault();\n  });\n  window.addEventListener('touchend', function(e) {\n    resume();\n    e.preventDefault();\n  });\n  window.addEventListener('touchmove', function(e) {\n    var cx = e.touches[0].clientX;\n    var dx = cx - _cx;\n    _cx = cx;\n\n    seek(dx);\n    e.preventDefault();\n  });\n}<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":1692,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[27,40,39],"class_list":["post-1691","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-effect","tag-gsap","tag-text","tag-tweenmax"],"_links":{"self":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1691","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/comments?post=1691"}],"version-history":[{"count":1,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1691\/revisions"}],"predecessor-version":[{"id":1693,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1691\/revisions\/1693"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/media\/1692"}],"wp:attachment":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/media?parent=1691"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/categories?post=1691"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/tags?post=1691"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}