Refine goal HUD animations
This commit is contained in:
@@ -56,6 +56,14 @@
|
||||
},
|
||||
},
|
||||
messages: { ...defaultMessageConfig },
|
||||
goalEffects: {
|
||||
enabled: true,
|
||||
nearThreshold: 0.7,
|
||||
completeThreshold: 0.98,
|
||||
pulseSpeedMs: 900,
|
||||
glowStrength: 0.55,
|
||||
gradientBlend: true,
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
15
src/main.js
15
src/main.js
@@ -65,8 +65,16 @@
|
||||
},
|
||||
});
|
||||
|
||||
const normalizeGoalEffects = (
|
||||
goalEffects = {},
|
||||
defaults = baseConfig.goalEffects || {},
|
||||
) => ({
|
||||
...defaults,
|
||||
...goalEffects,
|
||||
});
|
||||
|
||||
const normalizeSceneConfig = (sceneConfig = {}, defaults = baseConfig) => {
|
||||
const { link = {}, messages = {}, ...rest } = sceneConfig;
|
||||
const { link = {}, messages = {}, goalEffects = {}, ...rest } = sceneConfig;
|
||||
const base = defaults || {};
|
||||
return {
|
||||
...base,
|
||||
@@ -76,6 +84,7 @@
|
||||
messages,
|
||||
base.messages || defaultMessageConfig,
|
||||
),
|
||||
goalEffects: normalizeGoalEffects(goalEffects, base.goalEffects),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -403,7 +412,7 @@
|
||||
const checkWinCondition = () => {
|
||||
if (state.levelWon) return;
|
||||
const goal = goals.getGoalState();
|
||||
ui.setGoal(goal || { label: "—", progress: 0 });
|
||||
ui.setGoal(goal || { label: "—", progress: 0 }, config.goalEffects);
|
||||
if (!goal || !goal.met) return;
|
||||
applyWinEffects();
|
||||
state.levelWon = true;
|
||||
@@ -424,7 +433,7 @@
|
||||
activeColor: chain.color,
|
||||
});
|
||||
const goal = goals.getGoalState();
|
||||
ui.setGoal(goal || { label: "—", progress: 0 });
|
||||
ui.setGoal(goal || { label: "—", progress: 0 }, config.goalEffects);
|
||||
goals.maybeAnnounceGoalProgress(goal);
|
||||
};
|
||||
|
||||
|
||||
@@ -141,6 +141,14 @@
|
||||
|
||||
// Scoring/persistence
|
||||
noGameOver: false, // true disables game-over-on-blocked-entry checks
|
||||
goalEffects: {
|
||||
enabled: true, // set false to disable HUD goal bling
|
||||
nearThreshold: 0.7, // fraction (0-1) that triggers “near” pulse
|
||||
completeThreshold: 0.98, // fraction (0-1) for “almost there” glow
|
||||
pulseSpeedMs: 900, // pulse speed for near/complete states
|
||||
glowStrength: 0.55, // opacity multiplier for glow
|
||||
gradientBlend: true, // when colors are provided, blend them into the bar
|
||||
},
|
||||
},
|
||||
createBodies: (w, h) => {
|
||||
// Return an array of Matter bodies that make up scene obstacles/boundaries.
|
||||
|
||||
43
src/ui.js
43
src/ui.js
@@ -108,7 +108,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
const setGoal = ({ label, progress, colors }) => {
|
||||
const setGoal = ({ label, progress, colors }, effects = {}) => {
|
||||
if (goalLabelEl) {
|
||||
goalLabelEl.innerHTML = "";
|
||||
if (Array.isArray(colors) && colors.length > 0) {
|
||||
@@ -135,6 +135,47 @@
|
||||
0,
|
||||
Math.min(100, progress ?? 0),
|
||||
)}%`;
|
||||
|
||||
if (goalProgressEl) {
|
||||
const parentProgress = goalProgressEl.parentElement;
|
||||
const targetEls = [goalProgressEl, parentProgress].filter(Boolean);
|
||||
targetEls.forEach((el) => {
|
||||
el.classList.remove("goal-near", "goal-complete", "goal-gradient");
|
||||
});
|
||||
goalProgressEl.style.removeProperty("background-image");
|
||||
goalProgressEl.style.removeProperty("--goal-glow-alpha");
|
||||
const fraction = Math.max(0, Math.min(1, (progress ?? 0) / 100));
|
||||
if (effects?.enabled) {
|
||||
const near = effects.nearThreshold ?? 0.7;
|
||||
const complete = effects.completeThreshold ?? 0.98;
|
||||
const pulseSpeed = Math.max(200, effects.pulseSpeedMs ?? 900);
|
||||
goalProgressEl.style.setProperty(
|
||||
"--goal-pulse-speed",
|
||||
`${pulseSpeed}ms`,
|
||||
);
|
||||
goalProgressEl.style.setProperty(
|
||||
"--goal-glow-alpha",
|
||||
effects.glowStrength ?? 0.55,
|
||||
);
|
||||
if (fraction >= complete) {
|
||||
targetEls.forEach((el) => el.classList.add("goal-complete"));
|
||||
} else if (fraction >= near) {
|
||||
targetEls.forEach((el) => el.classList.add("goal-near"));
|
||||
}
|
||||
const useGradient =
|
||||
effects.gradientBlend !== false &&
|
||||
Array.isArray(colors) &&
|
||||
colors.length > 0;
|
||||
if (useGradient) {
|
||||
goalProgressEl.classList.add("goal-gradient");
|
||||
const denom = Math.max(1, colors.length - 1);
|
||||
const stops = colors
|
||||
.map((c, idx) => `${c} ${(idx / denom) * 100}%`)
|
||||
.join(", ");
|
||||
goalProgressEl.style.backgroundImage = `linear-gradient(90deg, ${stops})`;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const showWin = (message) => {
|
||||
|
||||
Reference in New Issue
Block a user