spacesvr-websessions
Version:
A standardized reality for future of the 3D Web
1,752 lines (1,547 loc) • 256 kB
JavaScript
import React from "react";
import _extends from '@babel/runtime/helpers/esm/extends';
import React$1, { useRef, useMemo, useEffect, useLayoutEffect, useState, Suspense, useCallback, createContext, useContext, Children, cloneElement, forwardRef } from 'react';
import { useFrame, useThree, createPortal, extend } from '@react-three/fiber';
import { Color, MeshStandardMaterial, DoubleSide, Uniform, Vector3, Vector2, Quaternion, Euler, Fog as Fog$1, AudioListener, PositionalAudio, AudioAnalyser, CanvasTexture, TextureLoader, BoxBufferGeometry, MeshBasicMaterial, AudioContext, NoToneMapping, MathUtils, Raycaster, Box3, sRGBEncoding, MeshLambertMaterial, Matrix4, BufferGeometry, Float32BufferAttribute, Scene, Light, AmbientLight, WebGLCubeRenderTarget, CubeCamera, WebGLRenderTarget, UnsignedByteType, RGBAFormat, Object3D, SphereBufferGeometry, CylinderBufferGeometry, MeshNormalMaterial, NearestFilter, WebGLRenderer } from 'three';
import { useSpring, config, animated, a } from '@react-spring/three';
import * as culori from 'culori';
import { Environment as Environment$1, useGLTF, useProgress, Text as Text$2, Html, PerspectiveCamera } from '@react-three/drei';
import { usePlane, useTrimesh, useCompoundBody, Physics as Physics$1 } from '@react-three/cannon';
import { WebGLExtensions } from 'three/src/renderers/webgl/WebGLExtensions';
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader';
import { suspend, preload, clear } from 'suspend-react';
import { mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils';
import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from 'three-mesh-bvh';
import { css, Global, keyframes } from '@emotion/react';
import nipplejs from 'nipplejs';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { isMobile } from 'react-device-detect';
import { XRCanvas, useXR, DefaultXRControllers, useController, Interactive } from '@react-three/xr';
import { DeviceOrientationControls, SkeletonUtils, mergeVertices, EffectComposer, RenderPass, ShaderPass } from 'three-stdlib';
import { ErrorBoundary } from 'react-error-boundary';
import { RoundedBoxGeometry } from 'three/examples/jsm/geometries/RoundedBoxGeometry';
import { getCaretAtPoint, Text as Text$3 } from 'troika-three-text';
import { SnapshotInterpolation } from '@geckos.io/snapshot-interpolation';
import { Peer } from 'peerjs';
import nodeFetch from 'node-fetch';
import { useTransition } from '@react-spring/core';
import { createPortal as createPortal$1 } from 'react-dom';
const vertHead$3 = `
// Description : Array and textureless GLSL 2D/3D/4D simplex
// noise functions.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : ijm
// Lastmod : 20110822 (ijm)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
//
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x*34.0)+1.0)*x);
}
vec4 taylorInvSqrt(vec4 r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec3 v)
{
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy) );
vec3 x0 = v - i + dot(i, C.xxx) ;
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
i = mod289(i);
vec4 p = permute( permute( permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
float n_ = 0.142857142857; // 1.0/7.0
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
vec3 p0 = vec3(a0.xy,h.x);
vec3 p1 = vec3(a0.zw,h.y);
vec3 p2 = vec3(a1.xy,h.z);
vec3 p3 = vec3(a1.zw,h.w);
//Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
dot(p2,x2), dot(p3,x3) ) );
}
float fsnoise(float val1, float val2, float val3){
return snoise(vec3(val1,val2,val3));
}
vec3 distortFunct(vec3 transformed, float factor) {
float radiusVariation = -fsnoise(
transformed.x * radiusNoiseFrequency + time,
transformed.y * radiusNoiseFrequency + time,
transformed.z * radiusNoiseFrequency + time
) * radiusVariationAmplitude * factor;
return normalize(transformed) * (radiusVariation + radius);
}
vec3 orthogonal(vec3 v) {
return normalize(abs(v.x) > abs(v.z) ? vec3(-v.y, v.x, 0.0)
: vec3(0.0, -v.z, v.y));
}
vec3 distortNormal(vec3 position, vec3 distortedPosition, vec3 normal){
vec3 tangent1 = orthogonal(normal);
vec3 tangent2 = normalize(cross(normal, tangent1));
vec3 nearby1 = position + tangent1 * 0.1;
vec3 nearby2 = position + tangent2 * 0.1;
vec3 distorted1 = distortFunct(nearby1, 1.0);
vec3 distorted2 = distortFunct(nearby2, 1.0);
return normalize(cross(distorted1 - distortedPosition, distorted2 - distortedPosition));
}
`;
const vert$3 = `
#include <begin_vertex>
float updateTime = time / 10.0;
transformed = distortFunct(transformed, 1.0);
vec3 distortedNormal = distortNormal(position, transformed, normal);
vNormal = normal + distortedNormal;
gl_Position = projectionMatrix * modelViewMatrix * vec4(transformed,1.);
`;
const frag$3 = `
#include <dithering_fragment>
float angle = clamp(dot(normalize(vNormal), vec3(0., -1., 0.)), 0., 1.);
gl_FragColor = vec4(gl_FragColor.rgb * color, gl_FragColor.a);
gl_FragColor.rgb = mix(gl_FragColor.rgb, mix(color, vec3(0.), 0.5), angle);
`;
/**
* Returns a function that, when used every frame, will mark itself
* as ready maximum {frequency} times per second.
*
* @param frequency How many times per second to be marked as ready
*/
const useLimiter = frequency => {
const lastCall = useRef(0);
return {
isReady: clock => {
const time = clock.elapsedTime;
const ready = time - lastCall.current > 1 / frequency;
if (ready) {
lastCall.current = time;
}
return ready;
}
};
};
/**
* A 1:1 copy of useFrame, but adds a limiter
*
* Callback will only run {frequency} times per second
*/
const useLimitedFrame = (frequency, callback, renderPriority) => {
const limiter = useLimiter(frequency);
useFrame((state, delta) => {
if (!limiter.isReady(state.clock)) return;
callback(state, delta);
}, renderPriority);
};
function VisualIdea(props) {
const {
idea,
...rest
} = props;
const hex = useMemo(() => (idea == null ? void 0 : idea.getHex()) || "#808080", [idea]);
const seed = useMemo(() => Math.random(), []);
const color = useMemo(() => new Color(hex), [hex]);
const RADIUS = 4;
const NOISE_AMPLITUDE = 0.82;
const NOISE_FREQ = 0.154;
const {
col
} = useSpring({
col: hex
});
const mat = useMemo(() => {
const material = new MeshStandardMaterial({
metalness: 0.18,
roughness: 0.49,
envMapIntensity: 0.66,
side: DoubleSide
});
material.onBeforeCompile = function (shader) {
shader.uniforms.radius = new Uniform(RADIUS);
shader.uniforms.time = new Uniform(0);
shader.uniforms.color = new Uniform(color);
shader.uniforms.radiusVariationAmplitude = new Uniform(NOISE_AMPLITUDE);
shader.uniforms.radiusNoiseFrequency = new Uniform(NOISE_FREQ);
const uniforms = `
uniform float radius;
uniform float time;
uniform vec3 color;
uniform float radiusVariationAmplitude;
uniform float radiusNoiseFrequency;
`;
shader.vertexShader = uniforms + vertHead$3 + shader.vertexShader.replace("#include <begin_vertex>", vert$3);
shader.fragmentShader = uniforms + shader.fragmentShader.replace("#include <dithering_fragment>", frag$3);
material.userData.shader = shader;
};
return material;
}, [RADIUS, color, NOISE_AMPLITUDE, NOISE_FREQ, frag$3, vert$3]);
const limiter = useLimiter(50);
useFrame(_ref => {
var _mat$userData;
let {
clock
} = _ref;
if (!(mat != null && (_mat$userData = mat.userData) != null && _mat$userData.shader) || !limiter.isReady(clock)) return;
mat.userData.shader.uniforms.time.value = clock.elapsedTime / 6 + seed * 1000;
mat.userData.shader.uniforms.color.value.set(col.get());
});
return /*#__PURE__*/React.createElement("group", _extends({
name: "spacesvr-basis-idea"
}, rest), /*#__PURE__*/React.createElement("mesh", {
material: mat,
scale: 0.2
}, /*#__PURE__*/React.createElement("sphereBufferGeometry", {
args: [RADIUS, 48, 32]
})));
}
const rgb_helper = `
vec3 rgb2hsv(vec3 c)
{
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c)
{
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
`;
const noise4D = `
vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
float permute(float x){return floor(mod(((x*34.0)+1.0)*x, 289.0));}
vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
float taylorInvSqrt(float r){return 1.79284291400159 - 0.85373472095314 * r;}
vec4 grad4(float j, vec4 ip){
const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);
vec4 p,s;
p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;
p.w = 1.5 - dot(abs(p.xyz), ones.xyz);
s = vec4(lessThan(p, vec4(0.0)));
p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www;
return p;
}
float snoise(vec4 v){
const vec2 C = vec2( 0.138196601125010504, // (5 - sqrt(5))/20 G4
0.309016994374947451); // (sqrt(5) - 1)/4 F4
// First corner
vec4 i = floor(v + dot(v, C.yyyy) );
vec4 x0 = v - i + dot(i, C.xxxx);
// Other corners
// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)
vec4 i0;
vec3 isX = step( x0.yzw, x0.xxx );
vec3 isYZ = step( x0.zww, x0.yyz );
// i0.x = dot( isX, vec3( 1.0 ) );
i0.x = isX.x + isX.y + isX.z;
i0.yzw = 1.0 - isX;
// i0.y += dot( isYZ.xy, vec2( 1.0 ) );
i0.y += isYZ.x + isYZ.y;
i0.zw += 1.0 - isYZ.xy;
i0.z += isYZ.z;
i0.w += 1.0 - isYZ.z;
// i0 now contains the unique values 0,1,2,3 in each channel
vec4 i3 = clamp( i0, 0.0, 1.0 );
vec4 i2 = clamp( i0-1.0, 0.0, 1.0 );
vec4 i1 = clamp( i0-2.0, 0.0, 1.0 );
// x0 = x0 - 0.0 + 0.0 * C
vec4 x1 = x0 - i1 + 1.0 * C.xxxx;
vec4 x2 = x0 - i2 + 2.0 * C.xxxx;
vec4 x3 = x0 - i3 + 3.0 * C.xxxx;
vec4 x4 = x0 - 1.0 + 4.0 * C.xxxx;
// Permutations
i = mod(i, 289.0);
float j0 = permute( permute( permute( permute(i.w) + i.z) + i.y) + i.x);
vec4 j1 = permute( permute( permute( permute (
i.w + vec4(i1.w, i2.w, i3.w, 1.0 ))
+ i.z + vec4(i1.z, i2.z, i3.z, 1.0 ))
+ i.y + vec4(i1.y, i2.y, i3.y, 1.0 ))
+ i.x + vec4(i1.x, i2.x, i3.x, 1.0 ));
// Gradients
// ( 7*7*6 points uniformly over a cube, mapped onto a 4-octahedron.)
// 7*7*6 = 294, which is close to the ring size 17*17 = 289.
vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ;
vec4 p0 = grad4(j0, ip);
vec4 p1 = grad4(j1.x, ip);
vec4 p2 = grad4(j1.y, ip);
vec4 p3 = grad4(j1.z, ip);
vec4 p4 = grad4(j1.w, ip);
// Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
p4 *= taylorInvSqrt(dot(p4,p4));
// Mix contributions from the five corners
vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0);
vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4) ), 0.0);
m0 = m0 * m0;
m1 = m1 * m1;
float final = 49.0 * ( dot(m0*m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 )))
+ dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ;
return (final + 1.) / 2.;
}
`;
const oklab$1 = `
float fixedpow(float a, float x)
{
return pow(abs(a), x) * sign(a);
}
float cbrt(float a)
{
return fixedpow(a, 0.3333333333);
}
vec3 lsrgb2oklab(vec3 c)
{
float l = 0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929 * c.b;
float m = 0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566 * c.b;
float s = 0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005 * c.b;
float l_ = cbrt(l);
float m_ = cbrt(m);
float s_ = cbrt(s);
return vec3(
0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,
1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,
0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_
);
}
vec3 oklab2lsrgb(vec3 c)
{
float l_ = c.r + 0.3963377774 * c.g + 0.2158037573 * c.b;
float m_ = c.r - 0.1055613458 * c.g - 0.0638541728 * c.b;
float s_ = c.r - 0.0894841775 * c.g - 1.2914855480 * c.b;
float l = l_ * l_ * l_;
float m = m_ * m_ * m_;
float s = s_ * s_ * s_;
return vec3(
4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
-0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
);
}
`;
const vertHead$2 = `
precision highp float;
varying vec2 vUv;
varying float terrain;
varying float terrain_perc;
varying vec3 vfNormal;
uniform float radius;
uniform float time;
uniform vec3 color;
${noise4D}
`;
const vert$2 = `
vec3 pos = position;
terrain = 0.;
float u_time = time * 0.25;
terrain += 1. * pow(snoise(vec4(pos.xyz * 0.15, u_time + 100.)), 1.);
terrain += 0.8 * pow(snoise(vec4(pos.xyz * 0.2, u_time + 200.)), 1.5);
terrain += 0.4 * pow(snoise(vec4(pos.xyz * 0.8, u_time + 300.)), 2.);
terrain += 0.2 * pow(snoise(vec4(pos.xyz * 1.6, u_time + 400.)), 8.);
terrain_perc = terrain / (1. + 0.8 + 0.4 + 0.2);
terrain_perc = terrain_perc;
pos = pos + normal * 2. * 2. * (terrain_perc - 0.5);
vfNormal = normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.);
`;
const fragHead$1 = `
precision highp float;
varying vec2 vUv;
varying vec3 vfNormal;
varying float terrain;
varying float terrain_perc;
uniform float time;
uniform vec3 axiom;
uniform float range;
uniform vec3 up_norm;
${rgb_helper}
${oklab$1}
`;
const frag$2 = `
vec3 hsv_col = rgb2hsv(gl_FragColor.rgb);
// todo: offset vfNormal by up_norm
vec3 oklab_axiom = lsrgb2oklab(axiom);
vec3 oklab_range_idea = lsrgb2oklab(axiom + 0.35 * range * vfNormal);
vec3 col = oklab2lsrgb(mix(oklab_axiom, oklab_range_idea, 1. - terrain_perc));
gl_FragColor.rgb = col * pow(hsv_col.z, 1.3);
gl_FragColor.rgb *= 0.15 + 1.85 * pow((1. - terrain_perc), 1.5);
`;
// @ts-ignore
/**
* an idea is the fundamental substrate of reality.
*/
class Idea {
// identifiers
// mediation
// [0, 1)
// [0, 1]
// [0, 1]
constructor(m, s, u) {
if (m === void 0) {
m = 0;
}
if (s === void 0) {
s = 0;
}
if (u === void 0) {
u = 0.5;
}
this.setFromCreation(m, s, u);
return this;
}
setFromCreation(m, s, u) {
if (m === void 0) {
m = 0;
}
if (s === void 0) {
s = 0;
}
if (u === void 0) {
u = 0.5;
}
this.mediation = m;
this.specificity = s;
this.utility = u;
return this;
}
setFromHex(hex) {
const color = culori.oklch(culori.rgb(hex));
if (!color) {
console.warn("idea :: setFromHex - invalid hex color");
return this;
}
this.mediation = color.h / 360;
this.specificity = color.c / 0.322;
this.utility = color.l;
return this;
}
updateFromText(text) {
const len = text.length;
this.mediation = hashStringToRange$1(text);
this.specificity = (1 - (len == 0 ? 1 : 1 / len)) * 0.5;
return this;
}
setUtility(utility) {
this.utility = utility;
return this;
}
getHex() {
const fixedColor = culori.rgb({
mode: "oklch",
l: this.utility,
c: this.specificity * 0.322,
h: this.mediation * 360
});
return culori.formatHex(fixedColor);
}
getOpposite() {
const newM = this.mediation + 0.5 > 1 ? this.mediation - 0.5 : this.mediation + 0.5;
const newS = this.specificity;
const newU = 0.5 - (this.utility - 0.5);
return new Idea().setFromCreation(newM, newS, newU);
}
clone() {
return new Idea(this.mediation, this.specificity, this.utility);
}
}
const AVG_CHAR_VAL$1 = 100; // each char is roughly 100, so loop every ~50 chars
const hashStringToRange$1 = function (str, loop) {
if (loop === void 0) {
loop = 20;
}
let count = 0;
for (let i = 0; i < str.length; i++) {
count += str.substr(i, 1).charCodeAt(0);
}
const scaledLoop = loop * AVG_CHAR_VAL$1;
return count % scaledLoop / scaledLoop;
};
function VisualWorld(props) {
const {
world,
...rest
} = props;
const RADIUS = 4;
const SEED = useMemo(() => Math.random(), []);
const mat = useMemo(() => {
const material = new MeshStandardMaterial({
metalness: 0.18,
roughness: 0.49,
side: DoubleSide
});
material.onBeforeCompile = function (shader) {
const uniforms = {
time: new Uniform(0),
axiom: new Uniform(new Color("#888888")),
up_norm: new Uniform(new Vector3(0, 1, 0)),
range: new Uniform(0)
};
shader.uniforms = { ...shader.uniforms,
...uniforms
};
shader.vertexShader = vertHead$2 + shader.vertexShader.replace("#include <worldpos_vertex>", "#include <worldpos_vertex>\n" + vert$2);
shader.fragmentShader = fragHead$1 + shader.fragmentShader.replace("#include <dithering_fragment>", "#include <dithering_fragment>\n" + frag$2);
material.userData.shader = shader;
};
material.needsUpdate = true;
return material;
}, []);
useEffect(() => {
if (!mat || !mat.userData.shader || !world) return;
const unifs = mat.userData.shader.uniforms;
const axiom = world ? world.getAxiom() : new Idea();
unifs.axiom.value.set(new Color(axiom.getHex()));
unifs.up_norm.value = world == null ? void 0 : world.getUpNorm();
unifs.range.value = world == null ? void 0 : world.getRange();
}, [world, mat]);
useLimitedFrame(50, _ref => {
let {
clock
} = _ref;
if (!mat || !mat.userData.shader) return;
mat.userData.shader.uniforms.time.value = clock.elapsedTime + SEED * 500;
});
return /*#__PURE__*/React.createElement("group", _extends({
name: "spacesvr-basis-world"
}, rest), /*#__PURE__*/React.createElement("mesh", {
material: mat,
scale: 0.2
}, /*#__PURE__*/React.createElement("sphereBufferGeometry", {
args: [RADIUS, 48, 32]
})));
}
const DOWN_AXIS = new Vector3(0, -1, 0);
/**
* Will smoothly rotate its children to face the camera along the Y axis, regardless of the parent's rotation.
*/
function LookAtPlayer(props) {
const {
enabled = true,
children
} = props;
const group = useRef(null);
const flatDelta = useMemo(() => new Vector2(), []);
const worldPos = useMemo(() => new Vector3(), []);
const worldQuat = useMemo(() => new Quaternion(), []);
const targetQuat = useMemo(() => new Quaternion(), []);
const parentQuat = useMemo(() => new Quaternion(), []);
const offsetRot = useMemo(() => new Euler(), []);
useLimitedFrame(50, (_ref, delta) => {
var _group$current$parent;
let {
camera
} = _ref;
if (!group.current) return;
(_group$current$parent = group.current.parent) == null ? void 0 : _group$current$parent.getWorldQuaternion(parentQuat);
offsetRot.setFromQuaternion(parentQuat, "YXZ");
targetQuat.set(0, 0, 0, 1);
if (enabled) {
group.current.getWorldPosition(worldPos);
group.current.getWorldQuaternion(worldQuat);
flatDelta.x = camera.position.x - worldPos.x;
flatDelta.y = camera.position.z - worldPos.z;
const angle = flatDelta.angle() - Math.PI / 2 + offsetRot.y;
targetQuat.setFromAxisAngle(DOWN_AXIS, angle);
}
group.current.quaternion.slerp(targetQuat, 0.11);
});
return /*#__PURE__*/React.createElement("group", {
name: "look-at-player",
ref: group
}, children);
}
function Background$1(props) {
const {
color
} = props;
const scene = useThree(state => state.scene);
useLayoutEffect(() => {
const oldBackground = scene.background;
const col = color instanceof Color ? color : new Color(color);
scene.background = col;
return () => {
scene.background = oldBackground;
};
}, [color]);
return null;
}
function Fog(props) {
const {
color = "white",
near = 10,
far = 80
} = props;
const scene = useThree(state => state.scene);
useEffect(() => {
const col = color instanceof Color ? color : new Color(color);
scene.fog = new Fog$1(col, near, far);
return () => {
scene.fog = null;
};
}, [scene, color, near, far]);
return null;
}
function InfinitePlane(props) {
const {
height = -0.0001,
size = [100, 100],
visible
} = props;
const [ref] = usePlane(() => ({
rotation: [-Math.PI / 2, 0, 0],
position: [0, height, 0],
args: size,
type: "Static"
}));
if (!visible) return null;
return /*#__PURE__*/React.createElement("mesh", {
name: "spacesvr-infinite-plane",
ref: ref
}, /*#__PURE__*/React.createElement("planeBufferGeometry", {
args: size
}), /*#__PURE__*/React.createElement("meshPhongMaterial", {
color: "#660000"
}));
}
function Audio$1(props) {
const {
url,
dCone = new Vector3(180, 230, 0.1),
rollOff = 1,
volume = 1,
setAudioAnalyser,
fftSize = 128,
...rest
} = props;
const [speaker, setSpeaker] = useState();
const camera = useThree(state => state.camera);
const audio = useMemo(() => {
const a = document.createElement("audio");
a.src = url;
a.autoplay = false;
a.preload = "auto";
a.crossOrigin = "Anonymous";
a.loop = true;
return a;
}, []);
useEffect(() => {
const setupAudio = () => {
if (!audio.paused && !speaker) {
const listener = new AudioListener();
camera.add(listener);
const speak = new PositionalAudio(listener);
speak.setMediaElementSource(audio);
speak.setRefDistance(0.75);
speak.setRolloffFactor(rollOff);
speak.setVolume(volume);
speak.setDirectionalCone(dCone.x, dCone.y, dCone.z);
if (setAudioAnalyser) {
setAudioAnalyser(new AudioAnalyser(speak, fftSize));
}
setSpeaker(speak);
}
};
const playAudio = () => audio.play().then(() => setupAudio());
if (audio) {
audio.setAttribute("src", url);
audio.play().then(() => setupAudio());
document.addEventListener("click", playAudio);
return () => {
document.removeEventListener("click", playAudio);
};
}
}, [speaker, audio, url]);
useEffect(() => {
if (!speaker) return;
speaker.setRolloffFactor(rollOff);
speaker.setVolume(volume);
speaker.setDirectionalCone(dCone.x, dCone.y, dCone.z);
}, [dCone, rollOff, volume]);
return /*#__PURE__*/React.createElement("group", _extends({
name: "spacesvr-audio"
}, rest), speaker && /*#__PURE__*/React.createElement("primitive", {
object: speaker
}));
}
function HDRI(props) {
const {
src,
disableBackground,
disableEnvironment
} = props;
return /*#__PURE__*/React.createElement(Suspense, {
fallback: null
}, /*#__PURE__*/React.createElement(Environment$1, {
files: src,
background: !disableBackground && !disableEnvironment ? true : disableEnvironment && !disableBackground ? "only" : false
}));
}
let fallbackTexture;
const SIZE = 128;
const SIZE_2 = SIZE / 2;
const RAD = 12;
const LINE_W = 1;
/**
* Provides a default texture that is created locally
*/
function getFallbackTexture() {
if (fallbackTexture) return fallbackTexture;
const canvas = document.createElement("canvas");
canvas.height = SIZE;
canvas.width = SIZE;
const context = canvas.getContext("2d");
context.fillStyle = "#FFFFFF";
context.fillRect(0, 0, SIZE, SIZE); // main circle
context.fillStyle = "#000000";
context.beginPath();
context.arc(SIZE_2, SIZE_2, RAD, 0, 2 * Math.PI);
context.fill(); // draw a white line down the middle of the circle
context.strokeStyle = "#FFFFFF";
context.lineWidth = Math.ceil(LINE_W);
context.beginPath();
context.moveTo(SIZE_2, SIZE_2 - RAD);
context.lineTo(SIZE_2, SIZE_2 + RAD);
context.stroke(); // draw a horizontal line across the middle of the circle
context.beginPath();
context.moveTo(SIZE_2 - RAD, SIZE_2);
context.lineTo(SIZE_2 + RAD, SIZE_2);
context.stroke();
fallbackTexture = new CanvasTexture(canvas);
return fallbackTexture;
}
const KTX_CDN = "https://cdn.jsdelivr.net/gh/pmndrs/drei-assets@master/basis/";
const textureLoader = new TextureLoader();
let ktx2loader; // it's inconvenient to have to produce a gl object to check for ktx2 support, especially when it comes to the cache keys
// solution is to create a skeleton object that provides the minimum requirements to check for ktx support, defined below
// https://github.com/mrdoob/three.js/blob/master/examples/jsm/loaders/KTX2Loader.js#L113-L135
const setupKtx2 = () => {
if (ktx2loader) return;
ktx2loader = new KTX2Loader();
ktx2loader.setTranscoderPath(KTX_CDN);
let supportsWebgl2;
const el = document.createElement("canvas");
let gl = el.getContext("webgl2");
if (gl) {
supportsWebgl2 = true;
} else {
gl = el.getContext("webgl");
supportsWebgl2 = false;
}
if (!gl) {
throw new Error("No WebGL support");
}
el.remove();
const minimumGL = {
extensions: new WebGLExtensions(gl),
capabilities: {
isWebGL2: supportsWebgl2
}
}; // @ts-ignore
ktx2loader.detectSupport(minimumGL);
};
function loadimage() {
return function (url) {
const IS_KTX2 = url.toLowerCase().endsWith("ktx2");
setupKtx2();
const loader = IS_KTX2 ? ktx2loader : textureLoader;
return new Promise(res => loader.load(url, res, undefined, error => {
console.error(error);
res(getFallbackTexture());
}));
};
}
/**
* A single hook akin to useTexture but with ktx support
*
* KTX_CDN is from drei so that we don't download two separate transcoders when using the useKtx2 hook elsewhere
* https://github.com/pmndrs/drei/blob/a2daf02853f624ef6062c70ba0b218bc03e5b626/src/core/useKTX2.tsx#L7
* @param url
*/
function useImage(url) {
return suspend(loadimage(), [url]);
}
useImage.preload = function (url) {
return preload(loadimage(), [url]);
};
useImage.clear = function (url) {
return clear([url]);
};
/**
* A hook to load gltf models with draco, meshopt, and ktx2 support out of the box
*
* For all cases, functionality is to only download decoder files if needed by the file
* @param url
*/
function useModel(url) {
return useGLTF(url, true, true, loader => {
setupKtx2();
loader.setKTX2Loader(ktx2loader);
});
}
useModel.preload = function (url) {
return useGLTF.preload(url, true, true, loader => {
setupKtx2();
loader.setKTX2Loader(ktx2loader);
});
};
useModel.clear = function (url) {
return useGLTF.clear([url]);
};
/**
*
* Builds a frame for a mesh with a texture (image, video, etc.)
*
* In the code, the frame is the back panel and the border is the
* four meshes that make up the top, left, right, and bottom sides
* of the border.
*
* @param props
* @constructor
*/
function Frame(props) {
const {
width,
height,
thickness = 1,
material: passedMaterial,
innerFrameMaterial
} = props;
const material = useMemo(() => passedMaterial || new MeshStandardMaterial({
color: 0x333333,
roughness: 0.8,
metalness: 0.05
}), [passedMaterial]);
const frameDepth = 0.075;
const frameWidth = 0.06;
const borderDepth = 0.08;
const borderThickness = 0.05 * thickness;
const meshOffset = 0.0005;
const geometry = useMemo(() => {
const backPanel = new BoxBufferGeometry(width + frameWidth, height + frameWidth, frameDepth);
backPanel.translate(0, 0, -frameDepth - meshOffset);
const topFrame = new BoxBufferGeometry(width + frameWidth, borderThickness, borderDepth);
topFrame.translate(0, height / 2 + frameWidth / 2 - borderThickness / 2, 0);
const bottomFrame = new BoxBufferGeometry(width + frameWidth, borderThickness, borderDepth);
bottomFrame.translate(0, -height / 2 - frameWidth / 2 + borderThickness / 2, 0);
const leftFrame = new BoxBufferGeometry(borderThickness, height + frameWidth, borderDepth);
leftFrame.translate(-width / 2 - frameWidth / 2 + borderThickness / 2, 0, 0);
const rightFrame = new BoxBufferGeometry(borderThickness, height + frameWidth, borderDepth);
rightFrame.translate(width / 2 + frameWidth / 2 - borderThickness / 2, 0, 0);
const geos = [backPanel, topFrame, bottomFrame, leftFrame, rightFrame];
const geo = mergeBufferGeometries(geos);
backPanel.dispose();
topFrame.dispose();
bottomFrame.dispose();
leftFrame.dispose();
rightFrame.dispose();
return geo;
}, [innerFrameMaterial, borderThickness, width, height]);
const backFrameGeometry = useMemo(() => {
if (!innerFrameMaterial) return undefined;
const backPanel = new BoxBufferGeometry(width + frameWidth, height + frameWidth, frameDepth);
backPanel.translate(0, 0, -frameDepth - meshOffset);
return backPanel;
}, [innerFrameMaterial, width, height]);
return /*#__PURE__*/React.createElement("group", {
name: "spacesvr-frame"
}, /*#__PURE__*/React.createElement("mesh", {
geometry: geometry,
material: material
}), backFrameGeometry && innerFrameMaterial && /*#__PURE__*/React.createElement("mesh", {
geometry: backFrameGeometry,
material: innerFrameMaterial
}));
}
function UnsuspensedImage(props) {
const {
src,
size = 1,
framed,
frameMaterial,
frameWidth = 1,
innerFrameMaterial,
...rest
} = props;
const tex = useImage(src);
const {
width,
height
} = tex.image;
const max = Math.max(width, height);
const WIDTH = width / max * size;
const HEIGHT = height / max * size;
const IS_COMPRESSED = tex.isCompressedTexture;
return /*#__PURE__*/React.createElement("group", _extends({
name: "spacesvr-image"
}, rest), /*#__PURE__*/React.createElement("mesh", {
rotation: IS_COMPRESSED ? [0, Math.PI, Math.PI] : [0, 0, 0]
}, /*#__PURE__*/React.createElement("planeBufferGeometry", {
args: [WIDTH, HEIGHT]
}), /*#__PURE__*/React.createElement("meshBasicMaterial", {
map: tex,
side: DoubleSide,
transparent: true
})), framed && /*#__PURE__*/React.createElement(Frame, {
width: WIDTH,
height: HEIGHT,
thickness: frameWidth,
material: frameMaterial,
innerFrameMaterial: innerFrameMaterial
}));
}
function Image$1(props) {
return /*#__PURE__*/React.createElement(Suspense, {
fallback: null
}, /*#__PURE__*/React.createElement(UnsuspensedImage, props));
}
/**
* a world is a set of ideas
*/
class World {
constructor() {
return this;
}
getIdea() {
return new Idea().setFromCreation(hashStringToRange(JSON.stringify(this.tree || this.id), 3), 0.3 + 0.7 * hashStringToRange(this.id), 0.8);
}
getAxiom() {
const str = JSON.stringify(this.tree || this.id);
const strHash = new Array(10).fill(1).map(() => str).join("");
return new Idea().setFromCreation(hashStringToRange(strHash, 15), 0.3 + 0.7 * hashStringToRange(strHash, 10), 0.8);
}
getUpNorm() {
// 4 digit long hex values
const x = parseInt(this.id.split("-")[1], 16) / Math.pow(16, 4);
const y = parseInt(this.id.split("-")[2], 16) / Math.pow(16, 4);
const z = parseInt(this.id.split("-")[3], 16) / Math.pow(16, 4);
return new Vector3(x, y, z).normalize();
}
getRange() {
const r = parseInt(this.id.split("-")[0], 16) / Math.pow(16, 8);
return 0.3 + 0.7 * r;
}
getHex() {
return this.getIdea().getHex();
}
}
const AVG_CHAR_VAL = 100; // each char is roughly 100, so loop every ~50 chars
const hashStringToRange = function (str, loop) {
if (loop === void 0) {
loop = 8;
}
let count = 0;
for (let i = 0; i < str.length; i++) {
count += str.substr(i, 1).charCodeAt(0);
}
const scaledLoop = loop * AVG_CHAR_VAL;
return count % scaledLoop / scaledLoop;
};
/**
* A site is a delivery method of a world.
*/
class Site {
constructor() {
return this;
}
}
/**
* Gets the number of triangles in a geometry
*/
const getGeometryTriCount$1 = geometry => {
return geometry.index ? geometry.index.count / 3 : geometry.attributes.position.count / 3;
};
/**
* For a given mesh, set up bvh raycasting for it if it meets the threshold for
* amount of triangles to use
*
* @param mesh
* @param threshold
*/
const enableBVHRaycast = function (mesh, threshold) {
if (threshold === void 0) {
threshold = 0;
}
if (!mesh.geometry || !mesh.geometry.isBufferGeometry) {
return;
}
const geometry = mesh.geometry;
const triCount = getGeometryTriCount$1(geometry);
if (geometry.boundsTree || triCount < threshold) return;
mesh.raycast = acceleratedRaycast;
geometry.computeBoundsTree = computeBoundsTree;
geometry.disposeBoundsTree = disposeBoundsTree;
geometry.computeBoundsTree({
verbose: true
});
};
const universe_cache = new Map();
function getResource(key, constructor, opts) {
let resource = universe_cache.get(key);
if (!resource) {
if (opts != null && opts.verbose) console.log(`[CACHE] ${key} not found, creating new`);
resource = constructor();
universe_cache.set(key, resource);
} else {
if (opts != null && opts.verbose) console.log(`[CACHE] ${key} found, returning`);
}
return resource;
}
const cache = {
getResource,
useResource: (key, constructor, opts) => {
const [resource, setResource] = useState(getResource(key, constructor, opts));
useEffect(() => {
setResource(getResource(key, constructor, opts));
}, [key]);
return resource;
},
get mat_standard_white() {
return getResource("mat_standard_white", () => new MeshStandardMaterial({
color: "white"
}));
},
get mat_standard_cream_double() {
return getResource("mat_standard_cream_double", () => new MeshStandardMaterial({
color: "#aaa",
side: DoubleSide
}));
},
get mat_standard_black() {
return getResource("mat_standard_black", () => new MeshStandardMaterial({
color: "black"
}));
},
get mat_standard_rose() {
return getResource("mat_standard_rose", () => new MeshStandardMaterial({
color: "#ff007f"
}));
},
get mat_standard_red() {
return getResource("mat_standard_red", () => new MeshStandardMaterial({
color: "#ff0000"
}));
},
get mat_basic_white() {
return getResource("mat_basic_white", () => new MeshBasicMaterial({
color: "white"
}));
},
get mat_basic_black() {
return getResource("mat_basic_black", () => new MeshBasicMaterial({
color: "black"
}));
},
get mat_basic_gray() {
return getResource("mat_basic_gray", () => new MeshBasicMaterial({
color: "#828282"
}));
},
get mat_basic_red() {
return getResource("mat_basic_red", () => new MeshBasicMaterial({
color: "red"
}));
},
get mat_basic_black_wireframe() {
return getResource("mat_basic_black_wireframe", () => new MeshBasicMaterial({
color: "black",
wireframe: true
}));
}
};
const useTrimeshCollision$1 = geometry => {
const indices = geometry.index.array;
const isInterleaved = // @ts-ignore
geometry.attributes.position.isInterleavedBufferAttribute;
let vertices = [];
if (isInterleaved) {
const attr = geometry.attributes.position;
const data = attr.data;
for (let i = attr.offset; i < data.array.length; i += data.stride) {
for (let x = 0; x < attr.itemSize; x++) {
vertices.push(data.array[i + x]);
}
}
} else {
vertices = geometry.attributes.position.array;
}
const [hitbox] = useTrimesh(() => ({
type: "Static",
args: [vertices, indices]
}));
return hitbox;
};
// check whether the user is currently typing
const isTyping = () => {
var _document, _document$activeEleme, _document2;
return ((_document = document) == null ? void 0 : (_document$activeEleme = _document.activeElement) == null ? void 0 : _document$activeEleme.tagName) === "INPUT" && ((_document2 = document) == null ? void 0 : _document2.hasFocus());
};
const useDrag = function (callback, domElem, deps) {
if (deps === void 0) {
deps = [];
}
const {
clock,
size,
viewport
} = useThree();
const aspect = size.width / viewport.width;
const [downPoint] = useState(new Vector2());
const [dragPoint] = useState(new Vector2());
const [velocity] = useState(new Vector2());
const [delta] = useState(new Vector2());
const lastTouchRead = useRef(0);
const onStart = useCallback(p => {
if (callback.onStart) callback.onStart(p);
}, [...deps]);
const onMove = useCallback(p => {
if (callback.onMove) callback.onMove(p);
}, [...deps]);
const onEnd = useCallback(p => {
if (callback.onEnd) callback.onEnd(p);
}, [...deps]);
const startDrag = useCallback(e => {
e.preventDefault();
const touch = e.changedTouches[0];
downPoint.set(touch.clientX, touch.clientY);
onStart({
e,
touch,
downPoint,
dragPoint: downPoint,
velocity
});
}, [onStart, downPoint, velocity]);
const moveDrag = useCallback(e => {
const touch = e.touches[0];
dragPoint.set(touch.clientX, touch.clientY);
const delta = dragPoint.sub(downPoint);
const time = clock.elapsedTime;
const elapsed = time - lastTouchRead.current;
velocity.set(delta.x / elapsed / aspect, delta.y / elapsed / aspect);
lastTouchRead.current = time;
onMove({
e,
touch,
downPoint,
dragPoint,
velocity,
delta
});
}, [aspect, onMove, clock, downPoint, dragPoint, velocity]);
const endDrag = useCallback(e => {
const touch = e.changedTouches[0];
dragPoint.set(touch.clientX, touch.clientY);
delta.copy(dragPoint).sub(downPoint);
onEnd({
e,
touch,
downPoint,
dragPoint,
velocity,
delta
});
}, [onEnd, delta, downPoint, dragPoint, velocity]);
useEffect(() => {
const elem = domElem || document;
elem.addEventListener("touchstart", startDrag);
elem.addEventListener("touchmove", moveDrag);
elem.addEventListener("touchend", endDrag);
return () => {
elem.removeEventListener("touchstart", startDrag);
elem.removeEventListener("touchmove", moveDrag);
elem.removeEventListener("touchend", endDrag);
};
}, [domElem, endDrag, moveDrag, startDrag]);
return {
startDrag,
moveDrag,
endDrag
};
};
const PADDING_X = 0.125;
const PADDING_X_2 = PADDING_X * 2;
const PADDING_Y = 0.125;
const PADDING_Y_2 = PADDING_Y * 2;
const RAD_PER_DEG_2 = Math.PI / 180 / 2;
const getHudPos = (pos, camera, distance, target) => {
const vFOV = camera.fov * RAD_PER_DEG_2;
const height = 2 * Math.tan(vFOV) * Math.abs(distance);
const width = height * camera.aspect;
const px = pos.x || pos[0];
const py = pos.y || pos[1];
const x = px * (width - PADDING_X_2) * 0.5;
const y = py * (height - PADDING_Y_2) * 0.5;
if (target) {
target.x = x;
target.y = y;
return target;
}
return new Vector2(x, y);
};
const getHudDims = (camera, distance) => {
const vFOV = camera.fov * RAD_PER_DEG_2;
const height = 2 * Math.tan(vFOV) * Math.abs(distance);
const width = height * camera.aspect;
return {
width,
height
};
};
const useHudDims = function (distance) {
if (distance === void 0) {
distance = 1;
}
const camera = useThree(state => state.camera);
return useMemo(() => {
return getHudDims(camera, distance); // make sure aspect is there
}, [camera, distance, camera.aspect]);
};
const Container$2 = styled.div`
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
canvas {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
outline: 0;
}
`;
const globalStyles = css`
@font-face {
font-family: "Quicksand";
src: url("https://cdn.websessions.co/select/fonts/FTBasicSpace-Regular.woff2");
}
html {
position: fixed;
height: 100%;
overflow: hidden;
}
body {
margin: 0;
width: 100vw;
height: 100vh;
user-select: none;
overflow: hidden;
touch-action: none;
-webkit-overflow-scrolling: touch;
font-family: "Quicksand", sans-serif;
font-size: 18px;
@media screen and (max-width: 500px) {
font-size: 16px;
}
}
`;
function GlobalStyles() {
useEffect(() => {
const view = document.createElement("meta");
view.name = "viewport";
view.content = "initial-scale=1, viewport-fit=cover";
document.head.append(view);
return () => {
document.head.removeChild(view);
};
}, []);
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Global, {
styles: globalStyles
}));
}
/**
* A modified version of the controlled progress hooks that adds
* - a minimum wait time, in case it takes a second to register an asset
* - a delay after it reaches 100 in case it goes back down
* - a timeout when it reaches > 50%, marked as stuck
*/
const useControlledProgress = () => {
const MIN_TIME = 400; // minimum time to wait before moving to 100
const AFTER_TIME = 300; // extra time to prevent bouncing at reaching 100
const {
progress,
total
} = useProgress();
const startTime = useRef(new Date());
const controlledProgress = useRef(0);
const finished = useRef(false);
const [, setForceRender] = useState(0);
useEffect(() => {
const newTime = new Date();
const timeElapsed = newTime.getTime() - startTime.current.getTime();
const diff = Math.min(progress - controlledProgress.current, timeElapsed < MIN_TIME ? 99 : 100);
if (diff > 0) {
if (progress === 100) {
finished.current = true; // if progress 100, check in AFTER_TIME ms to make sure it hasn't
// bounced back down
setTimeout(() => {
if (finished.current) {
controlledProgress.current = progress; // set state to force re render
setForceRender(Math.random());
}
}, AFTER_TIME);
} else {
finished.current = false;
controlledProgress.current = progress;
}
}
if (progress !== 100) {
finished.current = false;
}
}, [progress]); // wait TIMEOUT (ms) to check if any objects are waiting to be loaded
const [counter, setCounter] = useState(0);
const [skip, setSkip] = useState(false);
useEffect(() => {
if (total > 0) {
return;
} else if (counter > 0) {
setSkip(true);
} else {
setTimeout(() => setCounter(counter + 1), MIN_TIME);
}
}, [counter]);
return skip ? 100 : Math.floor(controlledProgress.current);
};
const float = keyframes`
0% {
transform: translatey(0px);
}
50% {
transform: translatey(-15px);
}
100% {
transform: translatey(0px);
}
`;
const grow = keyframes`
0% {
opacity: 0;
}
100% {
opacity: 1;
}
`;
const Container$1 = styled.div`
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 200;
background: white;
transition: opacity 0.75s ease-in;
transition-delay: 0.5s;
opacity: ${props => props.finished ? "0" : "1"};
pointer-events: ${props => props.finished ? "none" : "all"};
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
`;
const Text$1 = styled.div`
z-index: 999999999999;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
animation: ${grow} 1.2s ease-in-out infinite;
/* animation: ${float} 7s ease-in-out infinite; */
`;
const ProgressBar = styled(motion.div)`
position: fixed;
bottom: 0;
left: 0;
/* right: 0; */
width: 100%;
/* height: 10px; */
background: #f2f2f2;
transform-origin: 0%;
`;
const Wrapper$1 = styled.div`
position: relative;
&:before {
pointer-events: none;
position: absolute;
content: "";
top: 100%;
left: 5%;
height: 10px;
width: 90%;
}
`;
function LoadingScreen() {
// const [seconds, setSeconds] = useState(0);
const progress = useControlledProgress();
const [seconds, setSeconds] = useState(true);
useEffect(() => {
const interval = setInterval(() => {
// setSeconds((seconds) => seconds + 1);
setSeconds(!seconds);
}, 1000);
return () => clearInterval(interval);
}); // console.log('progress', progress)
return /*#__PURE__*/React$1.createElement(Container$1, {
finished: progress === 100
}, /*#__PURE__*/React$1.createElement(Wrapper$1, null, /*#__PURE__*/React$1.createElement(ProgressBar, {
animate: {
height: progress + "%"
},
transition: {
stiffness: 100,
damping: 30,
restDelta: 0.001
}
}), /*#__PURE__*/React$1.createElement(Text$1, null, seconds ? progress + "%" : "Experience Loading")));
}
const Container = styled.div`
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 100;
transition: opacity 0.25s ease;
background: rgba(0, 0, 0, ${props => props.dev ? 0 : 0.25});
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
opacity: ${props => props.paused ? 1 : 0};
pointer-events: ${props => props.paused ? "all" : "none"};
font-family: "Quicksand", sans-serif;
`;
const ClickContainer = styled.div`
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: -1;
`;
const Window = styled.div`
width: 100%;
height: 100%;
padding: 20px 20px;
color: black;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
position: relative;
/* background-color: #00000011;
backdrop-filter: blur(2px); */
background: rgb(255 255 255 / 20%);
backdrop-filter: blur(7px);
/* box-shadow: 12px 12px 16px 0 rgba(0, 0, 0, 0.25),
-8px -8px 12px 0 rgba(255, 255, 255, 0.3); */
`;
const Continue = styled.div`
border-radius: 5px;
padding: 10px 20px;
background: linear-gradient(
281.48deg,
rgba(255, 255, 255, 0.4) 0%,
rgba(255, 255, 255, 0) 96.42%
);
border: 0.5px solid #ffffff;
filter: drop-shadow(0px 4px 24px rgba(255, 255, 255, 0.4));
/* backdrop-filter: blur(16px); */
margin: 0 auto;
z-index: 10000;
color: white;
cursor: pointer;
font-size: 13px;
&:hover {
transition: fill 0.4s ease-in-out;
fill: #78e41f;
}
`;
const Instructions = styled.div`
width: 100%;
height: auto;
margin: 30px 0;
font-size: 18px;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
color: white;
& > p {
margin: 1em 0;
}
`;
styled.div`
border: 1px solid black;
border-radius: 10px;
background: rgba(255, 255, 255, 0);
padding: 5px 10px;
margin: 8px 4px;
transition: background 0.15s linear;
font-size: 0.5em;
cursor: pointer;
&:hover {
background: rgba(0, 0, 0, 0.15);
}
`;
styled.a`
border: 1px solid black;
border-radius: 10px;
background: rgba(255, 255, 255, 0);
padding: 5px 10px;
margin: 8px 4px;
transition: background 0.15s linear;
font-size: 0.5em;
cursor: pointer