codebase rework

This commit is contained in:
ad044 2022-07-24 19:00:11 +04:00
parent d2e3f1e924
commit 92b22ad2e6
305 changed files with 32371 additions and 71910 deletions

View file

@ -1,6 +0,0 @@
markdown
node_modules
.git
.gitignore
build
README.md

3
.eslintrc.json Normal file
View file

@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

34
.gitignore vendored
View file

@ -8,29 +8,35 @@
# testing # testing
/coverage /coverage
# next.js
/.next/
/out/
# production # production
/build /build
# progressbar # misc
.DS_Store .DS_Store
.env.local *.pem
.env.development.local
.env.test.local
.env.production.local
# debug
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
.pnpm-debug.log*
src/static/sprites/* # local env files
src/static/media/* .env*.local
!src/static/media/webvtt
src/static/voice/* # vercel
src/static/sfx/* .vercel
!src/static/sfx/index.ts
# typescript
*.tsbuildinfo
/public
!/public/models
!/public/media/webvtt
scripts/extract/discs scripts/extract/discs
scripts/extract/*.log scripts/extract/*.log
.idea

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "webvtt"]
path = src/static/media/webvtt
url = https://github.com/laingame-net/lainvtt

View file

@ -1,19 +0,0 @@
FROM node:15.12.0-alpine AS builder
WORKDIR /app
COPY scripts/ ./scripts
COPY package-lock.json .
COPY package.json .
RUN npm i
COPY . .
RUN npm run build
RUN ls build/
FROM nginx:alpine
COPY --from=builder /app/build/ /usr/share/nginx/html/

19
jest.config.js Normal file
View file

@ -0,0 +1,19 @@
const nextJest = require("next/jest");
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: "./",
});
// Add any custom config to be passed to Jest
const customJestConfig = {
// Add more setup options before each test is run
// setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleDirectories: ["node_modules", "<rootDir>/"],
moduleNameMapper: { "@/(.*)": "<rootDir>/src/$1" },
testEnvironment: "jest-environment-jsdom",
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);

5
next-env.d.ts vendored Normal file
View file

@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

24
next.config.js Normal file
View file

@ -0,0 +1,24 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack(config, { isServer }) {
// Allow importing of shader files (e.g. `.glsl` -- filenames below)
// @see: https://github.com/glslify/glslify-loader
config.module.rules.push(
{
test: /\.(glsl|vs|fs|vert|frag|ps)$/,
exclude: /node_modules/,
use: ["raw-loader"],
},
{
test: /\.(mp4|vtt)$/,
use: "file-loader",
}
);
return config;
},
reactStrictMode: true,
};
module.exports = nextConfig;

37087
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,57 +1,37 @@
{ {
"name": "lain-tsx", "name": "laintsx",
"version": "0.1.0", "version": "0.4.4",
"private": true, "private": true,
"dependencies": {
"@react-spring/three": "^9.0.0-rc.3",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"@types/jest": "^24.9.1",
"@types/node": "^12.12.54",
"@types/react": "^16.9.47",
"@types/react-dom": "^16.9.8",
"@types/react-router-dom": "^5.1.7",
"@types/three": "^0.126.0",
"music-metadata": "^7.8.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-scripts": "^4.0.0",
"react-three-fiber": "^4.2.20",
"three": "^0.125.0",
"three-plain-animator": "^1.0.6",
"typescript": "^3.7.5",
"zustand": "^3.1.3"
},
"scripts": { "scripts": {
"start": "react-scripts start", "dev": "next dev",
"build": "react-scripts build", "build": "next build",
"test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!three/.*)/\"", "start": "next start",
"eject": "react-scripts eject", "lint": "next lint",
"extract": "node scripts/extract/extract.mjs", "test": "jest --watch"
"postinstall": "node scripts/postinstall.js"
}, },
"eslintConfig": { "dependencies": {
"extends": "react-app" "@react-three/drei": "^9.13.2",
"@react-three/fiber": "^8.0.26",
"next": "12.1.6",
"react": "18.2.0",
"react-dom": "18.2.0",
"rxjs": "^7.5.5",
"three": "^0.141.0",
"three-plain-animator": "^1.1.2",
"zustand": "^4.0.0-rc.1"
}, },
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"homepage": ".",
"devDependencies": { "devDependencies": {
"eslint-loader": "^4.0.2", "@types/jest": "^28.1.4",
"kaitai-struct": "^0.9.0", "@types/node": "18.0.0",
"replace-in-file": "^6.2.0", "@types/react": "18.0.14",
"yargs": "^16.2.0" "@types/react-dom": "18.0.5",
"@types/three": "^0.141.0",
"eslint": "8.18.0",
"eslint-config-next": "12.1.6",
"file-loader": "^6.2.0",
"jest": "^28.1.2",
"jest-environment-jsdom": "^28.1.2",
"raw-loader": "^4.0.2",
"typescript": "4.7.4"
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -1,119 +0,0 @@
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(d,k,f){d!=Array.prototype&&d!=Object.prototype&&(d[k]=f.value)};$jscomp.getGlobal=function(d){return"undefined"!=typeof window&&window===d?d:"undefined"!=typeof global&&null!=global?global:d};$jscomp.global=$jscomp.getGlobal(this);
$jscomp.polyfill=function(d,k,f,u){if(k){f=$jscomp.global;d=d.split(".");for(u=0;u<d.length-1;u++){var h=d[u];h in f||(f[h]={});f=f[h]}d=d[d.length-1];u=f[d];k=k(u);k!=u&&null!=k&&$jscomp.defineProperty(f,d,{configurable:!0,writable:!0,value:k})}};$jscomp.polyfill("Math.imul",function(d){return d?d:function(d,f){d=Number(d);f=Number(f);var k=d&65535,h=f&65535;return k*h+((d>>>16&65535)*h+k*(f>>>16&65535)<<16>>>0)|0}},"es6","es3");
$jscomp.polyfill("Math.clz32",function(d){return d?d:function(d){d=Number(d)>>>0;if(0===d)return 32;var f=0;0===(d&4294901760)&&(d<<=16,f+=16);0===(d&4278190080)&&(d<<=8,f+=8);0===(d&4026531840)&&(d<<=4,f+=4);0===(d&3221225472)&&(d<<=2,f+=2);0===(d&2147483648)&&f++;return f}},"es6","es3");$jscomp.polyfill("Math.trunc",function(d){return d?d:function(d){d=Number(d);if(isNaN(d)||Infinity===d||-Infinity===d||0===d)return d;var f=Math.floor(Math.abs(d));return 0>d?-f:f}},"es6","es3");
$jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.Symbol=function(){var d=0;return function(k){return $jscomp.SYMBOL_PREFIX+(k||"")+d++}}();
$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var d=$jscomp.global.Symbol.iterator;d||(d=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[d]&&$jscomp.defineProperty(Array.prototype,d,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}};$jscomp.arrayIterator=function(d){var k=0;return $jscomp.iteratorPrototype(function(){return k<d.length?{done:!1,value:d[k++]}:{done:!0}})};
$jscomp.iteratorPrototype=function(d){$jscomp.initSymbolIterator();d={next:d};d[$jscomp.global.Symbol.iterator]=function(){return this};return d};$jscomp.makeIterator=function(d){$jscomp.initSymbolIterator();var k=d[Symbol.iterator];return k?k.call(d):$jscomp.arrayIterator(d)};$jscomp.FORCE_POLYFILL_PROMISE=!1;
$jscomp.polyfill("Promise",function(d){function k(){this.batch_=null}function f(d){return d instanceof h?d:new h(function(r,f){r(d)})}if(d&&!$jscomp.FORCE_POLYFILL_PROMISE)return d;k.prototype.asyncExecute=function(d){null==this.batch_&&(this.batch_=[],this.asyncExecuteBatch_());this.batch_.push(d);return this};k.prototype.asyncExecuteBatch_=function(){var d=this;this.asyncExecuteFunction(function(){d.executeBatch_()})};var u=$jscomp.global.setTimeout;k.prototype.asyncExecuteFunction=function(d){u(d,
0)};k.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var d=this.batch_;this.batch_=[];for(var B=0;B<d.length;++B){var f=d[B];delete d[B];try{f()}catch(v){this.asyncThrow_(v)}}}this.batch_=null};k.prototype.asyncThrow_=function(d){this.asyncExecuteFunction(function(){throw d;})};var h=function(d){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];var r=this.createResolveAndReject_();try{d(r.resolve,r.reject)}catch(Y){r.reject(Y)}};h.prototype.createResolveAndReject_=
function(){function d(d){return function(r){h||(h=!0,d.call(f,r))}}var f=this,h=!1;return{resolve:d(this.resolveTo_),reject:d(this.reject_)}};h.prototype.resolveTo_=function(d){if(d===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(d instanceof h)this.settleSameAsPromise_(d);else{a:switch(typeof d){case "object":var f=null!=d;break a;case "function":f=!0;break a;default:f=!1}f?this.resolveToNonPromiseObj_(d):this.fulfill_(d)}};h.prototype.resolveToNonPromiseObj_=function(d){var f=
void 0;try{f=d.then}catch(Y){this.reject_(Y);return}"function"==typeof f?this.settleSameAsThenable_(f,d):this.fulfill_(d)};h.prototype.reject_=function(d){this.settle_(2,d)};h.prototype.fulfill_=function(d){this.settle_(1,d)};h.prototype.settle_=function(d,f){if(0!=this.state_)throw Error("Cannot settle("+d+", "+f|"): Promise already settled in state"+this.state_);this.state_=d;this.result_=f;this.executeOnSettledCallbacks_()};h.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var d=
this.onSettledCallbacks_,f=0;f<d.length;++f)d[f].call(),d[f]=null;this.onSettledCallbacks_=null}};var ha=new k;h.prototype.settleSameAsPromise_=function(d){var f=this.createResolveAndReject_();d.callWhenSettled_(f.resolve,f.reject)};h.prototype.settleSameAsThenable_=function(d,f){var h=this.createResolveAndReject_();try{d.call(f,h.resolve,h.reject)}catch(v){h.reject(v)}};h.prototype.then=function(d,f){function k(d,f){return"function"==typeof d?function(f){try{v(d(f))}catch(O){r(O)}}:f}var v,r,B=new h(function(d,
f){v=d;r=f});this.callWhenSettled_(k(d,v),k(f,r));return B};h.prototype.catch=function(d){return this.then(void 0,d)};h.prototype.callWhenSettled_=function(d,f){function h(){switch(k.state_){case 1:d(k.result_);break;case 2:f(k.result_);break;default:throw Error("Unexpected state: "+k.state_);}}var k=this;null==this.onSettledCallbacks_?ha.asyncExecute(h):this.onSettledCallbacks_.push(function(){ha.asyncExecute(h)})};h.resolve=f;h.reject=function(d){return new h(function(f,h){h(d)})};h.race=function(d){return new h(function(h,
k){for(var v=$jscomp.makeIterator(d),r=v.next();!r.done;r=v.next())f(r.value).callWhenSettled_(h,k)})};h.all=function(d){var k=$jscomp.makeIterator(d),r=k.next();return r.done?f([]):new h(function(d,h){function v(f){return function(h){u[f]=h;B--;0==B&&d(u)}}var u=[],B=0;do u.push(void 0),B++,f(r.value).callWhenSettled_(v(u.length-1),h),r=k.next();while(!r.done)})};return h},"es6","es3");
var DracoDecoderModule=function(d){function k(a,c){c||(c=16);return Math.ceil(a/c)*c}function f(a,c){a||O("Assertion failed: "+c)}function u(a,c){if(0===c||!a)return"";for(var b=0,e,d=0;;){e=W[a+d>>0];b|=e;if(0==e&&!c)break;d++;if(c&&d==c)break}c||(c=d);e="";if(128>b){for(;0<c;)b=String.fromCharCode.apply(String,W.subarray(a,a+Math.min(c,1024))),e=e?e+b:b,a+=1024,c-=1024;return e}return h(W,a)}function h(a,c){for(var b=c;a[b];)++b;if(16<b-c&&a.subarray&&Ia)return Ia.decode(a.subarray(c,b));for(b=
"";;){var e=a[c++];if(!e)return b;if(e&128){var d=a[c++]&63;if(192==(e&224))b+=String.fromCharCode((e&31)<<6|d);else{var f=a[c++]&63;if(224==(e&240))e=(e&15)<<12|d<<6|f;else{var g=a[c++]&63;if(240==(e&248))e=(e&7)<<18|d<<12|f<<6|g;else{var h=a[c++]&63;if(248==(e&252))e=(e&3)<<24|d<<18|f<<12|g<<6|h;else{var k=a[c++]&63;e=(e&1)<<30|d<<24|f<<18|g<<12|h<<6|k}}}65536>e?b+=String.fromCharCode(e):(e-=65536,b+=String.fromCharCode(55296|e>>10,56320|e&1023))}}else b+=String.fromCharCode(e)}}function ha(a,c){0<
a%c&&(a+=c-a%c);return a}function r(){a.HEAP8=ia=new Int8Array(D);a.HEAP16=Ja=new Int16Array(D);a.HEAP32=E=new Int32Array(D);a.HEAPU8=W=new Uint8Array(D);a.HEAPU16=new Uint16Array(D);a.HEAPU32=new Uint32Array(D);a.HEAPF32=new Float32Array(D);a.HEAPF64=new Float64Array(D)}function B(e){for(;0<e.length;){var c=e.shift();if("function"==typeof c)c();else{var b=c.func;"number"===typeof b?void 0===c.arg?a.dynCall_v(b):a.dynCall_vi(b,c.arg):b(void 0===c.arg?null:c.arg)}}}function Y(a){return String.prototype.startsWith?
a.startsWith("data:application/octet-stream;base64,"):0===a.indexOf("data:application/octet-stream;base64,")}function v(){return!!v.uncaught_exception}function la(){var e=y.last;if(!e)return(sa(0),0)|0;var c=y.infos[e],b=c.type;if(!b)return(sa(0),e)|0;var p=Array.prototype.slice.call(arguments);a.___cxa_is_pointer_type(b);la.buffer||(la.buffer=Ka(4));E[la.buffer>>2]=e;e=la.buffer;for(var d=0;d<p.length;d++)if(p[d]&&a.___cxa_can_catch(p[d],b,e))return e=E[e>>2],c.adjusted=e,(sa(p[d]),e)|0;e=E[e>>2];
return(sa(b),e)|0}function Z(e,c){w.varargs=c;try{var b=w.get(),p=w.get(),d=w.get();e=0;Z.buffers||(Z.buffers=[null,[],[]],Z.printChar=function(c,b){var e=Z.buffers[c];f(e);0===b||10===b?((1===c?a.print:a.printErr)(h(e,0)),e.length=0):e.push(b)});for(c=0;c<d;c++){for(var g=E[p+8*c>>2],k=E[p+(8*c+4)>>2],l=0;l<k;l++)Z.printChar(b,W[g+l]);e+=k}return e}catch(ya){return"undefined"!==typeof FS&&ya instanceof FS.ErrnoError||O(ya),-ya.errno}}function ma(e,c){ma.seen||(ma.seen={});e in ma.seen||(a.dynCall_v(c),
ma.seen[e]=1)}function na(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}function wa(e){function c(){if(!a.calledRun&&(a.calledRun=!0,!oa)){La||(La=!0,B(Ma));B(Na);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)Oa.unshift(a.postRun.shift());B(Oa)}}if(!(0<ea)){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)Pa.unshift(a.preRun.shift());
B(Pa);0<ea||a.calledRun||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);c()},1)):c())}}function O(e){if(a.onAbort)a.onAbort(e);void 0!==e?(a.print(e),a.printErr(e),e=JSON.stringify(e)):e="";oa=!0;throw"abort("+e+"). Build with -s ASSERTIONS=1 for more info.";}function m(){}function t(a){return(a||m).__cache__}function T(a,c){var b=t(c),e=b[a];if(e)return e;e=Object.create((c||m).prototype);e.ptr=a;return b[a]=e}function U(a){if("string"===typeof a){for(var c=
0,b=0;b<a.length;++b){var e=a.charCodeAt(b);55296<=e&&57343>=e&&(e=65536+((e&1023)<<10)|a.charCodeAt(++b)&1023);127>=e?++c:c=2047>=e?c+2:65535>=e?c+3:2097151>=e?c+4:67108863>=e?c+5:c+6}c=Array(c+1);b=0;e=c.length;if(0<e){e=b+e-1;for(var d=0;d<a.length;++d){var f=a.charCodeAt(d);55296<=f&&57343>=f&&(f=65536+((f&1023)<<10)|a.charCodeAt(++d)&1023);if(127>=f){if(b>=e)break;c[b++]=f}else{if(2047>=f){if(b+1>=e)break;c[b++]=192|f>>6}else{if(65535>=f){if(b+2>=e)break;c[b++]=224|f>>12}else{if(2097151>=f){if(b+
3>=e)break;c[b++]=240|f>>18}else{if(67108863>=f){if(b+4>=e)break;c[b++]=248|f>>24}else{if(b+5>=e)break;c[b++]=252|f>>30;c[b++]=128|f>>24&63}c[b++]=128|f>>18&63}c[b++]=128|f>>12&63}c[b++]=128|f>>6&63}c[b++]=128|f&63}}c[b]=0}a=l.alloc(c,ia);l.copy(c,ia,a)}return a}function z(){throw"cannot construct a Status, no constructor in IDL";}function F(){this.ptr=Wa();t(F)[this.ptr]=this}function G(){this.ptr=Xa();t(G)[this.ptr]=this}function H(){this.ptr=Ya();t(H)[this.ptr]=this}function I(){this.ptr=Za();
t(I)[this.ptr]=this}function J(){this.ptr=$a();t(J)[this.ptr]=this}function n(){this.ptr=ab();t(n)[this.ptr]=this}function P(){this.ptr=bb();t(P)[this.ptr]=this}function x(){this.ptr=cb();t(x)[this.ptr]=this}function K(){this.ptr=db();t(K)[this.ptr]=this}function q(){this.ptr=eb();t(q)[this.ptr]=this}function L(){this.ptr=fb();t(L)[this.ptr]=this}function M(){this.ptr=gb();t(M)[this.ptr]=this}function V(){this.ptr=hb();t(V)[this.ptr]=this}function Q(){this.ptr=ib();t(Q)[this.ptr]=this}function g(){this.ptr=
jb();t(g)[this.ptr]=this}function C(){this.ptr=kb();t(C)[this.ptr]=this}function X(){throw"cannot construct a VoidPtr, no constructor in IDL";}function N(){this.ptr=lb();t(N)[this.ptr]=this}function R(){this.ptr=mb();t(R)[this.ptr]=this}d=d||{};var a="undefined"!==typeof d?d:{},Qa=!1,Ra=!1;a.onRuntimeInitialized=function(){Qa=!0;if(Ra&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Ra=!0;if(Qa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=
function(a){if("string"!==typeof a)return!1;a=a.split(".");return 2>a.length||3<a.length?!1:1==a[0]&&0<=a[1]&&3>=a[1]?!0:0!=a[0]||10<a[1]?!1:!0};var pa={},aa;for(aa in a)a.hasOwnProperty(aa)&&(pa[aa]=a[aa]);a.arguments=[];a.thisProgram="./this.program";a.quit=function(a,c){throw c;};a.preRun=[];a.postRun=[];var ja=!1,fa=!1,qa=!1,za=!1;if(a.ENVIRONMENT)if("WEB"===a.ENVIRONMENT)ja=!0;else if("WORKER"===a.ENVIRONMENT)fa=!0;else if("NODE"===a.ENVIRONMENT)qa=!0;else if("SHELL"===a.ENVIRONMENT)za=!0;else throw Error("Module['ENVIRONMENT'] value is not valid. must be one of: WEB|WORKER|NODE|SHELL.");
else ja="object"===typeof window,fa="function"===typeof importScripts,qa="object"===typeof process&&"function"===typeof require&&!ja&&!fa,za=!ja&&!qa&&!fa;if(qa){var Aa,Ba;a.read=function(a,c){Aa||(Aa=require("fs"));Ba||(Ba=require("path"));a=Ba.normalize(a);a=Aa.readFileSync(a);return c?a:a.toString()};a.readBinary=function(e){e=a.read(e,!0);e.buffer||(e=new Uint8Array(e));f(e.buffer);return e};1<process.argv.length&&(a.thisProgram=process.argv[1].replace(/\\/g,"/"));a.arguments=process.argv.slice(2);
process.on("uncaughtException",function(a){if(!(a instanceof na))throw a;});process.on("unhandledRejection",function(a,c){process.exit(1)});a.inspect=function(){return"[Emscripten Module object]"}}else if(za)"undefined"!=typeof read&&(a.read=function(a){return read(a)}),a.readBinary=function(a){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(a));a=read(a,"binary");f("object"===typeof a);return a},"undefined"!=typeof scriptArgs?a.arguments=scriptArgs:"undefined"!=typeof arguments&&
(a.arguments=arguments),"function"===typeof quit&&(a.quit=function(a,c){quit(a)});else if(ja||fa)a.read=function(a){var c=new XMLHttpRequest;c.open("GET",a,!1);c.send(null);return c.responseText},fa&&(a.readBinary=function(a){var c=new XMLHttpRequest;c.open("GET",a,!1);c.responseType="arraybuffer";c.send(null);return new Uint8Array(c.response)}),a.readAsync=function(a,c,b){var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer";e.onload=function(){200==e.status||0==e.status&&e.response?
c(e.response):b()};e.onerror=b;e.send(null)},a.setWindowTitle=function(a){document.title=a};a.print="undefined"!==typeof console?console.log.bind(console):"undefined"!==typeof print?print:null;a.printErr="undefined"!==typeof printErr?printErr:"undefined"!==typeof console&&console.warn.bind(console)||a.print;a.print=a.print;a.printErr=a.printErr;for(aa in pa)pa.hasOwnProperty(aa)&&(a[aa]=pa[aa]);pa=void 0;var oa=0,Ia="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;"undefined"!==typeof TextDecoder&&
new TextDecoder("utf-16le");var ia,W,Ja,E,ba,Ca,ta,ua,Da,ka;var Ea=ba=Ca=ta=ua=Da=ka=0;var Sa=!1;a.reallocBuffer||(a.reallocBuffer=function(a){try{if(ArrayBuffer.transfer)var c=ArrayBuffer.transfer(D,a);else{var b=ia;c=new ArrayBuffer(a);(new Int8Array(c)).set(b)}}catch(p){return!1}return nb(c)?c:!1});try{var Ta=Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype,"byteLength").get);Ta(new ArrayBuffer(4))}catch(e){Ta=function(a){return a.byteLength}}var Fa=a.TOTAL_STACK||
5242880,A=a.TOTAL_MEMORY||16777216;A<Fa&&a.printErr("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+A+"! (TOTAL_STACK="+Fa+")");if(a.buffer)var D=a.buffer;else"object"===typeof WebAssembly&&"function"===typeof WebAssembly.Memory?(a.wasmMemory=new WebAssembly.Memory({initial:A/65536}),D=a.wasmMemory.buffer):D=new ArrayBuffer(A),a.buffer=D;r();E[0]=1668509029;Ja[1]=25459;if(115!==W[2]||99!==W[3])throw"Runtime error: expected the system to be little-endian!";var Pa=[],Ma=[],Na=[],ob=[],Oa=[],
La=!1,ea=0,Ga=null,ra=null;a.preloadedImages={};a.preloadedAudios={};(function(){function e(){try{if(a.wasmBinary)return new Uint8Array(a.wasmBinary);if(a.readBinary)return a.readBinary(f);throw"on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)";}catch(Va){O(Va)}}function c(){return a.wasmBinary||!ja&&!fa||"function"!==typeof fetch?new Promise(function(a,c){a(e())}):fetch(f,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+
f+"'";return a.arrayBuffer()}).catch(function(){return e()})}function b(b,e,d){function p(c,b){k=c.exports;k.memory&&(c=k.memory,b=a.buffer,c.byteLength<b.byteLength&&a.printErr("the new buffer in mergeMemory is smaller than the previous one. in native wasm, we should grow memory here"),b=new Int8Array(b),(new Int8Array(c)).set(b),a.buffer=D=c,r());a.asm=k;a.usingWasm=!0;ea--;a.monitorRunDependencies&&a.monitorRunDependencies(ea);0==ea&&(null!==Ga&&(clearInterval(Ga),Ga=null),ra&&(c=ra,ra=null,c()))}
function g(a){p(a.instance,a.module)}function S(b){c().then(function(a){return WebAssembly.instantiate(a,h)}).then(b).catch(function(c){a.printErr("failed to asynchronously prepare wasm: "+c);O(c)})}if("object"!==typeof WebAssembly)return a.printErr("no native wasm support detected"),!1;if(!(a.wasmMemory instanceof WebAssembly.Memory))return a.printErr("no native wasm Memory in use"),!1;e.memory=a.wasmMemory;h.global={NaN:NaN,Infinity:Infinity};h["global.Math"]=Math;h.env=e;ea++;a.monitorRunDependencies&&
a.monitorRunDependencies(ea);if(a.instantiateWasm)try{return a.instantiateWasm(h,p)}catch(pb){return a.printErr("Module.instantiateWasm callback failed with error: "+pb),!1}a.wasmBinary||"function"!==typeof WebAssembly.instantiateStreaming||Y(f)||"function"!==typeof fetch?S(g):WebAssembly.instantiateStreaming(fetch(f,{credentials:"same-origin"}),h).then(g).catch(function(c){a.printErr("wasm streaming compile failed: "+c);a.printErr("falling back to ArrayBuffer instantiation");S(g)});return{}}var d=
"draco_decoder.wast",f="draco_decoder.wasm",g="draco_decoder.temp.asm.js";"function"===typeof a.locateFile&&(Y(d)||(d=a.locateFile(d)),Y(f)||(f=a.locateFile(f)),Y(g)||(g=a.locateFile(g)));var h={global:null,env:null,asm2wasm:{"f64-rem":function(a,c){return a%c},"debugger":function(){debugger}},parent:a},k=null;a.asmPreload=a.asm;var l=a.reallocBuffer;a.reallocBuffer=function(c){if("asmjs"===m)var b=l(c);else a:{c=ha(c,a.usingWasm?65536:16777216);var e=a.buffer.byteLength;if(a.usingWasm)try{b=-1!==
a.wasmMemory.grow((c-e)/65536)?a.buffer=a.wasmMemory.buffer:null;break a}catch(ud){b=null;break a}b=void 0}return b};var m="";a.asm=function(c,e,d){if(!e.table){var p=a.wasmTableSize;void 0===p&&(p=1024);var f=a.wasmMaxTableSize;e.table="object"===typeof WebAssembly&&"function"===typeof WebAssembly.Table?void 0!==f?new WebAssembly.Table({initial:p,maximum:f,element:"anyfunc"}):new WebAssembly.Table({initial:p,element:"anyfunc"}):Array(p);a.wasmTable=e.table}e.memoryBase||(e.memoryBase=a.STATIC_BASE);
e.tableBase||(e.tableBase=0);(c=b(c,e,d))||O("no binaryen method succeeded. consider enabling more options, like interpreting, if you want that: https://github.com/kripken/emscripten/wiki/WebAssembly#binaryen-methods");return c}})();Ea=1024;ba=Ea+14480;Ma.push();a.STATIC_BASE=Ea;a.STATIC_BUMP=14480;var qb=ba;ba+=16;var y={last:0,caught:[],infos:{},deAdjust:function(a){if(!a||y.infos[a])return a;for(var c in y.infos)if(y.infos[c].adjusted===a)return c;return a},addRef:function(a){a&&y.infos[a].refcount++},
decRef:function(e){if(e){var c=y.infos[e];f(0<c.refcount);c.refcount--;0!==c.refcount||c.rethrown||(c.destructor&&a.dynCall_vi(c.destructor,e),delete y.infos[e],___cxa_free_exception(e))}},clearRef:function(a){a&&(y.infos[a].refcount=0)}},w={varargs:0,get:function(a){w.varargs+=4;return E[w.varargs-4>>2]},getStr:function(){return u(w.get())},get64:function(){var a=w.get(),c=w.get();0<=a?f(0===c):f(-1===c);return a},getZero:function(){f(0===w.get())}},va={},Ha=1;ka=function(a){f(!Sa);var c=ba;ba=ba+
a+15&-16;return c}(4);Ca=ta=k(ba);ua=Ca+Fa;Da=k(ua);E[ka>>2]=Da;Sa=!0;a.wasmTableSize=468;a.wasmMaxTableSize=468;a.asmGlobalArg={};a.asmLibraryArg={abort:O,assert:f,enlargeMemory:function(){var e=a.usingWasm?65536:16777216,c=2147483648-e;if(E[ka>>2]>c)return!1;var b=A;for(A=Math.max(A,16777216);A<E[ka>>2];)A=536870912>=A?ha(2*A,e):Math.min(ha((3*A+2147483648)/4,e),c);e=a.reallocBuffer(A);if(!e||e.byteLength!=A)return A=b,!1;a.buffer=D=e;r();return!0},getTotalMemory:function(){return A},abortOnCannotGrowMemory:function(){O("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+
A+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")},invoke_ii:function(e,c){try{return a.dynCall_ii(e,c)}catch(b){if("number"!==typeof b&&"longjmp"!==b)throw b;a.setThrew(1,0)}},invoke_iii:function(e,c,b){try{return a.dynCall_iii(e,c,b)}catch(p){if("number"!==typeof p&&"longjmp"!==p)throw p;a.setThrew(1,0)}},invoke_iiii:function(e,c,b,d){try{return a.dynCall_iiii(e,
c,b,d)}catch(S){if("number"!==typeof S&&"longjmp"!==S)throw S;a.setThrew(1,0)}},invoke_iiiiiii:function(e,c,b,d,f,g,h){try{return a.dynCall_iiiiiii(e,c,b,d,f,g,h)}catch(da){if("number"!==typeof da&&"longjmp"!==da)throw da;a.setThrew(1,0)}},invoke_v:function(e){try{a.dynCall_v(e)}catch(c){if("number"!==typeof c&&"longjmp"!==c)throw c;a.setThrew(1,0)}},invoke_vi:function(e,c){try{a.dynCall_vi(e,c)}catch(b){if("number"!==typeof b&&"longjmp"!==b)throw b;a.setThrew(1,0)}},invoke_vii:function(e,c,b){try{a.dynCall_vii(e,
c,b)}catch(p){if("number"!==typeof p&&"longjmp"!==p)throw p;a.setThrew(1,0)}},invoke_viii:function(e,c,b,d){try{a.dynCall_viii(e,c,b,d)}catch(S){if("number"!==typeof S&&"longjmp"!==S)throw S;a.setThrew(1,0)}},invoke_viiii:function(e,c,b,d,f){try{a.dynCall_viiii(e,c,b,d,f)}catch(xa){if("number"!==typeof xa&&"longjmp"!==xa)throw xa;a.setThrew(1,0)}},invoke_viiiii:function(e,c,b,d,f,g){try{a.dynCall_viiiii(e,c,b,d,f,g)}catch(ca){if("number"!==typeof ca&&"longjmp"!==ca)throw ca;a.setThrew(1,0)}},invoke_viiiiii:function(e,
c,b,d,f,g,h){try{a.dynCall_viiiiii(e,c,b,d,f,g,h)}catch(da){if("number"!==typeof da&&"longjmp"!==da)throw da;a.setThrew(1,0)}},__ZSt18uncaught_exceptionv:v,___cxa_allocate_exception:function(a){return Ka(a)},___cxa_begin_catch:function(a){var c=y.infos[a];c&&!c.caught&&(c.caught=!0,v.uncaught_exception--);c&&(c.rethrown=!1);y.caught.push(a);y.addRef(y.deAdjust(a));return a},___cxa_find_matching_catch:la,___cxa_pure_virtual:function(){oa=!0;throw"Pure virtual function called!";},___cxa_throw:function(a,
c,b){y.infos[a]={ptr:a,adjusted:a,type:c,destructor:b,refcount:0,caught:!1,rethrown:!1};y.last=a;"uncaught_exception"in v?v.uncaught_exception++:v.uncaught_exception=1;throw a+" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";},___gxx_personality_v0:function(){},___resumeException:function(a){y.last||(y.last=a);throw a+" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
},___setErrNo:function(d){a.___errno_location&&(E[a.___errno_location()>>2]=d);return d},___syscall140:function(a,c){w.varargs=c;try{var b=w.getStreamFromFD();w.get();var d=w.get(),e=w.get(),f=w.get();FS.llseek(b,d,f);E[e>>2]=b.position;b.getdents&&0===d&&0===f&&(b.getdents=null);return 0}catch(ca){return"undefined"!==typeof FS&&ca instanceof FS.ErrnoError||O(ca),-ca.errno}},___syscall146:Z,___syscall6:function(a,c){w.varargs=c;try{var b=w.getStreamFromFD();FS.close(b);return 0}catch(p){return"undefined"!==
typeof FS&&p instanceof FS.ErrnoError||O(p),-p.errno}},_abort:function(){a.abort()},_emscripten_memcpy_big:function(a,c,b){W.set(W.subarray(c,c+b),a);return a},_llvm_trap:function(){O("trap!")},_pthread_getspecific:function(a){return va[a]||0},_pthread_key_create:function(a,c){if(0==a)return 22;E[a>>2]=Ha;va[Ha]=0;Ha++;return 0},_pthread_once:ma,_pthread_setspecific:function(a,c){if(!(a in va))return 22;va[a]=c;return 0},flush_NO_FILESYSTEM:function(){var d=a._fflush;d&&d(0);if(d=Z.printChar){var c=
Z.buffers;c[1].length&&d(1,10);c[2].length&&d(2,10)}},DYNAMICTOP_PTR:ka,tempDoublePtr:qb,ABORT:oa,STACKTOP:ta,STACK_MAX:ua};var Ua=a.asm(a.asmGlobalArg,a.asmLibraryArg,D);a.asm=Ua;a.___cxa_can_catch=function(){return a.asm.___cxa_can_catch.apply(null,arguments)};a.___cxa_is_pointer_type=function(){return a.asm.___cxa_is_pointer_type.apply(null,arguments)};var $a=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0.apply(null,
arguments)},rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1.apply(null,arguments)},sb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform___destroy___0.apply(null,arguments)},tb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return a.asm._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0.apply(null,
arguments)},cb=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0.apply(null,arguments)},ub=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1.apply(null,arguments)},vb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform___destroy___0.apply(null,
arguments)},wb=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_min_value_1.apply(null,arguments)},xb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0.apply(null,arguments)},yb=a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return a.asm._emscripten_bind_AttributeQuantizationTransform_range_0.apply(null,
arguments)},bb=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return a.asm._emscripten_bind_AttributeTransformData_AttributeTransformData_0.apply(null,arguments)},zb=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return a.asm._emscripten_bind_AttributeTransformData___destroy___0.apply(null,arguments)},Ab=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return a.asm._emscripten_bind_AttributeTransformData_transform_type_0.apply(null,
arguments)},ib=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=function(){return a.asm._emscripten_bind_DecoderBuffer_DecoderBuffer_0.apply(null,arguments)},Bb=a._emscripten_bind_DecoderBuffer_Init_2=function(){return a.asm._emscripten_bind_DecoderBuffer_Init_2.apply(null,arguments)},Cb=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return a.asm._emscripten_bind_DecoderBuffer___destroy___0.apply(null,arguments)},Db=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return a.asm._emscripten_bind_Decoder_DecodeBufferToMesh_2.apply(null,
arguments)},Eb=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return a.asm._emscripten_bind_Decoder_DecodeBufferToPointCloud_2.apply(null,arguments)},jb=a._emscripten_bind_Decoder_Decoder_0=function(){return a.asm._emscripten_bind_Decoder_Decoder_0.apply(null,arguments)},Fb=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeByUniqueId_2.apply(null,arguments)},Gb=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=
function(){return a.asm._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3.apply(null,arguments)},Hb=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeFloat_3.apply(null,arguments)},Ib=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3.apply(null,arguments)},Jb=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIdByName_2.apply(null,
arguments)},Kb=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeId_2.apply(null,arguments)},Lb=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3.apply(null,arguments)},Mb=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3.apply(null,arguments)},Nb=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=
function(){return a.asm._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3.apply(null,arguments)},Ob=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3.apply(null,arguments)},Pb=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return a.asm._emscripten_bind_Decoder_GetAttributeMetadata_2.apply(null,arguments)},Qb=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3.apply(null,
arguments)},Rb=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3.apply(null,arguments)},Sb=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return a.asm._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3.apply(null,arguments)},Tb=a._emscripten_bind_Decoder_GetAttribute_2=function(){return a.asm._emscripten_bind_Decoder_GetAttribute_2.apply(null,arguments)},Ub=a._emscripten_bind_Decoder_GetEncodedGeometryType_1=
function(){return a.asm._emscripten_bind_Decoder_GetEncodedGeometryType_1.apply(null,arguments)},Vb=a._emscripten_bind_Decoder_GetFaceFromMesh_3=function(){return a.asm._emscripten_bind_Decoder_GetFaceFromMesh_3.apply(null,arguments)},Wb=a._emscripten_bind_Decoder_GetMetadata_1=function(){return a.asm._emscripten_bind_Decoder_GetMetadata_1.apply(null,arguments)},Xb=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return a.asm._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2.apply(null,
arguments)},Yb=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return a.asm._emscripten_bind_Decoder_SkipAttributeTransform_1.apply(null,arguments)},Zb=a._emscripten_bind_Decoder___destroy___0=function(){return a.asm._emscripten_bind_Decoder___destroy___0.apply(null,arguments)},gb=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return a.asm._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0.apply(null,arguments)},$b=a._emscripten_bind_DracoFloat32Array_GetValue_1=
function(){return a.asm._emscripten_bind_DracoFloat32Array_GetValue_1.apply(null,arguments)},ac=a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoFloat32Array___destroy___0.apply(null,arguments)},bc=a._emscripten_bind_DracoFloat32Array_size_0=function(){return a.asm._emscripten_bind_DracoFloat32Array_size_0.apply(null,arguments)},fb=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return a.asm._emscripten_bind_DracoInt16Array_DracoInt16Array_0.apply(null,
arguments)},cc=a._emscripten_bind_DracoInt16Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoInt16Array_GetValue_1.apply(null,arguments)},dc=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return a.asm._emscripten_bind_DracoInt16Array___destroy___0.apply(null,arguments)},ec=a._emscripten_bind_DracoInt16Array_size_0=function(){return a.asm._emscripten_bind_DracoInt16Array_size_0.apply(null,arguments)},lb=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=function(){return a.asm._emscripten_bind_DracoInt32Array_DracoInt32Array_0.apply(null,
arguments)},fc=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoInt32Array_GetValue_1.apply(null,arguments)},gc=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoInt32Array___destroy___0.apply(null,arguments)},hc=a._emscripten_bind_DracoInt32Array_size_0=function(){return a.asm._emscripten_bind_DracoInt32Array_size_0.apply(null,arguments)},db=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return a.asm._emscripten_bind_DracoInt8Array_DracoInt8Array_0.apply(null,
arguments)},ic=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoInt8Array_GetValue_1.apply(null,arguments)},jc=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return a.asm._emscripten_bind_DracoInt8Array___destroy___0.apply(null,arguments)},kc=a._emscripten_bind_DracoInt8Array_size_0=function(){return a.asm._emscripten_bind_DracoInt8Array_size_0.apply(null,arguments)},Wa=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return a.asm._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0.apply(null,
arguments)},lc=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoUInt16Array_GetValue_1.apply(null,arguments)},mc=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return a.asm._emscripten_bind_DracoUInt16Array___destroy___0.apply(null,arguments)},nc=a._emscripten_bind_DracoUInt16Array_size_0=function(){return a.asm._emscripten_bind_DracoUInt16Array_size_0.apply(null,arguments)},Za=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return a.asm._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0.apply(null,
arguments)},oc=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoUInt32Array_GetValue_1.apply(null,arguments)},pc=a._emscripten_bind_DracoUInt32Array___destroy___0=function(){return a.asm._emscripten_bind_DracoUInt32Array___destroy___0.apply(null,arguments)},qc=a._emscripten_bind_DracoUInt32Array_size_0=function(){return a.asm._emscripten_bind_DracoUInt32Array_size_0.apply(null,arguments)},Ya=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return a.asm._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0.apply(null,
arguments)},rc=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return a.asm._emscripten_bind_DracoUInt8Array_GetValue_1.apply(null,arguments)},sc=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return a.asm._emscripten_bind_DracoUInt8Array___destroy___0.apply(null,arguments)},tc=a._emscripten_bind_DracoUInt8Array_size_0=function(){return a.asm._emscripten_bind_DracoUInt8Array_size_0.apply(null,arguments)},hb=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return a.asm._emscripten_bind_GeometryAttribute_GeometryAttribute_0.apply(null,
arguments)},uc=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return a.asm._emscripten_bind_GeometryAttribute___destroy___0.apply(null,arguments)},kb=a._emscripten_bind_Mesh_Mesh_0=function(){return a.asm._emscripten_bind_Mesh_Mesh_0.apply(null,arguments)},vc=a._emscripten_bind_Mesh___destroy___0=function(){return a.asm._emscripten_bind_Mesh___destroy___0.apply(null,arguments)},wc=a._emscripten_bind_Mesh_num_attributes_0=function(){return a.asm._emscripten_bind_Mesh_num_attributes_0.apply(null,
arguments)},xc=a._emscripten_bind_Mesh_num_faces_0=function(){return a.asm._emscripten_bind_Mesh_num_faces_0.apply(null,arguments)},yc=a._emscripten_bind_Mesh_num_points_0=function(){return a.asm._emscripten_bind_Mesh_num_points_0.apply(null,arguments)},zc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetDoubleEntry_2.apply(null,arguments)},Ac=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetEntryName_2.apply(null,
arguments)},Bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetIntEntry_2.apply(null,arguments)},Cc=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_GetStringEntry_2.apply(null,arguments)},Dc=a._emscripten_bind_MetadataQuerier_HasDoubleEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasDoubleEntry_2.apply(null,arguments)},Ec=a._emscripten_bind_MetadataQuerier_HasEntry_2=
function(){return a.asm._emscripten_bind_MetadataQuerier_HasEntry_2.apply(null,arguments)},Fc=a._emscripten_bind_MetadataQuerier_HasIntEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasIntEntry_2.apply(null,arguments)},Gc=a._emscripten_bind_MetadataQuerier_HasStringEntry_2=function(){return a.asm._emscripten_bind_MetadataQuerier_HasStringEntry_2.apply(null,arguments)},eb=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return a.asm._emscripten_bind_MetadataQuerier_MetadataQuerier_0.apply(null,
arguments)},Hc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return a.asm._emscripten_bind_MetadataQuerier_NumEntries_1.apply(null,arguments)},Ic=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return a.asm._emscripten_bind_MetadataQuerier___destroy___0.apply(null,arguments)},mb=a._emscripten_bind_Metadata_Metadata_0=function(){return a.asm._emscripten_bind_Metadata_Metadata_0.apply(null,arguments)},Jc=a._emscripten_bind_Metadata___destroy___0=function(){return a.asm._emscripten_bind_Metadata___destroy___0.apply(null,
arguments)},Kc=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=function(){return a.asm._emscripten_bind_PointAttribute_GetAttributeTransformData_0.apply(null,arguments)},ab=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return a.asm._emscripten_bind_PointAttribute_PointAttribute_0.apply(null,arguments)},Lc=a._emscripten_bind_PointAttribute___destroy___0=function(){return a.asm._emscripten_bind_PointAttribute___destroy___0.apply(null,arguments)},Mc=a._emscripten_bind_PointAttribute_attribute_type_0=
function(){return a.asm._emscripten_bind_PointAttribute_attribute_type_0.apply(null,arguments)},Nc=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return a.asm._emscripten_bind_PointAttribute_byte_offset_0.apply(null,arguments)},Oc=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return a.asm._emscripten_bind_PointAttribute_byte_stride_0.apply(null,arguments)},Pc=a._emscripten_bind_PointAttribute_data_type_0=function(){return a.asm._emscripten_bind_PointAttribute_data_type_0.apply(null,
arguments)},Qc=a._emscripten_bind_PointAttribute_normalized_0=function(){return a.asm._emscripten_bind_PointAttribute_normalized_0.apply(null,arguments)},Rc=a._emscripten_bind_PointAttribute_num_components_0=function(){return a.asm._emscripten_bind_PointAttribute_num_components_0.apply(null,arguments)},Sc=a._emscripten_bind_PointAttribute_size_0=function(){return a.asm._emscripten_bind_PointAttribute_size_0.apply(null,arguments)},Tc=a._emscripten_bind_PointAttribute_unique_id_0=function(){return a.asm._emscripten_bind_PointAttribute_unique_id_0.apply(null,
arguments)},Xa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return a.asm._emscripten_bind_PointCloud_PointCloud_0.apply(null,arguments)},Uc=a._emscripten_bind_PointCloud___destroy___0=function(){return a.asm._emscripten_bind_PointCloud___destroy___0.apply(null,arguments)},Vc=a._emscripten_bind_PointCloud_num_attributes_0=function(){return a.asm._emscripten_bind_PointCloud_num_attributes_0.apply(null,arguments)},Wc=a._emscripten_bind_PointCloud_num_points_0=function(){return a.asm._emscripten_bind_PointCloud_num_points_0.apply(null,
arguments)},Xc=a._emscripten_bind_Status___destroy___0=function(){return a.asm._emscripten_bind_Status___destroy___0.apply(null,arguments)},Yc=a._emscripten_bind_Status_code_0=function(){return a.asm._emscripten_bind_Status_code_0.apply(null,arguments)},Zc=a._emscripten_bind_Status_error_msg_0=function(){return a.asm._emscripten_bind_Status_error_msg_0.apply(null,arguments)},$c=a._emscripten_bind_Status_ok_0=function(){return a.asm._emscripten_bind_Status_ok_0.apply(null,arguments)},ad=a._emscripten_bind_VoidPtr___destroy___0=
function(){return a.asm._emscripten_bind_VoidPtr___destroy___0.apply(null,arguments)},bd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM.apply(null,arguments)},cd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM.apply(null,arguments)},dd=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=
function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM.apply(null,arguments)},ed=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return a.asm._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM.apply(null,arguments)},fd=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE.apply(null,
arguments)},gd=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD.apply(null,arguments)},hd=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return a.asm._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH.apply(null,arguments)},id=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_COLOR.apply(null,arguments)},jd=
a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_GENERIC.apply(null,arguments)},kd=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_INVALID.apply(null,arguments)},ld=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_NORMAL.apply(null,arguments)},md=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=
function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_POSITION.apply(null,arguments)},nd=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return a.asm._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD.apply(null,arguments)},od=a._emscripten_enum_draco_StatusCode_ERROR=function(){return a.asm._emscripten_enum_draco_StatusCode_ERROR.apply(null,arguments)},pd=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=function(){return a.asm._emscripten_enum_draco_StatusCode_INVALID_PARAMETER.apply(null,
arguments)},qd=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return a.asm._emscripten_enum_draco_StatusCode_IO_ERROR.apply(null,arguments)},rd=a._emscripten_enum_draco_StatusCode_OK=function(){return a.asm._emscripten_enum_draco_StatusCode_OK.apply(null,arguments)},sd=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return a.asm._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION.apply(null,arguments)},td=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return a.asm._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION.apply(null,
arguments)},nb=a._emscripten_replace_memory=function(){return a.asm._emscripten_replace_memory.apply(null,arguments)};a._free=function(){return a.asm._free.apply(null,arguments)};a._llvm_bswap_i32=function(){return a.asm._llvm_bswap_i32.apply(null,arguments)};var Ka=a._malloc=function(){return a.asm._malloc.apply(null,arguments)};a._memcpy=function(){return a.asm._memcpy.apply(null,arguments)};a._memmove=function(){return a.asm._memmove.apply(null,arguments)};a._memset=function(){return a.asm._memset.apply(null,
arguments)};a._sbrk=function(){return a.asm._sbrk.apply(null,arguments)};a.establishStackSpace=function(){return a.asm.establishStackSpace.apply(null,arguments)};a.getTempRet0=function(){return a.asm.getTempRet0.apply(null,arguments)};a.runPostSets=function(){return a.asm.runPostSets.apply(null,arguments)};var sa=a.setTempRet0=function(){return a.asm.setTempRet0.apply(null,arguments)};a.setThrew=function(){return a.asm.setThrew.apply(null,arguments)};a.stackAlloc=function(){return a.asm.stackAlloc.apply(null,
arguments)};a.stackRestore=function(){return a.asm.stackRestore.apply(null,arguments)};a.stackSave=function(){return a.asm.stackSave.apply(null,arguments)};a.dynCall_ii=function(){return a.asm.dynCall_ii.apply(null,arguments)};a.dynCall_iii=function(){return a.asm.dynCall_iii.apply(null,arguments)};a.dynCall_iiii=function(){return a.asm.dynCall_iiii.apply(null,arguments)};a.dynCall_iiiiiii=function(){return a.asm.dynCall_iiiiiii.apply(null,arguments)};a.dynCall_v=function(){return a.asm.dynCall_v.apply(null,
arguments)};a.dynCall_vi=function(){return a.asm.dynCall_vi.apply(null,arguments)};a.dynCall_vii=function(){return a.asm.dynCall_vii.apply(null,arguments)};a.dynCall_viii=function(){return a.asm.dynCall_viii.apply(null,arguments)};a.dynCall_viiii=function(){return a.asm.dynCall_viiii.apply(null,arguments)};a.dynCall_viiiii=function(){return a.asm.dynCall_viiiii.apply(null,arguments)};a.dynCall_viiiiii=function(){return a.asm.dynCall_viiiiii.apply(null,arguments)};a.asm=Ua;a.then=function(d){if(a.calledRun)d(a);
else{var c=a.onRuntimeInitialized;a.onRuntimeInitialized=function(){c&&c();d(a)}}return a};na.prototype=Error();na.prototype.constructor=na;ra=function c(){a.calledRun||wa();a.calledRun||(ra=c)};a.run=wa;a.exit=function(c,b){if(!b||!a.noExitRuntime||0!==c){if(!a.noExitRuntime&&(oa=!0,ta=void 0,B(ob),a.onExit))a.onExit(c);qa&&process.exit(c);a.quit(c,new na(c))}};a.abort=O;if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();a.noExitRuntime=!0;
wa();m.prototype=Object.create(m.prototype);m.prototype.constructor=m;m.prototype.__class__=m;m.__cache__={};a.WrapperObject=m;a.getCache=t;a.wrapPointer=T;a.castObject=function(a,b){return T(a.ptr,b)};a.NULL=T(0);a.destroy=function(a){if(!a.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";a.__destroy__();delete t(a.__class__)[a.ptr]};a.compare=function(a,b){return a.ptr===b.ptr};a.getPointer=function(a){return a.ptr};a.getClass=function(a){return a.__class__};var l=
{buffer:0,size:0,pos:0,temps:[],needed:0,prepare:function(){if(l.needed){for(var c=0;c<l.temps.length;c++)a._free(l.temps[c]);l.temps.length=0;a._free(l.buffer);l.buffer=0;l.size+=l.needed;l.needed=0}l.buffer||(l.size+=128,l.buffer=a._malloc(l.size),f(l.buffer));l.pos=0},alloc:function(c,b){f(l.buffer);c=c.length*b.BYTES_PER_ELEMENT;c=c+7&-8;l.pos+c>=l.size?(f(0<c),l.needed+=c,b=a._malloc(c),l.temps.push(b)):(b=l.buffer+l.pos,l.pos+=c);return b},copy:function(a,b,d){switch(b.BYTES_PER_ELEMENT){case 2:d>>=
1;break;case 4:d>>=2;break;case 8:d>>=3}for(var c=0;c<a.length;c++)b[d+c]=a[c]}};z.prototype=Object.create(m.prototype);z.prototype.constructor=z;z.prototype.__class__=z;z.__cache__={};a.Status=z;z.prototype.code=z.prototype.code=function(){return Yc(this.ptr)};z.prototype.ok=z.prototype.ok=function(){return!!$c(this.ptr)};z.prototype.error_msg=z.prototype.error_msg=function(){return u(Zc(this.ptr))};z.prototype.__destroy__=z.prototype.__destroy__=function(){Xc(this.ptr)};F.prototype=Object.create(m.prototype);
F.prototype.constructor=F;F.prototype.__class__=F;F.__cache__={};a.DracoUInt16Array=F;F.prototype.GetValue=F.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return lc(c,a)};F.prototype.size=F.prototype.size=function(){return nc(this.ptr)};F.prototype.__destroy__=F.prototype.__destroy__=function(){mc(this.ptr)};G.prototype=Object.create(m.prototype);G.prototype.constructor=G;G.prototype.__class__=G;G.__cache__={};a.PointCloud=G;G.prototype.num_attributes=G.prototype.num_attributes=
function(){return Vc(this.ptr)};G.prototype.num_points=G.prototype.num_points=function(){return Wc(this.ptr)};G.prototype.__destroy__=G.prototype.__destroy__=function(){Uc(this.ptr)};H.prototype=Object.create(m.prototype);H.prototype.constructor=H;H.prototype.__class__=H;H.__cache__={};a.DracoUInt8Array=H;H.prototype.GetValue=H.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return rc(c,a)};H.prototype.size=H.prototype.size=function(){return tc(this.ptr)};H.prototype.__destroy__=
H.prototype.__destroy__=function(){sc(this.ptr)};I.prototype=Object.create(m.prototype);I.prototype.constructor=I;I.prototype.__class__=I;I.__cache__={};a.DracoUInt32Array=I;I.prototype.GetValue=I.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return oc(c,a)};I.prototype.size=I.prototype.size=function(){return qc(this.ptr)};I.prototype.__destroy__=I.prototype.__destroy__=function(){pc(this.ptr)};J.prototype=Object.create(m.prototype);J.prototype.constructor=J;J.prototype.__class__=
J;J.__cache__={};a.AttributeOctahedronTransform=J;J.prototype.InitFromAttribute=J.prototype.InitFromAttribute=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return!!rb(c,a)};J.prototype.quantization_bits=J.prototype.quantization_bits=function(){return tb(this.ptr)};J.prototype.__destroy__=J.prototype.__destroy__=function(){sb(this.ptr)};n.prototype=Object.create(m.prototype);n.prototype.constructor=n;n.prototype.__class__=n;n.__cache__={};a.PointAttribute=n;n.prototype.size=n.prototype.size=
function(){return Sc(this.ptr)};n.prototype.GetAttributeTransformData=n.prototype.GetAttributeTransformData=function(){return T(Kc(this.ptr),P)};n.prototype.attribute_type=n.prototype.attribute_type=function(){return Mc(this.ptr)};n.prototype.data_type=n.prototype.data_type=function(){return Pc(this.ptr)};n.prototype.num_components=n.prototype.num_components=function(){return Rc(this.ptr)};n.prototype.normalized=n.prototype.normalized=function(){return!!Qc(this.ptr)};n.prototype.byte_stride=n.prototype.byte_stride=
function(){return Oc(this.ptr)};n.prototype.byte_offset=n.prototype.byte_offset=function(){return Nc(this.ptr)};n.prototype.unique_id=n.prototype.unique_id=function(){return Tc(this.ptr)};n.prototype.__destroy__=n.prototype.__destroy__=function(){Lc(this.ptr)};P.prototype=Object.create(m.prototype);P.prototype.constructor=P;P.prototype.__class__=P;P.__cache__={};a.AttributeTransformData=P;P.prototype.transform_type=P.prototype.transform_type=function(){return Ab(this.ptr)};P.prototype.__destroy__=
P.prototype.__destroy__=function(){zb(this.ptr)};x.prototype=Object.create(m.prototype);x.prototype.constructor=x;x.prototype.__class__=x;x.__cache__={};a.AttributeQuantizationTransform=x;x.prototype.InitFromAttribute=x.prototype.InitFromAttribute=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return!!ub(c,a)};x.prototype.quantization_bits=x.prototype.quantization_bits=function(){return xb(this.ptr)};x.prototype.min_value=x.prototype.min_value=function(a){var c=this.ptr;a&&"object"===
typeof a&&(a=a.ptr);return wb(c,a)};x.prototype.range=x.prototype.range=function(){return yb(this.ptr)};x.prototype.__destroy__=x.prototype.__destroy__=function(){vb(this.ptr)};K.prototype=Object.create(m.prototype);K.prototype.constructor=K;K.prototype.__class__=K;K.__cache__={};a.DracoInt8Array=K;K.prototype.GetValue=K.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return ic(c,a)};K.prototype.size=K.prototype.size=function(){return kc(this.ptr)};K.prototype.__destroy__=
K.prototype.__destroy__=function(){jc(this.ptr)};q.prototype=Object.create(m.prototype);q.prototype.constructor=q;q.prototype.__class__=q;q.__cache__={};a.MetadataQuerier=q;q.prototype.HasEntry=q.prototype.HasEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return!!Ec(c,a,b)};q.prototype.HasIntEntry=q.prototype.HasIntEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);
return!!Fc(c,a,b)};q.prototype.GetIntEntry=q.prototype.GetIntEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return Bc(c,a,b)};q.prototype.HasDoubleEntry=q.prototype.HasDoubleEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return!!Dc(c,a,b)};q.prototype.GetDoubleEntry=q.prototype.GetDoubleEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=
a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return zc(c,a,b)};q.prototype.HasStringEntry=q.prototype.HasStringEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return!!Gc(c,a,b)};q.prototype.GetStringEntry=q.prototype.GetStringEntry=function(a,b){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return u(Cc(c,a,b))};q.prototype.NumEntries=q.prototype.NumEntries=function(a){var c=this.ptr;
a&&"object"===typeof a&&(a=a.ptr);return Hc(c,a)};q.prototype.GetEntryName=q.prototype.GetEntryName=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return u(Ac(c,a,b))};q.prototype.__destroy__=q.prototype.__destroy__=function(){Ic(this.ptr)};L.prototype=Object.create(m.prototype);L.prototype.constructor=L;L.prototype.__class__=L;L.__cache__={};a.DracoInt16Array=L;L.prototype.GetValue=L.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&
(a=a.ptr);return cc(c,a)};L.prototype.size=L.prototype.size=function(){return ec(this.ptr)};L.prototype.__destroy__=L.prototype.__destroy__=function(){dc(this.ptr)};M.prototype=Object.create(m.prototype);M.prototype.constructor=M;M.prototype.__class__=M;M.__cache__={};a.DracoFloat32Array=M;M.prototype.GetValue=M.prototype.GetValue=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return $b(c,a)};M.prototype.size=M.prototype.size=function(){return bc(this.ptr)};M.prototype.__destroy__=M.prototype.__destroy__=
function(){ac(this.ptr)};V.prototype=Object.create(m.prototype);V.prototype.constructor=V;V.prototype.__class__=V;V.__cache__={};a.GeometryAttribute=V;V.prototype.__destroy__=V.prototype.__destroy__=function(){uc(this.ptr)};Q.prototype=Object.create(m.prototype);Q.prototype.constructor=Q;Q.prototype.__class__=Q;Q.__cache__={};a.DecoderBuffer=Q;Q.prototype.Init=Q.prototype.Init=function(a,b){var c=this.ptr;l.prepare();if("object"==typeof a&&"object"===typeof a){var d=l.alloc(a,ia);l.copy(a,ia,d);a=
d}b&&"object"===typeof b&&(b=b.ptr);Bb(c,a,b)};Q.prototype.__destroy__=Q.prototype.__destroy__=function(){Cb(this.ptr)};g.prototype=Object.create(m.prototype);g.prototype.constructor=g;g.prototype.__class__=g;g.__cache__={};a.Decoder=g;g.prototype.GetEncodedGeometryType=g.prototype.GetEncodedGeometryType=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return Ub(c,a)};g.prototype.DecodeBufferToPointCloud=g.prototype.DecodeBufferToPointCloud=function(a,b){var c=this.ptr;a&&"object"===typeof a&&
(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return T(Eb(c,a,b),z)};g.prototype.DecodeBufferToMesh=g.prototype.DecodeBufferToMesh=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return T(Db(c,a,b),z)};g.prototype.GetAttributeId=g.prototype.GetAttributeId=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return Kb(c,a,b)};g.prototype.GetAttributeIdByName=g.prototype.GetAttributeIdByName=function(a,b){var c=
this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);return Jb(c,a,b)};g.prototype.GetAttributeIdByMetadataEntry=g.prototype.GetAttributeIdByMetadataEntry=function(a,b,d){var c=this.ptr;l.prepare();a&&"object"===typeof a&&(a=a.ptr);b=b&&"object"===typeof b?b.ptr:U(b);d=d&&"object"===typeof d?d.ptr:U(d);return Ib(c,a,b,d)};g.prototype.GetAttribute=g.prototype.GetAttribute=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=
b.ptr);return T(Tb(c,a,b),n)};g.prototype.GetAttributeByUniqueId=g.prototype.GetAttributeByUniqueId=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return T(Fb(c,a,b),n)};g.prototype.GetMetadata=g.prototype.GetMetadata=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return T(Wb(c,a),R)};g.prototype.GetAttributeMetadata=g.prototype.GetAttributeMetadata=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&
(b=b.ptr);return T(Pb(c,a,b),R)};g.prototype.GetFaceFromMesh=g.prototype.GetFaceFromMesh=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Vb(c,a,b,d)};g.prototype.GetTriangleStripsFromMesh=g.prototype.GetTriangleStripsFromMesh=function(a,b){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);return Xb(c,a,b)};g.prototype.GetAttributeFloat=g.prototype.GetAttributeFloat=function(a,
b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Hb(c,a,b,d)};g.prototype.GetAttributeFloatForAllPoints=g.prototype.GetAttributeFloatForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Gb(c,a,b,d)};g.prototype.GetAttributeIntForAllPoints=g.prototype.GetAttributeIntForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===
typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ob(c,a,b,d)};g.prototype.GetAttributeInt8ForAllPoints=g.prototype.GetAttributeInt8ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Nb(c,a,b,d)};g.prototype.GetAttributeUInt8ForAllPoints=g.prototype.GetAttributeUInt8ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===
typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Sb(c,a,b,d)};g.prototype.GetAttributeInt16ForAllPoints=g.prototype.GetAttributeInt16ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Lb(c,a,b,d)};g.prototype.GetAttributeUInt16ForAllPoints=g.prototype.GetAttributeUInt16ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&
"object"===typeof d&&(d=d.ptr);return!!Qb(c,a,b,d)};g.prototype.GetAttributeInt32ForAllPoints=g.prototype.GetAttributeInt32ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Mb(c,a,b,d)};g.prototype.GetAttributeUInt32ForAllPoints=g.prototype.GetAttributeUInt32ForAllPoints=function(a,b,d){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);b&&"object"===typeof b&&(b=b.ptr);d&&"object"===typeof d&&(d=
d.ptr);return!!Rb(c,a,b,d)};g.prototype.SkipAttributeTransform=g.prototype.SkipAttributeTransform=function(a){var c=this.ptr;a&&"object"===typeof a&&(a=a.ptr);Yb(c,a)};g.prototype.__destroy__=g.prototype.__destroy__=function(){Zb(this.ptr)};C.prototype=Object.create(m.prototype);C.prototype.constructor=C;C.prototype.__class__=C;C.__cache__={};a.Mesh=C;C.prototype.num_faces=C.prototype.num_faces=function(){return xc(this.ptr)};C.prototype.num_attributes=C.prototype.num_attributes=function(){return wc(this.ptr)};
C.prototype.num_points=C.prototype.num_points=function(){return yc(this.ptr)};C.prototype.__destroy__=C.prototype.__destroy__=function(){vc(this.ptr)};X.prototype=Object.create(m.prototype);X.prototype.constructor=X;X.prototype.__class__=X;X.__cache__={};a.VoidPtr=X;X.prototype.__destroy__=X.prototype.__destroy__=function(){ad(this.ptr)};N.prototype=Object.create(m.prototype);N.prototype.constructor=N;N.prototype.__class__=N;N.__cache__={};a.DracoInt32Array=N;N.prototype.GetValue=N.prototype.GetValue=
function(a){var b=this.ptr;a&&"object"===typeof a&&(a=a.ptr);return fc(b,a)};N.prototype.size=N.prototype.size=function(){return hc(this.ptr)};N.prototype.__destroy__=N.prototype.__destroy__=function(){gc(this.ptr)};R.prototype=Object.create(m.prototype);R.prototype.constructor=R;R.prototype.__class__=R;R.__cache__={};a.Metadata=R;R.prototype.__destroy__=R.prototype.__destroy__=function(){Jc(this.ptr)};(function(){function c(){a.OK=rd();a.ERROR=od();a.IO_ERROR=qd();a.INVALID_PARAMETER=pd();a.UNSUPPORTED_VERSION=
td();a.UNKNOWN_VERSION=sd();a.INVALID_GEOMETRY_TYPE=fd();a.POINT_CLOUD=gd();a.TRIANGULAR_MESH=hd();a.ATTRIBUTE_INVALID_TRANSFORM=bd();a.ATTRIBUTE_NO_TRANSFORM=cd();a.ATTRIBUTE_QUANTIZATION_TRANSFORM=ed();a.ATTRIBUTE_OCTAHEDRON_TRANSFORM=dd();a.INVALID=kd();a.POSITION=md();a.NORMAL=ld();a.COLOR=id();a.TEX_COORD=nd();a.GENERIC=jd()}a.calledRun?c():Na.unshift(c)})();if("function"===typeof a.onModuleParsed)a.onModuleParsed();return d};
"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 B

View file

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/png" href="icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#000000" />
</head>
<body>
<noscript>Your browser has JavaScript disabled, please enable it.</noscript>
<div id="root"></div>
</body>
</html>

View file

Before

Width:  |  Height:  |  Size: 989 KiB

After

Width:  |  Height:  |  Size: 989 KiB

View file

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 149 KiB

View file

Before

Width:  |  Height:  |  Size: 888 KiB

After

Width:  |  Height:  |  Size: 888 KiB

View file

Before

Width:  |  Height:  |  Size: 500 KiB

After

Width:  |  Height:  |  Size: 500 KiB

View file

Before

Width:  |  Height:  |  Size: 457 KiB

After

Width:  |  Height:  |  Size: 457 KiB

View file

Before

Width:  |  Height:  |  Size: 729 KiB

After

Width:  |  Height:  |  Size: 729 KiB

View file

Before

Width:  |  Height:  |  Size: 449 KiB

After

Width:  |  Height:  |  Size: 449 KiB

View file

Before

Width:  |  Height:  |  Size: 892 KiB

After

Width:  |  Height:  |  Size: 892 KiB

View file

@ -1,35 +0,0 @@
import React, { useEffect } from "react";
import "./static/css/page.css";
import Game from "./dom-components/Game";
import { HashRouter, Route, Switch } from "react-router-dom";
import Notes from "./dom-components/Notes";
import MainPage from "./dom-components/MainPage";
import Guide from "./dom-components/Guide";
import Options from "./dom-components/Options";
import { useStore } from "./store";
const App = () => {
const setKeybindings = useStore((state) => state.setKeybindings);
const setLanguage = useStore((state) => state.setLanguage);
useEffect(() => {
const keybindingSettings = localStorage.getItem("lainKeybindings");
const language = localStorage.getItem("lainLanguage");
if (keybindingSettings) setKeybindings(JSON.parse(keybindingSettings));
if (language) setLanguage(JSON.parse(language));
}, [setKeybindings, setLanguage]);
return (
<HashRouter>
<Switch>
<Route path={"/"} exact component={MainPage} />
<Route path={"/notes"} exact component={Notes} />
<Route path={"/game"} exact component={Game} />
<Route path={"/guide"} exact component={Guide} />
<Route path={"/options"} exact component={Options} />
</Switch>
</HashRouter>
);
};
export default App;

View file

@ -1,50 +0,0 @@
import { isPolytanFullyUnlocked } from "../../store";
import { useStore } from "../../store";
const initialStoreState = useStore.getState();
describe("Idle helpers", () => {
it("Checks if polytan unlock works properly", () => {
expect(isPolytanFullyUnlocked()).toEqual(false);
const fullyUnlocked = {
body: true,
head: true,
left_arm: true,
right_arm: true,
left_leg: true,
right_leg: true,
};
const state = useStore.getState();
useStore.setState({
gameProgress: {
...state.gameProgress,
polytan_unlocked_parts: fullyUnlocked,
},
});
expect(isPolytanFullyUnlocked()).toEqual(true);
const partiallyUnlocked = {
body: false,
head: true,
left_arm: false,
right_arm: true,
left_leg: true,
right_leg: true,
};
useStore.setState({
gameProgress: {
...state.gameProgress,
polytan_unlocked_parts: partiallyUnlocked,
},
});
expect(isPolytanFullyUnlocked()).toEqual(false);
});
beforeEach(() => {
useStore.setState(initialStoreState, true);
});
});

View file

@ -1,37 +0,0 @@
import { findNodeFromWord } from "../../helpers/media-helpers";
it("Finds the next node with the same word", () => {
expect(findNodeFromWord("father", "Cou041", "b").node.node_name).toEqual(
"Lda151"
);
expect(findNodeFromWord("father", "Lda151", "b").node.node_name).toEqual(
"Lda155"
);
expect(findNodeFromWord("father", "Lda155", "b").node.node_name).toEqual(
"Lda164"
);
expect(findNodeFromWord("father", "Lda182", "b").node.node_name).toEqual(
"Lda200"
);
expect(findNodeFromWord("father", "Lda229", "b").node.node_name).toEqual(
"Cou041"
);
expect(findNodeFromWord("father", "Cou041", "b").node.node_name).toEqual(
"Lda151"
);
expect(findNodeFromWord("chaos", "Lda154", "b").node.node_name).toEqual(
"Tda056"
);
expect(findNodeFromWord("chaos", "Tda056", "b").node.node_name).toEqual(
"Tda059"
);
expect(findNodeFromWord("prompt", "Lda154", "b").node.node_name).toEqual(
"Tda072"
);
expect(findNodeFromWord("abuse", "Dc1012", "a").node.node_name).toEqual(
"Lda005"
);
expect(findNodeFromWord("abuse", "Lda005", "a").node.node_name).toEqual(
"Dc1012"
);
});

View file

@ -1,29 +0,0 @@
import { handleNameSelection } from "../../helpers/name-selection-helpers";
it("Handles the logic for Japanese characters", () => {
// cant be first character check
expect(handleNameSelection("", "ン")).toEqual(undefined);
// if its not first, then fine
expect(handleNameSelection("キ", "ン")).toEqual("キン");
//「ー」 cannot be added to 「ッ」 and 「ン」or itself
expect(handleNameSelection("キッ", "ー")).toEqual(undefined);
expect(handleNameSelection("キン", "ー")).toEqual(undefined);
expect(handleNameSelection("キー", "ー")).toEqual(undefined);
// characters that can be followed by the lowercase characters
expect(handleNameSelection("キ", "ャ")).toEqual("キャ");
// cant be followed by lowercase character
expect(handleNameSelection("ー", "ャ")).toEqual(undefined);
// for 「ッ」, it can added to any character except itself
expect(handleNameSelection("ャ", "ッ")).toEqual("ャッ");
// cant be added
expect(handleNameSelection("ッ", "ッ")).toEqual(undefined);
// dakuten
expect(handleNameSelection("カ", "゛")).toEqual("ガ");
// cant be appended
expect(handleNameSelection("ガ", "゛")).toEqual(undefined);
// handakuten
expect(handleNameSelection("ハ", "゜")).toEqual("パ");
// cant be appended
expect(handleNameSelection("キ", "゜")).toEqual(undefined);
expect(handleNameSelection("パ", "゜")).toEqual(undefined);
});

View file

@ -1,158 +0,0 @@
import { findNode, unknownNodeTemplate } from "../../helpers/node-helpers";
import site_a from "../../resources/site_a.json";
import gameProgress from "../../resources/initial_progress.json";
/*
visual representation of the data we're working with
[null, "0517", null, null],
[null, null, "0510", "0513"],
["0506", null, null, null],
|
[null, null, null, "0422"], ["0422", "0417", null, null], [null, "0416", "0417", "0420"],
[null, null, null, "0414"], - ["0414", null, null, "0413"], - ["0413", null, null, null],
[null, null, null, null], [null, null, null, "0405"], ["0405", null, null, null],
|
[null, null, null, null] [null, null, null, null], [null, null, null, null],
[null, null, null, null], [null, null, null, null], [null, null, null, null],
[null, null, null, null], [null, null, null, null], [null, null, null, null],
*/
const middleMatrixIdx = 7;
const leftMatrixIdx = 8;
it("Finds which node to go to", () => {
// from unknown to left unknown
expect(
findNode(
{
...unknownNodeTemplate,
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 2, colIdx: 3 },
},
"left",
3,
"a",
gameProgress,
true
)
).toEqual({
node: "unknown",
matrixIndices: { rowIdx: 2, colIdx: 3, matrixIdx: leftMatrixIdx },
didMove: true,
});
// from 0405 down
expect(
findNode(
{
...site_a["04"]["0405"],
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 2, colIdx: 3 },
},
"down",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "unknown",
matrixIndices: { rowIdx: 2, colIdx: 3, matrixIdx: middleMatrixIdx },
didMove: true,
});
// from 0422 (from left matrix) right
expect(
findNode(
{
...site_a["04"]["0422"],
matrixIndices: { matrixIdx: 8, rowIdx: 0, colIdx: 3 },
},
"right",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "0413",
matrixIndices: { rowIdx: 1, colIdx: 3, matrixIdx: 7 },
didMove: true,
});
// from 0422 left
expect(
findNode(
{
...site_a["04"]["0422"],
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 0, colIdx: 0 },
},
"left",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "0422",
matrixIndices: { rowIdx: 0, colIdx: 3, matrixIdx: 8 },
didMove: true,
});
// from 0422 up
expect(
findNode(
{
...site_a["04"]["0422"],
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 0, colIdx: 0 },
},
"up",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "0506",
matrixIndices: { rowIdx: 2, colIdx: 0, matrixIdx: 7 },
didMove: true,
});
// from 0422 right
expect(
findNode(
{
...site_a["04"]["0422"],
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 0, colIdx: 0 },
},
"right",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "0417",
matrixIndices: { rowIdx: 0, colIdx: 1, matrixIdx: 7 },
didMove: false,
});
// from 0414 up
expect(
findNode(
{
...site_a["04"]["0414"],
matrixIndices: { matrixIdx: middleMatrixIdx, rowIdx: 1, colIdx: 0 },
},
"up",
4,
"a",
gameProgress,
true
)
).toEqual({
node: "0422",
matrixIndices: { rowIdx: 0, colIdx: 0, matrixIdx: 7 },
didMove: false,
});
});

View file

@ -1,29 +0,0 @@
import { getNodeById, isNodeVisible } from "../../helpers/node-helpers";
import site_a from "../../resources/site_a.json";
import gameProgress from "../../resources/initial_progress.json";
it("Finds the node by it's id", () => {
expect(getNodeById("0422", "a").node_name).toEqual("Tda028");
expect(getNodeById("0000", "a").node_name).toEqual("Env001");
expect(getNodeById("0616", "a").node_name).toEqual("Cou015");
expect(getNodeById("0100", "b").node_name).toEqual("SSkn04#");
expect(getNodeById("0101", "b").node_name).toEqual("Dc1025");
});
const oneViewCount = { ...gameProgress, final_video_viewcount: 1 };
const twoViewCount = { ...gameProgress, final_video_viewcount: 2 };
const threeViewCount = { ...gameProgress, final_video_viewcount: 3 };
const fourViewCount = { ...gameProgress, final_video_viewcount: 4 };
it("Checks if the node is visible", () => {
expect(isNodeVisible(site_a["04"]["0422"], gameProgress)).toEqual(true);
expect(isNodeVisible(site_a["04"]["0413"], gameProgress)).toEqual(true);
expect(isNodeVisible(site_a["04"]["0406"], gameProgress)).toEqual(false);
expect(isNodeVisible(site_a["04"]["0410"], gameProgress)).toEqual(false);
expect(isNodeVisible(site_a["04"]["0406"], oneViewCount)).toEqual(true);
expect(isNodeVisible(site_a["06"]["0612"], gameProgress)).toEqual(false);
expect(isNodeVisible(site_a["06"]["0612"], oneViewCount)).toEqual(true);
expect(isNodeVisible(site_a["06"]["0612"], twoViewCount)).toEqual(true);
expect(isNodeVisible(site_a["08"]["0801"], fourViewCount)).toEqual(true);
expect(isNodeVisible(site_a["08"]["0801"], threeViewCount)).toEqual(false);
});

View file

@ -1,87 +0,0 @@
import * as eventTemplates from "../../core/eventTemplates";
import { getBootSceneContext } from "../../store";
import handleBootSceneInput from "../../core/input-handlers/handleBootSceneInput";
import {
enterLoadData,
enterUserAuthorization,
exitUserAuthorization,
startNewGame,
} from "../../core/eventTemplates";
import { BootSubscene, MainMenuComponent } from "../../types/types";
it("Checks whether or not the boot scene input handler reacts appropriately for each input", () => {
{
// change main menu active component
const spy = jest.spyOn(eventTemplates, "changeMainMenuComponent");
const testContext = getBootSceneContext();
handleBootSceneInput(testContext, "UP");
expect(spy).toHaveBeenCalled();
}
// select main menu component
{
const testContext = {
...getBootSceneContext(),
activeMainMenuComponent: "authorize_user" as MainMenuComponent,
};
expect(handleBootSceneInput(testContext, "CIRCLE")).toEqual(
enterUserAuthorization
);
}
{
const testContext = {
...getBootSceneContext(),
activeMainMenuComponent: "load_data" as MainMenuComponent,
};
expect(handleBootSceneInput(testContext, "CIRCLE")).toEqual(enterLoadData);
}
{
// change letter in authorize user scene
const spy = jest.spyOn(
eventTemplates,
"updateAuthorizeUserLetterMatrixIndices"
);
const testContext = {
...getBootSceneContext(),
subscene: "authorize_user" as BootSubscene,
};
handleBootSceneInput(testContext, "RIGHT");
expect(spy).toHaveBeenCalled();
}
{
// start new game
const testContext = {
...getBootSceneContext(),
subscene: "authorize_user" as BootSubscene,
playerName: "チ",
};
expect(handleBootSceneInput(testContext, "START")).toEqual(startNewGame);
}
{
// delete last char if player name is not empty
const spy = jest.spyOn(eventTemplates, "removePlayerNameLastChar");
const testContext = {
...getBootSceneContext(),
subscene: "authorize_user" as BootSubscene,
playerName: "チ",
};
handleBootSceneInput(testContext, "CROSS");
expect(spy).toHaveBeenCalled();
}
{
// go back to main menu if player name is empty
const testContext = {
...getBootSceneContext(),
subscene: "authorize_user" as BootSubscene,
playerName: "",
};
expect(handleBootSceneInput(testContext, "CROSS")).toEqual(
exitUserAuthorization
);
}
});

View file

@ -1,38 +0,0 @@
import * as eventTemplates from "../../core/eventTemplates";
import { getEndSceneContext } from "../../store";
import handleEndSceneInput from "../../core/input-handlers/handleEndSceneInput";
import { EndComponent } from "../../types/types";
it("Checks whether or not the end scene input handler reacts appropriately for each input", () => {
{
// changing end active component
const spy = jest.spyOn(eventTemplates, "changeEndComponent");
const testContext = { ...getEndSceneContext(), selectionVisible: true };
handleEndSceneInput(testContext, "DOWN");
expect(spy).toHaveBeenCalled();
}
// selecting end component
{
const spy = jest.spyOn(eventTemplates, "endGame");
const testContext = { ...getEndSceneContext(), selectionVisible: true };
handleEndSceneInput(testContext, "CIRCLE");
expect(spy).toHaveBeenCalled();
}
{
const spy = jest.spyOn(eventTemplates, "changeSite");
const testContext = {
...getEndSceneContext(),
selectionVisible: true,
activeEndComponent: "continue" as EndComponent,
};
handleEndSceneInput(testContext, "CIRCLE");
expect(spy).toHaveBeenCalled();
}
});

View file

@ -1,131 +0,0 @@
import { getMainSceneContext } from "../../store";
import handleMainSceneInput from "../../core/input-handlers/handleMainSceneInput";
import * as eventTemplates from "../../core/eventTemplates";
import site_a from "../../resources/site_a.json";
import {
enterLevelSelection,
pauseGame,
ripNode,
showAbout,
throwNode,
} from "../../core/eventTemplates";
import { nodeToScene } from "../../helpers/node-helpers";
import { PauseComponent } from "../../types/types";
const expectOr = (...tests: (() => void)[]) => {
try {
tests.shift()!();
} catch (e) {
if (tests.length) expectOr(...tests);
else throw e;
}
};
it("Checks whether or not the main scene input handler reacts appropriately for each input", () => {
{
const spy = jest.spyOn(eventTemplates, "changeNode");
const testContext = getMainSceneContext();
handleMainSceneInput(testContext, "UP");
expect(spy).toHaveBeenCalled();
}
{
// move vertically when utmost up node is currently selected
const spy = jest.spyOn(eventTemplates, "siteMoveVertical");
const testContext = {
...getMainSceneContext(),
activeNode: {
...site_a["04"]["0422"],
matrixIndices: { matrixIdx: 7, rowIdx: 0, colIdx: 0 },
},
};
handleMainSceneInput(testContext, "UP");
expect(spy).toHaveBeenCalled();
}
{
// move horizontally when utmost left node is currently selected
const spy = jest.spyOn(eventTemplates, "siteMoveHorizontal");
const testContext = getMainSceneContext();
handleMainSceneInput(testContext, "LEFT");
expect(spy).toHaveBeenCalled();
}
{
// play throw node/rip node animation and set the scene when the player selects a node
const testContext = getMainSceneContext();
const output = handleMainSceneInput(testContext, "CIRCLE");
expectOr(
() =>
expect(output).toEqual(
ripNode({ currentScene: nodeToScene(testContext.activeNode)! })
),
() =>
expect(output).toEqual(
throwNode({ currentScene: nodeToScene(testContext.activeNode)! })
)
);
}
{
// entering level selection
const testContext = getMainSceneContext();
expect(handleMainSceneInput(testContext, "L2")).toEqual(
enterLevelSelection({ selectedLevel: testContext.level })
);
}
{
// entering pause
const testContext = getMainSceneContext();
expect(handleMainSceneInput(testContext, "TRIANGLE")).toEqual(
pauseGame({ siteRot: [Math.PI / 2, testContext.siteRotY, 0] })
);
}
{
// changing level inside level selection
const spy = jest.spyOn(eventTemplates, "changeSelectedLevel");
const testContext = {
...getMainSceneContext(),
subscene: "level_selection",
};
handleMainSceneInput(testContext, "UP");
expect(spy).toHaveBeenCalled();
}
{
// selecting new level when currently below it
const spy = jest.spyOn(eventTemplates, "selectLevel");
const testContext = {
...getMainSceneContext(),
selectedLevel: 10,
subscene: "level_selection",
};
handleMainSceneInput(testContext, "CIRCLE");
expect(spy).toHaveBeenCalled();
}
{
// changing pause active component
const spy = jest.spyOn(eventTemplates, "changePauseComponent");
const testContext = {
...getMainSceneContext(),
subscene: "pause",
};
handleMainSceneInput(testContext, "UP");
expect(spy).toHaveBeenCalled();
}
{
// selecting pause component
const testContext = {
...getMainSceneContext(),
subscene: "pause",
activePauseComponent: "about" as PauseComponent,
};
expect(handleMainSceneInput(testContext, "CIRCLE")).toEqual(showAbout);
}
});

View file

@ -1,67 +0,0 @@
import * as eventTemplates from "../../core/eventTemplates";
import { exitMedia } from "../../core/eventTemplates";
import { getMediaSceneContext } from "../../store";
import handleMediaSceneInput from "../../core/input-handlers/handleMediaSceneInput";
import { LeftMediaComponent, MediaSide } from "../../types/types";
it("Checks whether or not the media scene input handler reacts appropriately for each input", () => {
{
// changing left side media active component
const spy = jest.spyOn(eventTemplates, "changeLeftMediaComponent");
const testContext = getMediaSceneContext();
handleMediaSceneInput(testContext, "DOWN");
expect(spy).toHaveBeenCalled();
}
{
// changing media side from left to right
const spy = jest.spyOn(eventTemplates, "changeMediaSide");
const testContext = getMediaSceneContext();
handleMediaSceneInput(testContext, "RIGHT");
expect(spy).toHaveBeenCalled();
}
{
// exit media
const testContext = {
...getMediaSceneContext(),
activeMediaComponent: "exit" as LeftMediaComponent,
};
expect(handleMediaSceneInput(testContext, "CIRCLE")).toEqual(exitMedia);
}
{
// play media
// const testContext = getMediaSceneContext();
// expect(handleMediaSceneInput(testContext, "CIRCLE")).toEqual(
// eventTemplates.playMedia
// );
}
{
// change right side media component
const spy = jest.spyOn(eventTemplates, "changeRightMediaComponent");
const testContext = {
...getMediaSceneContext(),
currentMediaSide: "right" as MediaSide,
};
handleMediaSceneInput(testContext, "DOWN");
expect(spy).toHaveBeenCalled();
}
{
// change from right side to left
const spy = jest.spyOn(eventTemplates, "changeMediaSide");
const testContext = {
...getMediaSceneContext(),
currentMediaSide: "right" as MediaSide,
};
handleMediaSceneInput(testContext, "LEFT");
expect(spy).toHaveBeenCalled();
}
});

View file

@ -1,34 +0,0 @@
import * as eventTemplates from "../../core/eventTemplates";
import { getSsknSceneContext } from "../../store";
import handleSsknSceneInput from "../../core/input-handlers/handleSsknSceneInput";
import { exitSskn } from "../../core/eventTemplates";
import { SsknComponent } from "../../types/types";
it("Checks whether or not the sskn scene input handler reacts appropriately for each input", () => {
{
// changing sskn active component
const spy = jest.spyOn(eventTemplates, "changeSsknComponent");
const testContext = getSsknSceneContext();
handleSsknSceneInput(testContext, "DOWN");
expect(spy).toHaveBeenCalled();
}
{
// select ok
const spy = jest.spyOn(eventTemplates, "upgradeSskn");
const testContext = getSsknSceneContext();
handleSsknSceneInput(testContext, "CIRCLE");
expect(spy).toHaveBeenCalled();
}
{
// select cancel
const testContext = {
...getSsknSceneContext(),
activeSsknComponent: "cancel" as SsknComponent,
};
expect(handleSsknSceneInput(testContext, "CIRCLE")).toEqual(exitSskn);
}
});

View file

@ -1,9 +0,0 @@
import { getCurrentUserState } from "../store";
it("Checks if setting state on localStorage works", () => {
const spy = jest.spyOn(Storage.prototype, "setItem");
const saveState = JSON.stringify(getCurrentUserState());
localStorage.setItem("lainSaveState", saveState);
expect(spy).toHaveBeenCalledTimes(1);
expect(localStorage.getItem("lainSaveState")).toEqual(saveState);
});

15
src/additional.d.ts vendored Normal file
View file

@ -0,0 +1,15 @@
declare module "*.mp4" {
const src: string;
export default src;
}
declare module "*.vert" {
const content: string;
export default content;
}
declare module "*.frag" {
const content: string;
export default content;
}

View file

@ -1,332 +0,0 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import bootLof from "../../static/sprites/boot/boot_lof.png";
import bootBottomBarLeft from "../../static/sprites/boot/boot_bottom_bar_left.png";
import bootBottomBarRight from "../../static/sprites/boot/boot_bottom_bar_right.png";
import bootPurpleSquare from "../../static/sprites/boot/boot_purple_square.png";
import bootGraySquare from "../../static/sprites/boot/boot_gray_square.png";
import bootDangoText from "../../static/sprites/boot/dango_text.png";
import bootMisoShio from "../../static/sprites/boot/miso_shio.png";
import bootArrows from "../../static/sprites/boot/boot_arrows.png";
import bootStatusTexts from "../../static/sprites/boot/boot_status_texts.png";
import bootBackgroundText from "../../static/sprites/boot/boot_background_text.png";
import bootBackgroundDistortedTex from "../../static/sprites/boot/distorted_text.png";
import { useFrame, useLoader } from "react-three-fiber";
import { a, useSpring } from "@react-spring/three";
import * as THREE from "three";
import sleep from "../../utils/sleep";
type BootAnimationProps = {
visible: boolean;
mainMenuVisible: boolean;
activeSubScene: string;
};
const BootAnimation = (props: BootAnimationProps) => {
const [
backgroundFloatingTextShown,
setBackgroundFloatingTextShown,
] = useState(false);
const bootLofTex = useLoader(THREE.TextureLoader, bootLof);
const bootBottomBarLeftTex = useLoader(
THREE.TextureLoader,
bootBottomBarLeft
);
const bootBottomBarRightTex = useLoader(
THREE.TextureLoader,
bootBottomBarRight
);
const bootPurpleSquareTex = useLoader(THREE.TextureLoader, bootPurpleSquare);
const bootGraySquareTex = useLoader(THREE.TextureLoader, bootGraySquare);
const bootDangoTextTex = useLoader(THREE.TextureLoader, bootDangoText);
const bootMisoShioTex = useLoader(THREE.TextureLoader, bootMisoShio);
const bootArrowsTex = useLoader(THREE.TextureLoader, bootArrows);
const bootStatusTextsTex = useLoader(THREE.TextureLoader, bootStatusTexts);
const bootBackgroundTextTex = useLoader(
THREE.TextureLoader,
bootBackgroundText
);
const bootBackgroundDistortedTextTex = useLoader(
THREE.TextureLoader,
bootBackgroundDistortedTex
);
const graySquareRef = useRef<THREE.SpriteMaterial>();
const arrowRef = useRef<THREE.Object3D>();
const deltaRef = useRef(0);
useFrame((state, delta) => {
deltaRef.current += delta;
if (deltaRef.current > 0.016) {
if (graySquareRef.current) {
graySquareRef.current.rotation -= 0.1;
}
if (arrowRef.current && Date.now() % 5 === 0) {
arrowRef.current.position.y =
arrowRef.current.position.y === -1.04 ? -0.96 : -1.04;
}
if (
backgroundFloatingTextShown &&
firstBackgroundTextRef.current &&
sndBackgroundTextRef.current &&
firstDistortedBackgroundTextRef.current &&
sndDistortedBackgroundTextRef.current
) {
if (firstBackgroundTextRef.current.position.y > 3.5) {
firstBackgroundTextRef.current.position.y = -3.5;
firstBackgroundTextRef.current.position.x = -0.85;
} else {
firstBackgroundTextRef.current.position.y += 0.01;
firstBackgroundTextRef.current.position.x += 0.001;
}
if (sndBackgroundTextRef.current.position.y > 3.5) {
sndBackgroundTextRef.current.position.y = -3.5;
sndBackgroundTextRef.current.position.x = -0.85;
} else {
sndBackgroundTextRef.current.position.y += 0.01;
sndBackgroundTextRef.current.position.x += 0.001;
}
if (firstDistortedBackgroundTextRef.current.position.y > 2.8) {
firstDistortedBackgroundTextRef.current.position.y = -3;
firstDistortedBackgroundTextRef.current.position.x = 0;
} else {
firstDistortedBackgroundTextRef.current.position.y += 0.025;
firstDistortedBackgroundTextRef.current.position.x -= 0.013;
}
if (sndDistortedBackgroundTextRef.current.position.y > 2.8) {
sndDistortedBackgroundTextRef.current.position.y = -3;
sndDistortedBackgroundTextRef.current.position.x = 0;
} else {
sndDistortedBackgroundTextRef.current.position.y += 0.025;
sndDistortedBackgroundTextRef.current.position.x -= 0.013;
}
}
deltaRef.current = deltaRef.current % 0.016;
}
});
const currentBootStatusTextTex = useMemo(() => {
bootStatusTextsTex.offset.y = 0.79;
bootStatusTextsTex.repeat.set(0.5, 0.2);
return bootStatusTextsTex;
}, [bootStatusTextsTex]);
useEffect(() => {
if (props.visible) {
(async () => {
await sleep(900);
currentBootStatusTextTex.offset.y = 0.528;
await sleep(300);
currentBootStatusTextTex.offset.y = 0.79;
await sleep(300);
currentBootStatusTextTex.offset.y = 0.264;
await sleep(100);
currentBootStatusTextTex.offset.y = 0.79;
await sleep(500);
currentBootStatusTextTex.offset.x = 0.5;
currentBootStatusTextTex.offset.y = 0.264;
await sleep(300);
currentBootStatusTextTex.offset.x = 0;
currentBootStatusTextTex.offset.y = 0.005;
await sleep(100);
currentBootStatusTextTex.offset.y = 0.79;
})();
}
}, [bootBackgroundTextTex, currentBootStatusTextTex.offset, props.visible]);
useEffect(() => {
if (props.mainMenuVisible) {
currentBootStatusTextTex.offset.x = 0.5;
currentBootStatusTextTex.offset.y = 0.005;
setBootOpacity(0);
setGraySquarePosY(0);
setLofPosX(1.3);
setLofPosY(1);
setBackgroundFloatingTextShown(true);
}
}, [currentBootStatusTextTex.offset, props.mainMenuVisible]);
const [bootOpacity, setBootOpacity] = useState(1);
const [graySquarePosY, setGraySquarePosY] = useState(-0.8);
const [lofPosX, setLofPosX] = useState(0);
const [lofPosY, setLofPosY] = useState(0);
const bootState = useSpring({
bootOpacity: bootOpacity,
config: { duration: 300 },
});
const animationState = useSpring({
graySquarePosY: graySquarePosY,
lofPosX: lofPosX,
lofPosY: lofPosY,
lofOpacity: props.activeSubScene === "main_menu" ? 1 : 0,
graySquareOpacity: props.activeSubScene === "main_menu" ? 1 : 0,
config: { duration: 500 },
});
const firstBackgroundTextRef = useRef<THREE.Object3D>();
const sndBackgroundTextRef = useRef<THREE.Object3D>();
const firstDistortedBackgroundTextRef = useRef<THREE.Object3D>();
const sndDistortedBackgroundTextRef = useRef<THREE.Object3D>();
return (
<group visible={props.visible}>
<a.sprite
scale={[1.2, 0.4, 0]}
position-x={animationState.lofPosX}
position-y={animationState.lofPosY}
>
<a.spriteMaterial
attach="material"
map={bootLofTex}
opacity={animationState.lofOpacity}
/>
</a.sprite>
<a.sprite
scale={[0.2, 0.2, 0]}
position-y={animationState.graySquarePosY}
>
<a.spriteMaterial
attach="material"
map={bootGraySquareTex}
ref={graySquareRef}
opacity={animationState.graySquareOpacity}
/>
</a.sprite>
{props.activeSubScene !== "authorize_user" && (
<>
{/*we have two of each to create looping effect*/}
<a.sprite
scale={[1.5, 3.5, 0]}
renderOrder={-1}
position={[-0.85, -3.5, 0]}
ref={firstBackgroundTextRef}
>
<spriteMaterial
attach="material"
rotation={-0.1}
map={bootBackgroundTextTex}
transparent={true}
opacity={0.6}
/>
</a.sprite>
<a.sprite
scale={[1.5, 3.5, 0]}
renderOrder={-1}
position={[-1.2, -7, 0]}
ref={sndBackgroundTextRef}
>
<spriteMaterial
attach="material"
rotation={-0.1}
map={bootBackgroundTextTex}
transparent={true}
opacity={0.6}
/>
</a.sprite>
<group position={[1, 0, 0]}>
<a.sprite
scale={[1, 3.5, 0]}
renderOrder={-1}
position={[0, -3.5, 0]}
ref={firstDistortedBackgroundTextRef}
>
<spriteMaterial
attach="material"
rotation={0.5}
map={bootBackgroundDistortedTextTex}
transparent={true}
/>
</a.sprite>
<a.sprite
scale={[1, 3.5, 0]}
renderOrder={-1}
position={[1.55, -6.5, 0]}
ref={sndDistortedBackgroundTextRef}
>
<spriteMaterial
attach="material"
rotation={0.5}
map={bootBackgroundDistortedTextTex}
transparent={true}
/>
</a.sprite>
</group>
<sprite scale={[2.2, 0.66, 0]} position={[-1.1, -0.8, 0]}>
<a.spriteMaterial
attach="material"
map={bootBottomBarLeftTex}
opacity={bootState.bootOpacity}
/>
</sprite>
<sprite scale={[2.2, 0.66, 0]} position={[1.1, -0.8, 0]}>
<a.spriteMaterial
attach="material"
map={bootBottomBarRightTex}
opacity={bootState.bootOpacity}
/>
</sprite>
<sprite
scale={[0.2, 0.2, 0]}
position={[0, -0.8, 0]}
renderOrder={-1}
>
<a.spriteMaterial
attach="material"
map={bootPurpleSquareTex}
opacity={bootState.bootOpacity}
/>
</sprite>
<sprite scale={[1.4, 0.5, 0]} position={[-1.2, -1.17, 0]}>
<a.spriteMaterial
attach="material"
map={bootDangoTextTex}
opacity={bootState.bootOpacity}
/>
</sprite>
<sprite scale={[0.6, 0.15, 0]} position={[0.9, -1, 0]}>
<a.spriteMaterial
attach="material"
map={bootMisoShioTex}
opacity={bootState.bootOpacity}
/>
</sprite>
<sprite
scale={[0.12, 0.06, 0]}
position={[0.5, -0.96, 0]}
ref={arrowRef}
>
<a.spriteMaterial
attach="material"
map={bootArrowsTex}
opacity={bootState.bootOpacity}
/>
</sprite>
<sprite scale={[1.4, 0.2, 0]} position={[1.15, -1.2, 0]}>
<a.spriteMaterial
attach="material"
map={currentBootStatusTextTex}
opacity={bootState.bootOpacity}
/>
</sprite>
</>
)}
</group>
);
};
export default BootAnimation;

View file

@ -1,195 +0,0 @@
import React, { useEffect, useMemo, useRef } from "react";
import authorizeHeaderUnderline from "../../static/sprites/boot/authorize_header_underline.png";
import authorizeGlass from "../../static/sprites/boot/authorize_glass.png";
import authorizeGlassUnderline from "../../static/sprites/boot/authorize_glass_underline.png";
import authorizeOrangeSquare from "../../static/sprites/boot/authorize_orange_square.png";
import authorizeStartToFinish from "../../static/sprites/boot/authorize_start_to_finish.png";
import authorizeInactiveLetters from "../../static/sprites/boot/authorize_inactive_letters.png";
import authorizeActiveLetters from "../../static/sprites/boot/authorize_active_letters.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../../store";
import StaticJpCharacter from "../TextRenderer/StaticJpCharacter";
type BootAuthorizeUserProps = {
visible: boolean;
};
const BootAuthorizeUser = (props: BootAuthorizeUserProps) => {
const authorizeHeaderUnderlineTex = useLoader(
THREE.TextureLoader,
authorizeHeaderUnderline
);
const authorizeGlassTex = useLoader(THREE.TextureLoader, authorizeGlass);
const authorizeGlassUnderlineTex = useLoader(
THREE.TextureLoader,
authorizeGlassUnderline
);
const authorizeOrangeSquareTex = useLoader(
THREE.TextureLoader,
authorizeOrangeSquare
);
const authorizeStartToFinishTex = useLoader(
THREE.TextureLoader,
authorizeStartToFinish
);
const authorizeInactiveLettersTex = useLoader(
THREE.TextureLoader,
authorizeInactiveLetters
);
const activeLettersTex = useLoader(
THREE.TextureLoader,
authorizeActiveLetters
);
const authorizeUserMatrixIndices = useStore(
(state) => state.authorizeUserMatrixIndices
);
const bgLettersRef = useRef<THREE.Object3D>();
const activeLetterMap = useMemo(() => {
activeLettersTex.wrapT = activeLettersTex.wrapS = THREE.RepeatWrapping;
activeLettersTex.repeat.set(0.06, 0.2);
activeLettersTex.offset.x = 0.0775 * authorizeUserMatrixIndices.colIdx;
activeLettersTex.offset.y = -0.2 - 0.2 * authorizeUserMatrixIndices.rowIdx;
return activeLettersTex;
}, [
activeLettersTex,
authorizeUserMatrixIndices.colIdx,
authorizeUserMatrixIndices.rowIdx,
]);
useEffect(() => {
if (bgLettersRef.current) {
bgLettersRef.current.position.y =
-0.7 + 0.25 * authorizeUserMatrixIndices.rowIdx;
bgLettersRef.current.position.x =
3.35 - 0.3 * authorizeUserMatrixIndices.colIdx;
}
}, [authorizeUserMatrixIndices.colIdx, authorizeUserMatrixIndices.rowIdx]);
const playerName = useStore((state) => state.playerName.split(""));
return (
<>
{props.visible && (
<>
<sprite
scale={[3.5, 0.01, 0]}
position={[0.5, 1.1, 0]}
renderOrder={2}
>
<spriteMaterial
map={authorizeHeaderUnderlineTex}
attach="material"
transparent={true}
/>
</sprite>
<sprite
scale={[2.2 * 0.9, 0.15 * 0.9, 0]}
position={[1, 1, 0]}
renderOrder={2}
>
<spriteMaterial
map={authorizeStartToFinishTex}
attach="material"
transparent={true}
/>
</sprite>
<sprite
scale={[0.85, 0.65, 0]}
position={[0.35, -0.1, 0]}
renderOrder={3}
>
<spriteMaterial
map={authorizeGlassTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<sprite
scale={[0.2, 0.2, 0]}
position={[-0.19, -0.3, 0]}
renderOrder={3}
visible={!(playerName.length === 8)}
>
<spriteMaterial
map={authorizeOrangeSquareTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<group
position={[
(playerName.length === 8 ? 0.2 : 0) +
playerName.length * -0.2 -
0.2,
-0.29,
0,
]}
>
{playerName.map((char, idx) => (
<StaticJpCharacter char={char} charIdx={idx} key={idx} />
))}
</group>
<sprite
scale={[2, 0.01, 0]}
position={[-1.06, -0.42, 0]}
renderOrder={2}
>
<spriteMaterial
map={authorizeGlassUnderlineTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<group position={[-1.15, 0.4, 0.3]} rotation={[-0.8, 0, -0.3]}>
<mesh
scale={[4, 1.28, 0]}
position={[1.25, -0.45, 0]}
ref={bgLettersRef}
>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
map={authorizeInactiveLettersTex}
attach="material"
transparent={true}
opacity={0.6}
/>
</mesh>
<mesh
scale={[0.35, 0.45, 0]}
position={[1.51, -0.12, 0]}
renderOrder={2}
>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
map={activeLetterMap}
attach="material"
transparent={true}
depthTest={false}
/>
</mesh>
<mesh position={[1.54, -0.13, 0]} renderOrder={1}>
<circleBufferGeometry attach="geometry" args={[0.221, 32]} />
<meshBasicMaterial
attach="material"
transparent={true}
depthTest={false}
color={0x000000}
/>
</mesh>
</group>
</>
)}
</>
);
};
export default BootAuthorizeUser;

View file

@ -1,132 +0,0 @@
import React, { useMemo } from "react";
import { a, useSpring } from "@react-spring/three";
import authorizeActive from "../../static/sprites/boot/authorize_user_active.png";
import authorizeInactive from "../../static/sprites/boot/authorize_user_inactive.png";
import loadDataActive from "../../static/sprites/boot/load_data_active.png";
import loadDataInactive from "../../static/sprites/boot/load_data_inactive.png";
import authorizeUserHeader from "../../static/sprites/boot/authorize_user_scene_header.png";
import loadDataHeader from "../../static/sprites/boot/load_data_header.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../../store";
type BootMainMenuProps = {
visible: boolean;
activeSubScene: string;
};
const BootMainMenuComponents = (props: BootMainMenuProps) => {
const authorizeActiveTex = useLoader(THREE.TextureLoader, authorizeActive);
const authorizeInactiveTex = useLoader(
THREE.TextureLoader,
authorizeInactive
);
const authorizeUserHeaderTex = useLoader(
THREE.TextureLoader,
authorizeUserHeader
);
const activeMainMenuElement = useStore(
(state) => state.activeMainMenuComponent
);
const loadDataActiveTex = useLoader(THREE.TextureLoader, loadDataActive);
const loadDataInactiveTex = useLoader(THREE.TextureLoader, loadDataInactive);
const loadDataHeaderTex = useLoader(THREE.TextureLoader, loadDataHeader);
const loadDataTextState = useMemo(() => {
if (props.activeSubScene === "load_data") {
return {
texture: loadDataHeaderTex,
position: { x: -1.13, y: -1 },
};
} else {
return {
texture:
activeMainMenuElement === "load_data"
? loadDataActiveTex
: loadDataInactiveTex,
position: { x: 0, y: -0.5 },
};
}
}, [
loadDataActiveTex,
loadDataHeaderTex,
loadDataInactiveTex,
activeMainMenuElement,
props.activeSubScene,
]);
const authorizeUserTextState = useMemo(() => {
if (props.activeSubScene === "authorize_user") {
return {
scale: [1.8, 0.16, 0],
texture: authorizeUserHeaderTex,
position: { x: 1.13, y: 1.2 },
};
} else {
return {
scale: [1.8, 0.3, 0],
texture:
activeMainMenuElement === "authorize_user"
? authorizeActiveTex
: authorizeInactiveTex,
position: { x: 0, y: 0.5 },
};
}
}, [
authorizeActiveTex,
authorizeInactiveTex,
authorizeUserHeaderTex,
activeMainMenuElement,
props.activeSubScene,
]);
const mainMenuAnimationState = useSpring({
authorizeUserOpacity: props.activeSubScene !== "load_data" ? 1 : 0,
authorizeUserPosX: authorizeUserTextState.position.x,
authorizeUserPosY: authorizeUserTextState.position.y,
loadDataOpacity: props.activeSubScene !== "authorize_user" ? 1 : 0,
loadDataPosX: loadDataTextState.position.x,
loadDataPosY: loadDataTextState.position.y,
config: { duration: 500 },
});
return (
<>
{props.visible && (
<>
<a.sprite
scale={authorizeUserTextState.scale as [number, number, number]}
renderOrder={1}
position-x={mainMenuAnimationState.authorizeUserPosX}
position-y={mainMenuAnimationState.authorizeUserPosY}
>
<a.spriteMaterial
attach="material"
map={authorizeUserTextState.texture}
transparent={true}
opacity={mainMenuAnimationState.authorizeUserOpacity}
/>
</a.sprite>
<a.sprite
scale={[1.4, 0.3, 0]}
renderOrder={1}
position-x={mainMenuAnimationState.loadDataPosX}
position-y={mainMenuAnimationState.loadDataPosY}
>
<a.spriteMaterial
attach="material"
map={loadDataTextState.texture}
transparent={true}
opacity={mainMenuAnimationState.loadDataOpacity}
/>
</a.sprite>
</>
)}
</>
);
};
export default BootMainMenuComponents;

View file

@ -1,56 +0,0 @@
import React, { useRef, memo } from "react";
import * as THREE from "three";
import { useFrame, useLoader } from "react-three-fiber";
import secondCylinder from "../../static/sprites/end/end_cylinder_2.png";
type EndSphereProps = {
position: number[];
outroAnim: boolean;
};
const EndSphere = memo((props: EndSphereProps) => {
const secondCylinderTex = useLoader(THREE.TextureLoader, secondCylinder);
const meshRef = useRef<THREE.Object3D>();
const deltaRef = useRef(0);
useFrame((state, delta) => {
deltaRef.current += delta;
if (deltaRef.current > 0.016 && meshRef.current) {
meshRef.current.rotation.y += 0.005;
if (
props.outroAnim &&
meshRef.current.scale.x > 0 &&
meshRef.current.scale.y > 0 &&
meshRef.current.scale.z > 0
) {
meshRef.current.scale.x -= 0.025;
meshRef.current.scale.y -= 0.025;
meshRef.current.scale.z -= 0.025;
}
deltaRef.current = deltaRef.current % 0.016;
}
});
return (
<mesh
position={props.position as [number, number, number]}
ref={meshRef}
renderOrder={3}
>
<sphereBufferGeometry args={[1, 16, 16]} attach="geometry" />
<meshStandardMaterial
attach="material"
map={secondCylinderTex}
color={0xffffff}
transparent={true}
side={THREE.DoubleSide}
depthTest={false}
opacity={0.7}
/>
</mesh>
);
});
export default EndSphere;

View file

@ -1,164 +0,0 @@
import React, { useEffect, useMemo, useRef } from "react";
import gateText from "../../static/sprites/gate/gate_pass.png";
import gateTextUnderline from "../../static/sprites/gate/gate_pass_underline.png";
import gateTextAccessPass from "../../static/sprites/gate/you_got_an_access_pass.png";
import changeSiteEnable from "../../static/sprites/gate/change_site_enable.png";
import gateLeftThing from "../../static/sprites/gate/left_gate_thing.png";
import gateRightThing from "../../static/sprites/gate/right_gate_thing.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
type GateMiddleProps = {
intro: boolean;
gateLvl: number;
};
const GateHUD = (props: GateMiddleProps) => {
const wordFont = useLoader(THREE.FontLoader, "/3d-fonts/MediaWord.blob");
const config = useMemo(
() => ({
font: wordFont,
size: 1,
}),
[wordFont]
);
const gatePassTexture = useLoader(THREE.TextureLoader, gateText);
const gatePassUnderline = useLoader(THREE.TextureLoader, gateTextUnderline);
const gateAccessPassTexture = useLoader(
THREE.TextureLoader,
gateTextAccessPass
);
const changeSiteEnableTexture = useLoader(
THREE.TextureLoader,
changeSiteEnable
);
const gateLeftThingTexture = useLoader(THREE.TextureLoader, gateLeftThing);
const gateRightThingTexture = useLoader(THREE.TextureLoader, gateRightThing);
const pressAnyRef = useRef<THREE.Object3D>();
useEffect(() => {
setInterval(() => {
if (pressAnyRef.current && !props.intro) {
pressAnyRef.current.visible = !pressAnyRef.current.visible;
}
}, 500);
}, [props.intro]);
return (
<>
<sprite scale={[1.5, 0.24, 0]} position={[0, 1.1, 0.07]} renderOrder={3}>
<spriteMaterial
attach="material"
map={gatePassTexture}
transparent={true}
depthTest={false}
/>
</sprite>
<sprite scale={[4.2, 0.01, 0]} position={[0, 0.98, 0.07]} renderOrder={3}>
<spriteMaterial
attach="material"
map={gatePassUnderline}
transparent={true}
depthTest={false}
/>
</sprite>
<sprite
scale={[1.6, 0.1, 1]}
position={[0, 0.8, 0.2]}
renderOrder={3}
visible={!props.intro && props.gateLvl === 4}
>
<spriteMaterial
attach="material"
map={changeSiteEnableTexture}
transparent={true}
depthTest={false}
/>
</sprite>
<sprite scale={[4.2, 0.01, 0]} position={[0, 0.79, 0.07]} renderOrder={3}>
<spriteMaterial
attach="material"
map={gatePassUnderline}
transparent={true}
depthTest={false}
visible={!props.intro && props.gateLvl === 4}
/>
</sprite>
<sprite
scale={[0.7, 0.35, 1]}
position={[-0.8, -0.8, 0.2]}
renderOrder={3}
>
<spriteMaterial
attach="material"
map={gateLeftThingTexture}
transparent={true}
depthTest={false}
visible={!props.intro && props.gateLvl === 4}
/>
</sprite>
<sprite
scale={[0.7, 0.35, 1]}
position={[0.8, -0.8, 0.2]}
renderOrder={3}
>
<spriteMaterial
attach="material"
map={gateRightThingTexture}
transparent={true}
depthTest={false}
visible={!props.intro && props.gateLvl === 4}
/>
</sprite>
<sprite scale={[1.25, 0.31, 1]} position={[0, -0.8, 0.2]} renderOrder={3}>
<spriteMaterial
attach="material"
map={gateAccessPassTexture}
transparent={true}
depthTest={false}
visible={!props.intro && props.gateLvl === 4}
/>
</sprite>
<group ref={pressAnyRef} visible={false}>
<mesh
scale={[0.17, 0.14, 0]}
position={[-0.8, -1.3, 0]}
renderOrder={5}
>
<textGeometry attach="geometry" args={["press ANY button", config]} />
<meshBasicMaterial
attach="material"
color={0xdb9200}
transparent={true}
depthTest={false}
/>
</mesh>
<mesh
scale={[0.17, 0.14, 0]}
position={[-0.793, -1.308, 0]}
renderOrder={4}
>
<textGeometry attach="geometry" args={["press ANY button", config]} />
<meshBasicMaterial
attach="material"
color={0xad7400}
transparent={true}
depthTest={false}
/>
</mesh>
</group>
</>
);
};
export default GateHUD;

View file

@ -1,96 +0,0 @@
import React, { useEffect, useState } from "react";
import { a, useSpring, useSprings } from "@react-spring/three";
import blue_digit_positions from "../../resources/blue_digit_positions.json";
import Mirror from "./GateMiddleObject/Mirror";
import BlueDigit from "./GateMiddleObject/BlueDigit";
type GateMiddleObjectProps = {
intro: boolean;
gateLvl: number;
};
const GateMiddleObject = (props: GateMiddleObjectProps) => {
const [middleGroupPos, setMiddleGroupPos] = useState<number[]>();
const [springs, set] = useSprings(44, (intIdx) => {
const idx = intIdx.toString();
return {
posX:
blue_digit_positions[idx as keyof typeof blue_digit_positions]
.initial_x,
posY:
blue_digit_positions[idx as keyof typeof blue_digit_positions]
.initial_y,
config: { duration: 150 },
};
});
useEffect(() => {
set((intIdx) => {
const idx = intIdx.toString();
return {
posX:
blue_digit_positions[idx as keyof typeof blue_digit_positions]
.final_x,
posY:
blue_digit_positions[idx as keyof typeof blue_digit_positions]
.final_y,
delay:
blue_digit_positions[idx as keyof typeof blue_digit_positions].delay,
};
});
setTimeout(() => setMiddleGroupPos([-0.15, -0.2, -0.1]), 1400);
}, [set]);
const middleObjectGroupState = useSpring({
posX: middleGroupPos ? middleGroupPos[0] : 0,
posY: middleGroupPos ? middleGroupPos[1] : 0,
posZ: middleGroupPos ? middleGroupPos[2] : 0,
config: { duration: 900 },
});
return (
<>
<a.group
position-x={middleObjectGroupState.posX}
position-y={middleObjectGroupState.posY}
position-z={middleObjectGroupState.posZ}
visible={props.intro}
>
{springs.map((item, idx) => (
<BlueDigit
type={
blue_digit_positions[
idx.toString() as keyof typeof blue_digit_positions
].type
}
posX={item.posX}
posY={item.posY}
key={idx}
/>
))}
</a.group>
<Mirror
visible={props.gateLvl === 1 ? !props.intro : props.gateLvl > 0}
rotation={[0, Math.PI / 2, 0]}
position={[0, 0, -0.4]}
/>
<Mirror
visible={props.gateLvl === 2 ? !props.intro : props.gateLvl > 1}
rotation={[0, Math.PI / 2, 0]}
position={[0, 0, 0.5]}
/>
<Mirror
visible={props.gateLvl === 3 ? !props.intro : props.gateLvl > 2}
position={[0.4, 0, 0.05]}
/>
<Mirror
visible={props.gateLvl === 4 ? !props.intro : props.gateLvl > 3}
position={[-0.4, 0, 0.05]}
/>
</>
);
};
export default GateMiddleObject;

View file

@ -1,95 +0,0 @@
import React, { useEffect, useMemo, useRef } from "react";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import gateBlueBinarySingularOne from "../../../static/sprites/gate/blue_binary_singular_one.png";
import { a, SpringValue } from "@react-spring/three";
import gateBlueBinarySingularZero from "../../../static/sprites/gate/blue_binary_singular_zero.png";
type BlueDigitProps = {
type: number;
posX: SpringValue<number>;
posY: SpringValue<number>;
};
const BlueDigit = (props: BlueDigitProps) => {
const gateBlueBinarySingularOneTex = useLoader(
THREE.TextureLoader,
gateBlueBinarySingularOne
);
const gateBlueBinarySingularZeroTex = useLoader(
THREE.TextureLoader,
gateBlueBinarySingularZero
);
const objRef = useRef<THREE.Mesh>();
const matRef = useRef<THREE.ShaderMaterial>();
const uniforms = useMemo(
() => ({
tex: {
type: "t",
value:
props.type === 1
? gateBlueBinarySingularOneTex
: gateBlueBinarySingularZeroTex,
},
brightnessMultiplier: { value: 1.5 },
}),
[gateBlueBinarySingularOneTex, gateBlueBinarySingularZeroTex, props.type]
);
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
uniform sampler2D tex;
uniform float brightnessMultiplier;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D(tex, vUv) * brightnessMultiplier;
}
`;
useEffect(() => {
setTimeout(() => {
if (matRef.current) {
matRef.current.uniforms.brightnessMultiplier.value = 3.5;
matRef.current.uniformsNeedUpdate = true;
}
}, 1400);
setTimeout(() => {
if (objRef.current) objRef.current.visible = true;
}, 150);
}, []);
return (
<a.mesh
scale={[props.type === 1 ? 0.04 : 0.08, 0.1, 0]}
position-x={props.posX}
position-y={props.posY}
renderOrder={5}
visible={false}
ref={objRef}
>
<planeBufferGeometry attach="geometry" />
<shaderMaterial
fragmentShader={fragmentShader}
vertexShader={vertexShader}
uniforms={uniforms}
attach="material"
transparent={true}
depthTest={false}
ref={matRef}
/>
</a.mesh>
);
};
export default BlueDigit;

View file

@ -1,84 +0,0 @@
import React, { useMemo, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import mirrorTexture from "../../../static/sprites/gate/gate_object_texture.png";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
type GLTFResult = GLTF & {
nodes: {
GatePass: THREE.Mesh;
};
materials: {
Material: THREE.MeshStandardMaterial;
};
};
type MirrorProps = {
visible: boolean;
position: number[];
rotation?: number[];
};
const Mirror = (props: MirrorProps) => {
const mirrorTex = useLoader(THREE.TextureLoader, mirrorTexture);
const { nodes } = useLoader<GLTFResult>(GLTFLoader, "models/gate_mirror.glb");
const mirrorGroupRef = useRef<THREE.Object3D>();
const materialRef = useRef<THREE.MeshBasicMaterial>();
const tex = useMemo(() => {
mirrorTex.wrapS = mirrorTex.wrapT = THREE.RepeatWrapping;
return mirrorTex;
}, [mirrorTex]);
const deltaRef = useRef(0);
useFrame((state, delta) => {
deltaRef.current += delta;
if (deltaRef.current > 0.016) {
if (mirrorGroupRef.current) {
mirrorGroupRef.current.rotation.y -= 0.03;
}
if (materialRef.current) {
tex.offset.x -= 0.0025;
}
deltaRef.current = deltaRef.current % 0.016;
}
});
return (
<>
<group position={[0, 0, -0.5]}>
<group
ref={mirrorGroupRef}
position={[0, 0, 0.2]}
scale={[0.8, 0.8, 1]}
>
<mesh
geometry={nodes.GatePass.geometry}
scale={[0.01, 0.6, 0.2]}
rotation={
props.rotation
? (props.rotation as [number, number, number])
: [0, 0, 0]
}
renderOrder={4}
position={props.position as [number, number, number]}
>
<meshBasicMaterial
ref={materialRef}
attach="material"
transparent={true}
map={mirrorTex}
depthTest={false}
visible={props.visible}
/>
</mesh>
</group>
</group>
</>
);
};
export default Mirror;

View file

@ -1,119 +0,0 @@
import React, { useMemo, useRef } from "react";
import blueBinary from "../../static/sprites/gate/blue_binary.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
const GateSide = () => {
const blueBinaryTex = useLoader(THREE.TextureLoader, blueBinary);
// this is really fucking weird
const texture = useMemo(() => {
blueBinaryTex.wrapS = THREE.RepeatWrapping;
blueBinaryTex.wrapT = THREE.RepeatWrapping;
blueBinaryTex.repeat.set(5, 5);
return blueBinaryTex;
}, [blueBinaryTex]);
const last = useRef(0);
useFrame(() => {
const now = Date.now();
if (matRef.current) {
if (now > last.current + 50) {
matRef.current.uniforms.offset.value += 0.5;
last.current = now;
}
}
});
const matRef = useRef<THREE.ShaderMaterial>();
const uniforms = useMemo(
() => ({
tex1: { type: "t", value: texture },
offset: { value: 0 },
}),
[texture]
);
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShaderLeft = `
uniform sampler2D tex1;
uniform float alpha;
uniform float offset;
varying vec2 vUv;
void main() {
float alpha = smoothstep(0.9, 1.0, vUv.x);
vec4 t1 = texture2D(tex1,vUv * 5.0 + offset);
gl_FragColor = mix(t1, vec4(0,0,0,0), alpha) * 0.8;
}
`;
const fragmentShaderRight = `
uniform sampler2D tex1;
uniform float alpha;
uniform float offset;
varying vec2 vUv;
void main() {
float alpha = smoothstep(1.0, 0.9, vUv.x);
vec4 t1 = texture2D(tex1,vUv * 5.0 + offset);
gl_FragColor = mix(vec4(0,0,0,0), t1, alpha) * 0.8;
}
`;
return (
<>
<mesh
rotation={[0, 0.2, 0]}
position={[-1.7, 0, 1.5]}
scale={[3, 1.5, 0]}
renderOrder={1}
>
<planeBufferGeometry attach="geometry" />
<shaderMaterial
attach="material"
uniforms={uniforms}
vertexShader={vertexShader}
fragmentShader={fragmentShaderLeft}
transparent={true}
ref={matRef}
/>
</mesh>
<mesh
rotation={[0, -0.2, 0]}
position={[1.7, 0, 1.5]}
scale={[-3, 1.5, 0]}
renderOrder={1}
>
<planeBufferGeometry attach="geometry" />
<shaderMaterial
attach="material"
uniforms={uniforms}
vertexShader={vertexShader}
fragmentShader={fragmentShaderRight}
transparent={true}
ref={matRef}
side={THREE.DoubleSide}
/>
</mesh>
</>
);
};
export default GateSide;

View file

@ -1,97 +0,0 @@
import React, { useEffect, useMemo, useState } from "react";
import { useStore } from "../store";
import { a, useSpring } from "@react-spring/three";
import dummy from "../static/sprites/dummy.png";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
const Images = () => {
const idleNodeImages = useStore((state) => state.idleImages);
const nodeImages = useStore((state) => state.activeNode.image_table_indices);
const currentScene = useStore((state) => state.currentScene);
const [imageScaleY, setImageScaleY] = useState(3.75);
const [sceneImages, setSceneImages] = useState([] as any);
const [activeImage, setActiveImage] = useState<THREE.Texture>();
const activeSite = useStore((state) => state.activeSite);
const dummyTex = useLoader(THREE.TextureLoader, dummy);
const mediaPercentageElapsed = useStore(
(state) => state.mediaPercentageElapsed
);
const imageScaleState = useSpring({
imageScaleY: imageScaleY,
config: { duration: 300 },
});
const textureLoader = useMemo(() => new THREE.TextureLoader(), []);
useEffect(() => {
const images = currentScene === "idle_media" ? idleNodeImages : nodeImages;
if (images) {
// checking the length of the img arr doesn't work in some cases
// since the amount of images varies from 1 to 3.
// we try all 3 of them for each case, so logging the count to
// determine whether or not its complete is optimal i think.
let imgTries = 0;
const imgArr: { default: string }[] = [];
Object.entries(images).forEach((img) => {
imgTries++;
if (img[1] !== "-1") {
import(
"../static/media/images/" + activeSite + "/" + img[1] + ".png"
).then((imageSrc: { default: string }) => {
imgArr.splice(parseInt(img[0]), 0, imageSrc);
if (imgTries === 3) {
setSceneImages(imgArr);
new THREE.TextureLoader().load(imgArr[0].default, setActiveImage);
}
});
}
});
}
}, [currentScene, activeSite, idleNodeImages, nodeImages]);
useEffect(() => {
let timer: ReturnType<typeof setTimeout>;
if (mediaPercentageElapsed === 0 && sceneImages[0]) {
textureLoader.load(sceneImages[0].default, setActiveImage);
} else if (mediaPercentageElapsed === 35 && sceneImages[1]) {
setImageScaleY(0);
timer = setTimeout(() => {
textureLoader.load(sceneImages[1].default, setActiveImage);
setImageScaleY(3.75);
}, 300);
} else if (mediaPercentageElapsed === 70 && sceneImages[2]) {
setImageScaleY(0);
timer = setTimeout(() => {
textureLoader.load(sceneImages[2].default, setActiveImage);
setImageScaleY(3.75);
}, 300);
}
return () => {
clearTimeout(timer);
};
}, [mediaPercentageElapsed, sceneImages, textureLoader]);
return (
<a.sprite
position={[-0.2, 0.6, -4]}
scale={[5, 3.75, 0]}
scale-y={imageScaleState.imageScaleY}
>
<spriteMaterial
attach="material"
map={activeImage ? activeImage : dummyTex}
/>
</a.sprite>
);
};
export default Images;

View file

@ -1,134 +0,0 @@
import React, { useCallback, useEffect, useRef, memo } from "react";
import {
getBootSceneContext,
getEndSceneContext,
getMainSceneContext,
getMediaSceneContext,
getSsknSceneContext,
useStore,
} from "../store";
import getKeyPress from "../utils/getKeyPress";
import handleMediaSceneInput from "../core/input-handlers/handleMediaSceneInput";
import handleSsknSceneInput from "../core/input-handlers/handleSsknSceneInput";
import handleMainSceneInput from "../core/input-handlers/handleMainSceneInput";
import handleBootSceneInput from "../core/input-handlers/handleBootSceneInput";
import handleEndSceneInput from "../core/input-handlers/handleEndSceneInput";
import handleEvent from "../core/handleEvent";
import { GameEvent } from "../types/types";
import IdleManager from "./IdleManager";
const InputHandler = memo(() => {
const scene = useStore((state) => state.currentScene);
const inputCooldown = useStore((state) => state.inputCooldown);
const timeSinceLastKeyPress = useRef(-1);
const lainIdleTimerRef = useRef(-1);
const idleSceneTimerRef = useRef(-1);
const handleKeyPress = useCallback(
(keyPress: string) => {
const now = Date.now();
if (
now > timeSinceLastKeyPress.current + inputCooldown &&
inputCooldown !== -1
) {
timeSinceLastKeyPress.current = now;
if (scene === "main") {
lainIdleTimerRef.current = now;
idleSceneTimerRef.current = now;
}
const sceneFns = (() => {
switch (scene) {
case "main":
return {
contextProvider: getMainSceneContext,
keyPressHandler: handleMainSceneInput,
};
case "media":
return {
contextProvider: getMediaSceneContext,
keyPressHandler: handleMediaSceneInput,
};
case "sskn":
return {
contextProvider: getSsknSceneContext,
keyPressHandler: handleSsknSceneInput,
};
case "boot":
return {
contextProvider: getBootSceneContext,
keyPressHandler: handleBootSceneInput,
};
case "end":
return {
contextProvider: getEndSceneContext,
keyPressHandler: handleEndSceneInput,
};
case "gate":
case "polytan":
useStore.setState({ currentScene: "main" });
break;
case "idle_media":
useStore.setState({
currentScene: "main",
idleStarting: false,
intro: false,
inputCooldown: -1,
});
break;
}
})();
if (sceneFns) {
const { contextProvider, keyPressHandler } = sceneFns;
const ctx = contextProvider();
const event: GameEvent | undefined = keyPressHandler(
ctx as any,
keyPress
);
if (event) handleEvent(event);
}
}
},
[inputCooldown, scene]
);
const firedRef = useRef(false);
const handleKeyBoardEvent = useCallback(
(event) => {
if (!firedRef.current) {
firedRef.current = true;
const key = getKeyPress(event.key);
if (key) handleKeyPress(key);
}
},
[handleKeyPress]
);
useEffect(() => {
window.addEventListener("keydown", handleKeyBoardEvent);
window.addEventListener("keyup", () => {
firedRef.current = false;
});
return () => {
window.removeEventListener("keydown", handleKeyBoardEvent);
};
}, [handleKeyBoardEvent]);
return (
<IdleManager
lainIdleTimerRef={lainIdleTimerRef}
idleSceneTimerRef={idleSceneTimerRef}
/>
);
});
export default InputHandler;

View file

@ -1,98 +0,0 @@
import React, { useMemo, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import takIntro from "../static/sprites/lain/lain_speak_intro.png";
import takOutro from "../static/sprites/lain/lain_speak_outro.png";
import mouth1 from "../static/sprites/lain/mouth_1.png";
import mouth2 from "../static/sprites/lain/mouth_2.png";
import mouth3 from "../static/sprites/lain/mouth_3.png";
import mouth4 from "../static/sprites/lain/mouth_4.png";
import { useStore } from "../store";
import { LainConstructor } from "./MainScene/Lain";
type LainTaKProps = {
intro: boolean;
outro: boolean;
};
const LainSpeak = (props: LainTaKProps) => {
const mouth1Tex = useLoader(THREE.TextureLoader, mouth1);
const mouth2Tex = useLoader(THREE.TextureLoader, mouth2);
const mouth3Tex = useLoader(THREE.TextureLoader, mouth3);
const mouth4Tex = useLoader(THREE.TextureLoader, mouth4);
const Intro = () => (
<LainConstructor
sprite={takIntro}
frameCount={31}
framesHorizontal={6}
framesVertical={6}
/>
);
const Outro = () => (
<LainConstructor
sprite={takOutro}
frameCount={39}
framesHorizontal={7}
framesVertical={6}
/>
);
const mouthRef = useRef<THREE.SpriteMaterial>();
const audioAnalyser = useStore((state) => state.audioAnalyser);
useFrame(() => {
if (audioAnalyser) {
const buffer = new Uint8Array(audioAnalyser.analyser.fftSize / 2);
audioAnalyser.analyser.getByteTimeDomainData(buffer);
let rms = 0;
for (let i = 0; i < buffer.length; i++) {
rms += buffer[i] * buffer[i];
}
rms = Math.sqrt(rms / buffer.length);
if (mouthRef.current) {
if (rms >= 130) {
mouthRef.current.map = mouth4Tex;
} else if (rms >= 129 && rms <= 130) {
mouthRef.current.map = mouth3Tex;
} else if (rms > 128 && rms <= 129) {
mouthRef.current.map = mouth2Tex;
} else {
mouthRef.current.map = mouth1Tex;
}
}
}
});
const animationDispatch = useMemo(() => {
if (props.intro) return <Intro />;
else if (props.outro) return <Outro />;
}, [props.intro, props.outro]);
return (
<>
<sprite scale={[11, 7.7, 0]} visible={props.intro || props.outro}>
{animationDispatch}
</sprite>
<sprite
scale={[11, 7.7, 0]}
renderOrder={2}
visible={!props.intro && !props.outro}
>
<spriteMaterial
attach="material"
map={mouth4Tex}
alphaTest={0.01}
ref={mouthRef}
depthTest={false}
/>
</sprite>
</>
);
};
export default LainSpeak;

View file

@ -1,49 +0,0 @@
import React, { memo, useState } from "react";
import loadingSpritesheet from "../static/sprites/loading/loading_spritesheet.png";
import lifeInstinct from "../static/sprites/loading/life_instinct_function_os.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import { PlainAnimator } from "three-plain-animator/lib/plain-animator";
const Loading = memo(() => {
const loadingTex: any = useLoader(THREE.TextureLoader, loadingSpritesheet);
const lifeInstinctTex = useLoader(THREE.TextureLoader, lifeInstinct);
const [animator] = useState(() => {
const anim = new PlainAnimator(loadingTex, 10, 3, 29, 60);
anim.init(0);
return anim;
});
useFrame(() => {
animator.animate();
});
return (
<>
<sprite scale={[5, 5, 5]} renderOrder={999}>
<spriteMaterial attach="material" color={0x000000} depthTest={false} />
</sprite>
<sprite
scale={[0.35, 0.6, 0.35]}
position={[0, 0.2, 0]}
renderOrder={1000}
>
<spriteMaterial attach="material" map={loadingTex} depthTest={false} />
</sprite>
<sprite
scale={[0.4, 0.6, 0.4]}
position={[0, -0.5, 0]}
renderOrder={1000}
>
<spriteMaterial
attach="material"
map={lifeInstinctTex}
depthTest={false}
/>
</sprite>
</>
);
});
export default Loading;

View file

@ -1,35 +0,0 @@
import React, { useMemo, useRef, memo } from "react";
import * as THREE from "three";
import { useFrame } from "react-three-fiber";
import GrayPlane from "./GrayPlane";
const GrayPlanes = memo(() => {
const grayPlaneGroupRef = useRef<THREE.Object3D>();
const grayPlanePoses = useMemo(
() => [
[1.2, 0, -1.2],
[1.2, 0, 1.2],
[1.2, 0, -0.5],
[-1.2, 0, -1.2],
[-1.2, 0, 1.2],
[-1.2, 0, 1],
[0.5, 0, 1],
],
[]
);
useFrame((state, delta) => {
grayPlaneGroupRef.current!.rotation.y -= delta / 1.5;
});
return (
<group position={[0.1, 0, -2]} ref={grayPlaneGroupRef}>
{grayPlanePoses.map((pos, idx: number) => (
<GrayPlane position={pos as [number, number, number]} key={idx} />
))}
</group>
);
});
export default GrayPlanes;

View file

@ -1,300 +0,0 @@
import React, { memo, useEffect, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import bigHud from "../../static/sprites/main/big_hud.png";
import longHud from "../../static/sprites/main/long_hud.png";
import boringHud from "../../static/sprites/main/boring_hud.png";
import { useStore } from "../../store";
import lerp from "../../utils/lerp";
import GreenTextRenderer from "../TextRenderer/GreenTextRenderer";
import usePrevious from "../../hooks/usePrevious";
import { getNodeHud } from "../../helpers/node-helpers";
import { HUDData } from "../../types/types";
// the hud is an imperative mess. unfortunately this seems to perform by far the best out of all the approaches i've tried.
const HUD = memo(() => {
const activeRef = useRef(true);
const currentHudRef = useRef(
getNodeHud(useStore.getState().activeNode.matrixIndices!)
);
const activeNode = useStore((state) => state.activeNode);
const siteRotY = useStore((state) => state.siteRot[1]);
const activeLevel = useStore((state) => state.activeLevel);
const subscene = useStore((state) => state.mainSubscene);
const scene = useStore((state) => state.currentScene);
const protocolLinesEnabled = useStore((state) => state.protocolLinesEnabled);
const prevData = usePrevious({
siteRotY,
activeLevel,
subscene,
scene,
protocolLinesEnabled,
});
const longHudRef = useRef<THREE.Object3D>();
const boringHudRef = useRef<THREE.Object3D>();
const bigHudRef = useRef<THREE.Object3D>();
const nodeTitleRef = useRef<THREE.Object3D>();
const protocolLine1Ref = useRef<THREE.Object3D>();
const protocolLine2Ref = useRef<THREE.Object3D>();
const protocolLine3Ref = useRef<THREE.Object3D>();
const protocolLineTitleRefs = useRef([
useRef<THREE.Object3D>(),
useRef<THREE.Object3D>(),
useRef<THREE.Object3D>(),
]);
const deltaRef = useRef(0);
useFrame((state, delta) => {
deltaRef.current += delta;
if (deltaRef.current > 0.016) {
if (longHudRef.current && bigHudRef.current && boringHudRef.current) {
const hud = currentHudRef.current;
longHudRef.current.position.x = lerp(
longHudRef.current.position.x,
activeRef.current
? hud.long.position[0]
: hud.long.initial_position[0],
0.12
);
boringHudRef.current.position.x = lerp(
boringHudRef.current.position.x,
activeRef.current
? hud.boring.position[0]
: hud.boring.initial_position[0],
0.12
);
bigHudRef.current.position.x = lerp(
bigHudRef.current.position.x,
activeRef.current ? hud.big.position[0] : hud.big.initial_position[0],
0.12
);
}
deltaRef.current = deltaRef.current % 0.016;
}
});
useEffect(() => {
const mirror = () => {
longHudRef.current!.scale.x = -Math.abs(longHudRef.current!.scale.x);
boringHudRef.current!.scale.x = -Math.abs(boringHudRef.current!.scale.x);
bigHudRef.current!.scale.x = -Math.abs(bigHudRef.current!.scale.x);
nodeTitleRef.current!.scale.x = -Math.abs(nodeTitleRef.current!.scale.x);
nodeTitleRef.current!.position.x = 0.2;
if (protocolLinesEnabled) {
protocolLineTitleRefs.current.forEach((ref) => {
ref.current!.scale.x = -Math.abs(ref.current!.scale.x);
ref.current!.position.x = 0.2;
});
}
};
const unMirror = () => {
longHudRef.current!.scale.x = Math.abs(longHudRef.current!.scale.x);
boringHudRef.current!.scale.x = Math.abs(boringHudRef.current!.scale.x);
bigHudRef.current!.scale.x = Math.abs(bigHudRef.current!.scale.x);
nodeTitleRef.current!.scale.x = Math.abs(nodeTitleRef.current!.scale.x);
nodeTitleRef.current!.position.x = -0.2;
if (protocolLinesEnabled) {
protocolLineTitleRefs.current.forEach((ref) => {
ref.current!.scale.x = Math.abs(ref.current!.scale.x);
ref.current!.position.x = -0.2;
});
}
};
const setPos = (hud: HUDData, pos: string) => {
longHudRef.current!.position.set(
...(hud.long[pos as keyof typeof hud.long] as [number, number, number])
);
boringHudRef.current!.position.set(
...(hud.boring[pos as keyof typeof hud.boring] as [
number,
number,
number
])
);
bigHudRef.current!.position.set(
...(hud.big[pos as keyof typeof hud.big] as [number, number, number])
);
if (
protocolLine1Ref.current &&
protocolLine2Ref.current &&
protocolLine3Ref.current
) {
protocolLine1Ref.current.position.set(
...(hud.big.protocol_line_positions[0] as [number, number, number])
);
protocolLine2Ref.current.position.set(
...(hud.big.protocol_line_positions[1] as [number, number, number])
);
protocolLine3Ref.current.position.set(
...(hud.big.protocol_line_positions[2] as [number, number, number])
);
}
};
if (activeRef.current !== undefined) {
const hud = getNodeHud(activeNode.matrixIndices!);
if (
!(scene === "main" && prevData?.scene === "main") ||
(subscene === "site" && prevData?.subscene === "pause") ||
subscene === "pause" ||
protocolLinesEnabled !== prevData?.protocolLinesEnabled
) {
// set to final pos instantly
setPos(hud, "position");
if (hud.mirrored) mirror();
else unMirror();
} else {
if (
prevData?.siteRotY !== siteRotY ||
prevData?.activeLevel !== activeLevel ||
subscene === "level_selection"
) {
activeRef.current = false;
} else {
const wasHidden = !activeRef.current;
activeRef.current = false;
setTimeout(
() => {
// set to initial pos instantly while its hidden
setPos(hud, "initial_position");
if (hud.mirrored) mirror();
else unMirror();
currentHudRef.current = hud;
activeRef.current = true;
},
wasHidden ? 0 : 500
);
}
}
}
}, [
activeLevel,
prevData?.activeLevel,
prevData?.scene,
prevData?.siteRotY,
prevData?.subscene,
prevData?.protocolLinesEnabled,
scene,
siteRotY,
subscene,
protocolLinesEnabled,
activeNode.matrixIndices,
activeNode.node_name,
]);
const longHudTex = useLoader(THREE.TextureLoader, longHud);
const boringHudTex = useLoader(THREE.TextureLoader, boringHud);
const bigHudTex = useLoader(THREE.TextureLoader, bigHud);
return (
<group position={[0, 0, 10]}>
<mesh scale={[1, 0.03, 1]} renderOrder={2} ref={longHudRef}>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
attach="material"
map={longHudTex}
transparent={true}
depthTest={false}
/>
</mesh>
<mesh scale={[1, 0.03, 1]} renderOrder={2} ref={boringHudRef}>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
attach="material"
map={boringHudTex}
transparent={true}
depthTest={false}
/>
</mesh>
<group ref={bigHudRef}>
<mesh scale={[0.5, 0.06, 1]} renderOrder={2}>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
attach="material"
map={bigHudTex}
transparent={true}
depthTest={false}
/>
</mesh>
<group ref={nodeTitleRef} scale={[0.016, 0.03, 0.016]}>
<GreenTextRenderer textToRender={activeNode.title.split("")} />
</group>
{protocolLinesEnabled && (
<>
<group ref={protocolLine1Ref}>
<mesh scale={[0.5, 0.06, 1]} renderOrder={2}>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
attach="material"
map={bigHudTex}
transparent={true}
depthTest={false}
/>
</mesh>
<group
scale={[0.016, 0.03, 0.016]}
ref={protocolLineTitleRefs.current[0]}
>
<GreenTextRenderer
textToRender={activeNode.protocol_lines["1"].split("")}
/>
</group>
</group>
<group ref={protocolLine2Ref}>
<mesh scale={[0.5, 0.06, 1]} renderOrder={2}>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
attach="material"
map={bigHudTex}
transparent={true}
depthTest={false}
/>
</mesh>
<group
scale={[0.016, 0.03, 0.016]}
ref={protocolLineTitleRefs.current[1]}
>
<GreenTextRenderer
textToRender={activeNode.protocol_lines["2"].split("")}
/>
</group>
</group>
<group ref={protocolLine3Ref}>
<mesh scale={[0.5, 0.06, 1]} renderOrder={2}>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
attach="material"
map={bigHudTex}
transparent={true}
depthTest={false}
/>
</mesh>
<group
scale={[0.016, 0.03, 0.016]}
ref={protocolLineTitleRefs.current[2]}
>
<GreenTextRenderer
textToRender={activeNode.protocol_lines["3"].split("")}
/>
</group>
</group>
</>
)}
</group>
</group>
);
});
export default HUD;

View file

@ -1,223 +0,0 @@
import React, { useEffect, useRef } from "react";
import level_selection_font from "../../static/sprites/main/select_level_font.png";
import verticalHud from "../../static/sprites/main/select_level_hud_vertical.png";
import horizontalHud from "../../static/sprites/main/select_level_hud_horizontal.png";
import levelSelectionText from "../../static/sprites/main/select_level_text.png";
import upArrow from "../../static/sprites/main/select_level_up_arrow.png";
import downArrow from "../../static/sprites/main/select_level_down_arrow.png";
import upArrowActive from "../../static/sprites/main/select_level_up_arrow_active.png";
import downArrowActive from "../../static/sprites/main/select_level_down_arrow_active.png";
import { useStore } from "../../store";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { a, useSpring } from "@react-spring/three";
import usePrevious from "../../hooks/usePrevious";
const LevelSelection = () => {
const levelSelectionFontTex = useLoader(
THREE.TextureLoader,
level_selection_font
);
const verticalHudTex = useLoader(THREE.TextureLoader, verticalHud);
const horizontalHudTex = useLoader(THREE.TextureLoader, horizontalHud);
const levelSelectionTextTex = useLoader(
THREE.TextureLoader,
levelSelectionText
);
const upArrowTex = useLoader(THREE.TextureLoader, upArrow);
const downArrowTex = useLoader(THREE.TextureLoader, downArrow);
const upArrowActiveTex = useLoader(THREE.TextureLoader, upArrowActive);
const downArrowActiveTex = useLoader(THREE.TextureLoader, downArrowActive);
const selectedLevel = useStore((state) => state.selectedLevel)
.toString()
.padStart(2, "0");
const activeLevel = useStore((state) => state.activeLevel);
const subscene = useStore((state) => state.mainSubscene);
const prevData = usePrevious({ subscene, selectedLevel });
const [pos, set] = useSpring(() => ({
vertPosY: -2.5,
horizPosX: -4,
config: { duration: 500 },
}));
const fstNumberRef = useRef<THREE.Mesh>();
const sndNumberRef = useRef<THREE.Mesh>();
const upArrowRef = useRef<THREE.Sprite>();
const downArrowRef = useRef<THREE.Sprite>();
const upperLimit = useStore((state) => (state.activeSite === "a" ? 22 : 13));
useEffect(() => {
const generateGeom = (number: number) => {
const geometry = new THREE.PlaneBufferGeometry();
const uvAttribute = geometry.attributes.uv;
for (let i = 0; i < uvAttribute.count; i++) {
let u = uvAttribute.getX(i);
let v = uvAttribute.getY(i);
u = (u * 22) / 240 + number / 10;
uvAttribute.setXY(i, u, v);
}
return geometry;
};
if (subscene === "level_selection") {
set({ vertPosY: 0, horizPosX: -0.6 });
if (fstNumberRef.current && sndNumberRef.current) {
fstNumberRef.current.geometry = generateGeom(parseInt(activeLevel[0]));
sndNumberRef.current.geometry = generateGeom(parseInt(activeLevel[1]));
}
} else if (
subscene === "site" &&
prevData?.subscene === "level_selection"
) {
set({ vertPosY: -2.5, horizPosX: -4 });
}
if (selectedLevel !== prevData?.selectedLevel) {
if (fstNumberRef.current && sndNumberRef.current) {
fstNumberRef.current.geometry = generateGeom(
parseInt(selectedLevel[0])
);
sndNumberRef.current.geometry = generateGeom(
parseInt(selectedLevel[1])
);
if (
prevData?.selectedLevel &&
upArrowRef.current &&
downArrowRef.current
) {
if (selectedLevel > prevData?.selectedLevel) {
upArrowRef.current.material.map = upArrowActiveTex;
upArrowRef.current.material.needsUpdate = true;
setTimeout(() => {
upArrowRef.current!.material.map = upArrowTex;
upArrowRef.current!.material.needsUpdate = true;
}, 100);
} else if (selectedLevel < prevData?.selectedLevel) {
downArrowRef.current.material.map = downArrowActiveTex;
downArrowRef.current.material.needsUpdate = true;
setTimeout(() => {
downArrowRef.current!.material.map = downArrowTex;
downArrowRef.current!.material.needsUpdate = true;
}, 100);
}
}
}
}
}, [
activeLevel,
downArrowActiveTex,
downArrowTex,
prevData?.selectedLevel,
prevData?.subscene,
selectedLevel,
set,
subscene,
upArrowActiveTex,
upArrowTex,
]);
return (
<>
<a.group position-y={pos.vertPosY} renderOrder={5}>
<mesh
scale={[0.3, 0.4, 0]}
position={[0.95, 0, 0]}
renderOrder={5}
ref={fstNumberRef}
>
<meshBasicMaterial
map={levelSelectionFontTex}
attach="material"
transparent={true}
depthTest={false}
/>
</mesh>
<mesh
scale={[0.3, 0.4, 0]}
position={[1.23, 0, 0]}
renderOrder={5}
ref={sndNumberRef}
>
<meshBasicMaterial
map={levelSelectionFontTex}
attach="material"
transparent={true}
depthTest={false}
/>
</mesh>
<sprite scale={[0.65, 3, 0]} position={[1.1, -0.8, 0]} renderOrder={4}>
<spriteMaterial
map={verticalHudTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<sprite scale={[0.5, 0.12, 0]} position={[1.1, 0.3, 0]} renderOrder={4}>
<spriteMaterial
map={levelSelectionTextTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<sprite
scale={[0.3, 0.15, 0]}
position={[1.1, -0.35, 0]}
renderOrder={4}
visible={parseInt(selectedLevel) !== 1}
ref={downArrowRef}
>
<spriteMaterial
map={downArrowTex}
attach="material"
transparent={true}
depthTest={false}
color={0xffffff}
/>
</sprite>
<sprite
scale={[0.3, 0.15, 0]}
position={[1.1, 0.5, 0]}
visible={ parseInt(selectedLevel) !== upperLimit}
renderOrder={4}
ref={upArrowRef}
>
<spriteMaterial
map={upArrowTex}
attach="material"
transparent={true}
depthTest={false}
color={0xffffff}
/>
</sprite>
</a.group>
<a.sprite
scale={[3, 0.3, 0]}
position={[-0.6, 0, 0]}
renderOrder={4}
position-x={pos.horizPosX}
>
<spriteMaterial
map={horizontalHudTex}
attach="material"
transparent={true}
depthTest={false}
/>
</a.sprite>
</>
);
};
export default LevelSelection;

View file

@ -1,436 +0,0 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import middleRingTexture from "../../../static/sprites/main/middle_ring_tex.png";
import * as THREE from "three";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../../store";
import MiddleRingPart from "./MiddleRingPart";
import usePrevious from "../../../hooks/usePrevious";
import lerp from "../../../utils/lerp";
import sleep from "../../../utils/sleep";
const MiddleRing = () => {
const middleRingTex = useLoader(THREE.TextureLoader, middleRingTexture);
const vertexShader = `
varying vec2 vUv;
uniform float uTime;
uniform float wobbleStrength;
uniform float noiseAmp;
//
// 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) ) );
}
void main() {
vUv = uv;
// offset of the wobble when jumping
const float angleOffset = -0.8;
// compute world position of the vertex
// (ie, position after model rotation and translation)
vec4 worldPos = modelMatrix * vec4(position, 0.0);
float wobbleAngle = atan(worldPos.x, worldPos.z) + angleOffset;
vec3 pos = position;
// noise modifiers
float noiseFreq = 0.5;
vec3 noisePos = vec3(pos.x * noiseFreq + uTime, pos.y, pos.z);
pos.y += snoise(noisePos) * noiseAmp + wobbleStrength * sin(wobbleAngle * 2.0);
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.);
}
`;
const fragmentShader = `
uniform sampler2D tex;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D( tex, vUv);
}
`;
const clock = new THREE.Clock();
const wordSelected = useStore((state) => state.wordSelected);
const [wobbleAmp, setWobbleAmp] = useState(0);
const [noiseAmp, setNoiseAmp] = useState(0.03);
const [rotating, setRotating] = useState(true);
const [fakeRingVisible, setFakeRingVisible] = useState(false);
const noiseAmpRef = useRef(0.03);
const wobbleAmpRef = useRef(0);
const middleRingMaterialRef = useRef<THREE.ShaderMaterial>();
const middleRingRef = useRef<THREE.Object3D>();
const middleRingPartRef = useRef<THREE.Object3D>();
const deltaRef = useRef(0);
useFrame((state, delta) => {
deltaRef.current += delta;
if (deltaRef.current > 0.016) {
if (middleRingMaterialRef.current) {
middleRingMaterialRef.current.uniforms.uTime.value = clock.getElapsedTime();
wobbleAmpRef.current = lerp(wobbleAmpRef.current, wobbleAmp, 0.1);
noiseAmpRef.current = lerp(noiseAmpRef.current, noiseAmp, 0.1);
middleRingMaterialRef.current.uniforms.wobbleStrength.value =
wobbleAmpRef.current;
middleRingMaterialRef.current.uniforms.noiseAmp.value =
noiseAmpRef.current;
middleRingMaterialRef.current.needsUpdate = true;
}
if (rotating && middleRingRef.current) {
middleRingRef.current!.rotation.y += 0.05;
}
if (rotating && middleRingPartRef.current) {
middleRingPartRef.current!.rotation.y += 0.05;
}
deltaRef.current = deltaRef.current % 0.016;
}
});
const [posState, setPos] = useSpring(() => ({
posY: -0.11,
config: { duration: 600 },
}));
const [rotState, setRot] = useSpring(() => ({
rotX: 0,
rotZ: 0,
config: { duration: 1000 },
}));
const uniforms = useMemo(
() => ({
tex: { type: "t", value: middleRingTex },
uTime: { value: 1.0 },
wobbleStrength: { value: 0.0 },
noiseAmp: { value: 0.03 },
}),
[middleRingTex]
);
const siteRotY = useStore((state) => state.siteRot[1]);
const activeLevel = useStore((state) => state.activeLevel);
const subscene = useStore((state) => state.mainSubscene);
const prevData = usePrevious({ siteRotY, activeLevel, subscene });
const isAnimatingRef = useRef(false);
useEffect(() => {
const rotate = async (rotValues: [number, number]) => {
await sleep(2300);
setRot({ rotZ: rotValues[0] });
await sleep(1200);
setRot({ rotZ: rotValues[1] });
isAnimatingRef.current = false;
await sleep(1000);
setRot({ rotZ: 0 });
};
const moveDown = async () => {
await sleep(800);
setNoiseAmp(0.06);
setRotating(false);
await sleep(400);
setPos({ posY: 1.39 });
await sleep(300);
setRot({ rotX: 0.3 });
await sleep(1500);
setPos({ posY: -0.31 });
await sleep(150);
setPos({ posY: -0.11 });
await sleep(350);
setRot({ rotX: -0.1 });
setNoiseAmp(0);
await sleep(1000);
setRot({ rotX: 0.05 });
await sleep(300);
setRot({ rotX: 0, rotZ: 0 });
setRotating(true);
isAnimatingRef.current = false;
await sleep(6000);
setNoiseAmp(0.03);
};
const moveUp = async () => {
await sleep(300);
setNoiseAmp(0);
setWobbleAmp(0.2);
await sleep(400);
setRotating(false);
await sleep(500);
setWobbleAmp(-0.3);
setPos({ posY: -1.39 });
await sleep(300);
setWobbleAmp(0);
setRot({ rotX: -0.2 });
setRotating(true);
await sleep(1400);
setPos({ posY: 0.09 });
await sleep(250);
setRot({ rotX: 0, rotZ: 0 });
setPos({ posY: -0.11 });
isAnimatingRef.current = false;
await sleep(3000);
setNoiseAmp(0.03);
};
const pause = async () => {
setPos({ posY: 0.5 });
await sleep(600);
setFakeRingVisible(true);
await sleep(500);
// move the hidden (main) ring below, cuz when the pause exists it needs to jump back up
// instead of reappearing
setPos({ posY: -2.5 });
await sleep(2700);
setFakeRingVisible(false);
isAnimatingRef.current = false;
};
const unpause = async () => {
await sleep(300);
setRot({ rotX: -0.4 });
setRotating(true);
await sleep(400);
setPos({ posY: -0.4 });
await sleep(250);
setRot({ rotZ: 0, rotX: 0 });
setPos({ posY: -0.11 });
isAnimatingRef.current = false;
};
const afterWordSelection = async () => {
setRotating(true);
setRot({ rotX: -0.4 });
// reset the rotation value to 0
await sleep(3100);
setRot({ rotZ: 0, rotX: 0 });
isAnimatingRef.current = false;
};
if (!isAnimatingRef.current) {
if (wordSelected) {
isAnimatingRef.current = true;
afterWordSelection();
} else if (
prevData?.siteRotY !== undefined &&
prevData?.siteRotY !== siteRotY
) {
isAnimatingRef.current = true;
rotate(prevData?.siteRotY > siteRotY ? [-0.07, 0.03] : [0.07, -0.03]);
} else if (
prevData?.activeLevel !== undefined &&
prevData.activeLevel !== activeLevel
) {
isAnimatingRef.current = true;
if (prevData?.activeLevel > activeLevel) {
moveDown();
} else if (prevData?.activeLevel < activeLevel) {
moveUp();
}
} else if (subscene === "pause") {
isAnimatingRef.current = true;
pause();
} else if (subscene === "site" && prevData?.subscene === "pause") {
isAnimatingRef.current = true;
unpause();
}
}
}, [
activeLevel,
prevData?.activeLevel,
prevData?.siteRotY,
prevData?.subscene,
setPos,
setRot,
siteRotY,
subscene,
wordSelected,
]);
return (
<a.group rotation-z={rotState.rotZ}>
<a.mesh
position={[0, 0, 0.3]}
position-y={posState.posY}
ref={middleRingRef}
rotation={[0, 0.9, 0]}
rotation-x={rotState.rotX}
visible={!fakeRingVisible}
>
<cylinderBufferGeometry
args={[0.75, 0.75, 0.027, 64, 64, true]}
attach="geometry"
/>
<shaderMaterial
attach="material"
side={THREE.DoubleSide}
uniforms={uniforms}
vertexShader={vertexShader}
fragmentShader={fragmentShader}
ref={middleRingMaterialRef}
transparent={true}
/>
</a.mesh>
{fakeRingVisible && (
<group
rotation={[0, 0.9, 0]}
ref={middleRingPartRef}
position={[0, 0.5, 0.3]}
>
{[...Array(30).keys()].map((i) => {
const angle = (i / 30) * 2 * Math.PI;
return (
<MiddleRingPart
position={[Math.cos(angle) / 1.35, 0, Math.sin(angle) / 1.35]}
rotation={[0, -angle + Math.PI / 2, 0]}
key={angle}
/>
);
})}
</group>
)}
</a.group>
);
};
export default MiddleRing;

View file

@ -1,75 +0,0 @@
import React, { useEffect, useMemo } from "react";
import middleRingTexture from "../../../static/sprites/main/middle_ring_tex.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../../store";
import sleep from "../../../utils/sleep";
type MiddleRingPartProps = {
position: number[];
rotation: number[];
};
const MiddleRingPart = (props: MiddleRingPartProps) => {
const middleRingTex = useLoader(THREE.TextureLoader, middleRingTexture);
const middleRingPartTex = useMemo(() => {
middleRingTex.repeat.set(0.4, 1);
return middleRingTex;
}, [middleRingTex]);
const [posState, setPos] = useSpring(() => ({
posX: props.position[0],
posZ: props.position[2],
config: { duration: 600 },
}));
const subscene = useStore((state) => state.mainSubscene);
useEffect(() => {
(async () => {
const posX = props.position[0];
const posZ = props.position[2];
await sleep(300);
setPos({ posX: posX / 0.9, posZ: posZ / 0.9 });
await sleep(400);
setPos({ posX: posX, posZ: posZ });
await sleep(400);
setPos({ posX: posX / 0.9, posZ: posZ / 0.9 });
await sleep(400);
setPos({ posX: posX, posZ: posZ });
await sleep(800);
setPos({ posX: posX / 0.2, posZ: posZ / 0.2 });
await sleep(700);
setPos({ posX: posX, posZ: posZ });
})();
}, [props.position, setPos, subscene]);
return (
<a.group
position-x={posState.posX}
position-z={posState.posZ}
position-y={props.position[1]}
rotation={props.rotation as [number, number, number]}
>
<a.mesh scale={[0.16, 0.032, 0]}>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
attach="material"
map={middleRingPartTex}
transparent={true}
side={THREE.DoubleSide}
/>
</a.mesh>
</a.group>
);
};
export default MiddleRingPart;

View file

@ -1,221 +0,0 @@
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import * as THREE from "three";
import PauseSquare from "./PauseSquare";
import PauseBigLetter from "../../TextRenderer/PauseBigLetter";
import { useStore } from "../../../store";
const Pause = () => {
const generateSqaureGeom = useCallback((row: number, square: number) => {
const geometry = new THREE.PlaneBufferGeometry();
const uvAttribute = geometry.attributes.uv;
for (let i = 0; i < uvAttribute.count; i++) {
let u = uvAttribute.getX(i);
let v = uvAttribute.getY(i);
u = (u * 16) / 256 + (row * 64) / 256 + (square * 16) / 256;
uvAttribute.setXY(i, u, v);
}
return geometry;
}, []);
const squareGeoms = useMemo(
() =>
[0, 1, 2, 3].map((row: number) =>
[0, 1, 2, 3, 2, 1, 0].map((col: number) => generateSqaureGeom(row, col))
),
[generateSqaureGeom]
);
const letterLocs = useMemo(
() => ({
"05": { letter: "E" },
"11": { letter: "S" },
"33": { letter: "C" },
"45": { letter: "A" },
"51": { letter: "L" },
}),
[]
);
const subscene = useStore((state) => state.mainSubscene);
const scene = useStore((state) => state.currentScene);
const setInputCooldown = useStore((state) => state.setInputCooldown);
const [visible, setVisible] = useState(false);
const [finished, setFinished] = useState(false);
const [exit, setExit] = useState(false);
const activeComponent = useStore(
useCallback((state) => (finished ? state.activePauseComponent : ""), [
finished,
])
);
const isMountedRef = useRef<boolean>();
useEffect(() => {
isMountedRef.current = true;
return () => {
isMountedRef.current = false;
};
}, [scene]);
useEffect(() => {
if (subscene === "pause") {
setTimeout(() => setVisible(true), 4400);
setTimeout(() => setFinished(true), 7300);
setTimeout(() => setInputCooldown(1000), 7600);
return () => {
setExit(true);
if (isMountedRef.current) {
setTimeout(() => {
setVisible(false);
setFinished(false);
setExit(false);
}, 1200);
} else {
setVisible(false);
setFinished(false);
setExit(false);
}
};
}
}, [setInputCooldown, subscene]);
const whenActive = useCallback((rowIdx: number, colIdx: number) => {
switch (rowIdx) {
case 5:
if (colIdx > 1 && colIdx < 5) return "load";
break;
case 4:
if (colIdx > 5 && colIdx < 7) return "about";
break;
case 3:
if (colIdx > 3 && colIdx < 7) return "change";
break;
case 1:
if (colIdx > 1 && colIdx < 5) return "save";
break;
case 0:
if (colIdx > 4 && colIdx < 7) return "exit";
break;
}
}, []);
return (
<>
{visible && (
<group position={[-0.9, -0.7, 0]} scale={[0.85, 0.85, 0]}>
{[0, 1, 2, 3, 2, 1, 0].map((r: number, rowIdx: number) =>
[0, 1, 2, 3, 4, 5, 6].map((c: number, colIdx: number) => {
const key = `${rowIdx}${colIdx}`;
const letter = letterLocs[key as keyof typeof letterLocs];
if (letter)
return (
<React.Fragment key={`${key}fragment`}>
<PauseBigLetter
letter={letter.letter}
letterIdx={0}
position={[colIdx / 2.8, rowIdx / 2.8, 0]}
rowIdx={rowIdx}
colIdx={colIdx}
mainLetter={true}
active={
letter.letter ===
activeComponent.charAt(0).toUpperCase()
}
introFinished={finished}
exit={exit}
/>
<PauseSquare
geometry={squareGeoms[r][c]}
colIdx={colIdx}
rowIdx={rowIdx}
letter={letter.letter}
introFinished={finished}
exit={exit}
/>
</React.Fragment>
);
else
return (
<PauseSquare
geometry={squareGeoms[r][c]}
colIdx={colIdx}
rowIdx={rowIdx}
key={key}
active={activeComponent === whenActive(rowIdx, colIdx)}
introFinished={finished}
exit={exit}
/>
);
})
)}
<>
{"oad".split("").map((letter, idx) => (
<PauseBigLetter
letter={letter}
letterIdx={idx}
key={idx}
position={[2 / 2.8 + idx / 2.8, 5 / 2.8, 0]}
active={activeComponent === "load"}
/>
))}
{"bout".split("").map((letter, idx) => (
<PauseBigLetter
letter={letter}
letterIdx={idx}
position={[6 / 2.8 + idx / 2.8, 4 / 2.8, 0]}
active={activeComponent === "about"}
key={idx}
/>
))}
{"hange".split("").map((letter, idx) => (
<PauseBigLetter
letter={letter}
letterIdx={idx}
position={[4 / 2.8 + idx / 2.8, 3 / 2.8, 0]}
active={activeComponent === "change"}
key={idx}
/>
))}
{"ave".split("").map((letter, idx) => (
<PauseBigLetter
letter={letter}
letterIdx={idx}
position={[2 / 2.8 + idx / 2.8, 1 / 2.8, 0]}
active={activeComponent === "save"}
key={idx}
/>
))}
{"xit".split("").map((letter, idx) => (
<PauseBigLetter
letter={letter}
letterIdx={idx}
position={[6 / 2.8 + idx / 2.8, 0, 0]}
key={idx}
active={activeComponent === "exit"}
/>
))}
</>
</group>
)}
</>
);
};
export default Pause;

View file

@ -1,98 +0,0 @@
import React, { memo, useMemo } from "react";
import pauseGrayBoxes from "../../../static/sprites/main/pause_gray_boxes.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { a, useSpring } from "@react-spring/three";
type PauseSquareProps = {
geometry: THREE.PlaneBufferGeometry;
colIdx: number;
rowIdx: number;
letter?: string;
active?: boolean;
introFinished?: boolean;
exit?: boolean;
};
const PauseSquare = memo((props: PauseSquareProps) => {
const squareTex = useLoader(THREE.TextureLoader, pauseGrayBoxes);
const introSpring = useSpring({
from: {
posX: 1.05,
posY: 1.07,
rotZ: -1,
rotX: Math.PI,
rotY: Math.PI,
},
to: async (next) => {
await next({
posX: props.colIdx / 2.8,
posY: props.rowIdx / 2.8,
rotZ: 0,
config: { duration: 500 },
});
await next({
rotX: 0,
rotY: props.letter ? Math.PI / 2 : 0,
delay: (props.rowIdx + props.colIdx) * 100,
config: { duration: 200 },
});
},
});
const exitAnimValue = useMemo(() => {
let col, row;
if (props.colIdx < 3) col = -1;
else if (props.colIdx > 3) col = 1;
else col = 0;
if (props.rowIdx < 3) row = -1;
else if (props.rowIdx > 3) row = 1;
else row = 0;
return { row: row * 2.2, col: col * 2.2 };
}, [props.colIdx, props.rowIdx]);
const spring = useSpring({
posX: props.colIdx / 2.8 + (props.exit ? exitAnimValue.col : 0),
posY: props.rowIdx / 2.8 + (props.exit ? exitAnimValue.row : 0),
rotY: props.active || props.exit ? Math.PI / 2 : 0,
rotX: props.active ? Math.PI : 0,
config: { duration: 500 },
});
return (
<a.mesh
position-x={props.introFinished ? spring.posX : introSpring.posX}
position-y={props.introFinished ? spring.posY : introSpring.posY}
rotation-z={props.introFinished ? 0 : introSpring.rotZ}
rotation-x={props.introFinished ? spring.rotX : introSpring.rotX}
rotation-y={
!props.letter && props.introFinished ? spring.rotY : introSpring.rotY
}
geometry={props.geometry}
scale={[
props.colIdx > 3 ? -0.25 : 0.25,
props.rowIdx <= 3 ? -0.25 : 0.25,
0,
]}
renderOrder={100}
>
<meshBasicMaterial
attach="material"
map={squareTex}
side={
(props.colIdx > 3 && props.rowIdx <= 3) ||
(props.colIdx <= 3 && props.rowIdx > 3)
? THREE.FrontSide
: THREE.BackSide
}
transparent={true}
depthTest={false}
/>
</a.mesh>
);
});
export default PauseSquare;

View file

@ -1,68 +0,0 @@
import React, { useEffect, useRef } from "react";
import aboutBg from "../../../static/sprites/main/about_background.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../../../store";
import { aboutSceneMusic } from "../../../static/sfx";
const About = () => {
const showingAbout = useStore((state) => state.showingAbout);
const setShowingAbout = useStore((state) => state.setShowingAbout);
const aboutBgTex = useLoader(THREE.TextureLoader, aboutBg);
const bgRef = useRef<THREE.Sprite>();
useFrame((state, delta) => {
if (bgRef.current) {
bgRef.current.position.y += delta;
if (Math.round(bgRef.current.position.y) === 14) {
setShowingAbout(false);
}
}
});
useEffect(() => {
const play = () => {
aboutSceneMusic.currentTime = 1;
aboutSceneMusic.volume = 0.5;
aboutSceneMusic.loop = true;
aboutSceneMusic.play();
};
if (showingAbout) play();
return () => {
aboutSceneMusic.pause();
};
}, [showingAbout]);
return (
<>
{showingAbout && (
<>
<sprite renderOrder={199} scale={[100, 100, 0]}>
<spriteMaterial
attach="material"
color={0x000000}
depthTest={false}
/>
</sprite>
<sprite
ref={bgRef}
scale={[10.5 / 2.5, 52.8 / 2.5, 0]}
position={[1.1, -11.5, 0.1]}
renderOrder={200}
>
<spriteMaterial
attach="material"
map={aboutBgTex}
depthTest={false}
/>
</sprite>
</>
)}
</>
);
};
export default About;

View file

@ -1,31 +0,0 @@
import React, { memo } from "react";
import notFound from "../../../static/sprites/main/not_found.png";
import notFoundLof from "../../../static/sprites/main/not_found_lof.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../../../store";
const NotFound = memo(() => {
const notFoundTex = useLoader(THREE.TextureLoader, notFound);
const notFoundLofTex = useLoader(THREE.TextureLoader, notFoundLof);
const wordNotFound = useStore((state) => state.wordNotFound);
return (
<group visible={wordNotFound}>
<sprite scale={[1, 0.25, 0]} renderOrder={106} position={[-1, -0.05, 0]}>
<spriteMaterial
attach="material"
map={notFoundLofTex}
depthTest={false}
/>
</sprite>
<sprite scale={[4.1, 0.6, 0]} renderOrder={105} position={[0, -0.15, 0]}>
<spriteMaterial attach="material" map={notFoundTex} depthTest={false} />
</sprite>
</group>
);
});
export default NotFound;

View file

@ -1,33 +0,0 @@
import React, { memo } from "react";
import headerContainer from "../../../static/sprites/prompt/prompt_question_container.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import StaticOrangeLetter from "../../TextRenderer/StaticOrangeLetter";
import { useStore } from "../../../store";
const PermissionDenied = memo(() => {
const headerContainerTex = useLoader(THREE.TextureLoader, headerContainer);
const permissionDenied = useStore((state) => state.permissionDenied);
return (
<group position={[0, 0.5, 0]} visible={permissionDenied}>
<sprite scale={[5, 0.36, 0]} renderOrder={200} position={[1, 0.2, 0]}>
<spriteMaterial
map={headerContainerTex}
attach="material"
transparent={true}
opacity={0.6}
depthTest={false}
/>
</sprite>
<group scale={[0.08, 0.7, 0]} position={[0, 0.19, 0]}>
{"Permission denied".split("").map((letter, idx) => (
<StaticOrangeLetter letter={letter} letterIdx={idx} key={idx} />
))}
</group>
</group>
);
});
export default PermissionDenied;

View file

@ -1,24 +0,0 @@
import React, { memo } from "react";
import About from "./About";
import Prompt from "../../Prompt";
import PermissionDenied from "./PermissionDenied";
import Status from "../../Status";
import NotFound from "./NotFound";
const Popups = memo(() => {
return (
<>
<group position={[-0.85, -0.7, 0]} scale={[0.85, 0.85, 0]}>
<group position={[1, 0.6, 0]} scale={[1.2, 1.2, 0]}>
<Prompt />
</group>
<About />
<PermissionDenied />
<Status />
</group>
<NotFound />
</>
);
});
export default Popups;

View file

@ -1,69 +0,0 @@
import React, { memo, useEffect, useState } from "react";
import Node from "./Node";
import node_positions from "../../../resources/node_positions.json";
import { useStore } from "../../../store";
import usePrevious from "../../../hooks/usePrevious";
import {NodeData, SiteData} from "../../../types/types";
type ActiveLevelNodesProps = {
visibleNodes: SiteData;
};
const ActiveLevelNodes = memo((props: ActiveLevelNodesProps) => {
const activeNodeId = useStore((state) => state.activeNode.id);
const activeLevel = useStore((state) => state.activeLevel);
const prevData = usePrevious({ activeLevel });
const [visibleNodes, setVisibleNodes] = useState(
props.visibleNodes[activeLevel]
);
useEffect(() => {
if (
prevData?.activeLevel !== activeLevel &&
prevData?.activeLevel !== undefined
) {
const prevLevel = parseInt(prevData?.activeLevel);
const newLevel = parseInt(activeLevel);
if (prevLevel - 1 === newLevel || prevLevel + 1 === newLevel) {
setVisibleNodes(
props.visibleNodes[activeLevel as keyof typeof props.visibleNodes]
);
} else {
setTimeout(
() =>
setVisibleNodes(
props.visibleNodes[activeLevel as keyof typeof props.visibleNodes]
),
1500
);
}
}
}, [activeLevel, prevData?.activeLevel, props, props.visibleNodes]);
return (
<>
{Object.values(visibleNodes).map((node: NodeData) => {
return (
<Node
nodeName={node.node_name}
position={
node_positions[node.id.substr(2) as keyof typeof node_positions]
.position
}
rotation={
node_positions[node.id.substr(2) as keyof typeof node_positions]
.rotation
}
key={node.node_name}
active={node.id === activeNodeId}
level={node.id.substr(0, 2)}
viewed={Boolean(node.is_viewed)}
/>
);
})}
</>
);
});
export default ActiveLevelNodes;

View file

@ -1,36 +0,0 @@
import React, { memo } from "react";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
type CrystalRingProps = {
crystalRingPosY: number;
};
type GLTFResult = GLTF & {
nodes: {
gron: THREE.Mesh;
};
materials: {};
};
const CyanCrystal = memo((props: CrystalRingProps) => {
const { nodes } = useLoader<GLTFResult>(GLTFLoader, "models/cyan_crystal.glb");
return (
<mesh
geometry={nodes.gron.geometry}
position={[1.3, props.crystalRingPosY, -0.1]}
scale={[4, 8, 4]}
rotation={[0, -4.6, 0]}
>
<meshPhongMaterial
attach="material"
color={0x04f9d2}
side={THREE.DoubleSide}
/>
</mesh>
);
});
export default CyanCrystal;

View file

@ -1,181 +0,0 @@
import React, { memo, useMemo } from "react";
import * as THREE from "three";
import lofTexture from "../../../static/sprites/main/gray_ring_lof.png";
import holeTexture from "../../../static/sprites/main/hole.png";
import lifeTexture from "../../../static/sprites/main/life.png";
import { useLoader } from "react-three-fiber";
type GrayRingProps = {
grayRingPosY: number;
};
const GrayRing = memo((props: GrayRingProps) => {
const lofTex = useLoader(THREE.TextureLoader, lofTexture);
const holeTex = useLoader(THREE.TextureLoader, holeTexture);
const lifeTex = useLoader(THREE.TextureLoader, lifeTexture);
const uniforms = useMemo(() => {
const uniform = THREE.UniformsUtils.merge([THREE.UniformsLib["lights"]]);
uniform.lof = { type: "t", value: lofTex };
uniform.hole = { type: "t", value: holeTex };
uniform.life = { type: "t", value: lifeTex };
return uniform;
}, [holeTex, lifeTex, lofTex]);
const vertexShader = `
varying vec2 vUv;
varying vec3 vPos;
varying vec3 vNormal;
void main() {
vUv = uv;
vPos = (modelMatrix * vec4(position, 1.0 )).xyz;
vNormal = normalMatrix * normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.);
}
`;
const fragmentShader = `
varying vec2 vUv;
uniform sampler2D lof;
uniform sampler2D hole;
uniform sampler2D life;
// lights
varying vec3 vPos;
varying vec3 vNormal;
struct PointLight {
vec3 position;
vec3 color;
float distance;
};
uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
// transform coordinates to uniform within segment
float tolocal(float x, int segments, float step) {
float period = 1.0/step*float(segments);
return mod(x, period) / period;
}
// check if coordinate is within the given height
bool isheight(float y, float thin) {
return y > 0.5-thin/2.0 && y < 0.5+thin/2.0;
}
// sloping function
float slope(float x, float thin) {
return x*(1.0-thin)/2.0;
}
// frag color / texture
// #424252 hex in original textures
vec4 color(vec2 vUv, int quadnum, bool textureexists, int thinperiod, int quadlen, float step) {
if (!textureexists) {
return vec4(0.259,0.259,0.322, 1);
} else if (mod(float(quadnum), 2.0) == 1.0) {
return texture2D(hole, vec2(tolocal(vUv.x, quadlen-thinperiod, step), vUv.y));
// return vec4(tolocal(vUv.x, quadlen-thinperiod, step), 0, 0, 1);
} else if (quadnum == 0) {
return texture2D(lof, vec2(tolocal(vUv.x, quadlen-thinperiod, step), vUv.y));
} else {
return texture2D(life, vec2(tolocal(vUv.x, quadlen-thinperiod, step), vUv.y));
}
}
void main() {
//lights
vec4 addedLights = vec4(0.0,
0.0,
0.0,
1.0);
for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
vec3 lightDirection = normalize(vPos
- pointLights[l].position);
addedLights.rgb += clamp(dot(-lightDirection,
vNormal), 0.0, 1.0)
* pointLights[l].color
* 50.0;
}
// number of segments
float step = 64.0;
// thin line height
float thin = 0.3;
// segment within circle
int segment = int(floor(vUv.x * step));
int quadlen = int(step)/4;
// segment within circle's quad
int quadel = int(mod(float(segment), float(quadlen)));
// which quad
int quadnum = int(int(segment) / int(quadlen));
// how big thin part is
int thinperiod = 8;
if (quadel < thinperiod && isheight(vUv.y, thin)) {
// thin line
gl_FragColor = color(vUv, quadnum, false, thinperiod, quadlen, step) * addedLights;
} else if (quadel == thinperiod) {
// slope up
float dist = tolocal(vUv.x, 1, step);
if (vUv.y > slope(1.0-dist, thin) && vUv.y < 1.0-slope(1.0-dist, thin)) {
gl_FragColor = color(vUv, quadnum, true, thinperiod, quadlen, step) * addedLights;
} else {
gl_FragColor = vec4(0, 0, 0, 0);
}
} else if (quadel == quadlen-1) {
// slope down
float dist = tolocal(vUv.x, 1, step);
if (vUv.y > slope(dist, thin) && vUv.y < 1.0-slope(dist, thin)) {
gl_FragColor = color(vUv, quadnum, true, thinperiod, quadlen, step) * addedLights;
} else {
gl_FragColor = vec4(0, 0, 0, 0);
}
} else if (quadel > thinperiod) {
gl_FragColor = color(vUv, quadnum, true, thinperiod, quadlen, step) * addedLights;
} else {
// transparent
gl_FragColor = vec4(0, 0, 0, 0);
}
}
`;
return (
<mesh
position={[0, props.grayRingPosY, 0]}
rotation={[0, 3.95, 0]}
renderOrder={1}
scale={[33, 33, 33]}
>
<cylinderBufferGeometry
args={[0.036, 0.036, 0.003, 64, 64, true]}
attach="geometry"
/>
<shaderMaterial
attach="material"
side={THREE.DoubleSide}
vertexShader={vertexShader}
fragmentShader={fragmentShader}
transparent={true}
uniforms={uniforms}
lights={true}
/>
</mesh>
);
});
export default GrayRing;

View file

@ -1,95 +0,0 @@
import React, { memo, useMemo } from "react";
import { useLoader } from "react-three-fiber";
import { a } from "@react-spring/three";
import * as THREE from "three";
import Cou from "../../../static/sprites/nodes/Cou.png";
import CouViewed from "../../../static/sprites/nodes/Cou_viewed.png";
import Dc from "../../../static/sprites/nodes/Dc.png";
import DcViewed from "../../../static/sprites/nodes/Dc_viewed.png";
import Sskn from "../../../static/sprites/nodes/SSkn.png";
import SsknViewed from "../../../static/sprites/nodes/SSkn_viewed.png";
import Tda from "../../../static/sprites/nodes/Tda.png";
import TdaViewed from "../../../static/sprites/nodes/Tda_viewed.png";
import Dia from "../../../static/sprites/nodes/Dia.png";
import DiaViewed from "../../../static/sprites/nodes/Dia_viewed.png";
import Lda from "../../../static/sprites/nodes/Lda.png";
import LdaViewed from "../../../static/sprites/nodes/Lda_viewed.png";
import MULTI from "../../../static/sprites/nodes/MULTI.png";
import MULTIViewed from "../../../static/sprites/nodes/MULTI_viewed.png";
import level_y_values from "../../../resources/level_y_values.json";
type NodeContructorProps = {
nodeName: string;
position: number[];
rotation: number[];
level: string;
viewed: boolean;
};
const InactiveLevelNode = memo((props: NodeContructorProps) => {
const tex = useMemo(() => {
if (props.nodeName.includes("S")) {
return [Sskn, SsknViewed];
} else if (
props.nodeName.startsWith("P") ||
props.nodeName.startsWith("G") ||
props.nodeName.includes("?")
) {
return [MULTI, MULTIViewed];
} else if (props.nodeName.includes("Dc")) {
return [Dc, DcViewed];
} else {
switch (props.nodeName.substr(0, 3)) {
case "Tda":
return [Tda, TdaViewed];
case "Cou":
return [Cou, CouViewed];
case "Dia":
return [Dia, DiaViewed];
case "Lda":
return [Lda, LdaViewed];
case "Ere":
case "Ekm":
case "Eda":
case "TaK":
case "Env":
return [MULTI, MULTIViewed];
}
}
}, [props.nodeName]);
const nonActiveTexture = useLoader(
THREE.TextureLoader,
props.viewed ? tex![1] : tex![0]
);
return (
<group
position={[
0,
level_y_values[props.level as keyof typeof level_y_values],
0,
]}
>
<a.mesh
position-x={props.position[0]}
position-y={props.position[1]}
position-z={props.position[2]}
rotation-y={props.rotation[1]}
rotation-z={0}
scale={[0.36, 0.18, 0.36]}
renderOrder={1}
>
<planeBufferGeometry attach="geometry" />
<meshStandardMaterial
attach="material"
map={nonActiveTexture}
side={THREE.DoubleSide}
transparent={true}
/>
</a.mesh>
</group>
);
});
export default InactiveLevelNode;

View file

@ -1,66 +0,0 @@
import React, { memo, useEffect, useState } from "react";
import node_positions from "../../../resources/node_positions.json";
import { useStore } from "../../../store";
import InactiveLevelNode from "./InactiveLevelNode";
import usePrevious from "../../../hooks/usePrevious";
import { generateInactiveNodes } from "../../../helpers/node-helpers";
import {SiteData} from "../../../types/types";
type ActiveLevelNodesProps = {
visibleNodes: SiteData;
};
const InactiveLevelNodes = memo((props: ActiveLevelNodesProps) => {
const activeLevel = useStore((state) => state.activeLevel);
const prevData = usePrevious({ activeLevel });
const [visibleNodes, setVisibleNodes] = useState<{}>(
generateInactiveNodes(props.visibleNodes, activeLevel)
);
useEffect(() => {
if (
prevData?.activeLevel !== activeLevel &&
prevData?.activeLevel !== undefined
) {
const prevLevel = parseInt(prevData?.activeLevel);
const newLevel = parseInt(activeLevel);
// if singular jump
if (prevLevel - 1 === newLevel || prevLevel + 1 === newLevel) {
setVisibleNodes(generateInactiveNodes(props.visibleNodes, activeLevel));
} else {
// if changed from level selection
setTimeout(
() =>
setVisibleNodes(
generateInactiveNodes(props.visibleNodes, activeLevel)
),
1500
);
}
}
}, [activeLevel, prevData?.activeLevel, props.visibleNodes]);
return (
<>
{Object.entries(visibleNodes).map((node: [string, any]) => (
<InactiveLevelNode
nodeName={node[1].node_name}
position={
node_positions[node[0].substr(2) as keyof typeof node_positions]
.position
}
rotation={
node_positions[node[0].substr(2) as keyof typeof node_positions]
.rotation
}
key={node[1].node_name}
level={node[0].substr(0, 2)}
viewed={Boolean(node[1].is_viewed)}
/>
))}
</>
);
});
export default InactiveLevelNodes;

View file

@ -1,21 +0,0 @@
import React, { memo } from "react";
import mainSceneBg from "../../../static/sprites/main/main_scene_background.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
const MainSceneBackground = memo(() => {
const mainSceneBgTex = useLoader(THREE.TextureLoader, mainSceneBg);
return (
<mesh renderOrder={-5} scale={[5, 1, 0]}>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
attach="material"
map={mainSceneBgTex}
depthTest={false}
/>
</mesh>
);
});
export default MainSceneBackground;

View file

@ -1,230 +0,0 @@
import React, { memo, useEffect, useMemo, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import { a, useSpring } from "@react-spring/three";
import * as THREE from "three";
import Cou from "../../../static/sprites/nodes/Cou.png";
import CouActive from "../../../static/sprites/nodes/Cou_active.png";
import CouViewed from "../../../static/sprites/nodes/Cou_viewed.png";
import Dc from "../../../static/sprites/nodes/Dc.png";
import DcActive from "../../../static/sprites/nodes/Dc_active.png";
import DcViewed from "../../../static/sprites/nodes/Dc_viewed.png";
import Sskn from "../../../static/sprites/nodes/SSkn.png";
import SsknActive from "../../../static/sprites/nodes/SSkn_active.png";
import SsknViewed from "../../../static/sprites/nodes/SSkn_viewed.png";
import Tda from "../../../static/sprites/nodes/Tda.png";
import TdaActive from "../../../static/sprites/nodes/Tda_active.png";
import TdaViewed from "../../../static/sprites/nodes/Tda_viewed.png";
import Dia from "../../../static/sprites/nodes/Dia.png";
import DiaActive from "../../../static/sprites/nodes/Dia_active.png";
import DiaViewed from "../../../static/sprites/nodes/Dia_viewed.png";
import Lda from "../../../static/sprites/nodes/Lda.png";
import LdaActive from "../../../static/sprites/nodes/Lda_active.png";
import LdaViewed from "../../../static/sprites/nodes/Lda_viewed.png";
import MULTI from "../../../static/sprites/nodes/MULTI.png";
import MULTIActive from "../../../static/sprites/nodes/MULTI_active.png";
import MULTIViewed from "../../../static/sprites/nodes/MULTI_viewed.png";
import level_y_values from "../../../resources/level_y_values.json";
import { useStore } from "../../../store";
type NodeContructorProps = {
nodeName: string;
position: number[];
rotation: number[];
active: boolean;
level: string;
viewed: boolean;
};
const Node = memo((props: NodeContructorProps) => {
const tex = useMemo(() => {
if (props.nodeName.includes("S")) {
return [Sskn, SsknActive, SsknViewed];
} else if (
props.nodeName.startsWith("P") ||
props.nodeName.startsWith("G") ||
props.nodeName.includes("?")
) {
return [MULTI, MULTIActive, MULTIViewed];
} else if (props.nodeName.includes("Dc")) {
return [Dc, DcActive, DcViewed];
} else {
switch (props.nodeName.substr(0, 3)) {
case "Tda":
return [Tda, TdaActive, TdaViewed];
case "Cou":
return [Cou, CouActive, CouViewed];
case "Dia":
return [Dia, DiaActive, DiaViewed];
case "Lda":
return [Lda, LdaActive, LdaViewed];
case "Ere":
case "Ekm":
case "Eda":
case "TaK":
case "Env":
return [MULTI, MULTIActive, MULTIViewed];
}
}
}, [props.nodeName]);
const paused = useStore((state) => state.mainSubscene === "pause");
const materialRef = useRef<THREE.ShaderMaterial>();
const nonActiveTexture = useLoader(
THREE.TextureLoader,
props.viewed ? tex![2] : tex![0]
);
const activeTexture = useLoader(THREE.TextureLoader, tex![1]);
const uniforms = useMemo(
() => ({
tex1: { type: "t", value: nonActiveTexture },
tex2: { type: "t", value: activeTexture },
timeMSeconds: { value: (Date.now() % (Math.PI * 2000)) / 1000.0 },
}),
[nonActiveTexture, activeTexture]
);
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
precision highp float;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform float timeMSeconds;
varying vec2 vUv;
void main() {
vec4 t1 = texture2D(tex1,vUv);
vec4 t2 = texture2D(tex2,vUv);
float bias = (1.0 - timeMSeconds) - floor(1.0 - timeMSeconds);
gl_FragColor = mix(t1, t2, bias);
}
`;
const [
{
activeNodePosX,
activeNodePosY,
activeNodePosZ,
activeNodeRotZ,
activeNodeVisible,
activeNodeScale,
},
set,
] = useSpring(() => ({
activeNodePosX: props.position[0],
activeNodePosY: props.position[1],
activeNodePosZ: props.position[2],
activeNodeRotZ: 0,
activeNodeScale: 1,
activeNodeVisible: true,
config: { duration: 800 },
}));
useEffect(
() =>
useStore.subscribe(set, (state) => ({
activeNodePosX: state.activeNodeAttributes.interactedWith
? state.activeNodePos[0]
: props.position[0],
activeNodePosY: state.activeNodeAttributes.interactedWith
? state.activeNodePos[1]
: props.position[1],
activeNodePosZ: state.activeNodeAttributes.interactedWith
? state.activeNodePos[2]
: props.position[2],
activeNodeRotZ: state.activeNodeAttributes.interactedWith
? state.activeNodeRot[2]
: 0,
activeNodeScale: state.activeNodeAttributes.shrinking ? 0 : 1,
activeNodeVisible: state.activeNodeAttributes.visible,
})),
[
props.level,
activeNodePosX,
activeNodePosZ,
activeNodeRotZ,
props.position,
set,
props.rotation,
]
);
useFrame(() => {
if (materialRef.current) {
materialRef.current.uniforms.timeMSeconds.value =
(Date.now() % 3000) / 1500.0;
}
});
return (
<group
position={[
0,
level_y_values[props.level as keyof typeof level_y_values],
0,
]}
>
{props.active && !paused ? (
<a.group
scale-x={activeNodeScale}
scale-y={activeNodeScale}
scale-z={activeNodeScale}
>
<a.mesh
position-x={activeNodePosX}
position-y={activeNodePosY}
position-z={activeNodePosZ}
rotation-z={activeNodeRotZ}
rotation-y={props.rotation[1]}
visible={activeNodeVisible}
scale={[0.36, 0.18, 0.36]}
renderOrder={1}
>
<planeBufferGeometry attach="geometry" />
<shaderMaterial
ref={materialRef}
attach="material"
uniforms={uniforms}
fragmentShader={fragmentShader}
vertexShader={vertexShader}
side={THREE.DoubleSide}
transparent={true}
/>
</a.mesh>
</a.group>
) : (
<a.mesh
position-x={props.position[0]}
position-y={props.position[1]}
position-z={props.position[2]}
rotation-y={props.rotation[1]}
rotation-z={0}
scale={[0.36, 0.18, 0.36]}
renderOrder={1}
>
<planeBufferGeometry attach="geometry" />
<meshStandardMaterial
attach="material"
map={nonActiveTexture}
side={THREE.DoubleSide}
transparent={true}
/>
</a.mesh>
)}
</group>
);
});
export default Node;

View file

@ -1,23 +0,0 @@
import React from "react";
import { useStore } from "../../../store";
import NodeExplosion from "./NodeAnimations/NodeExplosion";
import NodeRip from "./NodeAnimations/NodeRip";
const NodeAnimations = () => {
const nodeShrinking = useStore(
(state) => state.activeNodeAttributes.shrinking
);
const nodeExploding = useStore(
(state) => state.activeNodeAttributes.exploding
);
return (
<>
{nodeExploding && <NodeExplosion />}
{nodeShrinking && <NodeRip />}
</>
);
};
export default NodeAnimations;

View file

@ -1,74 +0,0 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import ExplosionLine from "./NodeExplosion/ExplosionLine";
import node_explosion_line_positions from "../../../../resources/node_explosion_line_positions.json";
import { useFrame } from "react-three-fiber";
import GoldNode from "./NodeExplosion/GoldNode";
import { useStore } from "../../../../store";
const NodeExplosion = () => {
const explosionVisible = useStore(
(state) => state.activeNodeAttributes.exploding
);
const [shouldAnimate, setShouldAnimate] = useState(false);
const [shouldRotate, setShouldRotate] = useState(false);
const [currentFrame, setCurrentFrame] = useState(1);
const linePoses = useMemo(
() =>
node_explosion_line_positions[
currentFrame.toString() as keyof typeof node_explosion_line_positions
],
[currentFrame]
);
const lastTime = useRef(0);
useFrame(() => {
if (shouldAnimate) {
const now = Date.now();
if (now > lastTime.current + 100) {
if (currentFrame < 6) {
setCurrentFrame(currentFrame + 1);
lastTime.current = now;
}
}
}
});
useEffect(() => {
if (explosionVisible) {
setShouldRotate(true);
setTimeout(() => setShouldAnimate(true), 1100);
} else {
setShouldAnimate(false);
setShouldRotate(false);
setCurrentFrame(1);
}
}, [explosionVisible]);
return explosionVisible ? (
<group position={[-0.5, 0.45, 0]}>
<group
visible={shouldAnimate}
position={[-0.1, 0.1, 0]}
scale={[1.2, 1.2, 1.2]}
>
{Object.values(linePoses).map((entry, idx) => (
<ExplosionLine
rotation={entry.rotation as [number, number, number]}
position={entry.position as [number, number, number]}
color={entry.color}
length={entry.length}
key={idx}
/>
))}
</group>
<GoldNode visible={shouldRotate} goldTexture={shouldAnimate} />
</group>
) : (
<></>
);
};
export default NodeExplosion;

View file

@ -1,70 +0,0 @@
import React, { useMemo } from "react";
import * as THREE from "three";
type LineProps = {
rotation: number[];
position: number[];
color: string;
length: number;
};
const ExplosionLine = (props: LineProps) => {
const uniforms = useMemo(
() => ({
color1: {
value: new THREE.Color("white"),
},
color2: {
value: new THREE.Color(
props.color === "yellow" ? "#f5cc16" : "#e33d00"
),
},
}),
[props.color]
);
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
uniform vec3 color1;
uniform vec3 color2;
uniform float alpha;
varying vec2 vUv;
void main() {
float alpha = smoothstep(1.0, 0.0, vUv.y);
float colorMix = smoothstep(1.0, 2.0, 1.8);
gl_FragColor = vec4(mix(color1, color2, colorMix), alpha) * 0.6;
}
`;
return (
<mesh
rotation={props.rotation as [number, number, number]}
position={props.position as [number, number, number]}
scale={[0.01, props.length, 0]}
renderOrder={2}
>
<boxBufferGeometry attach="geometry" args={[1, 1, 1]} />
<shaderMaterial
attach="material"
fragmentShader={fragmentShader}
vertexShader={vertexShader}
transparent={true}
depthWrite={false}
uniforms={uniforms}
/>
</mesh>
);
};
export default ExplosionLine;

View file

@ -1,108 +0,0 @@
import React, { useEffect, useMemo, useRef } from "react";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import * as THREE from "three";
import { useFrame, useLoader } from "react-three-fiber";
import Cou from "../../../../../static/sprites/nodes/Cou.png";
import CouGold from "../../../../../static/sprites/nodes/Cou_gold.png";
import Dc from "../../../../../static/sprites/nodes/Dc.png";
import DcGold from "../../../../../static/sprites/nodes/Dc_gold.png";
import Sskn from "../../../../../static/sprites/nodes/SSkn.png";
import SsknGold from "../../../../../static/sprites/nodes/SSkn_gold.png";
import Tda from "../../../../../static/sprites/nodes/Tda.png";
import TdaGold from "../../../../../static/sprites/nodes/Tda_gold.png";
import Dia from "../../../../../static/sprites/nodes/Dia.png";
import DiaGold from "../../../../../static/sprites/nodes/Dia_gold.png";
import Lda from "../../../../../static/sprites/nodes/Lda.png";
import LdaGold from "../../../../../static/sprites/nodes/Lda_gold.png";
import MULTI from "../../../../../static/sprites/nodes/MULTI.png";
import MULTIGold from "../../../../../static/sprites/nodes/MULTI_gold.png";
import { useStore } from "../../../../../store";
type GLTFResult = GLTF & {
nodes: {
Cube: THREE.Mesh;
};
materials: {
Material: THREE.MeshStandardMaterial;
};
};
type GoldNodeProps = {
visible: boolean;
goldTexture: boolean;
};
const GoldNode = (props: GoldNodeProps) => {
const { nodes } = useLoader<GLTFResult>(GLTFLoader, "models/gold_node.glb");
const activeNodeName = useStore((state) => state.activeNode.node_name);
const tex = useMemo(() => {
if (activeNodeName.includes("S")) {
return [Sskn, SsknGold];
} else if (
activeNodeName.startsWith("P") ||
activeNodeName.startsWith("G") ||
activeNodeName.includes("?")
) {
return [MULTI, MULTIGold];
} else if (activeNodeName.includes("Dc")) {
return [Dc, DcGold];
} else {
switch (activeNodeName.substr(0, 3)) {
case "Tda":
return [Tda, TdaGold];
case "Cou":
return [Cou, CouGold];
case "Dia":
return [Dia, DiaGold];
case "Lda":
return [Lda, LdaGold];
case "Ere":
case "Ekm":
case "Eda":
case "TaK":
case "Env":
return [MULTI, MULTIGold];
}
}
}, [activeNodeName]);
const goldNodeRef = useRef<THREE.Object3D>();
const regularTex = useLoader(THREE.TextureLoader, tex![0]);
const goldTex = useLoader(THREE.TextureLoader, tex![1]);
useEffect(() => {
if (goldNodeRef.current && !props.visible) {
goldNodeRef.current.rotation.x = Math.PI / 2;
goldNodeRef.current.rotation.y = 0;
goldNodeRef.current.rotation.z = Math.PI / 2 - 0.3;
}
}, [props.visible]);
useFrame((state, delta) => {
if (goldNodeRef.current && props.visible) {
goldNodeRef.current.rotation.y -= delta * 2;
goldNodeRef.current.rotation.z += delta * 2;
}
});
return (
<mesh
geometry={nodes.Cube.geometry}
position={[-0.155, -0.45, 0]}
rotation={[Math.PI / 2, 0, Math.PI / 2 - 0.3]}
scale={[-0.1 / 1.15, 0.2 / 1.35, 0.1 / 1.15]}
ref={goldNodeRef}
>
<meshBasicMaterial
attach="material"
map={props.goldTexture ? goldTex : regularTex}
transparent={true}
/>
</mesh>
);
};
export default GoldNode;

View file

@ -1,109 +0,0 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import TriangleNode from "./NodeRip/TriangleNode";
import { useStore } from "../../../../store";
import RipLine from "./NodeRip/RipLine";
import { useFrame } from "react-three-fiber";
const NodeRip = () => {
const nodeShrinking = useStore(
(state) => state.activeNodeAttributes.shrinking
);
const [shouldAnimate, setShouldAnimate] = useState(false);
const LCG = (a: number, c: number, m: number, s: number) => () =>
(s = (s * a + c) % m);
const lcgInstance = useMemo(() => LCG(1664525, 1013904223, 2 ** 32, 2), []);
const firstLineSet = Array.from({ length: 25 }, (_, idx) => {
let coordSet = [lcgInstance() / 7000000000, lcgInstance() / 7000000000];
if (coordSet[0] > 0.45) coordSet[0] = coordSet[0] * -1;
if (coordSet[1] > 0.45) coordSet[1] = coordSet[1] * -1;
const color = idx % 2 === 0 ? "red" : "yellow";
return { coordinates: coordSet, color: color };
});
const sndLineSet = Array.from({ length: 25 }, (_, idx) => {
let coordSet = [lcgInstance() / 6000000000, lcgInstance() / 6000000000];
if (coordSet[0] > 0.65) coordSet[0] = coordSet[0] * -1;
if (coordSet[1] > 0.65) coordSet[1] = coordSet[1] * -1;
const color = idx % 2 === 0 ? "yellow" : "red";
return { coordinates: coordSet, color: color };
});
const [currentFrame, setCurrentFrame] = useState(0);
const lastTime = useRef(0);
useFrame(() => {
if (shouldAnimate) {
const now = Date.now();
if (currentFrame < 3) {
if (now > lastTime.current + 200) {
setCurrentFrame(currentFrame + 1);
lastTime.current = now;
}
}
}
});
useEffect(() => {
if (nodeShrinking) setTimeout(() => setShouldAnimate(true), 1150);
else {
setShouldAnimate(false);
setCurrentFrame(1);
}
}, [nodeShrinking]);
return (
<group visible={shouldAnimate}>
<TriangleNode
rotation={[1.3, 1.6, 0]}
pivotRotation={[0, -Math.PI / 4 - 0.5, 0]}
shouldAnimate={shouldAnimate}
/>
<TriangleNode
rotation={[0.4, 0.3, 0]}
pivotRotation={[0, -Math.PI / 8, 0]}
shouldAnimate={shouldAnimate}
/>
<TriangleNode
rotation={[1.6, 2.6, 0]}
pivotRotation={[0, Math.PI / 4 + 0.5, 0]}
shouldAnimate={shouldAnimate}
/>
<TriangleNode
rotation={[-0.7, 1.8, 0]}
pivotRotation={[0, Math.PI / 8, 0]}
shouldAnimate={shouldAnimate}
/>
<group position={[-0.05, -0.3, 0.1]}>
<group visible={currentFrame === 1}>
{firstLineSet.map((data, idx) => (
<RipLine
color={data.color}
endPoints={data.coordinates}
key={idx}
/>
))}
</group>
<group visible={currentFrame === 2}>
{sndLineSet.map((data, idx) => (
<RipLine
color={data.color}
endPoints={data.coordinates}
key={idx}
/>
))}
</group>
</group>
</group>
);
};
export default NodeRip;

View file

@ -1,36 +0,0 @@
import React, { useMemo } from "react";
import * as THREE from "three";
import { useUpdate } from "react-three-fiber";
type RipLineProps = {
color: string;
endPoints: number[];
};
const RipLine = (props: RipLineProps) => {
const points = useMemo(
() => [
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(props.endPoints[0], props.endPoints[1], 0),
],
[props.endPoints]
);
const lineGeomRef = useUpdate((geometry: THREE.BufferGeometry) => {
geometry.setFromPoints(points);
}, []);
return (
<line>
<bufferGeometry attach="geometry" ref={lineGeomRef} />
<lineBasicMaterial
attach="material"
color={props.color === "yellow" ? "#f5cc16" : "#e33d00"}
transparent={true}
opacity={0.4}
/>
</line>
);
};
export default RipLine;

View file

@ -1,44 +0,0 @@
import React, { useEffect, useRef } from "react";
import MULTI from "../../../../../static/sprites/nodes/MULTI.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
type TriangleNodeProps = {
rotation: number[];
pivotRotation: number[];
shouldAnimate: boolean;
};
const TriangleNode = (props: TriangleNodeProps) => {
const tex = useLoader(THREE.TextureLoader, MULTI);
const triangleNodeRef = useRef<THREE.Object3D>();
useFrame((state, delta) => {
if (triangleNodeRef.current && props.shouldAnimate) {
triangleNodeRef.current.position.z += delta * 2.8;
}
});
useEffect(() => {
if (triangleNodeRef.current && !props.shouldAnimate) {
triangleNodeRef.current.position.z = 0;
}
}, [props.shouldAnimate]);
return (
<group rotation={props.pivotRotation as [number, number, number]}>
<mesh
position={[-0.1, -0.3, 0.1]}
rotation={props.rotation as [number, number, number]}
scale={[0.1, 0.1, 0.1]}
ref={triangleNodeRef}
>
<coneBufferGeometry attach="geometry" args={[1, 2, 3]} />
<meshBasicMaterial attach="material" map={tex} transparent={true} />
</mesh>
</group>
);
};
export default TriangleNode;

View file

@ -1,255 +0,0 @@
import React, { memo, useEffect, useMemo, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import siteATex from "../../../static/sprites/main/site_a.png";
import siteBTex from "../../../static/sprites/main/site_b.png";
import siteLevelTex from "../../../static/sprites/main/site_levels.png";
type PurpleRingProps = {
purpleRingPosY: number;
level: string;
site: string;
};
const PurpleRing = memo((props: PurpleRingProps) => {
const siteA = useLoader(THREE.TextureLoader, siteATex);
const siteB = useLoader(THREE.TextureLoader, siteBTex);
const siteLevels = useLoader(THREE.TextureLoader, siteLevelTex);
const purpleRingRef = useRef<THREE.Object3D>();
const levelTextureOffsets = useMemo(() => {
const formattedLevel = props.level.padStart(2, "0");
const offsets: { [key: string]: number } = {
"9": 0.035,
"8": 0.039,
"7": 0.001,
"6": 0.005,
"5": 0.009,
"4": 0.0131,
"3": 0.0176,
"2": 0.0218,
"1": 0.026,
"0": 0.031,
};
return [
offsets[formattedLevel.charAt(0)],
offsets[formattedLevel.charAt(1)],
];
}, [props.level]);
const uniforms = useMemo(() => {
const uniform = THREE.UniformsUtils.merge([THREE.UniformsLib["lights"]]);
uniform.tex = { type: "t", value: null };
uniform.siteLevels = { type: "t", value: siteLevels };
uniform.siteLevelFirstCharacterOffset = {
value: levelTextureOffsets[0],
};
uniform.siteLevelSecondCharacterOffset = {
value: levelTextureOffsets[1],
};
return uniform;
}, [siteLevels, levelTextureOffsets]);
const vertexShader = `
varying vec2 vUv;
varying vec3 vPos;
varying vec3 vNormal;
void main() {
vUv = uv;
vPos = (modelMatrix * vec4(position, 1.0 )).xyz;
vNormal = normalMatrix * normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.);
}
`;
const fragmentShader = `
varying vec2 vUv;
uniform sampler2D tex;
uniform sampler2D siteLevels;
uniform float siteLevelFirstCharacterOffset;
uniform float siteLevelSecondCharacterOffset;
// lights
varying vec3 vPos;
varying vec3 vNormal;
struct PointLight {
vec3 position;
vec3 color;
float distance;
};
uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
// transform coordinates to uniform within segment
float tolocal(float x, int segments, float step) {
float period = 1.0/step*float(segments);
return mod(x, period) / period;
}
// check if coordinate is within the given height
bool isheight(float y, float thin) {
return y > 0.5-thin/2.0 && y < 0.5+thin/2.0;
}
bool istop(float y, float thin) {
return y > 1.0-thin;
}
bool isbottom(float y, float thin) {
return y < thin;
}
// sloping function
float slope(float x, float thin) {
return x*(1.0-thin);
}
// frag color
vec4 color(vec2 vUv, float step, bool textureexists) {
if (!textureexists) {
return vec4(0.325,0.325,0.698, 1);
} else {
float dist = 1.0-tolocal(0.5 - mod(vUv.x+0.172, 0.5), 12, step);
return texture2D(tex, vec2(dist, vUv.y)) ;
}
}
void main() {
// lights
vec4 addedLights = vec4(0.0,
0.0,
0.0,
1.0);
for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
vec3 lightDirection = normalize(vPos
- pointLights[l].position);
addedLights.rgb += clamp(dot(-lightDirection,
vNormal), 0.0, 1.0)
* pointLights[l].color
* 30.0;
}
// number of segments
float step = 256.0;
float thin = 0.2;
float thick = 1.0;
float slopefactor = 2.0;
int halfc = int(step)/2;
// segment within circle
int segment = int(floor(vUv.x * step));
int thinperiod = halfc-16;
int halfel = int(mod(float(segment), float(halfc)));
if (halfel < thinperiod-1 && istop(vUv.y, thin)) {
// thin line top
gl_FragColor = color(vUv, step, false) * addedLights;
} else if (halfel == thinperiod - 1) {
// thin line and corner
float dist = tolocal(vUv.x, 1, step);
float val = 1.0-slope(1.0-dist, thin);
if (istop(vUv.y, thin) || (1.0-vUv.y < val-(1.0-thin*slopefactor))) {
gl_FragColor = color(vUv, step, false) * addedLights;
} else {
gl_FragColor = vec4(0, 0, 0, 0);
}
} else if (halfel > thinperiod-2 && halfel < thinperiod+1) {
// slope down
float dist = tolocal(vUv.x, 1, step);
float val = 1.0-slope(dist, thin);
if (vUv.y < val && vUv.y > val-thin*slopefactor) {
gl_FragColor = color(vUv, step, false) * addedLights;
} else {
gl_FragColor = vec4(0, 0, 0, 0);
}
} else if (halfel > thinperiod && halfel < thinperiod+4 && isbottom(vUv.y, thin)) {
// thin line bottom
gl_FragColor = vec4(0.325,0.325,0.698, 1) * addedLights;
} else if (halfel > thinperiod + 3 && halfel < thinperiod + 6) {
// slope up
float dist = tolocal(vUv.x, 2, step);
float val = 1.0-slope(1.0-dist, thin);
if ((isbottom(vUv.y, thin) && dist < thin*slopefactor) || (vUv.y < val)) {
gl_FragColor = color(vUv, step, true) * addedLights;
} else {
gl_FragColor = vec4(0, 0, 0, 0);
}
} else if (halfel > thinperiod + 5 && halfel < thinperiod+12) {
// thick part
gl_FragColor = color(vUv, step, true) * addedLights;
} else if (halfel == thinperiod + 12){
// level first char texture
float dist = 1.0-tolocal(0.5 - mod(vUv.x-siteLevelFirstCharacterOffset +0.004, 0.5), 11, step);
gl_FragColor = texture2D(siteLevels, vec2(dist, vUv.y)) * addedLights;
} else if (halfel == thinperiod + 13){
// level second char texture
float dist = 1.0-tolocal(0.5 - mod(vUv.x-siteLevelSecondCharacterOffset, 0.5), 11, step);
gl_FragColor = texture2D(siteLevels, vec2(dist, vUv.y)) * addedLights;
} else if (halfel > thinperiod + 13 && halfel < thinperiod + 16) {
// slope up
float dist = tolocal(vUv.x, 2, step);
float val = slope(dist, thin);
if (vUv.y > val) {
gl_FragColor = color(vUv, step, true) * addedLights;
} else {
gl_FragColor = vec4(0, 0, 0, 0);
}
} else {
// transparent
gl_FragColor = vec4(0, 0, 0, 0);
}
}
`;
const matRef = useRef<THREE.ShaderMaterial>();
useFrame((state, delta) => {
purpleRingRef.current!.rotation.y += delta / 3;
});
useEffect(() => {
if (matRef.current) {
matRef.current.uniforms.tex.value = props.site === "a" ? siteA : siteB;
matRef.current.uniformsNeedUpdate = true;
}
}, [props.site, siteA, siteB]);
return (
<mesh
position={[0, props.purpleRingPosY, 0]}
scale={[26, 26, 26]}
renderOrder={1}
ref={purpleRingRef}
>
<cylinderBufferGeometry
args={[0.05, 0.05, 0.0035, 64, 64, true]}
attach="geometry"
/>
<shaderMaterial
attach="material"
side={THREE.DoubleSide}
vertexShader={vertexShader}
fragmentShader={fragmentShader}
transparent={true}
uniforms={uniforms}
lights={true}
ref={matRef}
/>
</mesh>
);
});
export default PurpleRing;

View file

@ -1,68 +0,0 @@
import React, { memo, useMemo } from "react";
import level_y_values from "../../../resources/level_y_values.json";
import PurpleRing from "./PurpleRing";
import GrayRing from "./GrayRing";
import CyanCrystal from "./CyanCrystal";
import { useStore } from "../../../store";
type RingsProps = {
activateAllRings: boolean;
};
const Rings = memo((props: RingsProps) => {
const activeLevel = useStore((state) => state.activeLevel);
const activeSite = useStore((state) => state.activeSite);
const levelUpperLimit = useMemo(() => (activeSite === "a" ? 22 : 13), [
activeSite,
]);
const possibleLevels = useMemo(
() =>
Array.from({ length: levelUpperLimit }, (_, i) =>
(i + 1).toString().padStart(2, "0")
),
[levelUpperLimit]
);
const visibleRings: [string, number][] = useMemo(() => {
if (props.activateAllRings) {
return Object.entries(level_y_values)
.sort((a, b) => a[0].localeCompare(b[0]))
.slice(0, levelUpperLimit);
} else {
const activeLevelIdx = parseInt(activeLevel) - 1;
return possibleLevels
.slice(
activeLevelIdx < 3 ? 0 : activeLevelIdx - 3,
activeLevelIdx > levelUpperLimit - 3
? levelUpperLimit
: activeLevelIdx + 3
)
.map((level) => [
level,
level_y_values[level as keyof typeof level_y_values],
]);
}
}, [props.activateAllRings, activeLevel, possibleLevels, levelUpperLimit]);
return (
<>
{visibleRings.map((level: [string, number]) => (
<group position={[0, level[1], 0]} key={level[0]}>
<PurpleRing
purpleRingPosY={0.44}
level={level[0]}
site={activeSite}
/>
<GrayRing grayRingPosY={-0.29} />
<CyanCrystal crystalRingPosY={-0.45} />
</group>
))}
</>
);
});
export default Rings;

View file

@ -1,108 +0,0 @@
import React, { Suspense, useEffect, useMemo } from "react";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../../store";
import ActiveLevelNodes from "./ActiveLevelNodes";
import Rings from "./Rings";
import NodeAnimations from "./NodeAnimations";
import InactiveLevelNodes from "./InactiveLevelNodes";
import site_a from "../../../resources/site_a.json";
import site_b from "../../../resources/site_b.json";
import level_y_values from "../../../resources/level_y_values.json";
import { filterInvisibleNodes } from "../../../helpers/node-helpers";
import Loading from "../../Loading";
type SiteProps = {
introFinished: boolean;
};
const Site = (props: SiteProps) => {
const wordSelected = useStore((state) => state.wordSelected);
const [rotXState, setRotX] = useSpring(() => ({
x: 0,
config: { duration: 1200 },
}));
const [rotYState, setRotY] = useSpring(() => ({
y: wordSelected
? useStore.getState().oldSiteRot[1]
: useStore.getState().siteRot[1],
delay: 1100,
config: { duration: 1200 },
}));
const [posState, setPos] = useSpring(() => ({
y: wordSelected
? -level_y_values[
useStore.getState().oldLevel as keyof typeof level_y_values
]
: -level_y_values[
useStore.getState().activeLevel as keyof typeof level_y_values
],
delay: 1300,
config: { duration: 1200 },
}));
const [tiltState, setTiltState] = useSpring(() => ({
tilt: 0,
config: { duration: 200 },
}));
useEffect(
() =>
useStore.subscribe(setRotY, (state) => ({
y: state.siteRot[1],
delay: 1100,
})),
[setRotY]
);
useEffect(
() =>
useStore.subscribe(setRotX, (state) => ({
x: state.siteRot[0],
})),
[setRotX]
);
useEffect(
() =>
useStore.subscribe(setPos, (state) => ({
y: -level_y_values[state.activeLevel as keyof typeof level_y_values],
delay: 1300,
})),
[setPos]
);
useEffect(() =>
useStore.subscribe(setTiltState, (state) => ({
tilt: state.cameraTiltValue,
}))
);
const activeSite = useStore((state) => state.activeSite);
const gameProgress = useStore((state) => state.gameProgress);
const visibleNodes = useMemo(
() =>
filterInvisibleNodes(activeSite === "a" ? site_a : site_b, gameProgress),
[activeSite, gameProgress]
);
return (
<Suspense fallback={props.introFinished ? <Loading /> : null}>
<a.group rotation-x={tiltState.tilt}>
<a.group rotation-x={rotXState.x}>
<a.group rotation-y={rotYState.y} position-y={posState.y}>
<ActiveLevelNodes visibleNodes={visibleNodes} />
<InactiveLevelNodes visibleNodes={visibleNodes} />
<Rings activateAllRings={props.introFinished} />
</a.group>
<NodeAnimations />
</a.group>
</a.group>
</Suspense>
);
};
export default Site;

View file

@ -1,88 +0,0 @@
import React, { useMemo, useRef } from "react";
import { a } from "@react-spring/three";
import * as THREE from "three";
import { useFrame } from "react-three-fiber";
type IntroStarProps = {
position: number[];
color: string;
};
const IntroStar = (props: IntroStarProps) => {
const uniforms = useMemo(
() => ({
color1: {
value: new THREE.Color("white"),
},
color2: {
value: new THREE.Color(props.color),
},
}),
[props.color]
);
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
uniform vec3 color1;
uniform vec3 color2;
uniform float alpha;
varying vec2 vUv;
void main() {
float alpha = smoothstep(0.0, 1.0, vUv.y);
float colorMix = smoothstep(1.0, 2.0, 1.8);
gl_FragColor = vec4(mix(color1, color2, colorMix), alpha) * 0.8;
}
`;
const starRef = useRef<THREE.Object3D>();
const amp = useRef(Math.random() / 10);
const deltaRef = useRef(0);
useFrame((state, delta) => {
deltaRef.current += delta;
if (
deltaRef.current > 0.016 &&
starRef.current &&
starRef.current.visible
) {
starRef.current.position.y += 0.25 + amp.current;
if (starRef.current.position.y > 40) starRef.current.visible = false;
deltaRef.current = deltaRef.current % 0.016;
}
});
return (
<mesh
position={props.position as [number, number, number]}
scale={[0.01, 2, 0.01]}
renderOrder={-1}
ref={starRef}
>
<boxBufferGeometry attach="geometry" args={[1, 1, 1]} />
<a.shaderMaterial
attach="material"
fragmentShader={fragmentShader}
vertexShader={vertexShader}
transparent={true}
depthWrite={false}
uniforms={uniforms}
/>
</mesh>
);
};
export default IntroStar;

View file

@ -1,91 +0,0 @@
import React, { useMemo, useRef } from "react";
import { a } from "@react-spring/three";
import * as THREE from "three";
import { useFrame } from "react-three-fiber";
import lerp from "../../../utils/lerp";
type StarProps = {
position: number[];
color: string;
shouldIntro: boolean;
};
const Star = (props: StarProps) => {
const uniforms = useMemo(
() => ({
color1: {
value: new THREE.Color("white"),
},
color2: {
value: new THREE.Color(props.color),
},
}),
[props.color]
);
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
uniform vec3 color1;
uniform vec3 color2;
uniform float alpha;
varying vec2 vUv;
void main() {
float alpha = smoothstep(0.0, 1.0, vUv.y);
float colorMix = smoothstep(1.0, 2.0, 1.8);
gl_FragColor = vec4(mix(color1, color2, colorMix), alpha) * 0.8;
}
`;
const starRef = useRef<THREE.Object3D>();
const amp = useRef(Math.random() / 10);
const introAmpRef = useRef(props.shouldIntro ? 1 : 0);
const deltaRef = useRef(0);
useFrame((state, delta) => {
deltaRef.current += delta;
if (deltaRef.current > 0.016 && starRef.current) {
if (starRef.current.position.y > 4) {
starRef.current.position.y = props.position[1];
}
starRef.current.position.y += 0.01 + amp.current + introAmpRef.current;
introAmpRef.current = lerp(introAmpRef.current, 0, 0.01);
deltaRef.current = deltaRef.current % 0.016;
}
});
return (
<mesh
position={props.position as [number, number, number]}
scale={[0.01, 2, 0.01]}
renderOrder={-1}
ref={starRef}
>
<boxBufferGeometry attach="geometry" args={[1, 1, 1]} />
<a.shaderMaterial
attach="material"
fragmentShader={fragmentShader}
vertexShader={vertexShader}
transparent={true}
depthWrite={false}
uniforms={uniforms}
/>
</mesh>
);
};
export default Star;

View file

@ -1,116 +0,0 @@
import React, { memo, useMemo } from "react";
import Star from "./Star";
import IntroStar from "./IntroStar";
type StarfieldProps = {
shouldIntro: boolean;
mainVisible: boolean;
};
const Starfield = memo((props: StarfieldProps) => {
const LCG = (a: number, c: number, m: number, s: number) => () =>
(s = (s * a + c) % m);
const lcgInstance = useMemo(() => LCG(1664525, 1013904223, 2 ** 32, 2), []);
const [
posesBlueFromRight,
posesBlueFromLeft,
posesCyanFromRight,
posesCyanFromLeft,
posesWhiteFromRight,
posesWhiteFromLeft,
] = [5, 5, 5, 5, 5, 5].map((x) =>
Array.from({ length: x }, () => [
lcgInstance() / 1000000000,
lcgInstance() / 10000000000 - 10,
lcgInstance() / 1000000000,
])
);
const [posesBlueFromBottom, posesCyanFromBottom, posesWhiteFromBottom] = [
80,
80,
80,
].map((x) =>
Array.from({ length: x }, () => [
lcgInstance() / 1000000050,
lcgInstance() / 100000059 + 5,
lcgInstance() / 1000000050,
])
);
return (
<>
<group position={[0, -1, 2]} visible={props.mainVisible}>
<group rotation={[0, 0.75, Math.PI / 2]} position={[-0.7, -1, -5]}>
{posesBlueFromLeft.map((poses, idx) => (
<Star
position={poses}
color={"blue"}
key={idx}
shouldIntro={props.shouldIntro}
/>
))}
{posesWhiteFromLeft.map((poses, idx) => (
<Star
position={poses}
color={"white"}
key={idx}
shouldIntro={props.shouldIntro}
/>
))}
{posesCyanFromLeft.map((poses, idx) => (
<Star
position={poses}
color={"cyan"}
key={idx}
shouldIntro={props.shouldIntro}
/>
))}
</group>
<group rotation={[0, 2.5, Math.PI / 2]} position={[-0.7, -1, -1]}>
{posesBlueFromRight.map((poses, idx) => (
<Star
position={poses}
color={"blue"}
key={idx}
shouldIntro={props.shouldIntro}
/>
))}
{posesWhiteFromRight.map((poses, idx) => (
<Star
position={poses}
color={"white"}
key={idx}
shouldIntro={props.shouldIntro}
/>
))}
{posesCyanFromRight.map((poses, idx) => (
<Star
position={poses}
color={"cyan"}
key={idx}
shouldIntro={props.shouldIntro}
/>
))}
</group>
</group>
{props.shouldIntro && (
<group position={[-2, -15, -30]} rotation={[Math.PI / 3, 0, 0]}>
{posesBlueFromBottom.map((poses, idx) => (
<IntroStar position={poses} color={"blue"} key={idx} />
))}
{posesWhiteFromBottom.map((poses, idx) => (
<IntroStar position={poses} color={"white"} key={idx} />
))}
{posesCyanFromBottom.map((poses, idx) => (
<IntroStar position={poses} color={"cyan"} key={idx} />
))}
</group>
)}
</>
);
});
export default Starfield;

View file

@ -1,133 +0,0 @@
import React, { memo, useMemo, useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import orbSprite from "../../static/sprites/main/orb.png";
import { useStore } from "../../store";
type YellowOrbProps = {
visible: boolean;
};
const YellowOrb = memo((props: YellowOrbProps) => {
const idleStarting = useStore((state) => state.idleStarting);
// ref for the object itself
const orbRef = useRef<THREE.Object3D>(new THREE.Mesh());
// position on the curve
const idxRef = useRef(0);
// how many times the orb changed direction
const directionChangeCountRef = useRef(0);
// current direction - left or right (0/1)
const directionRef = useRef(0);
// first curve and second curve (0/1)
const curveIdxRef = useRef(0);
const orbSpriteTexture = useLoader(THREE.TextureLoader, orbSprite);
// first one goes from up to down left to right
// second one goes from down to up left to right
const curves = useMemo(
() => [
new THREE.QuadraticBezierCurve3(
new THREE.Vector3(1.2, 0, 0),
new THREE.Vector3(0.5, -0.8, 0),
new THREE.Vector3(-1.2, 1, 0)
),
new THREE.QuadraticBezierCurve3(
new THREE.Vector3(-1.2, -0.8, 0),
new THREE.Vector3(-0.5, -0.1, 0),
new THREE.Vector3(1.2, 0.8, 0)
),
],
[]
);
const bigOrbScale = useMemo(() => new THREE.Vector3(2, 2, 2), []);
const deltaRef = useRef(0);
useFrame((state, delta) => {
deltaRef.current += delta;
if (deltaRef.current > 0.016 && props.visible) {
const orbPosFirst = curves[0].getPoint(idxRef.current / 250);
const orbPosSecond = curves[1].getPoint(idxRef.current / 250);
if (orbPosFirst.x < -1.4) {
if (curveIdxRef.current === 0) orbRef.current.renderOrder = 0;
directionRef.current = Number(!curveIdxRef.current);
directionChangeCountRef.current++;
}
if (orbPosFirst.x > 1.4) {
if (curveIdxRef.current === 1) orbRef.current.renderOrder = -1;
directionRef.current = curveIdxRef.current;
directionChangeCountRef.current++;
}
if (directionRef.current === 0) {
if (curveIdxRef.current === 0) {
idxRef.current++;
} else {
idxRef.current--;
}
} else {
if (curveIdxRef.current === 0) {
idxRef.current--;
} else {
idxRef.current++;
}
}
if (
directionChangeCountRef.current % 3 === 0 &&
directionChangeCountRef.current !== 0
) {
directionChangeCountRef.current = 0;
if (curveIdxRef.current === 0) {
idxRef.current = 250;
curveIdxRef.current = 1;
} else {
idxRef.current = 0;
curveIdxRef.current = 0;
}
directionRef.current = 0;
}
if (idleStarting) {
orbRef.current.scale.lerp(bigOrbScale, 0.01);
orbRef.current.position.x = THREE.MathUtils.lerp(
orbRef.current.position.x,
0,
0.01
);
orbRef.current.position.y = THREE.MathUtils.lerp(
orbRef.current.position.y,
0,
0.01
);
} else {
if (curveIdxRef.current === 0) {
orbRef.current.position.x = orbPosFirst.x;
orbRef.current.position.y = orbPosFirst.y;
} else {
orbRef.current.position.x = orbPosSecond.x;
orbRef.current.position.y = orbPosSecond.y;
}
}
deltaRef.current = deltaRef.current % 0.016;
}
});
return (
<group position={[0, -0.1, 1]}>
<sprite scale={[0.5, 0.5, 0.5]} ref={orbRef}>
<spriteMaterial
attach="material"
map={orbSpriteTexture}
depthTest={false}
transparent={true}
/>
</sprite>
</group>
);
});
export default YellowOrb;

View file

@ -1,178 +0,0 @@
import React, { useMemo, useRef } from "react";
import { useStore } from "../../store";
import progressBarContainer from "../../static/sprites/media/media_loading_bar_container.png";
import progressBar from "../../static/sprites/progressbar/progress_bar0.png";
import progressBar1 from "../../static/sprites/progressbar/progress_bar1.png";
import progressBar2 from "../../static/sprites/progressbar/progress_bar2.png";
import progressBar3 from "../../static/sprites/progressbar/progress_bar3.png";
import progressBar4 from "../../static/sprites/progressbar/progress_bar4.png";
import progressBar5 from "../../static/sprites/progressbar/progress_bar5.png";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
const MediaProgressBar = () => {
const mediaPercentageElapsed = useStore(
(state) => state.mediaPercentageElapsed
);
const progressBarContainerTex = useLoader(
THREE.TextureLoader,
progressBarContainer
);
const progressBarTex = useLoader(THREE.TextureLoader, progressBar);
const progressBar1Tex = useLoader(THREE.TextureLoader, progressBar1);
const progressBar2Tex = useLoader(THREE.TextureLoader, progressBar2);
const progressBar3Tex = useLoader(THREE.TextureLoader, progressBar3);
const progressBar4Tex = useLoader(THREE.TextureLoader, progressBar4);
const progressBar5Tex = useLoader(THREE.TextureLoader, progressBar5);
// the additions here are very linear, but just +ing the values wouldn't work
// since in case the video were to get rewinded the bar wouldn't react properly
// doing it declaratively like this fixes that concern
const progressBarState = useMemo(() => {
const mediaPercentageDispatch = {
0: {
scaleX: 0,
texture: progressBar1Tex,
offsetX: 0,
},
5: {
scaleX: 0.25,
texture: progressBar1Tex,
offsetX: 0,
},
10: { scaleX: 0.5, texture: progressBar2Tex, offsetX: 0.145 },
15: { scaleX: 0.75, texture: progressBar3Tex, offsetX: 0.25 },
20: {
scaleX: 1,
texture: progressBar4Tex,
offsetX: 0.4,
},
25: {
scaleX: 1.25,
texture: progressBar5Tex,
offsetX: 0.55,
},
30: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 0.8,
},
35: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 1.05,
},
40: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 1.3,
},
45: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 1.55,
},
50: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 1.8,
},
55: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 2.05,
},
60: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 2.3,
},
65: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 2.55,
},
70: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 2.8,
},
75: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.05,
},
80: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.3,
},
85: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.55,
},
90: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.65,
},
95: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.85,
},
100: {
scaleX: 1.5,
texture: progressBarTex,
offsetX: 3.95,
},
};
return mediaPercentageDispatch[
mediaPercentageElapsed as keyof typeof mediaPercentageDispatch
];
}, [
progressBar1Tex,
progressBar2Tex,
progressBar3Tex,
progressBar4Tex,
progressBar5Tex,
progressBarTex,
mediaPercentageElapsed,
]);
const progressBarMatRef = useRef<THREE.Material>();
useFrame(() => {
if (progressBarMatRef) {
progressBarMatRef.current!.needsUpdate = true;
}
});
return (
<>
<sprite scale={[5.2, 0.5, 1]} position={[2.15, 3.005, 0]} renderOrder={3}>
<spriteMaterial attach="material" map={progressBarContainerTex} />
</sprite>
<mesh
scale={[progressBarState ? progressBarState.scaleX : 0, 0.195, 1]}
position={[
progressBarState ? -0.2 + progressBarState.offsetX : -0.2,
2.945,
0,
]}
renderOrder={3}
>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
ref={progressBarMatRef}
attach="material"
transparent={true}
map={progressBarState ? progressBarState.texture : null}
/>
</mesh>
</>
);
};
export default MediaProgressBar;

View file

@ -1,24 +0,0 @@
import React from "react";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
import mediaNodeNameContainer from "../../static/sprites/media/media_node_name_container.png";
const NodeNameContainer = () => {
const mediaNodeNameContainerTex = useLoader(
THREE.TextureLoader,
mediaNodeNameContainer
);
return (
<sprite scale={[2.6, 0.5, 1]} position={[3.425, 2.5, 0]} renderOrder={3}>
<spriteMaterial
attach="material"
map={mediaNodeNameContainerTex}
transparent={true}
depthTest={false}
/>
</sprite>
);
};
export default NodeNameContainer;

View file

@ -1,108 +0,0 @@
import React, { memo, useMemo } from "react";
import TriangularPrism from "./LeftSide/TriangularPrism";
import Cube from "./LeftSide/Cube";
import { a, useSpring } from "@react-spring/three";
import { useStore } from "../../../store";
export type ShapeProps = {
position: number[];
selectable?: boolean;
active?: boolean;
};
const LeftSide = memo(() => {
const activeMediaComponent = useStore((state) => state.activeMediaComponent);
const cubesActive = useMemo(() => activeMediaComponent === "exit", [
activeMediaComponent,
]);
const trianglesActive = useMemo(() => activeMediaComponent === "play", [
activeMediaComponent,
]);
const groupSpringConfig = useMemo(() => ({ duration: 500 }), []);
const groupSpringFinalDest = useMemo(
() => ({ posX: 0, posZ: 0, posY: 0 }),
[]
);
const topFrontGroupPos = useSpring({
config: groupSpringConfig,
to: groupSpringFinalDest,
from: { posX: 4, posZ: 2, posY: 1 },
});
const bottomFrontGroupPos = useSpring({
config: groupSpringConfig,
to: groupSpringFinalDest,
from: { posX: 0, posZ: 2, posY: 0 },
});
const topBehindGroupPos = useSpring({
config: groupSpringConfig,
to: groupSpringFinalDest,
from: { posX: 0, posZ: -3, posY: 2 },
});
const bottomBehindGroupPos = useSpring({
config: groupSpringConfig,
to: groupSpringFinalDest,
from: { posX: 4, posZ: -2, posY: 1 },
});
return (
<group position={[0, 0, -3]}>
<a.group
position-x={bottomBehindGroupPos.posX}
position-z={bottomBehindGroupPos.posZ}
position-y={bottomBehindGroupPos.posY}
>
<Cube position={[-2.7, -1.6, 0.6]} active={cubesActive} />
<TriangularPrism
position={[-3.5, -1.6, 0.6]}
active={trianglesActive}
/>
</a.group>
<a.group
position-x={topBehindGroupPos.posX}
position-z={topBehindGroupPos.posZ}
position-y={topBehindGroupPos.posY}
>
<Cube position={[-3.5, -0.9, 0.6]} active={cubesActive} />
<TriangularPrism
position={[-2.7, -0.9, 0.6]}
active={trianglesActive}
/>
</a.group>
<a.group
position-x={topFrontGroupPos.posX}
position-z={topFrontGroupPos.posZ}
position-y={topFrontGroupPos.posY}
>
<Cube position={[-3.5, -0.9, 1.2]} active={cubesActive} />
<TriangularPrism
position={[-2.7, -0.9, 1.2]}
active={trianglesActive}
selectable={true}
/>
</a.group>
<a.group
position-x={bottomFrontGroupPos.posX}
position-z={bottomFrontGroupPos.posZ}
position-y={bottomFrontGroupPos.posY}
>
<Cube
position={[-2.7, -1.6, 1.2]}
active={cubesActive}
selectable={true}
/>
<TriangularPrism
position={[-3.5, -1.6, 1.2]}
active={trianglesActive}
/>
</a.group>
</group>
);
});
export default LeftSide;

View file

@ -1,39 +0,0 @@
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import grayTextureFile from "../../../../static/sprites/media/gray_box.png";
import darkGrayTextureFile from "../../../../static/sprites/media/dark_gray_box.png";
import React, {memo, useRef} from "react";
import { ShapeProps } from "../LeftSide";
const Cube = memo((props: ShapeProps) => {
const grayTex = useLoader(THREE.TextureLoader, grayTextureFile);
const darkGrayTex = useLoader(THREE.TextureLoader, darkGrayTextureFile);
const cubeRef = useRef<THREE.Object3D>();
useFrame((state, delta) => {
if (props.selectable && props.active) {
cubeRef.current!.rotation.y -= delta;
} else {
cubeRef.current!.rotation.y = 0;
}
});
return (
<mesh
scale={[0.45, 0.5, 0.45]}
position={props.position as [number, number, number]}
rotation-y={0.15}
rotation-z={-0.02}
ref={cubeRef}
>
<boxBufferGeometry args={[1, 1, 1]} attach="geometry" />
<meshLambertMaterial
attach="material"
map={props.active ? grayTex : darkGrayTex}
/>
</mesh>
);
});
export default Cube;

View file

@ -1,51 +0,0 @@
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import grayTextureFile from "../../../../static/sprites/media/gray_box.png";
import darkGrayTextureFile from "../../../../static/sprites/media/dark_gray_box.png";
import React, { memo, useRef } from "react";
import { ShapeProps } from "../LeftSide";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
type GLTFResult = GLTF & {
nodes: {
Cube001: THREE.Mesh;
};
materials: {
["Material.001"]: THREE.MeshStandardMaterial;
};
};
const TriangularPrism = memo((props: ShapeProps) => {
const grayTex = useLoader(THREE.TextureLoader, grayTextureFile);
const darkGrayTex = useLoader(THREE.TextureLoader, darkGrayTextureFile);
const { nodes } = useLoader<GLTFResult>(GLTFLoader, "models/cut_cube.glb");
const prismRef = useRef<THREE.Object3D>();
useFrame((state, delta) => {
if (props.selectable && props.active) {
prismRef.current!.rotation.y -= delta;
} else {
prismRef.current!.rotation.y = 0;
}
});
return (
<mesh
scale={[0.45 / 2, 0.5 / 2, 0.45 / 2]}
position={props.position as [number, number, number]}
rotation-y={0.15}
rotation-z={-0.02}
ref={prismRef}
geometry={nodes["Cube001"].geometry}
>
<meshLambertMaterial
attach="material"
map={props.active ? grayTex : darkGrayTex}
/>
</mesh>
);
});
export default TriangularPrism;

View file

@ -1,100 +0,0 @@
import React, { memo, useMemo } from "react";
import { useStore } from "../../../store";
import Word from "./RightSide/Word";
import { a, useSpring } from "@react-spring/three";
import word_position_states from "../../../resources/word_position_states.json";
import * as THREE from "three";
import Lof from "../Lof";
import { useUpdate } from "react-three-fiber";
const RightSide = memo(() => {
const words = useStore((state) => state.activeNode.words);
const wordPositionState = useStore(
(state) =>
word_position_states[
state.mediaWordPosStateIdx.toString() as keyof typeof word_position_states
]
);
const wordPositionStateSpring = useSpring({
fstWordPosX: wordPositionState.fstWord.posX,
fstWordPosY: wordPositionState.fstWord.posY,
sndWordPosX: wordPositionState.sndWord.posX,
sndWordPosY: wordPositionState.sndWord.posY,
thirdWordPosX: wordPositionState.thirdWord.posX,
thirdWordPosY: wordPositionState.thirdWord.posY,
crossPosX: wordPositionState.cross.posX,
crossPosY: wordPositionState.cross.posY,
config: { duration: 300 },
});
const horizontalPoints = useMemo(
() => [new THREE.Vector3(-10, 0, 0), new THREE.Vector3(10, 0, 0)],
[]
);
const verticalPoints = useMemo(
() => [new THREE.Vector3(0, 10, 0), new THREE.Vector3(0, -10, 0)],
[]
);
const activeMediaComponent = useStore((state) => state.activeMediaComponent);
const horizontalRef = useUpdate((geometry: THREE.BufferGeometry) => {
geometry.setFromPoints(horizontalPoints);
}, []);
const verticalRef = useUpdate((geometry: THREE.BufferGeometry) => {
geometry.setFromPoints(verticalPoints);
}, []);
return (
<group position={[0, 0, -3]}>
<Lof />
<a.group
position-x={wordPositionStateSpring.crossPosX}
position-y={wordPositionStateSpring.crossPosY}
>
<line>
<bufferGeometry attach="geometry" ref={horizontalRef} />
<lineBasicMaterial
attach="material"
color={0xc9d6d5}
transparent={true}
opacity={0.8}
/>
</line>
<line>
<bufferGeometry attach="geometry" ref={verticalRef} />
<lineBasicMaterial
attach="material"
color={0xc9d6d5}
transparent={true}
opacity={0.8}
/>
</line>
</a.group>
<Word
word={words[1]}
posX={wordPositionStateSpring.fstWordPosX}
posY={wordPositionStateSpring.fstWordPosY}
active={activeMediaComponent === "fstWord"}
/>
<Word
word={words[2]}
posX={wordPositionStateSpring.sndWordPosX}
posY={wordPositionStateSpring.sndWordPosY}
active={activeMediaComponent === "sndWord"}
/>
<Word
word={words[3]}
posX={wordPositionStateSpring.thirdWordPosX}
posY={wordPositionStateSpring.thirdWordPosY}
active={activeMediaComponent === "thirdWord"}
/>
</group>
);
});
export default RightSide;

View file

@ -1,50 +0,0 @@
import React, { useMemo } from "react";
import * as THREE from "three";
import wordInactiveTexture from "../../../../static/sprites/media/word_background.png";
import wordActiveTexture from "../../../../static/sprites/media/word_background_active.png";
import { useLoader } from "react-three-fiber";
import { a, SpringValue } from "@react-spring/three";
type WordProps = {
word: string;
posX: SpringValue<number>;
posY: SpringValue<number>;
active: boolean;
};
const Word = (props: WordProps) => {
const wordFont = useLoader(THREE.FontLoader, "/3d-fonts/MediaWord.blob");
const config = useMemo(
() => ({
font: wordFont,
size: 1,
}),
[wordFont]
);
const wordInactiveTex = useLoader(THREE.TextureLoader, wordInactiveTexture);
const wordActiveTex = useLoader(THREE.TextureLoader, wordActiveTexture);
return (
<a.group position-x={props.posX} position-y={props.posY}>
<mesh scale={[0.4, 0.4, 0]} position={[-3.9, 1.915, 0]} renderOrder={3}>
<textGeometry attach="geometry" args={[props.word, config]} />
<meshBasicMaterial
attach="material"
color={props.active ? 0xffffff : 0x000000}
transparent={true}
/>
</mesh>
<sprite scale={[4.2, 0.45, 1]} position={[-2, 2, 0]} renderOrder={2}>
<spriteMaterial
attach="material"
map={props.active ? wordActiveTex : wordInactiveTex}
alphaTest={0.01}
/>
</sprite>
</a.group>
);
};
export default Word;

View file

@ -1,103 +0,0 @@
import React, { useEffect, useMemo, useRef } from "react";
import header from "../../static/sprites/polytan/polytan_header.png";
import background from "../../static/sprites/polytan/polytan_background.png";
import leftArmHud from "../../static/sprites/polytan/poly_larm_hud.png";
import rightArmHud from "../../static/sprites/polytan/poly_rarm_hud.png";
import rightLegHud from "../../static/sprites/polytan/poly_rleg_hud.png";
import leftLegHud from "../../static/sprites/polytan/poly_lleg_hud.png";
import headHud from "../../static/sprites/polytan/poly_head_hud.png";
import bodyHud from "../../static/sprites/polytan/poly_body_hud.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
const PolytanBackground = () => {
const headerTex = useLoader(THREE.TextureLoader, header);
const backgroundTex = useLoader(THREE.TextureLoader, background);
const leftArmHudTex = useLoader(THREE.TextureLoader, leftArmHud);
const rightArmHudTex = useLoader(THREE.TextureLoader, rightArmHud);
const rightLegHudTex = useLoader(THREE.TextureLoader, rightLegHud);
const leftLegHudTex = useLoader(THREE.TextureLoader, leftLegHud);
const headHudTex = useLoader(THREE.TextureLoader, headHud);
const bodyHudTex = useLoader(THREE.TextureLoader, bodyHud);
const wordFont = useLoader(THREE.FontLoader, "/3d-fonts/MediaWord.blob");
const config = useMemo(
() => ({
font: wordFont,
size: 2.5,
}),
[wordFont]
);
const pressAnyRef = useRef<THREE.Object3D>();
useEffect(() => {
setInterval(() => {
if (pressAnyRef.current) {
pressAnyRef.current.visible = !pressAnyRef.current.visible;
}
}, 500);
}, []);
return (
<>
<sprite scale={[4, 4, 0]} position={[3.5, 2, 0]} renderOrder={-1}>
<spriteMaterial attach="material" map={headerTex} />
</sprite>
<sprite scale={[4, 4, 0]} position={[-3.5, -2, 0]} renderOrder={-1}>
<spriteMaterial attach="material" map={backgroundTex} />
</sprite>
<sprite scale={[3.5, 1, 0]} position={[2.8, 0.5, 0]} renderOrder={2}>
<spriteMaterial attach="material" map={leftArmHudTex} />
</sprite>
<sprite scale={[3.5, 1.5, 0]} position={[-3, -0.8, 0]} renderOrder={2}>
<spriteMaterial attach="material" map={rightArmHudTex} />
</sprite>
<sprite scale={[3.5, 1.5, 0]} position={[2.4, -1.4, 0]} renderOrder={2}>
<spriteMaterial attach="material" map={leftLegHudTex} />
</sprite>
<sprite scale={[3, 0.8, 0]} position={[-3, -2.8, 0]} renderOrder={2}>
<spriteMaterial attach="material" map={rightLegHudTex} />
</sprite>
<sprite scale={[3.4, 1, 0]} position={[-1.5, 2.3, 0]} renderOrder={2}>
<spriteMaterial attach="material" map={headHudTex} />
</sprite>
<sprite scale={[3.4, 1, 0]} position={[1.5, -2.2, 0]} renderOrder={2}>
<spriteMaterial attach="material" map={bodyHudTex} />
</sprite>
<group ref={pressAnyRef} visible={false} position={[-1.2, -1.8, 0]}>
<mesh
scale={[0.17, 0.14, 0]}
position={[-0.8, -1.3, 0]}
renderOrder={5}
>
<textGeometry attach="geometry" args={["press ANY button", config]} />
<meshBasicMaterial
attach="material"
color={0x00ba7c}
transparent={true}
depthTest={false}
/>
</mesh>
<mesh
scale={[0.17, 0.14, 0]}
position={[-0.793, -1.308, 0]}
renderOrder={4}
>
<textGeometry attach="geometry" args={["press ANY button", config]} />
<meshBasicMaterial
attach="material"
color={0x000000}
transparent={true}
depthTest={false}
/>
</mesh>
</group>
</>
);
};
export default PolytanBackground;

View file

@ -1,79 +0,0 @@
import React, { memo } from "react";
import body from "../../static/sprites/polytan/body.png";
import head from "../../static/sprites/polytan/head.png";
import leftLeg from "../../static/sprites/polytan/left_leg.png";
import leftArm from "../../static/sprites/polytan/left_arm.png";
import rightArm from "../../static/sprites/polytan/right_arm.png";
import rightLeg from "../../static/sprites/polytan/right_leg.png";
import skeleton from "../../static/sprites/polytan/polytan_skeleton.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../../store";
const PolytanBear = memo(() => {
const skeletonTex = useLoader(THREE.TextureLoader, skeleton);
const headTex = useLoader(THREE.TextureLoader, head);
const bodyTex = useLoader(THREE.TextureLoader, body);
const leftArmTex = useLoader(THREE.TextureLoader, leftArm);
const leftLegTex = useLoader(THREE.TextureLoader, leftLeg);
const rightArmTex = useLoader(THREE.TextureLoader, rightArm);
const rightLegTex = useLoader(THREE.TextureLoader, rightLeg);
const unlockedParts = useStore(
(state) => state.gameProgress.polytan_unlocked_parts
);
return (
<>
<sprite scale={[4, 5, 0]} position={[0, -0.4, 0]}>
<spriteMaterial attach="material" map={skeletonTex} />
</sprite>
<sprite scale={[2.1, 1.9, 0]} position={[-0.05, -1, 0]}>
<spriteMaterial
attach="material"
map={bodyTex}
visible={unlockedParts.body}
/>
</sprite>
<sprite scale={[2.5, 2.5, 0]} position={[-0.05, 0.8, 0]}>
<spriteMaterial
attach="material"
map={headTex}
visible={unlockedParts.head}
/>
</sprite>
<sprite scale={[1.9, 1, 0]} position={[1, -2.2, 0]}>
<spriteMaterial
attach="material"
map={leftLegTex}
visible={unlockedParts.left_leg}
/>
</sprite>
<sprite scale={[1.5, 1.9, 0]} position={[1.2, -0.4, 0]}>
<spriteMaterial
attach="material"
map={leftArmTex}
visible={unlockedParts.left_arm}
/>
</sprite>
<sprite scale={[1.6, 2, 0]} position={[-1.2, -1.2, 0]}>
<spriteMaterial
attach="material"
map={rightArmTex}
visible={unlockedParts.right_arm}
/>
</sprite>
<sprite scale={[1.9, 1, 0]} position={[-1, -2.2, 0]}>
<spriteMaterial
attach="material"
map={rightLegTex}
visible={unlockedParts.right_leg}
/>
</sprite>
</>
);
});
export default PolytanBear;

View file

@ -1,159 +0,0 @@
import introSpriteSheet from "../static/sprites/lain/intro.png";
import moveDownSpriteSheet from "../static/sprites/lain/jump_down.png";
import moveUpSpriteSheet from "../static/sprites/lain/jump_up.png";
import standingSpriteSheet from "../static/sprites/lain/standing.png";
import moveLeftSpriteSheet from "../static/sprites/lain/move_left.png";
import moveRightSpriteSheet from "../static/sprites/lain/move_right.png";
import throwNodeSpriteSheet from "../static/sprites/lain/throw_node.png";
import ripMiddleRingSpriteSheet from "../static/sprites/lain/rip_middle_ring.png";
import ripNodeSpriteSheet from "../static/sprites/lain/rip_node.png";
import prayerSpriteSheet from "../static/sprites/lain/prayer.png";
import knockSpriteSheet from "../static/sprites/lain/knock.png";
import knockAndFallSpriteSheet from "../static/sprites/lain/knock_and_fall.png";
import touchAndScareSpriteSheet from "../static/sprites/lain/touch_node_and_get_scared.png";
import touchSleeveSpriteSheet from "../static/sprites/lain/touch_sleeve.png";
import thinkingSpriteSheet from "../static/sprites/lain/thinking.png";
import stretchSpriteSheet from "../static/sprites/lain/stretch.png";
import stretch2SpriteSheet from "../static/sprites/lain/stretch_2.png";
import spinSpriteSheet from "../static/sprites/lain/spin.png";
import scratchHeadSpriteSheet from "../static/sprites/lain/scratch_head.png";
import blushSpriteSheet from "../static/sprites/lain/blush.png";
import handsBehindHeadSpriteSheet from "../static/sprites/lain/hands_behind_head.png";
import handsOnHipsSpriteSheet from "../static/sprites/lain/hands_on_hips.png";
import handsOnHips2SpriteSheet from "../static/sprites/lain/hands_on_hips_2.png";
import handsTogetherSpriteSheet from "../static/sprites/lain/hands_together.png";
import leanForwardSpriteSheet from "../static/sprites/lain/lean_forward.png";
import leanLeftSpriteSheet from "../static/sprites/lain/lean_left.png";
import leanRightSpriteSheet from "../static/sprites/lain/lean_right.png";
import lookAroundSpriteSheet from "../static/sprites/lain/look_around.png";
import playWithHairSpriteSheet from "../static/sprites/lain/play_with_hair.png";
import bigHudSpriteSheet from "../static/sprites/main/big_hud.png";
import longHudSpriteSheet from "../static/sprites/main/long_hud.png";
import boringHudSpriteSheet from "../static/sprites/main/boring_hud.png";
import * as THREE from "three";
import { useLoader, useThree } from "react-three-fiber";
import { memo, useLayoutEffect } from "react";
// this function just preloads lain's spritesheets and other assets cuz they're big and lazy loading them
// used to make the suspense run for a couple milliseconds, resulting in flickering
const Preloader = memo(() => {
const intro = useLoader(THREE.TextureLoader, introSpriteSheet);
const moveDown = useLoader(THREE.TextureLoader, moveDownSpriteSheet);
const moveUp = useLoader(THREE.TextureLoader, moveUpSpriteSheet);
const moveLeft = useLoader(THREE.TextureLoader, moveLeftSpriteSheet);
const moveRight = useLoader(THREE.TextureLoader, moveRightSpriteSheet);
const stand = useLoader(THREE.TextureLoader, standingSpriteSheet);
const throwNode = useLoader(THREE.TextureLoader, throwNodeSpriteSheet);
const bigHud = useLoader(THREE.TextureLoader, bigHudSpriteSheet);
const longHud = useLoader(THREE.TextureLoader, longHudSpriteSheet);
const boringHud = useLoader(THREE.TextureLoader, boringHudSpriteSheet);
const ripMiddleRing = useLoader(
THREE.TextureLoader,
ripMiddleRingSpriteSheet
);
const ripNode = useLoader(THREE.TextureLoader, ripNodeSpriteSheet);
const prayer = useLoader(THREE.TextureLoader, prayerSpriteSheet);
const knock = useLoader(THREE.TextureLoader, knockSpriteSheet);
const knockAndFall = useLoader(THREE.TextureLoader, knockAndFallSpriteSheet);
const touchAndScare = useLoader(
THREE.TextureLoader,
touchAndScareSpriteSheet
);
const touchSleeve = useLoader(THREE.TextureLoader, touchSleeveSpriteSheet);
const thinking = useLoader(THREE.TextureLoader, thinkingSpriteSheet);
const stretch = useLoader(THREE.TextureLoader, stretchSpriteSheet);
const stretch2 = useLoader(THREE.TextureLoader, stretch2SpriteSheet);
const spinSprite = useLoader(THREE.TextureLoader, spinSpriteSheet);
const scratchHead = useLoader(THREE.TextureLoader, scratchHeadSpriteSheet);
const blush = useLoader(THREE.TextureLoader, blushSpriteSheet);
const handsBehindHead = useLoader(
THREE.TextureLoader,
handsBehindHeadSpriteSheet
);
const handsOnHips = useLoader(THREE.TextureLoader, handsOnHipsSpriteSheet);
const handsOnHips2 = useLoader(THREE.TextureLoader, handsOnHips2SpriteSheet);
const handsTogether = useLoader(
THREE.TextureLoader,
handsTogetherSpriteSheet
);
const leanForward = useLoader(THREE.TextureLoader, leanForwardSpriteSheet);
const leanLeft = useLoader(THREE.TextureLoader, leanLeftSpriteSheet);
const leanRight = useLoader(THREE.TextureLoader, leanRightSpriteSheet);
const lookAround = useLoader(THREE.TextureLoader, lookAroundSpriteSheet);
const playWithHair = useLoader(THREE.TextureLoader, playWithHairSpriteSheet);
const { gl } = useThree();
useLayoutEffect(() => {
gl.initTexture(intro);
gl.initTexture(moveDown);
gl.initTexture(moveUp);
gl.initTexture(moveLeft);
gl.initTexture(moveRight);
gl.initTexture(stand);
gl.initTexture(longHud);
gl.initTexture(bigHud);
gl.initTexture(boringHud);
gl.initTexture(throwNode);
gl.initTexture(ripMiddleRing);
gl.initTexture(ripNode);
gl.initTexture(prayer);
gl.initTexture(touchAndScare);
gl.initTexture(knock);
gl.initTexture(knockAndFall);
gl.initTexture(touchSleeve);
gl.initTexture(thinking);
gl.initTexture(stretch);
gl.initTexture(stretch2);
gl.initTexture(spinSprite);
gl.initTexture(scratchHead);
gl.initTexture(blush);
gl.initTexture(handsBehindHead);
gl.initTexture(leanForward);
gl.initTexture(leanLeft);
gl.initTexture(leanRight);
gl.initTexture(lookAround);
gl.initTexture(playWithHair);
gl.initTexture(handsOnHips);
gl.initTexture(handsOnHips2);
gl.initTexture(handsTogether);
}, [
moveDown,
moveUp,
moveLeft,
moveRight,
stand,
gl,
bigHud,
boringHud,
longHud,
intro,
throwNode,
ripMiddleRing,
ripNode,
prayer,
touchAndScare,
knock,
knockAndFall,
touchSleeve,
thinking,
stretch,
stretch2,
spinSprite,
scratchHead,
blush,
handsBehindHead,
leanForward,
leanLeft,
leanRight,
lookAround,
playWithHair,
handsOnHips,
handsOnHips2,
handsTogether,
]);
return null;
});
export default Preloader;

View file

@ -1,88 +0,0 @@
import React, { memo } from "react";
import answerContainer from "../static/sprites/prompt/prompt_answer_container.png";
import questionContainer from "../static/sprites/prompt/prompt_question_container.png";
import yes from "../static/sprites/prompt/prompt_yes.png";
import no from "../static/sprites/prompt/prompt_no.png";
import question from "../static/sprites/prompt/prompt_question.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../store";
const Prompt = memo(() => {
const questionContainerTex = useLoader(
THREE.TextureLoader,
questionContainer
);
const answerContainerTex = useLoader(THREE.TextureLoader, answerContainer);
const questionTex = useLoader(THREE.TextureLoader, question);
const yesTex = useLoader(THREE.TextureLoader, yes);
const noTex = useLoader(THREE.TextureLoader, no);
const activeComponent = useStore((state) => state.activePromptComponent);
const promptVisible = useStore((state) => state.promptVisible);
return (
<group visible={promptVisible}>
<sprite scale={[4.1, 0.3, 0]} renderOrder={200} position={[0, 0.2, 0]}>
<spriteMaterial
map={questionContainerTex}
attach="material"
transparent={true}
opacity={0.6}
depthTest={false}
/>
</sprite>
<sprite scale={[2, 0.24, 0]} renderOrder={200} position={[0, 0.19, 0]}>
<spriteMaterial
map={questionTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<sprite
scale={[0.5, 0.19, 0]}
renderOrder={200}
position={[-1.2, -0.2, 0]}
>
<spriteMaterial
map={yesTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<sprite
scale={[0.7, 0.3, 0]}
renderOrder={199}
position={activeComponent === "yes" ? [-1.2, -0.2, 0] : [1.2, -0.2, 0]}
>
<spriteMaterial
map={answerContainerTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
<sprite
scale={[0.4, 0.19, 0]}
renderOrder={200}
position={[1.2, -0.2, 0]}
>
<spriteMaterial
map={noTex}
attach="material"
transparent={true}
depthTest={false}
/>
</sprite>
</group>
);
});
export default Prompt;

View file

@ -1,46 +0,0 @@
import React, { memo } from "react";
import ssknBackground from "../../static/sprites/sskn/sskn_background.png";
import ssknBackgroundText from "../../static/sprites/sskn/sskn_background_text.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import ssknTopLabel from "../../static/sprites/sskn/sskn_top_label.png";
import ssknDango from "../../static/sprites/sskn/sskn_dango.png";
const SsknBackground = memo(() => {
const ssknBackgroundTex = useLoader(THREE.TextureLoader, ssknBackground);
const ssknBackgroundTextTex = useLoader(
THREE.TextureLoader,
ssknBackgroundText
);
const ssknTopLabelTex = useLoader(THREE.TextureLoader, ssknTopLabel);
const ssknDangoTex = useLoader(THREE.TextureLoader, ssknDango);
return (
<>
<mesh scale={[5, 6.4, 0]} position={[-0.25, -0.5, 0]}>
<planeBufferGeometry attach="geometry" />
<meshBasicMaterial
attach="material"
map={ssknBackgroundTex}
transparent={true}
/>
</mesh>
<sprite scale={[4.5, 2.5, 0]} position={[2.2, 0, 0]} renderOrder={3}>
<spriteMaterial
attach="material"
map={ssknBackgroundTextTex}
transparent={true}
opacity={0.5}
/>
</sprite>
<sprite position={[-3, 3, 0]} scale={[3.5, 0.4, 0]} renderOrder={4}>
<spriteMaterial attach="material" map={ssknDangoTex} opacity={0.5} />
</sprite>
<sprite position={[3.5, 3, 0]} scale={[2, 0.5, 0]}>
<spriteMaterial attach="material" map={ssknTopLabelTex} />
</sprite>
</>
);
});
export default SsknBackground;

View file

@ -1,102 +0,0 @@
import React, { memo } from "react";
import ssknOk from "../../static/sprites/sskn/sskn_ok.png";
import ssknOkInactive from "../../static/sprites/sskn/sskn_ok_inactive.png";
import ssknCancel from "../../static/sprites/sskn/sskn_cancel.png";
import ssknCancelInactive from "../../static/sprites/sskn/sskn_cancel_inactive.png";
import ssknUpgrade from "../../static/sprites/sskn/sskn_upgrade.png";
import ssknArrow from "../../static/sprites/sskn/sskn_arrow.png";
import ssknTextWrapper from "../../static/sprites/sskn/sskn_text_wrapper.png";
import ssknTextWrapperInactive from "../../static/sprites/sskn/sskn_text_wrapper_inactive.png";
import ssknLine from "../../static/sprites/sskn/sskn_line.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import SsknProgressBar from "./SsknProgressBar";
import { useStore } from "../../store";
const SsknHUD = memo(() => {
const ssknOkTex = useLoader(THREE.TextureLoader, ssknOk);
const ssknOkInactiveTex = useLoader(THREE.TextureLoader, ssknOkInactive);
const ssknCancelTex = useLoader(THREE.TextureLoader, ssknCancel);
const ssknCancelInactiveTex = useLoader(
THREE.TextureLoader,
ssknCancelInactive
);
const ssknUpgradeTex = useLoader(THREE.TextureLoader, ssknUpgrade);
const ssknArrowTex = useLoader(THREE.TextureLoader, ssknArrow);
const ssknTextWrapperTex = useLoader(THREE.TextureLoader, ssknTextWrapper);
const ssknTextWrapperInactiveTex = useLoader(
THREE.TextureLoader,
ssknTextWrapperInactive
);
const ssknLineTex = useLoader(THREE.TextureLoader, ssknLine);
const activeSsknComponent = useStore((state) => state.activeSsknComponent);
const loading = useStore((state) => state.ssknLoading);
return (
<>
{loading ? (
<SsknProgressBar />
) : (
<group>
<sprite position={[2.8, -2, 0]} scale={[1, 0.5, 0]}>
<spriteMaterial
attach="material"
map={activeSsknComponent === "ok" ? ssknOkTex : ssknOkInactiveTex}
/>
</sprite>
<sprite position={[3.3, -3, 0]} scale={[2, 0.5, 0]}>
<spriteMaterial
attach="material"
map={
activeSsknComponent === "cancel"
? ssknCancelTex
: ssknCancelInactiveTex
}
/>
</sprite>
<sprite position={[3.3, -2.15, 0]} scale={[3, 0.4, 0]}>
<spriteMaterial
attach="material"
map={
activeSsknComponent === "ok"
? ssknTextWrapperTex
: ssknTextWrapperInactiveTex
}
/>
</sprite>
<sprite position={[3.3, -3.15, 0]} scale={[3, 0.4, 0]}>
<spriteMaterial
attach="material"
map={
activeSsknComponent === "cancel"
? ssknTextWrapperTex
: ssknTextWrapperInactiveTex
}
/>
</sprite>
<sprite
position={[0.2, -2.7, 0]}
scale={[2.2, 0.3, 0]}
renderOrder={4}
>
<spriteMaterial attach="material" map={ssknArrowTex} />
</sprite>
<sprite
position={[-4.65, -2.7, 0]}
scale={[1, 0.03, 0]}
renderOrder={4}
>
<spriteMaterial attach="material" map={ssknLineTex} />
</sprite>
</group>
)}
<sprite position={[-2.5, -2.7, 0]} scale={[2.9, 0.7, 0]} renderOrder={4}>
<spriteMaterial attach="material" map={ssknUpgradeTex} />
</sprite>
</>
);
});
export default SsknHUD;

View file

@ -1,95 +0,0 @@
import React, { useRef } from "react";
import { useFrame, useLoader } from "react-three-fiber";
import * as THREE from "three";
import ssknProgressBarContainer from "../../static/sprites/sskn/sskn_progress_bar.png";
import progressBar1 from "../../static/sprites/progressbar/progress_bar1.png";
import progressBar2 from "../../static/sprites/progressbar/progress_bar2.png";
import progressBar3 from "../../static/sprites/progressbar/progress_bar3.png";
import progressBar4 from "../../static/sprites/progressbar/progress_bar4.png";
import progressBar5 from "../../static/sprites/progressbar/progress_bar5.png";
import progressBar from "../../static/sprites/progressbar/progress_bar0.png";
const SsknProgressBar = () => {
const ssknProgressBarContainerTex = useLoader(
THREE.TextureLoader,
ssknProgressBarContainer
);
const progressBarTex = useLoader(THREE.TextureLoader, progressBar);
const progressBar1Tex = useLoader(THREE.TextureLoader, progressBar1);
const progressBar2Tex = useLoader(THREE.TextureLoader, progressBar2);
const progressBar3Tex = useLoader(THREE.TextureLoader, progressBar3);
const progressBar4Tex = useLoader(THREE.TextureLoader, progressBar4);
const progressBar5Tex = useLoader(THREE.TextureLoader, progressBar5);
const progressBarRef = useRef<THREE.Object3D>();
const progressBarMatRef = useRef<THREE.SpriteMaterial>();
const percentageElapsed = useRef(0);
const last = useRef(0);
useFrame(() => {
const now = Date.now();
if (
now > last.current + 200 &&
progressBarRef.current &&
progressBarMatRef.current
) {
percentageElapsed.current += 5;
switch (percentageElapsed.current) {
case 5:
progressBarRef.current.scale.x = 0.25;
progressBarMatRef.current.map = progressBar1Tex;
break;
case 10:
progressBarRef.current.scale.x += 0.25;
progressBarRef.current.position.x += 0.1;
progressBarMatRef.current.map = progressBar2Tex;
break;
case 15:
progressBarRef.current.scale.x += 0.25;
progressBarRef.current.position.x += 0.1;
progressBarMatRef.current.map = progressBar3Tex;
break;
case 20:
progressBarRef.current.scale.x += 0.25;
progressBarRef.current.position.x += 0.1;
progressBarMatRef.current.map = progressBar4Tex;
break;
case 25:
progressBarRef.current.scale.x += 0.25;
progressBarRef.current.position.x += 0.1;
progressBarMatRef.current.map = progressBar5Tex;
break;
default:
if (progressBarRef.current.position.x < 4.1) {
progressBarMatRef.current.map = progressBarTex;
progressBarRef.current.position.x += 0.2;
}
}
last.current = now;
}
});
return (
<>
<sprite scale={[5.5, 0.3, 0]} position={[2, -2.7, 0]} renderOrder={4}>
<spriteMaterial attach="material" map={ssknProgressBarContainerTex} />
</sprite>
<sprite
scale={[0.2, 0.15, 0]}
position={[-0.5, -2.68, 0]}
renderOrder={4}
ref={progressBarRef}
>
<spriteMaterial
attach="material"
ref={progressBarMatRef}
map={progressBar1Tex}
opacity={0.8}
/>
</sprite>
</>
);
};
export default SsknProgressBar;

View file

@ -1,67 +0,0 @@
import React, { memo } from "react";
import statusContainer from "../static/sprites/status/status_container.png";
import loadSuccessfulImg from "../static/sprites/status/load_successful.png";
import loadFailImg from "../static/sprites/status/load_fail.png";
import saveSuccessfulImg from "../static/sprites/status/save_successful.png";
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import { useStore } from "../store";
const Status = memo(() => {
const loadSuccessful = useStore((state) => state.loadSuccessful);
const saveSuccessful = useStore((state) => state.saveSuccessful);
const statusContainerTex = useLoader(THREE.TextureLoader, statusContainer);
const loadSuccessfulTex = useLoader(THREE.TextureLoader, loadSuccessfulImg);
const loadFailTex = useLoader(THREE.TextureLoader, loadFailImg);
const saveSuccessfulTex = useLoader(THREE.TextureLoader, saveSuccessfulImg);
return (
<group
visible={loadSuccessful !== undefined || saveSuccessful !== undefined}
>
<sprite scale={[4, 0.3, 2]} renderOrder={200} position={[1, 0.2, 0]}>
<spriteMaterial
map={statusContainerTex}
attach="material"
depthTest={false}
/>
</sprite>
<sprite
scale={[2, 0.17, 2]}
renderOrder={200}
position={[1, 0.2, 0]}
visible={saveSuccessful === true}
>
<spriteMaterial
map={saveSuccessfulTex}
attach="material"
depthTest={false}
/>
</sprite>
<sprite
scale={[2, 0.17, 2]}
renderOrder={200}
position={[1, 0.2, 0]}
visible={loadSuccessful === true}
>
<spriteMaterial
map={loadSuccessfulTex}
attach="material"
depthTest={false}
/>
</sprite>
<sprite
scale={[2, 0.17, 2]}
renderOrder={200}
position={[1, 0.2, 0]}
visible={loadSuccessful === false}
>
<spriteMaterial map={loadFailTex} attach="material" depthTest={false} />
</sprite>
</group>
);
});
export default Status;

View file

@ -1,152 +0,0 @@
import orangeFont from "../../static/sprites/fonts/orange_font_texture.png";
import yellowFont from "../../static/sprites/fonts/yellow_font_texture.png";
import * as THREE from "three";
import { useLoader } from "react-three-fiber";
import orange_font_json from "../../resources/fonts/big_font.json";
import { a, useSpring } from "@react-spring/three";
import React, { memo, useEffect, useMemo, useState } from "react";
import { useStore } from "../../store";
import usePrevious from "../../hooks/usePrevious";
const BigLetter = memo((props: { letter: string; letterIdx: number }) => {
const [color, setColor] = useState("yellow");
const tex = useMemo(
() =>
color === "orange" || props.letterIdx === 0 ? orangeFont : yellowFont,
[color, props.letterIdx]
);
const colorTexture: THREE.Texture = useLoader(THREE.TextureLoader, tex);
const lineYOffset = useMemo(() => {
const lineOne = "ABCDEFGHIJKLMNOPQ";
const lineTwo = "RSTUVWXYZ01234567";
const lineThree = "89abcdefghijklmnopqrs";
let lineNum: number;
if (props.letter === " ") {
lineNum = 5;
} else {
if (lineOne.includes(props.letter)) {
lineNum = 1;
} else if (lineTwo.includes(props.letter)) {
lineNum = 2;
} else if (lineThree.includes(props.letter)) {
lineNum = 3;
} else {
lineNum = 4;
}
}
const offsets = {
1: 0.884,
2: 0.765,
3: 0.648,
4: 0.47,
5: 1,
};
return offsets[lineNum as keyof typeof offsets];
}, [props.letter]);
const letterData = useMemo(
() =>
orange_font_json.glyphs[
props.letter as keyof typeof orange_font_json.glyphs
],
[props.letter]
);
const geom = useMemo(() => {
const geometry = new THREE.PlaneBufferGeometry();
const uvAttribute = geometry.attributes.uv;
for (let i = 0; i < uvAttribute.count; i++) {
let u = uvAttribute.getX(i);
let v = uvAttribute.getY(i);
u = (u * letterData[2]) / 256 + letterData[0] / 256;
v = (v * letterData[3]) / 136 + lineYOffset - letterData[4] / 136;
uvAttribute.setXY(i, u, v);
}
return geometry;
}, [letterData, lineYOffset]);
const activeNode = useStore((state) => state.activeNode);
const activeMediaComponent = useStore((state) => state.activeMediaComponent);
const subscene = useStore((state) => state.mainSubscene);
const scene = useStore((state) => state.currentScene);
const prevData = usePrevious({ scene, subscene, activeNode });
const [lastMediaLeftComponent, setLastMediaLeftComponent] = useState("play");
const [shrinkState, set] = useSpring(() => ({
x: props.letterIdx + 0.3,
config: { duration: 200 },
}));
useEffect(() => {
if (
subscene === "pause" ||
(subscene === "site" && prevData?.subscene === "pause") ||
(activeNode === prevData?.activeNode &&
!(
subscene === "level_selection" ||
color === "orange" ||
scene === "media"
))
)
return;
if (scene === "main" && prevData?.scene === "main") {
set({ x: 0 });
if (subscene === "level_selection") setColor("orange");
else if (color === "orange") setColor("yellow");
setTimeout(() => set({ x: props.letterIdx + 0.3 }), 1200);
} else if (scene === "media") {
if (
(activeMediaComponent === "play" || activeMediaComponent === "exit") &&
activeMediaComponent !== lastMediaLeftComponent
) {
setLastMediaLeftComponent(activeMediaComponent);
set({ x: 0 });
setTimeout(() => set({ x: props.letterIdx + 0.3 }), 1200);
}
}
}, [
activeNode,
props.letterIdx,
subscene,
set,
color,
scene,
activeMediaComponent,
lastMediaLeftComponent,
prevData?.scene,
prevData?.subscene,
prevData?.activeNode,
]);
return (
<a.mesh
position-x={shrinkState.x}
position-y={-letterData[4] / 12.5}
scale={[1, 1, 0]}
geometry={geom}
renderOrder={props.letterIdx === 0 ? 11 : 10}
>
<meshBasicMaterial
map={colorTexture}
attach="material"
transparent={true}
/>
</a.mesh>
);
});
export default BigLetter;

View file

@ -1,92 +0,0 @@
import { useLoader } from "react-three-fiber";
import * as THREE from "three";
import greenFont from "../../static/sprites/fonts/white_and_green_texture.png";
import medium_font_json from "../../resources/fonts/medium_font.json";
import { a } from "@react-spring/three";
import React, { memo, useMemo } from "react";
const GreenTextRenderer = memo((props: { textToRender: string[] }) => {
const colorTexture = useLoader(THREE.TextureLoader, greenFont);
const getLineYOffset = (letter: string) => {
const lineOne = "ABCDEFGHIJKLMNOPQQRSTUVW";
const lineTwo = "XYZ0123456789abcdefghij";
const lineThree = "klmnopqrstuvwxyz,.*";
let lineNum: number;
if (letter === " ") {
lineNum = 6;
} else {
if (lineOne.includes(letter)) {
lineNum = 1;
} else if (lineTwo.includes(letter)) {
lineNum = 2;
} else if (lineThree.includes(letter)) {
lineNum = 3;
} else {
lineNum = 4;
}
}
const offsets = {
1: 0.355,
2: 0.297,
3: 0.238,
4: 0.18,
5: 1,
};
return offsets[lineNum as keyof typeof offsets];
};
const text = useMemo(() => {
const getGeom = (letter: string, letterData: number[]) => {
const geometry = new THREE.PlaneBufferGeometry();
const uvAttribute = geometry.attributes.uv;
for (let i = 0; i < uvAttribute.count; i++) {
let u = uvAttribute.getX(i);
let v = uvAttribute.getY(i);
u = (u * letterData[2]) / 256 + letterData[0] / 256;
v =
(v * letterData[3]) / 136 +
getLineYOffset(letter) -
letterData[4] / 136;
uvAttribute.setXY(i, u, v);
}
return geometry;
};
return props.textToRender.map((letter, idx) => {
const letterData =
medium_font_json.glyphs[letter as keyof typeof medium_font_json.glyphs];
const geom = getGeom(letter, letterData);
return (
<a.mesh
position-x={idx * 1.6}
position-y={0 - letterData[4] / 12.5}
scale={[1.7, 1, 1.7]}
geometry={geom}
renderOrder={100}
key={idx}
>
<meshBasicMaterial
map={colorTexture}
attach="material"
transparent={true}
depthTest={false}
/>
</a.mesh>
);
});
}, [colorTexture, props.textToRender]);
return <>{text}</>;
});
export default GreenTextRenderer;

View file

@ -1,61 +0,0 @@
import React, { useEffect, useState } from "react";
import { useStore } from "../../store";
import { a, useTrail } from "@react-spring/three";
import BigLetter from "./BigLetter";
import usePrevious from "../../hooks/usePrevious";
import { getNodeHud, isNodeVisible } from "../../helpers/node-helpers";
const MainYellowTextAnimator = (props: { visible?: boolean }) => {
const activeNode = useStore((state) => state.activeNode);
const subscene = useStore((state) => state.mainSubscene);
const prevData = usePrevious({ subscene });
const gameProgress = useStore((state) => state.gameProgress);
const [text, setText] = useState(
useStore.getState().activeNode.node_name.split("")
);
const [trail, set] = useTrail(text.length, () => ({
posX: getNodeHud(useStore.getState().activeNode.matrixIndices!).big_text[0],
posY: getNodeHud(useStore.getState().activeNode.matrixIndices!).big_text[1],
config: { duration: 280 },
}));
useEffect(() => {
const hud = getNodeHud(activeNode.matrixIndices!);
if (subscene === "level_selection") {
setTimeout(() => set({ posX: -0.02, posY: 0.005 }), 400);
setTimeout(() => setText("JumpTo".split("")), 1000);
} else {
setTimeout(
() => set({ posX: hud.big_text[0], posY: hud.big_text[1] }),
400
);
if (isNodeVisible(activeNode, gameProgress)) {
setTimeout(() => setText(activeNode.node_name.split("")), 1000);
} else {
setText("Unknown".split(""));
}
}
}, [activeNode, prevData?.subscene, set, subscene, gameProgress]);
return (
<group position={[0, 0, 10]} visible={props.visible}>
{trail.map(({ posX, posY }, idx) => (
<a.group
key={idx}
position-x={posX}
position-y={posY}
position-z={-8.6}
scale={[0.035, 0.055, 0.035]}
>
<BigLetter letter={text[idx]} letterIdx={idx} key={idx} />
</a.group>
))}
</group>
);
};
export default MainYellowTextAnimator;

Some files were not shown because too many files have changed in this diff Show more