feat: add finale text

This commit is contained in:
2026-06-01 22:02:22 -03:00
parent b9eeed848b
commit 8c4080f10c
5 changed files with 102 additions and 3 deletions
Binary file not shown.
+4 -1
View File
@@ -15,6 +15,7 @@ import Player from './scene-components/player';
import Hallway from './scene-components/hallway'; import Hallway from './scene-components/hallway';
import { AudioListener } from 'three'; import { AudioListener } from 'three';
import FinaleText from './scene-components/finale-text';
function PostProcessing() { function PostProcessing() {
const [wasCaught, setWasCaught] = useState(fearState.wasCaught); const [wasCaught, setWasCaught] = useState(fearState.wasCaught);
@@ -94,7 +95,7 @@ export default function Fear() {
<TheCreature /> <TheCreature />
<Player /> <Player />
</Suspense> </Suspense>
<AmbientSound <AmbientSound
key="ambient-1" key="ambient-1"
url='fear/snd/ambience.mp3' url='fear/snd/ambience.mp3'
@@ -113,5 +114,7 @@ export default function Fear() {
volume={1} volume={1}
/> : null} /> : null}
</Canvas> </Canvas>
<FinaleText />
</>) </>)
} }
@@ -0,0 +1,52 @@
@font-face {
font-family: 'VCR';
src: url('/fear/fonts/vcr.ttf') format('truetype');
font-weight: normal;
font-style: normal;
font-display: swap;
}
.finale-container {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0vh;
display: grid;
align-items: center;
align-content: center;
justify-content: center;
overflow: hidden;
grid-auto-rows: 2.5vh;
/* grid-template-columns: 0; */
grid-template-rows: repeat(auto-fit, max-content);
user-select: none;
}
.finale-text {
font-family: 'VCR', sans-serif;
height: 0px;
width: 100%;
color: rgb(255, 255, 255);
font-size: 5vh;
text-align: center;
white-space: nowrap;
}
.scanlines {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 900;
background: repeating-linear-gradient(rgba(0, 0, 0, 0) 0px,
rgba(0, 0, 0, 0) 2px,
rgba(0, 0, 0, 0.3) 2px,
rgba(0, 0, 0, 0.3) 4px);
}
@@ -0,0 +1,36 @@
import { JSX, useEffect, useState } from "react"
import { FEAR_SETTINGS, fearState } from "../state"
import './finale-text.css';
export default function FinaleText() {
const [progression, setProgression] = useState(fearState.finaleProgression);
const [wasCaught, setWasCaught] = useState(fearState.isRustActive);
useEffect(() => {
const unsubscribe = fearState.subscribe(() => {
setProgression(fearState.finaleProgression);
setWasCaught(fearState.wasCaught)
});
return () => unsubscribe();
});
let elementCount = (FEAR_SETTINGS.EVENT_FINALE_TEXT_COUNT / FEAR_SETTINGS.EVENT_FINALE_DURATION) * progression;
let testElements: Array<JSX.Element> = [];
for (let x = 0; x < elementCount; x++)
testElements.push(<span className="finale-text" key={x}>the deal has been sealed</span>)
if (wasCaught)
return (<>
<div className="finale-container">
{testElements}
</div>
<div className="scanlines" />
</>)
return <></>
}
+10 -2
View File
@@ -12,7 +12,10 @@ export const FEAR_SETTINGS = {
EVENT_NARROW_LOOP_COUNT: 2, EVENT_NARROW_LOOP_COUNT: 2,
EVENT_RUST_LOOP_COUNT: 4, EVENT_RUST_LOOP_COUNT: 4,
EVENT_FINALE_LOOP_COUNT: 5 EVENT_FINALE_LOOP_COUNT: 5,
EVENT_FINALE_DURATION: 3,
EVENT_FINALE_TEXT_COUNT: 128
}; };
const listeners = new Set<() => void>(); const listeners = new Set<() => void>();
@@ -23,6 +26,7 @@ export const fearState = {
isRustActive: false, isRustActive: false,
finaleTriggered: false, finaleTriggered: false,
wasCaught: false, wasCaught: false,
finaleProgression: 0,
subscribe(listener: () => void) { subscribe(listener: () => void) {
listeners.add(listener); listeners.add(listener);
@@ -39,8 +43,12 @@ export const fearState = {
if (Math.abs(this.currentWidth - newWidth) > 0.001) { if (Math.abs(this.currentWidth - newWidth) > 0.001) {
this.currentWidth = newWidth; this.currentWidth = newWidth;
this.emit();
} }
if (this.wasCaught && this.finaleProgression < FEAR_SETTINGS.EVENT_FINALE_DURATION)
this.finaleProgression = Math.min(this.finaleProgression + delta, FEAR_SETTINGS.EVENT_FINALE_DURATION);
this.emit();
}, },
registerLoop(direction: 'forward' | 'backward') { registerLoop(direction: 'forward' | 'backward') {