diff --git a/package.json b/package.json index d7f498fbc..cf86bc266 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,7 @@ "classnames": "2.3.2", "dayjs": "1.11.9", "default-passive-events": "2.0.0", - "detect-gpu": "5.0.37", "echarts": "4.9.0", - "gsap": "3.12.2", "history": "5.3.0", "i18next": "20.6.1", "js-base64": "^3.7.5", @@ -35,8 +33,7 @@ "react-router-dom": "5.3.4", "react-scripts": "5.0.1", "sass": "1.66.1", - "styled-components": "5.3.11", - "three": "0.149.0" + "styled-components": "5.3.11" }, "devDependencies": { "@sentry/webpack-plugin": "2.7.1", diff --git a/src/components/BannerFallback/index.module.scss b/src/components/BannerFallback/index.module.scss deleted file mode 100644 index e98dc92b9..000000000 --- a/src/components/BannerFallback/index.module.scss +++ /dev/null @@ -1,15 +0,0 @@ -$backgroudColor: #232323; - -.Root { - width: 100%; - background-color: $backgroudColor; - height: 200px; - position: relative; - background-image: url('../../assets/ckb_explorer_banner.svg'); - background-repeat: no-repeat; - background-position: center center; - background-size: auto 100%; - @media (max-width: 750px) { - background-image: url('../../assets/ckb_explorer_banner_phone.svg'); - } -} diff --git a/src/components/BannerFallback/index.tsx b/src/components/BannerFallback/index.tsx deleted file mode 100644 index f4272ebf7..000000000 --- a/src/components/BannerFallback/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import styles from './index.module.scss' - -export default () =>
diff --git a/src/pages/Home/Banner/anime.ts b/src/pages/Home/Banner/anime.ts deleted file mode 100644 index 74261ac8b..000000000 --- a/src/pages/Home/Banner/anime.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { Mesh } from 'three' -import { gsap } from 'gsap' -import { singleton } from '../../../utils/util' -import { assert } from '../../../utils/error' -import { CubeOffset, InstancedCubeUnitControl } from './renderUtils' - -export const playNewBlockAnime = singleton(_playNewBlockAnime) - -const DURATION_TO_PROTRUDE = 5 // duration to protrude -const DELAY_OF_RIPPLE = 10 // change the distance between edges of a ripple - -// eslint-disable-next-line no-underscore-dangle -function _playNewBlockAnime( - cubeOffsets: CubeOffset[], - getCubeControl: ( - x: number, - z: number, - ) => - | (InstancedCubeUnitControl & { - isTextCube: boolean - isDataCube: boolean - isFloatCubeCreator: boolean - }) - | null, - createFloatCube: () => Mesh, -) { - return Promise.all(cubeOffsets.map(startCubeAnime)) - - function startCubeAnime(offset: CubeOffset): gsap.core.Animation | null { - const control = getCubeControl(offset.x, offset.z) - if (control == null) return null - const { position, onUpdate, isTextCube, isDataCube, isFloatCubeCreator } = control - - const textCubeFirstUpDistance = 40 - const ySpeedPerSecond = 75 - const getMoveTime = (distance: number, multiply = 1) => distance / ySpeedPerSecond / multiply - - if (isTextCube) { - return gsap - .timeline() - .to(position, { - y: position.y + textCubeFirstUpDistance * 2, - duration: getMoveTime(DURATION_TO_PROTRUDE * 4), - onUpdate, - }) - .to(position, { - y: -40, - duration: getMoveTime(DURATION_TO_PROTRUDE * 3), - onUpdate, - }) - .to(position, { - y: position.y + textCubeFirstUpDistance, - duration: getMoveTime(DURATION_TO_PROTRUDE * 4), - onUpdate, - }) - .to(position, { - y: position.y, - duration: getMoveTime(DURATION_TO_PROTRUDE * 5), - onUpdate, - }) - } - - const distance = Math.sqrt(position.x ** 2 + position.z ** 2) - const maxDistanceWithReduction = 1000 - const reductionRatio = distance > maxDistanceWithReduction ? 0 : 1 - distance / maxDistanceWithReduction - const textCubeFirstUpDuration = getMoveTime(textCubeFirstUpDistance, 2) * 4e3 - - const timeline = gsap - .timeline() - .to(position, { - delay: (distance + textCubeFirstUpDuration - 500 * reductionRatio) / 2000, - y: position.y + 40, - duration: getMoveTime(DURATION_TO_PROTRUDE), - onUpdate, - }) - .to(position, { - delay: getMoveTime(DELAY_OF_RIPPLE), - y: position.y, - duration: getMoveTime(DURATION_TO_PROTRUDE), - onUpdate, - }) - - if (!isDataCube) return timeline - - const createFloatCubeTimeline = () => { - const moveLength = 1500 - const moveTime = getMoveTime(moveLength, 5) - const floatCube = createFloatCube() - assert(!Array.isArray(floatCube.material)) - floatCube.material.opacity = 0 - floatCube.position.copy(position) - - return gsap - .timeline() - .addLabel('start') - .to( - floatCube.material, - { - opacity: 1, - duration: moveTime * 0.4, - }, - 'start', - ) - .to( - floatCube.material, - { - opacity: 0, - delay: moveTime * 0.6, - duration: moveTime * 0.4, - }, - 'start', - ) - .to( - floatCube.position, - { - y: moveLength, - duration: moveTime, - onComplete() { - floatCube.removeFromParent() - floatCube.geometry.dispose() - assert(!Array.isArray(floatCube.material)) - floatCube.material.dispose() - }, - }, - 'start', - ) - .to( - floatCube.rotation, - { - x: 2.42 / 8, - y: 3.21 / 8, - z: 14 / 8, - duration: moveTime, - }, - 'start', - ) - } - - const dataCubeProtrudingHeight = 40 - timeline - .to(position, { - y: position.y + dataCubeProtrudingHeight, - duration: getMoveTime(dataCubeProtrudingHeight), - onUpdate, - }) - // ">" The end of the previous animation, "<" The start of previous animation - .addLabel('onDataCubeScaleEnd', '>') - .addLabel('onDataCubeScaleStart', '<') - .add(isFloatCubeCreator ? createFloatCubeTimeline() : [], 'onDataCubeScaleStart') - .to( - position, - { - delay: getMoveTime(150), - y: position.y, - duration: getMoveTime(dataCubeProtrudingHeight), - onUpdate, - }, - 'onDataCubeScaleEnd', - ) - - return timeline - } -} diff --git a/src/pages/Home/Banner/index.module.scss b/src/pages/Home/Banner/index.module.scss deleted file mode 100644 index 86da74ad5..000000000 --- a/src/pages/Home/Banner/index.module.scss +++ /dev/null @@ -1,19 +0,0 @@ -.banner { - background: #000; - --rendererWidth: 1200px; - - &.mobile { - --rendererWidth: 600px; - } - - .renderer { - position: relative; - left: calc(50% - var(--rendererWidth) / 2); - width: var(--rendererWidth); - height: calc(var(--rendererWidth) / 4); - } - - canvas { - filter: drop-shadow(2px 4px 6px #000); - } -} diff --git a/src/pages/Home/Banner/index.tsx b/src/pages/Home/Banner/index.tsx deleted file mode 100644 index 0a8be3f72..000000000 --- a/src/pages/Home/Banner/index.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { FC, memo, useEffect, useRef, useState } from 'react' -import classNames from 'classnames' -import { getGPUTier } from 'detect-gpu' -import { BannerRender, createBannerRender } from './render' -import styles from './index.module.scss' -import { useIsMobile, usePrevious } from '../../../utils/hook' -import { isMainnet as isMainnetFunc } from '../../../utils/chain' -import BannerFallback from '../../../components/BannerFallback' - -const GPUTier = { - MIN_TIER: 2, - key: 'gpu-info', - get(): number | null { - try { - const cache = localStorage.getItem(this.key) - return cache ? JSON.parse(cache).tier : null - } catch { - return null - } - }, - async update() { - const info = await getGPUTier() - localStorage.setItem(this.key, JSON.stringify(info)) - return info.tier - }, -} - -// eslint-disable-next-line no-underscore-dangle -const _Banner: FC<{ latestBlock?: State.Block }> = ({ latestBlock }) => { - const isMobile = useIsMobile() - const ref = useRef(null) - const [render, setRender] = useState() - const [gpuTier, setGPUTier] = useState(GPUTier.get()) - - const isFallbackDisplayed = gpuTier === null || gpuTier < GPUTier.MIN_TIER - - useEffect(() => { - GPUTier.update().then(setGPUTier).catch(console.error) - }, [setGPUTier]) - - useEffect(() => { - if (isFallbackDisplayed) return - - const container = ref.current - if (!container) return - try { - const r = createBannerRender(container) - setRender(r) - return () => r.destroy() - } catch (e) { - if (e instanceof Error) { - console.error(e.message) - } - // ignore - } - }, [setRender, isFallbackDisplayed]) - - const prevLatestBlock = usePrevious(latestBlock) - useEffect(() => { - if (!latestBlock || !prevLatestBlock) return - render?.onNewBlock(latestBlock) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [latestBlock]) - - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(() => render?.onResize(), [isMobile]) - - if (isFallbackDisplayed) { - return - } - - return ( -
-
-
- ) -} - -/* - * FIXME: this is a fallback for https://github.com/Magickbase/ckb-explorer-public-issues/issues/218 and should be restored once performance issue is fixed - */ -const isMainnet = isMainnetFunc() -export const Banner = isMainnet - ? BannerFallback - : memo(_Banner, (a, b) => a.latestBlock?.number === b.latestBlock?.number) diff --git a/src/pages/Home/Banner/render.ts b/src/pages/Home/Banner/render.ts deleted file mode 100644 index 6d25f7cd7..000000000 --- a/src/pages/Home/Banner/render.ts +++ /dev/null @@ -1,342 +0,0 @@ -import { - Camera, - DirectionalLight, - Frustum, - Matrix4, - Mesh, - MeshPhysicalMaterial, - OrthographicCamera, - Scene, - Vector3, - WebGLRenderer, - sRGBEncoding, - MeshLambertMaterial, -} from 'three' -import { RoundedBoxGeometry } from 'three/examples/jsm/geometries/RoundedBoxGeometry' -import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer' -import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass' -import { playNewBlockAnime } from './anime' -import { isMainnet } from '../../../utils/chain' -import { createSideFadeOutPass } from './shaderPass/sideFadeOutPass' -import { createTextureOverlapPass } from './shaderPass/textureOverlapPass' -import { - containsPoint, - createBloomComposerController, - createInstancedCubeMesh, - CubeOffset, - InstancedCubeUnitControl, -} from './renderUtils' -import { assert } from '../../../utils/error' -import { randomInt } from '../../../utils/util' -import { getPrimaryColor } from '../../../constants/common' - -const COLORS = { - primary: getPrimaryColor(), - float: isMainnet() ? 0x00330b : 0x4d1676, -} - -export interface BannerRender { - onNewBlock: (block: State.Block) => void - onResize: () => void - destroy: () => void -} - -export function createBannerRender(container: HTMLElement) { - const width = container.clientWidth - const height = container.clientHeight - const aspect = width / height - const scene = new Scene() - // The following number constants are from the design draft. - const camera = new OrthographicCamera(-700 * aspect, 700 * aspect, 150 * aspect, -150 * aspect, -100000, 100000) - const renderer = new WebGLRenderer({ antialias: true, alpha: true }) - renderer.setPixelRatio(window.devicePixelRatio) - renderer.outputEncoding = sRGBEncoding - renderer.setSize(width, height) - container.appendChild(renderer.domElement) - - // Fixed a viewing angle. - camera.rotation.x = Math.PI / (180 / -37.46) - camera.rotation.y = Math.PI / (180 / -33.83) - camera.rotation.z = Math.PI / (180 / -28) - camera.position.x = -540 - camera.position.z = 880 - camera.position.y = 720 - camera.updateWorldMatrix(true, false) - - const cubeSize = new Vector3(100, 200, 100) - const gap = 10 - const { - mesh: textCubes, - cubeOffsets: textCubeOffsets, - getCubeControl: getTextCubeControl, - } = createTextCubes(cubeSize, gap) - const { - mesh: normalCubes, - cubeOffsets: normalCubeOffsets, - getCubeControl: getNormalCubeControl, - } = createNormalCubes(cubeSize, gap, camera, textCubeOffsets) - scene.add(normalCubes) - scene.add(textCubes) - - const highlight1 = new DirectionalLight(0x999999, 12) - highlight1.position.set(1, 1, 0) - scene.add(highlight1) - - const highlight2 = new DirectionalLight(COLORS.primary, 600) - highlight2.position.set(1, -80, 1) - scene.add(highlight2) - - const highlight3 = new DirectionalLight(0xffffff, 20) - highlight3.position.set(-1, -5, 0) - scene.add(highlight3) - - const renderPass = new RenderPass(scene, camera) - const sideFadeOutPass = createSideFadeOutPass() - const bloomComposerCtl = createBloomComposerController(renderer, scene, width, height, [renderPass]) - const bloomTextureOverlapPass = createTextureOverlapPass(bloomComposerCtl.composer.renderTarget2.texture) - - const finalComposer = new EffectComposer(renderer) - finalComposer.addPass(renderPass) - finalComposer.addPass(bloomTextureOverlapPass) - finalComposer.addPass(sideFadeOutPass) - - let stopRenderLoop: (() => void) | null = null - function render() { - const handle = requestAnimationFrame(render) - stopRenderLoop = () => cancelAnimationFrame(handle) - - bloomComposerCtl.render() - finalComposer.render() - } - render() - - function createFloatCube() { - const boxGeometry = new RoundedBoxGeometry(100, 100, 100, 6, 6) - const boxMaterial = new MeshLambertMaterial({ - color: COLORS.float, - emissive: COLORS.float, - emissiveIntensity: 0.001, - transparent: true, - opacity: 0.8, - }) - const cube = new Mesh(boxGeometry, boxMaterial) - bloomComposerCtl.toggleBloom(cube) - scene.add(cube) - return cube - } - - return { - onNewBlock(block: State.Block) { - const dataCubeOffsets = getDataCubeOffsets(camera, getNormalCubeControl, textCubeOffsets, block.transactionsCount) - const combinedGetCubeControl = (x: number, z: number) => { - const control = getNormalCubeControl(x, z) ?? getTextCubeControl(x, z) - if (control == null) return null - - const isTextCube = textCubeOffsets.some(offset => CubeOffset.isEqual(offset, { x, z })) - const isDataCube = dataCubeOffsets.some(offset => CubeOffset.isEqual(offset, { x, z })) - const isFloatCubeCreator = isDataCube && CubeOffset.isEqual(dataCubeOffsets[0], { x, z }) - return { ...control, isTextCube, isDataCube, isFloatCubeCreator } - } - - playNewBlockAnime([...normalCubeOffsets, ...textCubeOffsets], combinedGetCubeControl, createFloatCube) - }, - onResize() { - renderer.setSize(container.clientWidth, container.clientHeight) - }, - destroy() { - stopRenderLoop?.() - - // It is expected that the rest of the resources will be automatically reclaimed by GC. - finalComposer.dispose() - renderer.dispose() - - renderPass.dispose() - sideFadeOutPass.dispose() - bloomComposerCtl.dispose() - bloomTextureOverlapPass.dispose() - - highlight1.dispose() - highlight2.dispose() - highlight3.dispose() - - const meshes = [normalCubes, textCubes] - meshes.forEach(mesh => { - mesh.removeFromParent() - mesh.geometry.dispose() - assert(!Array.isArray(mesh.material)) - mesh.material.dispose() - }) - - renderer.domElement.remove() - }, - } -} - -function createNormalCubes( - cubeSize: Vector3, - spacingBetweenCubes: number, - camera: Camera, - disabledOffsets: CubeOffset[], - centerPos: Vector3 = new Vector3(0, 0, 0), -) { - const cubeCanvasRangeLimit = { minX: -25, maxX: 25, minZ: -30, maxZ: 25 } - const cubeWidth = cubeSize.x - const cubeHeight = cubeSize.y - const cubeLong = cubeSize.z - - const frustum = new Frustum() - frustum.setFromProjectionMatrix(new Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)) - const isVisibleToCamera = (pos: Vector3) => containsPoint(frustum, pos, Math.max(cubeWidth, cubeLong)) - - const cubes: { x: number; z: number; initPosition: Vector3 }[] = [] - const cubeIndexMap: Record> = {} - for (let x = cubeCanvasRangeLimit.minX; x < cubeCanvasRangeLimit.maxX; x++) { - for (let z = cubeCanvasRangeLimit.minZ; z < cubeCanvasRangeLimit.maxZ; z++) { - const xOffset = x * (cubeWidth + spacingBetweenCubes) - const zOffset = z * (cubeLong + spacingBetweenCubes) - const position = new Vector3( - centerPos.x + (xOffset + spacingBetweenCubes / 2 + cubeWidth), - centerPos.y + 0, - centerPos.z + (zOffset + spacingBetweenCubes / 2 + cubeLong), - ) - const disabled = disabledOffsets.some(offset => CubeOffset.isEqual(offset, { x, z })) - if (!disabled && isVisibleToCamera(position)) { - const index = cubes.push({ x, z, initPosition: position }) - 1 - const mapWithColumn = cubeIndexMap[x] ?? (cubeIndexMap[x] = {}) - mapWithColumn[z] = index - } - } - } - - const boxGeometry = new RoundedBoxGeometry(cubeWidth, cubeHeight, cubeLong, 5, 8) - const boxMaterial = new MeshPhysicalMaterial({ - metalness: 0.01, - roughness: 0.9, - clearcoatRoughness: 1, - transmission: 1, - }) - - return createInstancedCubeMesh(cubes, cubeIndexMap, boxGeometry, boxMaterial) -} - -function createTextCubes(cubeSize: Vector3, spacingBetweenCubes: number, centerPos: Vector3 = new Vector3(0, 0, 0)) { - const cubeWidth = cubeSize.x - const cubeHeight = cubeSize.y - const cubeLong = cubeSize.z - - const textCubePoints = getTextPoints('C K B') - const cubes: { x: number; z: number; initPosition: Vector3 }[] = [] - const cubeIndexMap: Record> = {} - textCubePoints.forEach(({ x, z }) => { - const xOffset = x * (cubeWidth + spacingBetweenCubes) - const zOffset = z * (cubeLong + spacingBetweenCubes) - const position = new Vector3( - centerPos.x + (xOffset + spacingBetweenCubes / 2 + cubeWidth), - centerPos.y + 40, - centerPos.z + (zOffset + spacingBetweenCubes / 2 + cubeLong), - ) - const index = cubes.push({ x, z, initPosition: position }) - 1 - const mapWithColumn = cubeIndexMap[x] ?? (cubeIndexMap[x] = {}) - mapWithColumn[z] = index - }) - - const boxGeometry = new RoundedBoxGeometry(cubeWidth, cubeHeight, cubeLong, 5, 8) - const boxMaterial = new MeshPhysicalMaterial({ - clearcoatRoughness: 1, - metalness: 0.08, - roughness: 0.95, - transmission: 1, - color: 0xcccccc, - }) - - return createInstancedCubeMesh(cubes, cubeIndexMap, boxGeometry, boxMaterial) -} - -function getDataCubeOffsets( - camera: OrthographicCamera, - getCubeControl: (x: number, z: number) => InstancedCubeUnitControl | null, - textCubeOffsets: CubeOffset[], - count: number, -) { - const smallVisionCamera = camera.clone() - smallVisionCamera.left *= 0.7 - smallVisionCamera.right *= 0.7 - smallVisionCamera.updateProjectionMatrix() - const frustum = new Frustum() - frustum.setFromProjectionMatrix( - new Matrix4().multiplyMatrices(smallVisionCamera.projectionMatrix, smallVisionCamera.matrixWorldInverse), - ) - const isNearToViewport = (pos: Vector3) => containsPoint(frustum, pos, -100) - - const textRect = { x1: 0, z1: 0, x2: 0, z2: 0 } - textCubeOffsets.forEach(({ x, z }) => { - textRect.x1 = Math.min(textRect.x1, x) - textRect.z1 = Math.min(textRect.z1, z) - textRect.x2 = Math.max(textRect.x2, x) - textRect.z2 = Math.max(textRect.z2, z) - }) - const isInTextRect = ({ x, z }: CubeOffset) => - x >= textRect.x1 && x <= textRect.x2 && z >= textRect.z1 && z <= textRect.z2 - - const offsets: CubeOffset[] = [] - while (count > offsets.length) { - const offset: CubeOffset = { x: randomInt(-25, 25), z: randomInt(-30, 25) } - const info = getCubeControl(offset.x, offset.z) - if ( - info == null || - offsets.some(existed => CubeOffset.isEqual(existed, offset)) || - isInTextRect(offset) || - !isNearToViewport(info.position) - ) - continue - offsets.push(offset) - } - - return offsets -} - -function getTextPoints(text: string, font = '100 8px Arial') { - if (text !== 'C K B' || font !== '100 8px Arial') { - throw new Error( - 'This function is not fully implemented, you need to refactor this function to pass in parameters freely', - ) - } - - return [ - // C - [-7, -1], - [-7, 0], - [-6, -2], - [-6, 1], - [-5, -3], - [-5, 2], - [-4, -3], - [-4, 2], - // K - [-1, -3], - [-1, -2], - [-1, -1], - [-1, 0], - [-1, 1], - [-1, 2], - [0, -1], - [0, 0], - [1, -2], - [1, 1], - [2, -3], - [2, 2], - // B - [5, -3], - [5, -2], - [5, -1], - [5, 0], - [5, 1], - [5, 2], - [6, -3], - [6, -1], - [6, 2], - [7, -2], - [7, 0], - [7, 1], - ].map(([x, z]) => ({ x, z })) -} diff --git a/src/pages/Home/Banner/renderUtils.ts b/src/pages/Home/Banner/renderUtils.ts deleted file mode 100644 index 49082ce81..000000000 --- a/src/pages/Home/Banner/renderUtils.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { - Mesh, - Frustum, - Vector3, - Layers, - Object3D, - Vector2, - Scene, - WebGLRenderer, - Quaternion, - BoxGeometry, - InstancedMesh, - Material, - Matrix4, -} from 'three' -import { EffectComposer, Pass } from 'three/examples/jsm/postprocessing/EffectComposer' -import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass' -import { pick } from '../../../utils/object' - -export type CubeMap = Partial<{ - [x: number]: Partial<{ - [z: number]: Mesh - }> -}> - -export interface CubeOffset { - x: number - z: number -} - -// eslint-disable-next-line no-redeclare -export namespace CubeOffset { - export function isEqual(a: CubeOffset, b: CubeOffset) { - return a.x === b.x && a.z === b.z - } -} - -export interface InstancedCubeUnitControl { - position: Vector3 - quaternion: Quaternion - scale: Vector3 - onUpdate: () => void -} - -// `frustum.containsPoint` of the variation -export function containsPoint(frustum: Frustum, point: Vector3, tolerance = 0) { - const { planes } = frustum - - for (let i = 0; i < 6; i++) { - if (planes[i].distanceToPoint(point) < -tolerance) { - return false - } - } - - return true -} - -// Reference from: -// https://github.com/mrdoob/three.js/blob/master/examples/webgl_postprocessing_unreal_bloom_selective.html -export function createBloomComposerController( - renderer: WebGLRenderer, - scene: Scene, - width: number, - height: number, - beforePasses: Pass[], -): { - composer: EffectComposer - toggleBloom: (mesh: Mesh) => void - render: (delta?: number) => void - dispose: () => void -} { - const BLOOM_SCENE = 1 - const bloomLayer = new Layers() - bloomLayer.set(BLOOM_SCENE) - - function setNoRenderIfNonBloomed() { - const objs: Object3D[] = [] - scene.traverse((obj: Object3D | Mesh) => { - if ('isMesh' in obj && obj.isMesh && bloomLayer.test(obj.layers) === false) { - objs.push(obj) - } - }) - - objs.forEach(obj => scene.remove(obj)) - return () => objs.forEach(obj => scene.add(obj)) - } - - const bloomPass = new UnrealBloomPass(new Vector2(width, height), 1.5, 0.5, 0) - - const composer = new EffectComposer(renderer) - composer.renderToScreen = false - beforePasses.forEach(p => composer.addPass(p)) - composer.addPass(bloomPass) - - return { - composer, - toggleBloom(mesh) { - mesh.layers.toggle(BLOOM_SCENE) - }, - render(delta) { - const restore = setNoRenderIfNonBloomed() - composer.render(delta) - restore() - }, - dispose() { - composer.dispose() - bloomPass.dispose() - }, - } -} - -export function createInstancedCubeMesh( - cubes: { x: number; z: number; initPosition: Vector3 }[], - cubeIndexMap: Record>, - geometry: BoxGeometry, - material: Material, -) { - const mesh = new InstancedMesh(geometry, material, cubes.length) - const matrix = new Matrix4() - cubes.forEach(({ initPosition }, idx) => { - matrix.setPosition(initPosition) - mesh.setMatrixAt(idx, matrix) - }) - - return { - mesh, - cubeOffsets: cubes.map(cube => pick(cube, ['x', 'z'])), - getCubeControl(xOrIndex: number, z?: number): InstancedCubeUnitControl | null { - const idx = z == null ? xOrIndex : cubeIndexMap[xOrIndex]?.[z] - if (idx == null) return null - - mesh.getMatrixAt(idx, matrix) - const position = new Vector3() - const quaternion = new Quaternion() - const scale = new Vector3() - matrix.decompose(position, quaternion, scale) - - return { - position, - quaternion, - scale, - onUpdate() { - mesh.setMatrixAt(idx, new Matrix4().compose(position, quaternion, scale)) - mesh.instanceMatrix.needsUpdate = true - }, - } - }, - } -} diff --git a/src/pages/Home/Banner/shaderPass/sideFadeOutPass.ts b/src/pages/Home/Banner/shaderPass/sideFadeOutPass.ts deleted file mode 100644 index 5d1a31898..000000000 --- a/src/pages/Home/Banner/shaderPass/sideFadeOutPass.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass' - -export function createSideFadeOutPass() { - const pass = new ShaderPass({ - uniforms: { - tDiffuse: { value: null }, - }, - - vertexShader: /* glsl */ ` - varying vec2 vUv; - varying float x; - void main() { - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); - x = (gl_Position.x + 1.0) * 0.5; - }`, - - fragmentShader: /* glsl */ ` - uniform sampler2D tDiffuse; - varying vec2 vUv; - varying float x; - void main() { - gl_FragColor = texture2D( tDiffuse, vUv ); - float edgeDist = (0.5 - abs(x - 0.5)); - gl_FragColor.a = edgeDist * 2.0; - }`, - }) - - pass.material.transparent = true - - return pass -} diff --git a/src/pages/Home/Banner/shaderPass/textureOverlapPass.ts b/src/pages/Home/Banner/shaderPass/textureOverlapPass.ts deleted file mode 100644 index d0ac7b790..000000000 --- a/src/pages/Home/Banner/shaderPass/textureOverlapPass.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ShaderMaterial, Texture } from 'three' -import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass' - -export function createTextureOverlapPass(texture: Texture) { - const pass = new ShaderPass( - new ShaderMaterial({ - uniforms: { - baseTexture: { value: null }, - overlapTexture: { value: texture }, - }, - - vertexShader: /* glsl */ ` - varying vec2 vUv; - void main() { - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); - }`, - - fragmentShader: /* glsl */ ` - uniform sampler2D baseTexture; - uniform sampler2D overlapTexture; - varying vec2 vUv; - void main() { - gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( overlapTexture, vUv ) ); - }`, - - defines: {}, - }), - 'baseTexture', - ) - pass.needsSwap = true - - return pass -} diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index b2ec4c870..b07e9f2f8 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -30,7 +30,7 @@ import { BlockCardItem, TransactionCardItem } from './TableCard' import { getTipBlockNumber } from '../../service/app/address' import Loading from '../../components/Loading/SmallLoading' import { useElementIntersecting, useInterval, useIsLGScreen, useIsMobile } from '../../utils/hook' -import { Banner } from './Banner' +import Banner from '../../components/Banner' import { handleBlockchainAlert } from '../../service/app/blockchain' import Search from '../../components/Search' import AverageBlockTimeChart from './AverageBlockTimeChart' @@ -262,7 +262,7 @@ export default () => { return ( - +
diff --git a/yarn.lock b/yarn.lock index e93819e30..a77565d7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5108,13 +5108,6 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detect-gpu@5.0.37: - version "5.0.37" - resolved "https://registry.yarnpkg.com/detect-gpu/-/detect-gpu-5.0.37.tgz#27febe44d478ef4d35cd38007355da795ba075d5" - integrity sha512-EraWs84faI4iskB4qvE39bevMIazEvd1RpoyGLOBesRLbiz6eMeJqqRPHjEFClfRByYZzi9IzU35rBXIO76oDw== - dependencies: - webgl-constants "^1.1.1" - detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -6692,11 +6685,6 @@ grapheme-splitter@^1.0.4: resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== -gsap@3.12.2: - version "3.12.2" - resolved "https://registry.yarnpkg.com/gsap/-/gsap-3.12.2.tgz#6e88203eed360761cbf2a2cb3a8d702aa87f3f6d" - integrity sha512-EkYnpG8qHgYBFAwsgsGEqvT1WUidX0tt/ijepx7z8EUJHElykg91RvW1XbkT59T0gZzzszOpjQv7SE41XuIXyQ== - gzip-size@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" @@ -12102,11 +12090,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -three@0.149.0: - version "0.149.0" - resolved "https://registry.yarnpkg.com/three/-/three-0.149.0.tgz#a9cf78b17d02f063ffe6dfca1e300eff2eab2927" - integrity sha512-tohpUxPDht0qExRLDTM8sjRLc5d9STURNrdnK3w9A+V4pxaTBfKWWT/IqtiLfg23Vfc3Z+ImNfvRw1/0CtxrkQ== - throat@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" @@ -12613,11 +12596,6 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" -webgl-constants@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/webgl-constants/-/webgl-constants-1.1.1.tgz#f9633ee87fea56647a60b9ce735cbdfb891c6855" - integrity sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg== - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"