Cubetti.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <template>
  2. <figure id="cubetti" ref="cubetti" />
  3. </template>
  4. <style lang="pcss" scoped>
  5. @reference '../assets/css/main.css';
  6. @media screen and (width >= theme(breakpoint.sm)) {
  7. #cubetti {
  8. position: absolute;
  9. width: 200px !important;
  10. height: 200px !important;
  11. top: -55px !important;
  12. left: 0px !important;
  13. }
  14. }
  15. #cubetti {
  16. position: absolute;
  17. width: 120px;
  18. height: 120px;
  19. overflow: visible;
  20. top: -24px;
  21. left: -22px;
  22. }
  23. </style>
  24. <script lang="ts" setup>
  25. import {
  26. AmbientLight,
  27. DirectionalLight,
  28. BoxGeometry,
  29. Mesh,
  30. MeshStandardMaterial,
  31. PerspectiveCamera,
  32. Scene,
  33. Vector3,
  34. WebGLRenderer,
  35. MathUtils,
  36. LinearToneMapping,
  37. } from 'three';
  38. import { animate, stagger, type AnimationParams } from 'animejs';
  39. const scene = new Scene()
  40. const camera = new PerspectiveCamera(80, 1, 0.1, 1000)
  41. const renderer = new WebGLRenderer({ antialias: true, alpha: true })
  42. renderer.setPixelRatio(window.devicePixelRatio);
  43. renderer.toneMapping = LinearToneMapping
  44. renderer.toneMappingExposure = 2.5
  45. const directionalLight = new DirectionalLight(0xffffff)
  46. const ambientLight = new AmbientLight(0xffffff)
  47. const geometry = new BoxGeometry(1, 1, 1)
  48. const blueMaterial = new MeshStandardMaterial({ color: 'dodgerblue' })
  49. const greenMaterial = new MeshStandardMaterial({ color: 'greenyellow' })
  50. const orangeMaterial = new MeshStandardMaterial({ color: 'orange' })
  51. const blueCube = new Mesh(geometry, blueMaterial)
  52. blueCube.position.set(-1, 0, 1)
  53. const greenCube = new Mesh(geometry, greenMaterial)
  54. greenCube.position.set(1, 0, 1)
  55. const orangeCube = new Mesh(geometry, orangeMaterial)
  56. orangeCube.position.set(0, 0, -1)
  57. const cubeGroup = new Scene()
  58. cubeGroup.add(blueCube, greenCube, orangeCube)
  59. const cubettiAnims = [
  60. { // group spin
  61. targets: [cubeGroup.rotation],
  62. params: {
  63. keyframes: [
  64. { y: 2 * Math.PI, duration: 1000 },
  65. ],
  66. easing: 'easeOutCubic',
  67. duration: 1000,
  68. onComplete: playRandomAnimation,
  69. }
  70. },
  71. { // floating cubes
  72. targets: [orangeCube.position, blueCube.position, greenCube.position],
  73. params: {
  74. keyframes: [
  75. { y: -0.5, duration: 500/3 },
  76. { y: 0.5, duration: 707/3 },
  77. { y: 0.0, duration: 500/3 },
  78. ],
  79. easing: 'easeInOutSine',
  80. delay: stagger(500/3),
  81. onComplete: playRandomAnimation,
  82. }
  83. },
  84. { // rotating cubes
  85. targets: [orangeCube.rotation, blueCube.rotation, greenCube.rotation],
  86. params: {
  87. x: MathUtils.randInt(0, 1) * 2 * Math.PI, y: MathUtils.randInt(0, 1) * 2 * Math.PI, z: MathUtils.randInt(0, 1) * 2 * Math.PI, duration: 1000,
  88. easing: 'easeOutSine',
  89. delay: stagger(500/3),
  90. onComplete: playRandomAnimation
  91. }
  92. }
  93. ]
  94. const cubetti = ref()
  95. function playRandomAnimation() {
  96. setTimeout(() => {
  97. const n = MathUtils.randInt(0, cubettiAnims.length-1)
  98. const a = cubettiAnims[n] as any
  99. animate(a.targets, a.params)
  100. }, MathUtils.randInt(1000, 8000))
  101. }
  102. const runAnimation = () => {
  103. renderer.render(scene, camera)
  104. requestAnimationFrame(runAnimation)
  105. }
  106. const resizeCanvas = () => {
  107. if (window.innerWidth < 640) {
  108. renderer.setSize(120, 120);
  109. } else {
  110. renderer.setSize(200, 200);
  111. }
  112. }
  113. onMounted(() => {
  114. scene.add(camera)
  115. scene.add(ambientLight, directionalLight)
  116. scene.add(cubeGroup)
  117. // renderer.setSize(200, 200)
  118. resizeCanvas();
  119. camera.position.copy((new Vector3(-2, 1.5, 2)).multiplyScalar(1.2))
  120. camera.lookAt(0, 0, 0)
  121. scene.background = null
  122. cubetti.value.appendChild(renderer.domElement)
  123. window.addEventListener('resize', resizeCanvas);
  124. playRandomAnimation()
  125. runAnimation()
  126. })
  127. onUnmounted(() => {
  128. window.removeEventListener('resize', resizeCanvas);
  129. })
  130. </script>