Skip to content

Commit 768d1f6

Browse files
committed
merged in cyberspace-viewer files
1 parent b48824e commit 768d1f6

File tree

11 files changed

+3453
-2
lines changed

11 files changed

+3453
-2
lines changed

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
"test": "yarn ts-node ./src/libraries/Hash.test.ts"
1616
},
1717
"dependencies": {
18+
"@react-three/drei": "^9.77.0",
1819
"@react-three/fiber": "^8.13.0",
1920
"@types/node": "^20.5.1",
2021
"@types/three": "^0.152.1",
21-
"nostr-tools": "^1.11.1",
22+
"nostr-tools": "^1.12.0",
2223
"react": "^18.2.0",
2324
"react-dom": "^18.2.0",
2425
"react-router-dom": "^6.11.2",
@@ -38,6 +39,7 @@
3839
"sass": "^1.62.1",
3940
"ts-node": "^10.9.1",
4041
"typescript": "^5.0.2",
41-
"vite": "^4.3.9"
42+
"vite": "^4.3.9",
43+
"vitest": "^0.34.3"
4244
}
4345
}

src/components/ConstructViewer.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { useEffect, useState } from 'react'
2+
import { Canvas } from '@react-three/fiber'
3+
import { OrbitControls } from "@react-three/drei"
4+
import { Cyberspace } from './components/ThreeCyberspace'
5+
import { UNIVERSE_DOWNSCALE, UNIVERSE_SIZE, CENTERCOORD } from "./libraries/Cyberspace"
6+
import { Construct } from './components/ThreeConstruct'
7+
import './App.css'
8+
import { BigCoords, decodeHexToCoordinates, downscaleCoords } from './libraries/Constructs'
9+
import * as THREE from 'three'
10+
11+
export type ConstructViewerProps = {
12+
constructSize?: number,
13+
hexLocation?: string, // 64 character hex string
14+
style?: React.CSSProperties,
15+
}
16+
17+
const ConstructViewer = ({constructSize = 1, hexLocation = CENTERCOORD, style = {height: "100vh"}}: ConstructViewerProps) => {
18+
19+
const [scale] = useState(UNIVERSE_SIZE)
20+
const [size, setSize] = useState(constructSize)
21+
const [coord, setCoord] = useState<BigCoords>(decodeHexToCoordinates(hexLocation))
22+
23+
useEffect(() => {
24+
const urlParams = new URLSearchParams(window.location.search)
25+
const coordParam = urlParams.get('coord') || CENTERCOORD
26+
setCoord(decodeHexToCoordinates(coordParam))
27+
const sizeParam = urlParams.get('constructSize') || ""
28+
setSize(parseInt(sizeParam) || 1)
29+
}, [])
30+
31+
const downscaled = downscaleCoords(coord, UNIVERSE_DOWNSCALE)
32+
const orbitTarget = new THREE.Vector3(downscaled.x, downscaled.y, downscaled.z)
33+
34+
return (
35+
<div className="cyberspace-viewer">
36+
<Canvas style={style} camera={{
37+
near: 0.001,
38+
far: scale*2*2*2*2*2*2*2*2,
39+
position: [0, 0, scale]
40+
}}>
41+
<ambientLight intensity={0.8} />
42+
<Cyberspace targetCoord={coord} targetSize={size}>
43+
<Construct coord={coord} size={size}/>
44+
</Cyberspace>
45+
<OrbitControls target={orbitTarget} zoomSpeed={5}/>
46+
</Canvas>
47+
</div>
48+
)
49+
}
50+
51+
export default ConstructViewer

src/components/ThreeConstruct.tsx

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React, { useMemo, useRef } from "react"
2+
import * as THREE from "three"
3+
import { Line } from "three"
4+
import { InverseConstructLineData, getCubeWireframeVertices } from "../data/ConstructLineData.js"
5+
import { Operator } from "./ThreeOperator"
6+
import { BigCoords, downscaleCoords } from "../libraries/Constructs.js"
7+
import { UNIVERSE_DOWNSCALE } from "../libraries/Cyberspace.js"
8+
9+
const LOGO_TEAL = 0x06a4a4
10+
const LOGO_PURPLE = 0x78004e
11+
// const LOGO_BLUE = 0x0062cd
12+
13+
const TealLineMaterial = new THREE.LineBasicMaterial({
14+
color: LOGO_TEAL,
15+
})
16+
const PurpleLineMaterial = new THREE.LineBasicMaterial({
17+
color: LOGO_PURPLE,
18+
})
19+
20+
// const BlueLineMaterial = new THREE.LineBasicMaterial({
21+
// color: LOGO_BLUE,
22+
// })
23+
24+
export const Construct: React.FC<{ coord: BigCoords, size?: number }> = ({ coord, size = 1 }) => {
25+
const groupRef = useRef<THREE.Group>(null)
26+
27+
const downscaledCoord = downscaleCoords(coord, UNIVERSE_DOWNSCALE)
28+
29+
let count = 0
30+
31+
// Compute the lines and grids only once
32+
const { lines, cube } = useMemo(() => {
33+
const lines = InverseConstructLineData.map(([start, end]) => {
34+
const points = [new THREE.Vector3(...start), new THREE.Vector3(...end)]
35+
const geometry = new THREE.BufferGeometry().setFromPoints(points)
36+
return (
37+
<primitive
38+
key={"line"+JSON.stringify({ start, end })}
39+
object={new Line(geometry, TealLineMaterial)}
40+
/>
41+
)
42+
})
43+
44+
const cube = getCubeWireframeVertices(1).map(([start, end]) => {
45+
const points = [new THREE.Vector3(...start), new THREE.Vector3(...end)]
46+
const geometry = new THREE.BufferGeometry().setFromPoints(points)
47+
count++
48+
return (
49+
<primitive
50+
key={`cube${count}`}
51+
object={new Line(geometry, PurpleLineMaterial)}
52+
/>
53+
)
54+
})
55+
56+
return { lines, cube }
57+
}, [])
58+
59+
return (
60+
<group scale={[size, size, size]} ref={groupRef} position={[downscaledCoord.x, downscaledCoord.y, downscaledCoord.z]} renderOrder={2}>
61+
{lines}
62+
{cube}
63+
</group>
64+
)
65+
}

src/components/ThreeCyberspace.tsx

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import React, { useMemo, useRef, useState, useEffect } from "react"
2+
import { useThree, useFrame } from "@react-three/fiber"
3+
import * as THREE from "three"
4+
import { BigCoords, downscaleCoords } from "../libraries/Constructs.js"
5+
import { UNIVERSE_SIZE_HALF, UNIVERSE_DOWNSCALE, UNIVERSE_SIZE } from "../libraries/Cyberspace.js"
6+
import { invert } from "three/examples/jsm/nodes/Nodes.js"
7+
8+
const INTERACTION_RESET_DELAY = 5_000
9+
10+
// const LOGO_TEAL = 0x06a4a4
11+
const LOGO_PURPLE = 0x78004e
12+
const LOGO_BLUE = 0x0062cd
13+
14+
// const TealLineMaterial = new THREE.LineBasicMaterial({
15+
// color: LOGO_TEAL,
16+
// })
17+
const PurpleLineMaterial = new THREE.LineBasicMaterial({
18+
color: LOGO_PURPLE,
19+
})
20+
21+
const BlueLineMaterial = new THREE.LineBasicMaterial({
22+
color: LOGO_BLUE,
23+
})
24+
25+
const SunMaterial = new THREE.MeshBasicMaterial({
26+
color: 0x2b0c40,
27+
side: THREE.DoubleSide,
28+
})
29+
30+
interface CyberspaceProps {
31+
targetSize: number, // size of construct to determine camera orbit radius
32+
targetCoord: BigCoords, // for camera orbit
33+
children: React.ReactNode,
34+
}
35+
36+
const centerVec = new THREE.Vector3(UNIVERSE_SIZE_HALF, UNIVERSE_SIZE_HALF, UNIVERSE_SIZE_HALF) // The center of cyberspace
37+
38+
export const Cyberspace: React.FC<CyberspaceProps> = ({ targetSize, targetCoord, children }) => {
39+
const groupRef = useRef<THREE.Group>(null)
40+
const [interactionActive, setInteractionActive] = useState(false)
41+
const [defaultView, setDefaultView] = useState(true)
42+
const defaultViewTimeoutRef = useRef<NodeJS.Timeout|undefined>(undefined)
43+
const [elapsedTime, setElapsedTime] = useState(0)
44+
const [lerpAlpha, setLerpAlpha] = useState(1)
45+
const { camera } = useThree()
46+
47+
const targetPosition = centerVec
48+
const downscaledTargetCoord = downscaleCoords(targetCoord, UNIVERSE_DOWNSCALE)
49+
// const radius = targetSize * 10 // The radius of the circular path the camera will follow
50+
51+
const minSize = 1
52+
const maxSize = 2**50/256/256
53+
54+
// const ratio = ( targetSize + (maxSize * 0.1)) / maxSize
55+
const ratio = targetSize / maxSize
56+
57+
// const radius = 100 * Math.pow(targetSize, ratio) + targetSize
58+
// const radius = 100 + targetSize * (1 + ratio)
59+
const invertRatioLimit = Math.max(1-ratio, minSize/maxSize)
60+
61+
const radius = Math.max(100, targetSize + targetSize * invertRatioLimit)
62+
63+
// Attach pointerdown and pointerup event listeners
64+
useEffect(() => {
65+
const handleInteractionStart = () => {
66+
setLerpAlpha(0.05) // permanent
67+
clearTimeout(defaultViewTimeoutRef.current)
68+
setInteractionActive(true)
69+
setDefaultView(false)
70+
}
71+
const handleInteractionEnd = () => {
72+
setInteractionActive(false)
73+
defaultViewTimeoutRef.current = setTimeout(() => {
74+
// LERP camera back to default orbit
75+
setDefaultView(true)
76+
}, INTERACTION_RESET_DELAY)
77+
}
78+
79+
window.addEventListener('pointerdown', handleInteractionStart)
80+
window.addEventListener('pointerup', handleInteractionEnd)
81+
window.addEventListener('wheel', handleInteractionStart)
82+
83+
// Cleanup event listeners on unmount
84+
return () => {
85+
window.removeEventListener('pointerdown', handleInteractionStart)
86+
window.removeEventListener('pointerup', handleInteractionEnd)
87+
window.addEventListener('wheel', handleInteractionStart)
88+
}
89+
}, [])
90+
91+
// Compute the lines and grids only once
92+
const { grids, blacksun } = useMemo(() => {
93+
const grids = [
94+
<gridHelper
95+
key="y+"
96+
args={[UNIVERSE_SIZE, 32]}
97+
position={[UNIVERSE_SIZE_HALF, UNIVERSE_SIZE, UNIVERSE_SIZE_HALF]}
98+
material={BlueLineMaterial}
99+
renderOrder={1}
100+
/>,
101+
<gridHelper
102+
key="y-"
103+
args={[UNIVERSE_SIZE, 32]}
104+
position={[UNIVERSE_SIZE_HALF, 0, UNIVERSE_SIZE_HALF]}
105+
material={PurpleLineMaterial}
106+
renderOrder={1}
107+
/>,
108+
]
109+
110+
const blacksun = (
111+
<mesh geometry={new THREE.CircleGeometry(UNIVERSE_SIZE_HALF/2, 64)} material={SunMaterial} position={[UNIVERSE_SIZE_HALF,UNIVERSE_SIZE_HALF,-UNIVERSE_SIZE_HALF]} renderOrder={-1}/>
112+
)
113+
114+
return { grids, blacksun }
115+
}, [])
116+
117+
useFrame(({ clock }) => {
118+
if (defaultView) {
119+
if (!clock.running) clock.start()
120+
const angle = (clock.elapsedTime + elapsedTime) * 0.2 // Controls the speed of rotation
121+
targetPosition.set(
122+
downscaledTargetCoord.x + radius * Math.sin(angle),
123+
downscaledTargetCoord.y + radius/5,
124+
downscaledTargetCoord.z + radius * Math.cos(angle)
125+
)
126+
camera.position.lerp(targetPosition, lerpAlpha)
127+
} else {
128+
if (clock.running) {
129+
setElapsedTime(clock.elapsedTime + elapsedTime)
130+
clock.stop()
131+
}
132+
}
133+
})
134+
135+
// if (groupRef.current) {
136+
// groupRef.current.scale.set(scale, scale, scale)
137+
// }
138+
139+
return (
140+
<group ref={groupRef}>
141+
{blacksun}
142+
{grids}
143+
{children}
144+
</group>
145+
)
146+
}

src/components/ThreeOperator.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from "react"
2+
import * as THREE from "three"
3+
4+
const OperatorMaterial = new THREE.MeshStandardMaterial({
5+
color: 0xff2323,
6+
metalness: 0.8,
7+
roughness: 0.4,
8+
emissive: 0xff2323,
9+
emissiveIntensity: 0.2,
10+
})
11+
12+
const OperatorGeometry = new THREE.IcosahedronGeometry(.5,1)
13+
14+
// Create edges geometry for the golden wireframe
15+
const OperatorGeometryEdges = new THREE.EdgesGeometry(OperatorGeometry)
16+
const OperatorMaterialEdges = new THREE.LineBasicMaterial({ color: 0xff2323 })
17+
18+
// Add the wireframe to your scene
19+
20+
export const Operator: React.FC<{ position?: number[]}> = ({position = [0,0,0]}) => {
21+
return (
22+
<group position={new THREE.Vector3(...position)}>
23+
<lineSegments scale={[1,1,1]} geometry={OperatorGeometryEdges} material={OperatorMaterialEdges} />
24+
<mesh geometry={OperatorGeometry} material={OperatorMaterial} />
25+
</group>
26+
)
27+
}

0 commit comments

Comments
 (0)