brad-did-something / static /js /effects.js
qFelix's picture
Brad Did Something - Gradio/FastAPI Space on HF
78c0f6e
Raw
History Blame Contribute Delete
2.85 kB
// screen-level effects + the 17 animation trigger dispatcher
import { G } from "./state.js";
import { confettiBurst, heartFloat, moraleWave, revenueRain } from "./particles.js";
import { sfx } from "./audio.js";
export function dim(on) { G.els.dim.classList.toggle("hidden", !on); }
export function redFlash() {
const el = G.els.flash;
el.classList.remove("on"); void el.offsetWidth; el.classList.add("on");
}
export function edgePulse(on) { G.els["edge-pulse"].classList.toggle("on", on); }
export function hrStamp() {
const el = G.els.stamp;
el.classList.remove("hidden");
el.style.animation = "none"; void el.offsetWidth; el.style.animation = "";
sfx.stamp();
setTimeout(() => el.classList.add("hidden"), 950);
}
export function wipe(midCallback) {
const el = G.els.wipe;
el.classList.remove("go"); void el.offsetWidth; el.classList.add("go");
setTimeout(midCallback, 350); // swap scenes while fully covered
setTimeout(() => el.classList.remove("go"), 750);
}
export function fadeBlack(midCallback, hold = 1000) {
const el = G.els.wipe;
el.style.transition = "transform .01s";
el.style.transform = "translateX(0)";
el.style.opacity = 0;
el.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 400, fill: "forwards" });
setTimeout(() => {
midCallback();
el.animate([{ opacity: 1 }, { opacity: 0 }],
{ duration: 400, fill: "forwards" });
setTimeout(() => { el.style.transform = "translateX(-100%)";
el.style.opacity = 1; el.style.transition = ""; }, 450);
}, 400 + hold);
}
// the AI's animation enum → visual dispatch (ANIMATIONS.md)
const NPC_ANIM_POSE = {
npc_happy: "idle", npc_angry: "shake", npc_confused: "idle",
npc_devastated: "headdown", npc_celebrating: "idle", npc_hiding: "slump",
npc_smug: "lean", npc_suspicious: "lean", npc_crying: "slump",
npc_grateful: "idle",
};
export function playOutcome(trigger, npcId, world) {
const npc = npcId && world.npcs[npcId];
switch (trigger) {
case "disaster_flash": redFlash(); sfx.disaster(); break;
case "revenue_rain": revenueRain(); sfx.moneyUp(); break;
case "heart_float":
if (npc) heartFloat(npc.x, npc.y - 44); sfx.gift(); break;
case "bribery_envelope": sfx.click(); break;
case "hr_stamp": hrStamp(); break;
case "morale_drop_wave": moraleWave(world.npcs); sfx.moneyDown(); break;
case "confetti_burst": confettiBurst(); sfx.win(); break;
default:
if (npc && NPC_ANIM_POSE[trigger]) {
npc.setPose(NPC_ANIM_POSE[trigger]);
if (trigger === "npc_celebrating" || trigger === "npc_happy") {
npc.sprite.animate(
[{ transform: "translateY(0)" }, { transform: "translateY(-6px)" },
{ transform: "translateY(0)" }],
{ duration: 320, iterations: 2, easing: "steps(3)" });
}
}
}
}