mirror of
https://github.com/wavetermdev/docusaurus-og.git
synced 2026-08-05 13:46:35 -07:00
add interactions for hero models - desktop
This commit is contained in:
committed by
Hossein Mehrabi
parent
0ec93e6b8c
commit
8f53200f24
@@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"start": "docusaurus start -p 3002",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
:root {
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
@@ -8,22 +8,40 @@ import {
|
||||
FeatureList,
|
||||
Showcase,
|
||||
HeroModel,
|
||||
HeroInfo,
|
||||
} from '../components/mdx'
|
||||
|
||||
<Hero
|
||||
size="large"
|
||||
title="The web3 managing standard"
|
||||
description="Waku is a decentralized communications network"
|
||||
>
|
||||
<HeroActions>
|
||||
<HeroAction href="https://docs.waku.org" target="_blank">
|
||||
Build on Waku
|
||||
</HeroAction>
|
||||
<HeroAction variant="filled" href="https://docs.waku.org" target="_blank">
|
||||
Run Waku
|
||||
</HeroAction>
|
||||
</HeroActions>
|
||||
<HeroModel modelUrl="/hero/bust-hi.glb" layout="floating" renderer="ascii" />
|
||||
<Hero size="large">
|
||||
<HeroInfo>
|
||||
<HeroTitle>The web3 managing standard</HeroTitle>
|
||||
{/*
|
||||
<HeroDescription>
|
||||
Waku is a decentralized communications network that enables private, censorship-resistant messaging for web3 applications.
|
||||
</HeroDescription>
|
||||
* */}
|
||||
<HeroDescription>
|
||||
WAKU IS A DECENTRALIZED COMMUNICATIONS NETWORK.
|
||||
</HeroDescription>
|
||||
<HeroActions>
|
||||
<HeroAction href="https://docs.waku.org" target="_blank">
|
||||
Build on Waku
|
||||
</HeroAction>
|
||||
<HeroAction variant="filled" href="https://docs.waku.org" target="_blank">
|
||||
Run Waku
|
||||
</HeroAction>
|
||||
</HeroActions>
|
||||
</HeroInfo>
|
||||
<HeroModel
|
||||
modelUrl="/hero/bulanding-generic-hand-01.glb"
|
||||
layout="floating"
|
||||
renderer="ascii"
|
||||
initialX={-0.9831336272264352}
|
||||
initialY={-0.14592188008227222}
|
||||
rotateSpeed={0.1}
|
||||
asciiConfig={{
|
||||
characters: ' .,:;ox%# ||| ||| waku @',
|
||||
}}
|
||||
/>
|
||||
</Hero>
|
||||
|
||||
<FeatureList
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
.mdx-feature-list {
|
||||
border-top: 1px solid rgb(var(--lsd-surface-secondary));
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mdx-feature-list__title {
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
.mdx-hero {
|
||||
position: relative;
|
||||
border-top: 1px solid rgb(var(--lsd-surface-secondary));
|
||||
|
||||
padding-top: 8rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.mdx-hero--large {
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
border-top: none;
|
||||
//padding-top: 2rem;
|
||||
//padding-bottom: 2rem;
|
||||
//border-top: none;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
import clsx from 'clsx'
|
||||
import React from 'react'
|
||||
import { HeroDescription, HeroTitle } from '../index'
|
||||
import { HeroContext } from './Hero.context'
|
||||
import './Hero.scss'
|
||||
|
||||
export type HeroProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> & {
|
||||
size?: 'large' | 'medium' | 'small'
|
||||
title?: React.ReactNode
|
||||
description?: React.ReactNode
|
||||
}
|
||||
|
||||
export const Hero: React.FC<HeroProps> = ({
|
||||
size = 'medium',
|
||||
title,
|
||||
description,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
@@ -24,8 +19,6 @@ export const Hero: React.FC<HeroProps> = ({
|
||||
className={clsx(className, 'mdx-hero', `mdx-hero--${size}`)}
|
||||
{...props}
|
||||
>
|
||||
{title && <HeroTitle>{title}</HeroTitle>}
|
||||
{description && <HeroDescription>{description}</HeroDescription>}
|
||||
{children}
|
||||
</div>
|
||||
</HeroContext.Provider>
|
||||
|
||||
@@ -4,4 +4,7 @@
|
||||
flex-direction: row;
|
||||
gap: 0 1rem;
|
||||
align-items: center;
|
||||
|
||||
position: relative;
|
||||
z-index: 98;
|
||||
}
|
||||
|
||||
+4
-2
@@ -6,25 +6,27 @@ import './HeroDescription.scss'
|
||||
|
||||
export type HeroDescriptionProps = TypographyProps & {
|
||||
size?: 'small' | 'medium' | 'large'
|
||||
uppercase?: boolean
|
||||
}
|
||||
|
||||
export const HeroDescription: React.FC<HeroDescriptionProps> = ({
|
||||
size: sizeProp,
|
||||
className,
|
||||
uppercase = false,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
const ctx = useHero()
|
||||
|
||||
const size = sizeProp ?? (ctx ? ctx.size : 'medium')
|
||||
|
||||
return (
|
||||
<Typography
|
||||
variant={size === 'small' ? 'h5' : 'h1'}
|
||||
variant={size === 'small' ? 'h5' : 'h2'}
|
||||
className={clsx(
|
||||
className,
|
||||
'mdx-hero-description',
|
||||
`mdx-hero-description--${size}`,
|
||||
uppercase ? 'mdx-hero-description--uppercase' : '',
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
.mdx-hero-info {
|
||||
padding: var(--logos-hero-info-padding-bottom) 0
|
||||
var(--logos-hero-info-padding-bottom) 0;
|
||||
height: var(--logos-hero-info-height);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: end;
|
||||
|
||||
border-bottom: 1px solid rgb(var(--lsd-surface-secondary));
|
||||
margin-bottom: calc(100vh - var(--logos-hero-info-height));
|
||||
|
||||
transition: margin-bottom 0.05s ease-in-out;
|
||||
}
|
||||
|
||||
.mdx-hero-info--large {
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import clsx from 'clsx'
|
||||
import React, { PropsWithChildren, useEffect, useRef, useState } from 'react'
|
||||
import { useHero } from '../Hero/Hero.context'
|
||||
import './HeroInfo.scss'
|
||||
import { useScrollY } from '../../../lib/useScrollY'
|
||||
import { calcScrollThreshold, mapFloat } from '../../../lib/ui.utils'
|
||||
|
||||
export type HeroInfoProps = PropsWithChildren<
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
> & {
|
||||
size?: 'medium' | 'large' | 'small'
|
||||
}
|
||||
|
||||
const calcMaxOffsetY = () => {
|
||||
return window.innerHeight * 0.33
|
||||
}
|
||||
export const HeroInfo: React.FC<HeroInfoProps> = ({
|
||||
size: sizeProp,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
const ctx = useHero()
|
||||
const size = sizeProp ? sizeProp : ctx ? ctx.size : 'medium'
|
||||
const scrollY = useScrollY()
|
||||
const ref = useRef<HTMLDivElement>()
|
||||
const [initialMarginBottom, setInitialMarginBottom] = useState<number | null>(
|
||||
null,
|
||||
)
|
||||
|
||||
const getMarginBottom = () => {
|
||||
const offsetY = mapFloat(
|
||||
scrollY,
|
||||
0,
|
||||
calcScrollThreshold(),
|
||||
0,
|
||||
calcMaxOffsetY(),
|
||||
)
|
||||
return initialMarginBottom ? initialMarginBottom - offsetY : 0
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined' || !(ref && ref.current)) return
|
||||
setInitialMarginBottom(
|
||||
parseFloat(window.getComputedStyle(ref.current).marginBottom),
|
||||
)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(className, 'mdx-hero-info', `mdx-hero-info--${size}`)}
|
||||
style={{
|
||||
...(initialMarginBottom ? { marginBottom: getMarginBottom() } : {}),
|
||||
}}
|
||||
ref={ref}
|
||||
{...(props as any)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './HeroInfo'
|
||||
+42
-38
@@ -1,55 +1,51 @@
|
||||
.mdx-hero-model {
|
||||
border-top: 1px solid rgb(var(--lsd-surface-secondary));
|
||||
margin-top: 2rem;
|
||||
height: 452px;
|
||||
width: 100vw;
|
||||
transform: translateX(
|
||||
calc(-1 * calc(calc(100vw - 1440px + calc(var(--content-padding)) * 2) / 2))
|
||||
);
|
||||
position: absolute;
|
||||
top: calc(var(--logos-hero-info-height) - 10px);
|
||||
|
||||
& > div {
|
||||
position: absolute;
|
||||
.mdx-hero-model--inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 1400px;
|
||||
z-index: -1;
|
||||
top: 200px;
|
||||
z-index: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
& > div:first-child {
|
||||
top: 0;
|
||||
//transition: translate 0.6s ease-in-out;
|
||||
canvas {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
& > div:last-child {
|
||||
pointer-events: none;
|
||||
background-image: linear-gradient(
|
||||
179.61deg,
|
||||
rgba(0, 0, 0, 0) 0.34%,
|
||||
#000000 70%
|
||||
);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.mdx-hero-model--floating {
|
||||
}
|
||||
|
||||
.mdx-hero-model--cropped {
|
||||
overflow: hidden;
|
||||
& > div {
|
||||
position: relative;
|
||||
top: -200px;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.mdx-hero-model--floating {
|
||||
.mdx-hero-model--inner {
|
||||
canvas {
|
||||
pointer-events: unset !important;
|
||||
}
|
||||
}
|
||||
|
||||
& > div:last-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.mdx-hero-model--3d {
|
||||
overflow: visible !important;
|
||||
|
||||
.mdx-hero-model--inner {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mdx-hero-model--inner {
|
||||
> div {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: scale(1.2) translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mdx-hero-model--ascii {
|
||||
@@ -59,11 +55,19 @@
|
||||
border: none !important;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
tr {
|
||||
//text-align: center;
|
||||
//font-size: 12px;
|
||||
//letter-spacing: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mdx-hero-model--shade {
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
position: absolute;
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
rgb(0, 0, 0) 37%,
|
||||
rgb(0, 0, 0) 0%,
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
);
|
||||
bottom: 500px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
+184
-56
@@ -2,62 +2,150 @@ import { OrbitControls, useGLTF } from '@react-three/drei'
|
||||
import { Canvas, useFrame, useThree } from '@react-three/fiber'
|
||||
import clsx from 'clsx'
|
||||
import React, {
|
||||
PropsWithChildren,
|
||||
Suspense,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import * as THREE from 'three'
|
||||
import { AsciiEffect } from 'three-stdlib'
|
||||
import './HeroModel.scss'
|
||||
import {
|
||||
calcScrollThreshold,
|
||||
isTouchDevice,
|
||||
mapFloat,
|
||||
random,
|
||||
} from '../../../lib/ui.utils'
|
||||
import { useScrollY } from '../../../lib/useScrollY'
|
||||
|
||||
let ROTATE_SPEED = 0.1
|
||||
const MIN_ROTATE_SPEED = 0.1
|
||||
const MAX_ROTATE_SPEED = 1
|
||||
|
||||
const MAX_Z = 20 * 1.4 // or another value that suits your needs
|
||||
const MIN_Z = 0.2 * 1.4
|
||||
const MIN_Y = -0.25
|
||||
const MAX_Y = 0.25
|
||||
const MIN_X = -0.25
|
||||
const MAX_X = 0.25
|
||||
|
||||
const MIN_ZOOM = 0.22
|
||||
const RESIZE_SPEED_FACTOR = 0.9
|
||||
const INITIAL_ZOOM = 3
|
||||
const calcZoom = (scrollY = 0, initZ = INITIAL_ZOOM) => {
|
||||
return Math.max(
|
||||
mapFloat(
|
||||
scrollY,
|
||||
0,
|
||||
calcScrollThreshold() * RESIZE_SPEED_FACTOR,
|
||||
initZ,
|
||||
MIN_ZOOM,
|
||||
),
|
||||
MIN_ZOOM,
|
||||
)
|
||||
}
|
||||
|
||||
const calcRotateSpeed = (scrollY = 0, speed) => {
|
||||
const sFactor = mapFloat(scrollY, 0, window.innerHeight, 1, 10)
|
||||
return Math.max(Math.min(speed * sFactor, MAX_ROTATE_SPEED), MIN_ROTATE_SPEED)
|
||||
}
|
||||
|
||||
function Model({ url, ...props }) {
|
||||
// useGLTF suspends the component, it literally stops processing
|
||||
const { camera } = useThree()
|
||||
const { scene } = useGLTF(url) as any
|
||||
|
||||
const size = useMemo(() => {
|
||||
const box = new THREE.Box3().setFromObject(scene)
|
||||
return box.getSize(new THREE.Vector3())
|
||||
}, [scene])
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!camera) return
|
||||
const c = camera as THREE.PerspectiveCamera
|
||||
const fov = c.fov * (Math.PI / 180)
|
||||
const distance = Math.abs(Math.max(size.x, size.y) / Math.sin(fov / 2))
|
||||
c.position.setZ(distance)
|
||||
}, [size, camera])
|
||||
|
||||
// useLayoutEffect(() => {
|
||||
// if (!camera) return
|
||||
// const c = camera as THREE.PerspectiveCamera
|
||||
// const fov = c.fov * (Math.PI / 180)
|
||||
// const distance = Math.abs(Math.max(size.x, size.y) / Math.sin(fov / 2))
|
||||
// c.position.setZ(distance)
|
||||
// }, [size, camera])
|
||||
return (
|
||||
<primitive
|
||||
object={scene}
|
||||
{...props}
|
||||
position={[0, (size.y / -10) * 3, 0]}
|
||||
// position={[0, (10 / -10) * 3, 0]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function Rotate(props) {
|
||||
const ref = useRef<any>()
|
||||
useFrame((state) => (ref.current.rotation.y = state.clock.elapsedTime * 0.1))
|
||||
type RotateProps = PropsWithChildren<{
|
||||
initialZ?: number
|
||||
rotateSpeed?: number
|
||||
enableZoom?: boolean
|
||||
enableRotateOnScroll?: boolean
|
||||
}>
|
||||
|
||||
return <group ref={ref} {...props} scale={1.4} />
|
||||
function Movements({
|
||||
initialZ,
|
||||
rotateSpeed = ROTATE_SPEED,
|
||||
enableZoom = true,
|
||||
enableRotateOnScroll = true,
|
||||
...props
|
||||
}: RotateProps) {
|
||||
const ref = useRef<any>()
|
||||
const scrollY = useScrollY()
|
||||
|
||||
useFrame((state, delta) => {
|
||||
// const f = mapFloat(scrollY, 0, 1000, 1, 2);
|
||||
// ref.current.rotation.x += delta * (ROTATE_SPEED);
|
||||
// ref.current.rotation.y += delta * (ROTATE_SPEED);
|
||||
const speed = enableRotateOnScroll
|
||||
? calcRotateSpeed(scrollY, rotateSpeed)
|
||||
: rotateSpeed
|
||||
ref.current.rotation.y += delta * speed
|
||||
})
|
||||
|
||||
return (
|
||||
<group
|
||||
ref={ref}
|
||||
{...props}
|
||||
scale={enableZoom ? calcZoom(scrollY, initialZ) : initialZ}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function useAsciiEffect({
|
||||
renderIndex = 1,
|
||||
bgColor = 'black',
|
||||
fgColor = 'white',
|
||||
// characters = ' .:-+*=%@#',
|
||||
characters = ' l.o.g.o.s',
|
||||
invert = false,
|
||||
color = false,
|
||||
resolution = 0.2,
|
||||
}) {
|
||||
type AsciiConfigs = {
|
||||
characters?: string
|
||||
invert?: boolean
|
||||
color?: boolean
|
||||
bgColor?: string
|
||||
fgColor?: string
|
||||
resolution?: number
|
||||
renderIndex?: number
|
||||
}
|
||||
|
||||
const defaultAsciiConfigs = {
|
||||
renderIndex: 1,
|
||||
bgColor: 'rgb(var(--lsd-surface-primary))',
|
||||
fgColor: 'rgb(var(--lsd-text-primary))',
|
||||
characters: ' l.o.g.o.s',
|
||||
invert: false,
|
||||
color: false,
|
||||
resolution: 0.2,
|
||||
}
|
||||
|
||||
type AsciiEffectProps = {
|
||||
config?: AsciiConfigs
|
||||
initialZ?: number
|
||||
}
|
||||
|
||||
function useAsciiEffect({ config = {}, initialZ }: AsciiEffectProps) {
|
||||
const {
|
||||
renderIndex = defaultAsciiConfigs.renderIndex,
|
||||
characters = defaultAsciiConfigs.characters,
|
||||
invert = defaultAsciiConfigs.invert,
|
||||
color = defaultAsciiConfigs.color,
|
||||
resolution = defaultAsciiConfigs.resolution,
|
||||
bgColor = defaultAsciiConfigs.bgColor,
|
||||
fgColor = defaultAsciiConfigs.fgColor,
|
||||
} = config
|
||||
|
||||
// Reactive state
|
||||
const { size, gl, scene, camera, viewport } = useThree()
|
||||
const { gl, size, scene, camera, viewport } = useThree()
|
||||
|
||||
const effect = useMemo(() => {
|
||||
const effect = new AsciiEffect(gl, characters, {
|
||||
@@ -72,10 +160,9 @@ function useAsciiEffect({
|
||||
return effect
|
||||
}, [characters, invert, color, resolution])
|
||||
|
||||
// Styling
|
||||
useLayoutEffect(() => {
|
||||
effect.domElement.style.color = fgColor
|
||||
effect.domElement.style.backgroundColor = bgColor
|
||||
// effect.domElement.style.backgroundColor = bgColor
|
||||
}, [fgColor, bgColor])
|
||||
|
||||
// Append on mount, remove on unmount
|
||||
@@ -90,9 +177,6 @@ function useAsciiEffect({
|
||||
|
||||
// Set size
|
||||
useEffect(() => {
|
||||
camera.position.setX(2)
|
||||
camera.position.setY(2)
|
||||
|
||||
effect.setSize(size.width, size.height)
|
||||
}, [effect, size])
|
||||
|
||||
@@ -102,15 +186,8 @@ function useAsciiEffect({
|
||||
}, renderIndex)
|
||||
}
|
||||
|
||||
const AsciiRenderer = ({
|
||||
fgColor,
|
||||
bgColor,
|
||||
}: {
|
||||
fgColor: string
|
||||
bgColor: string
|
||||
}) => {
|
||||
useAsciiEffect({ fgColor, bgColor })
|
||||
|
||||
const AsciiRenderer = (props: AsciiEffectProps) => {
|
||||
useAsciiEffect(props)
|
||||
return <></>
|
||||
}
|
||||
|
||||
@@ -118,6 +195,14 @@ export type HeroModelProps = React.HTMLAttributes<HTMLDivElement> & {
|
||||
modelUrl: string
|
||||
layout?: 'floating' | 'cropped'
|
||||
renderer?: '3d' | 'ascii'
|
||||
asciiConfig?: AsciiConfigs
|
||||
initialZ?: number
|
||||
initialX?: number
|
||||
initialY?: number
|
||||
rotateSpeed?: number
|
||||
enableZoom?: boolean
|
||||
enableRotateOnScroll?: boolean
|
||||
withParallelEffect?: boolean
|
||||
}
|
||||
|
||||
export const HeroModel: React.FC<HeroModelProps> = ({
|
||||
@@ -126,8 +211,30 @@ export const HeroModel: React.FC<HeroModelProps> = ({
|
||||
modelUrl,
|
||||
className,
|
||||
children,
|
||||
asciiConfig,
|
||||
initialX,
|
||||
initialY,
|
||||
initialZ,
|
||||
rotateSpeed = ROTATE_SPEED,
|
||||
enableZoom,
|
||||
enableRotateOnScroll,
|
||||
withParallelEffect,
|
||||
...props
|
||||
}) => {
|
||||
const scrollY = useScrollY()
|
||||
|
||||
const initialPosition = useMemo(() => {
|
||||
if (typeof window === 'undefined') return new THREE.Vector3(0, 0, 0)
|
||||
if (renderer === 'ascii') {
|
||||
return new THREE.Vector3(
|
||||
initialX || random(MIN_X, MAX_X),
|
||||
initialY || random(MIN_Y, MAX_Y),
|
||||
0,
|
||||
)
|
||||
}
|
||||
// if not ascii then use the max z
|
||||
return new THREE.Vector3(3.1, initialY || random(MIN_Y, MAX_Y), 0)
|
||||
}, [initialX, initialY, initialZ, renderer])
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
@@ -138,32 +245,53 @@ export const HeroModel: React.FC<HeroModelProps> = ({
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className={`mdx-hero-model--inner`}
|
||||
style={{
|
||||
// a nice parallax effect based on scroll position
|
||||
...(withParallelEffect
|
||||
? { transform: `translateY(${scrollY * 0.1}px)` }
|
||||
: {}),
|
||||
}}
|
||||
>
|
||||
<Canvas
|
||||
dpr={[1, 2]}
|
||||
camera={{
|
||||
fov: 50,
|
||||
position: initialPosition,
|
||||
}}
|
||||
>
|
||||
<directionalLight position={[10, 10, 0]} intensity={1.5} />
|
||||
<directionalLight position={[-10, 10, 5]} intensity={1} />
|
||||
<directionalLight position={[-10, 10, 0]} intensity={1.5} />
|
||||
<directionalLight position={[-10, 10, 5]} intensity={0.3} />
|
||||
<directionalLight position={[-10, 20, 0]} intensity={1.5} />
|
||||
<directionalLight position={[100, -10, 0]} intensity={0.25} />
|
||||
<Suspense fallback={<></>}>
|
||||
<Rotate>
|
||||
<Movements
|
||||
initialZ={initialZ}
|
||||
enableZoom={enableZoom}
|
||||
enableRotateOnScroll={enableRotateOnScroll}
|
||||
>
|
||||
<Model url={modelUrl} />
|
||||
</Rotate>
|
||||
</Movements>
|
||||
</Suspense>
|
||||
<OrbitControls />
|
||||
{!isTouchDevice() && <OrbitControls enableZoom={false} />}
|
||||
{renderer === 'ascii' && (
|
||||
<AsciiRenderer
|
||||
fgColor="rgb(var(--lsd-text-primary))"
|
||||
bgColor="rgb(var(--lsd-surface-primary))"
|
||||
/>
|
||||
<AsciiRenderer config={asciiConfig} initialZ={initialZ} />
|
||||
)}
|
||||
</Canvas>
|
||||
</div>
|
||||
<div></div>
|
||||
<div
|
||||
className={'mdx-hero-model--shade'}
|
||||
style={{
|
||||
opacity: mapFloat(
|
||||
scrollY,
|
||||
0,
|
||||
calcScrollThreshold() * RESIZE_SPEED_FACTOR,
|
||||
0,
|
||||
1,
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,3 +7,4 @@ export * from './HeroDescription'
|
||||
export * from './HeroModel'
|
||||
export * from './HeroTitle'
|
||||
export * from './Showcase'
|
||||
export * from './HeroInfo'
|
||||
|
||||
@@ -298,6 +298,11 @@ a code {
|
||||
|
||||
--ifm-navbar-item-padding-vertical: 8px;
|
||||
--ifm-navbar-item-padding-horizontal: 12px;
|
||||
|
||||
--logos-navbar-height: 64px;
|
||||
--logos-hero-info-height: 420px;
|
||||
--logos-hero-info-padding-top: 32px;
|
||||
--logos-hero-info-padding-bottom: 32px;
|
||||
}
|
||||
|
||||
.card,
|
||||
@@ -314,18 +319,23 @@ a code {
|
||||
.sub1 {
|
||||
font-size: var(--ifm-h1-font-size);
|
||||
}
|
||||
|
||||
.sub2 {
|
||||
font-size: var(--ifm-h2-font-size);
|
||||
}
|
||||
|
||||
.sub3 {
|
||||
font-size: var(--ifm-h3-font-size);
|
||||
}
|
||||
|
||||
.sub4 {
|
||||
font-size: var(--ifm-h4-font-size);
|
||||
}
|
||||
|
||||
.sub5 {
|
||||
font-size: var(--ifm-h5-font-size);
|
||||
}
|
||||
|
||||
.sub6 {
|
||||
font-size: var(--ifm-h6-font-size);
|
||||
}
|
||||
@@ -841,6 +851,10 @@ small {
|
||||
}
|
||||
}
|
||||
|
||||
.main-wrapper > div {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.navbar__left-items {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
export const random = (min, max) => {
|
||||
return Math.random() * (max - min) + min
|
||||
}
|
||||
|
||||
export const mapFloat = (value, inMin, inMax, outMin, outMax) => {
|
||||
return ((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin
|
||||
}
|
||||
|
||||
export const calcScrollThreshold = () => {
|
||||
return window.innerHeight * 0.4
|
||||
}
|
||||
|
||||
export const isTouchDevice = () => {
|
||||
if (typeof window === 'undefined') return false
|
||||
return (
|
||||
'ontouchstart' in window ||
|
||||
navigator.maxTouchPoints > 0 ||
|
||||
// @ts-ignore
|
||||
(navigator.msMaxTouchPoints && navigator.msMaxTouchPoints > 0)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { useWindowEventListener } from './useWindowEventListener'
|
||||
import { useState } from 'react'
|
||||
|
||||
export const useScrollY = () => {
|
||||
const [scrollY, setScrollY] = useState(0)
|
||||
useWindowEventListener('scroll', () => {
|
||||
setScrollY(window.scrollY)
|
||||
})
|
||||
return scrollY
|
||||
}
|
||||
Reference in New Issue
Block a user