텍스트 던지기 - 키네틱 타이포그래피 파트 2: matter.js 덕분에 중력을 속이기! 📃🛫🤯

Part 2 of my series about kinetic typography! Let's move some text around with HTML, CSS and JS! If you missed how I came about throwing around text and deforming it with only web stuff, be sure !

🎉🎉 I also want to celebrate 2500 followers! Thank you for your support everyone! It means so much to me and keeps me inspired to write even more! 🎉🎉



자, 이번에는 JS를 사용하고 있으므로 말할 수 있는 것이 많습니다. 파트 1은 CSS 전용이었지만 JS가 제공하는 수학적 옵션을 얻으면 열광할 수 있습니다. 가자!

텍스트 떨어지는... 위로?



나는 몇 가지 좋은 예를 찾기 위해 A Popular Search Engine™에 다시 문의했습니다. 일부는 우리가 이미 한 것보다 조금 더 복잡합니다. Creatopy blog에서 Siddhart Mate에서 이 작은 GIF를 찾았습니다.



이제 이 애니메이션에서 내가 좋아하는 것은 글자가 작동하는 방식입니다. 반드시 떨어지는 자체가 아니라 이미지의 상단/하단에 도달하면 서로 떨어지는 방식입니다. 그것은 단어에서 문자를 분리하여 기본적으로 올바른 순서와 위치에 있을 때 문자가 나타내는 의미에서 독립적으로 만듭니다. 아주 예술적인 감각이 있습니다.

이것이 바로 오늘날 우리가 이것을 재건하는 이유입니다.

물리학을 따르는 강체



이미지의 절반이 중력을 거스르면 텍스트가 처음에 물리학 법칙을 따르게 하려면 어떻게 해야 할까요? 물리 엔진은 새로운 것이 아니며(수많은 컴퓨터 게임 참조) JS용 엔진, 즉 matter.js이 확실히 있습니다. 먼저 다운로드하고 약간의 상용구를 실행해 보겠습니다.

npm i matter-js pathseg poly-decomp



<!DOCTYPE html>
<html>
<head>
</head>
<body>

  <div id="left"></div>
  <div id="right"></div>

  <script src="./node_modules/matter-js/build/matter.js"></script>
  <script src="./node_modules/pathseg/pathseg.js"></script>
  <script src="example2.js"></script>

</body>
</html>


또한 오목한 모양(예: 문자 U )을 허용하고 SVG 경로를 신체의 좌표로 변환할 수 있도록 patheg 및 poly-decomp를 설치했습니다.

이제 바로 Matter.js를 시작하겠습니다.

Matter.js는 많은 것을 제공합니다. 먼저 더 간단한 액세스를 위해 먼저 Matter 객체를 분해하고 실제로 필요한 것이 무엇인지 확인합니다.

const {
  Engine,
  Render,
  Runner,
  Composite,
  Bodies,
  Body,
  Svg,
  Vertices,
  World
} = window.Matter


그런 다음 처음부터 모든 문자를 만드는 대신 기존 글꼴을 대신 사용하여 SVG로 변환해 보겠습니다. 나는 실제로 글자를 다시 추적해야 했지만 정확히 그렇게 할 수 있는 정교한 도구가 있다고 확신합니다. 분명히 matter.js는 SVG 경로를 정점으로 변환할 때 속이 빈 몸체를 좋아하지 않습니다.

const A = 'M 18 114 46 114 70 37 81 74 57 74 51 94 87 94 93 114 121 114 81 7 57 7 z'
const U = 'M 16 7 16 82 C 17 125 101 125 99 82 L 99 82 99 7 74 7 74 82 C 73 100 41 99 41 82 L 41 82 41 7 16 7 z'
const W = 'M 6 7 29 114 56 114 70 53 84 114 111 114 134 7 108 7 96 74 81 7 59 7 44 74 32 7 6 7 z'
const N = 'M 16 114 16 7 42 7 80 74 80 7 106 7 106 114 80 114 42 48 42 114 16 114 z'
const P = 'M 20 8 20 114 46 114 46 28 66 28 C 83 28 83 59 66 58 L 66 58 46 58 46 78 67 78 C 116 78 116 7 65 8 L 65 8 z'
const D = 'M 19 7 57 7 C 120 13 120 109 57 114 L 57 114 45 114 45 94 56 94 C 85 93 86 30 56 27 L 56 27 45 27 45 114 19 114 19 7 z'
const O = 'M 13 59 C 9 -12 109 -12 107 59 L 107 59 80 59 C 84 14 34 14 39 59 L 39 59 C 33 107 86 107 80 59 L 80 59 107 59 C 109 133 9 133 13 59 L 13 59 z'
const R = 'M 21 114 21 7 64 7 C 122 8 105 67 85 69 L 85 69 107 113 80 113 61 76 47 76 47 56 65 56 C 84 57 84 26 65 27 L 65 27 47 27 47 114 z'


좋습니다. 렌더링할 때 여전히 약간 바지처럼 보이지만 올바르게 렌더링할 수 있는 방법이 있다고 확신합니다...

과제: 내가 사용한 글꼴을 알 수 있는 사람이 있습니까? 힌트: 구글 폰트입니다.

이 경로를 실제 몸체로 변환하기 위해 경로를 정점으로 변환한 다음 정점을 몸체로 변환하는 함수를 만듭니다.

const toVertices = path => {
  const pathEl = document.createElementNS(
    'http://www.w3.org/2000/svg',
    'path'
  )
  pathEl.setAttribute('d', path)
  return Svg.pathToVertices(pathEl, 1)
}

const toBody = function (letter) {
  const vertices = toVertices(letter)

  return Bodies.fromVertices(0, 0, vertices, {
    render: {
      fillStyle: '#fff',
      strokeStyle: '#fff',
      lineWidth: 1,
    }
  })
}


그런 다음 이러한 함수를 사용하여 단어를 본문 배열로 생성할 수 있습니다.

const bodiesUpward = [
  toBody(U),
  toBody(P),
  toBody(W),
  toBody(A),
  toBody(R),
  toBody(D),
]

const bodiesDownward = [
  toBody(D),
  toBody(O),
  toBody(W),
  toBody(N),
  toBody(W),
  toBody(A),
  toBody(R),
  toBody(D),
]


대박. 이제 두 개의 세계를 만들어야 합니다. 하나는 왼쪽, 다른 하나는 오른쪽입니다.

// Create the engines
const leftEngine = Engine.create()
const rightEngine = Engine.create()

// Get both worlds
const leftWorld = leftEngine.world
const rightWorld = rightEngine.world

// Create the render instances with the same options
const options = {
  wireframes: false,
  width: 400,
  height: 600,
  background: '#000'
}

const leftRender = Render.create({
  element: document.querySelector('#left'),
  engine: leftEngine,
  options
})
const rightRender = Render.create({
  element: document.querySelector('#right'),
  engine: leftEngine,
  options
})

Render.run(leftRender)
const leftRunner = Runner.create()
Runner.run(leftRunner, leftEngine)

Render.run(rightRender)
const rightRunner = Runner.create()
Runner.run(rightRunner, rightEngine)


이것들은 이제 우리가 물건을 렌더링할 수 있는 두 개의 다른 세계입니다. 세계에는 기본적으로 경계가 없으므로 왼쪽과 오른쪽 세계에 각각 바닥과 천장을 추가해야 합니다. 또한 중력을 조정하여 사물이 위아래로 "떨어지도록"만듭니다.

// Stuff falls down
leftEngine.gravity.y = 1

// Stuff goes up
rightEngine.gravity.y = -1

// The floor and ceiling are rectangles
World.add(leftWorld, Bodies.rectangle(0, -1, 800, 1, { isStatic: true }))
World.add(rightWorld, Bodies.rectangle(0, 601, 800, 1, { isStatic: true }))


그런 다음 모든 문자를 각각의 세계에 추가합니다.

bodiesUpward.forEach(body =>{
  World.add(leftWorld, body)
})

bodiesDownward.forEach(body =>{
  World.add(rightWorld, body)
})


이제 재미있는 부분이 나옵니다. 문자 위치 지정, 회전 및 떨어뜨리기. 이것이 계속 반복되기를 원하기 때문에 모든 문자의 위치를 ​​변경하고 다시 떨어지게 하는 간격을 도입합니다.

const positionLeftBodies = () =>{
  let leftY = 0
  bodiesUpward.forEach(body => {
    Body.setPosition(body, {
      x: 200,
      y: leftY,
    })
    Body.setAngle(body, -Math.PI / 2) // 90deg in Radians

    // Important to not have any "left-over" movement.
    Body.setVelocity(body, { x: 0, y: 0 })

    leftY -= 100
    console.log(leftY)
  })
}

const positionRightBodies = () => {
  let rightY = 600
  bodiesDownward.forEach(body => {
    Body.setPosition(body, {
      x: 200,
      y: rightY,
    })
    Body.setAngle(body, -Math.PI / 2) // 90deg in Radians

    // Important to not have any "left-over" movement.
    Body.setVelocity(body, { x: 0, y: 0 })

    rightY += 120
  })
}

positionLeftBodies()
positionRightBodies()

setInterval(() => {
  positionLeftBodies()
  positionRightBodies()
}, 6000)


그리고 이것은 행동으로 보이는 것입니다:



그리고 그것이 시리즈의 두 번째 부분입니다!


제가 이 글을 쓰면서 즐거웠던 만큼 여러분도 이 글을 즐겁게 읽으셨기를 바랍니다! 그렇다면 ❤️ 또는 🦄를 남겨주세요! 또한 다른 예제가 어떻게 나오는지 보고 싶다면 저를 팔로우하는 것도 고려해 보세요! 나는 여가 시간에 기술 기사를 작성하고 가끔 커피를 마시는 것을 좋아합니다.

저의 노력을 응원하고 싶다면 you can offer me a coffee or ! Paypal을 통해 저를 직접 지원할 수도 있습니다!

좋은 웹페이지 즐겨찾기