Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions app/Canvas.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
'use client'

import { useCanvasApi } from './canvas-state'
import CausticOverlay from '@/components/scenes/caustic/CausticOverlay'
import CausticScene from '@/components/scenes/caustic/CausticScene'
import FlowShieldControls from '@/components/scenes/flow-shield/FlowShieldControls'
import FlowShieldOverlay from '@/components/scenes/flow-shield/FlowShieldOverlay'
import FlowShieldScene from '@/components/scenes/flow-shield/FlowShieldScene'
import { useSpring } from '@react-spring/web'
import { PerformanceMonitor } from '@react-three/drei'
import { Canvas, invalidate, useThree } from '@react-three/fiber'
import { usePathname } from 'next/navigation'
import { memo, useEffect, useRef, useState } from 'react'
import { useEffect, useRef, useState } from 'react'
import * as THREE from 'three'

THREE.Texture.DEFAULT_ANISOTROPY = 8

const Scene = memo(CausticScene)
const Scene = FlowShieldScene

export default function PmndrsCanvas() {
const parentRef = useRef<HTMLDivElement>(null!)
Expand Down Expand Up @@ -111,7 +112,8 @@ export default function PmndrsCanvas() {

return (
<>
<CausticOverlay show={showOverlay} />
<FlowShieldControls show={isHome} />
<FlowShieldOverlay show={showOverlay} />
<Canvas
ref={(node) => {
if (!node) return
Expand Down
10 changes: 7 additions & 3 deletions app/tag-data.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
{
"react-three-fiber": 1,
"glsl": 1,
"shaders": 1,
"vfx": 1,
"react": 2,
"global-state": 2,
"valtio": 1,
"zustand": 1,
"pmndrs": 1,
"valtio": 1,
"xr": 1,
"react-three": 1
"react-three": 1,
"pmndrs": 1
}
21 changes: 21 additions & 0 deletions components/scenes/flow-shield/FlowShieldControls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use client'

import { Leva } from 'leva'

export default function FlowShieldControls({ show = true }: { show?: boolean }) {
return (
<div style={{ opacity: show ? 1 : 0, transition: 'opacity 700ms ease-out' }}>
<Leva
collapsed={false}
flat={false}
oneLineLabels={false}
titleBar={{
title: 'CONTROLS',
drag: true,
filter: false,
position: { x: -10, y: 120 },
}}
/>
</div>
)
}
63 changes: 63 additions & 0 deletions components/scenes/flow-shield/FlowShieldOverlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use client'

import Logo from '@/data/logo.svg'
import Link from 'next/link'

export default function FlowShieldOverlay({ show = true }: { show?: boolean }) {
return (
<div className="pointer-events-none fixed inset-0 z-[5]">
<div
className="absolute top-24 left-6 max-w-[34rem] md:top-28 md:left-10"
style={{
opacity: show ? 1 : 0,
transform: `translateY(${show ? 0 : 12}px)`,
transitionProperty: 'opacity, transform',
transitionDuration: show ? '700ms' : '250ms',
transitionTimingFunction: show ? 'cubic-bezier(0.2, 0.9, 0.2, 1)' : 'ease-out',
}}
>
<p className="mb-3 text-[11px] font-medium tracking-[0.28em] text-white/55 uppercase">
New Article
</p>
<h1 className="max-w-[16ch] text-4xl leading-tight font-semibold tracking-tight text-white sm:text-4xl md:text-5xl">
Creating an Interactive Sci-Fi Shield
</h1>
<p className="mt-4 max-w-md text-sm leading-6 text-white/70 md:text-base">
Interactive sci-fi shielding with hit detection, procedural hexes, flowing noise, and
custom shader work in React Three Fiber.
</p>
<p className="mt-3 text-[11px] tracking-[0.15em] text-white/40 uppercase">
by Christian Oritz
</p>
<div className="pointer-events-auto mt-5 flex items-center gap-4">
<Link
href="/blog/creating-flow-shield"
className="rounded-full border border-white/20 bg-white/10 px-4 py-2 text-sm font-medium text-white backdrop-blur-sm transition hover:bg-white/15"
>
Read article
</Link>
</div>
</div>

<div
className="fixed bottom-10 left-6 z-[5] text-[18px] select-none md:bottom-[120px] md:left-10"
style={{
opacity: show ? 1 : 0,
transitionProperty: 'opacity',
transitionDuration: `${show ? 700 : 250}ms`,
transitionTimingFunction: 'ease-out',
transitionDelay: '240ms',
}}
>
<div className="flex items-center">
<Logo className="mr-4 size-8 opacity-70 invert" />
<div className="text-[13px] leading-tight text-white/85">
pmndrs
<br />
dev collective
</div>
</div>
</div>
</div>
)
}
39 changes: 39 additions & 0 deletions components/scenes/flow-shield/FlowShieldScene.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client'

import SceneContent from './src/components/playground/SceneContent'
import { useCanvasApi } from 'app/canvas-state'
import { memo, useEffect } from 'react'
import { useThree } from '@react-three/fiber'
import * as THREE from 'three'

const MODE = 'Background' as const
const PRESET = 'default' as const

export default memo(function FlowShieldScene({
perfSucks: _perfSucks = false,
}: {
perfSucks?: boolean
}) {
const setIsLoaded = useCanvasApi((state) => state.setIsLoaded)

useEffect(() => {
setIsLoaded(true)
}, [setIsLoaded])

return (
<>
<SceneBackground />
<SceneContent showGrid mode={MODE} glbUrl={null} preset={PRESET} />
</>
)
})

function SceneBackground() {
const scene = useThree((state) => state.scene)

useEffect(() => {
scene.background = new THREE.Color('#050816')
}, [scene])

return null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { Preset } from '../../../types'

export const MAX_HITS = 6

export const SHIELD_PRESETS: Record<Preset, Record<string, unknown>> = {
default: {
color: '#26aeff',
opacity: 0.76,
showHex: true,
hexScale: 3.0,
hexOpacity: 0.13,
edgeWidth: 0.06,
fresnelPower: 1.8,
fresnelStrength: 1.75,
flashSpeed: 0.6,
flashIntensity: 0.11,
noiseScale: 1.3,
noiseEdgeColor: '#26aeff',
noiseEdgeWidth: 0.02,
noiseEdgeIntensity: 10.0,
noiseEdgeSmoothness: 0.5,
flowScale: 2.4,
flowSpeed: 1.13,
flowIntensity: 4,
hitRingSpeed: 1.75,
hitRingWidth: 0.12,
hitMaxRadius: 0.85,
fadeStart: -1,
},
droideka: {
hexScale: 3,
hexOpacity: 0.27,
showHex: false,
edgeWidth: 0.2,
fresnelPower: 1.8,
fadeStart: 1,
fresnelStrength: 1.75,
flashSpeed: 0.6,
color: '#5992f7',
noiseEdgeColor: '#7faaf5',
noiseEdgeWidth: 0.1,
noiseEdgeIntensity: 0.6,
noiseEdgeSmoothness: 0.5,
noiseScale: 1,
opacity: 0.29,
flashIntensity: 0.11,
flowScale: 6.2,
flowSpeed: 1.08,
flowIntensity: 4,
hitRingSpeed: 0.8,
hitRingWidth: 0.12,
hitMaxRadius: 2.1,
},
}
Loading