Lay the party logo over the background
Centred, spanning 60% of the screen width, on the poster's layer so the video frame and the stills still pass in front of it. The file lives in assets/ with the posters, so it has to be kept out of the background rotation — it is the one image there that is never a background. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9v2Xoa6eoeGYpK6gp95k9
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
@@ -115,6 +115,15 @@ export const DEFAULT_ANIMATION = AUTO_ANIMATION;
|
||||
const ASSET_DIR = join(dirname(fileURLToPath(import.meta.url)), 'assets');
|
||||
const IMAGE_TYPES = new Set(['.jpg', '.jpeg', '.png', '.webp', '.avif']);
|
||||
|
||||
// The party's logo, laid over every background. Lives in assets/ with the
|
||||
// posters, so it has to be kept out of the rotation below — it is the one
|
||||
// image there that is never a background of its own.
|
||||
const LOGO_FILE = 'logo.png';
|
||||
export const LOGO_SRC = `/assets/${LOGO_FILE}`;
|
||||
|
||||
// How much of the screen's width the logo spans, centred.
|
||||
export const LOGO_WIDTH = 0.6;
|
||||
|
||||
function readBackgrounds() {
|
||||
let files;
|
||||
try {
|
||||
@@ -125,7 +134,7 @@ function readBackgrounds() {
|
||||
|
||||
return Object.fromEntries(
|
||||
files
|
||||
.filter((file) => IMAGE_TYPES.has(extname(file).toLowerCase()))
|
||||
.filter((file) => file !== LOGO_FILE && IMAGE_TYPES.has(extname(file).toLowerCase()))
|
||||
.sort()
|
||||
.map((file) => {
|
||||
const key = file.slice(0, -extname(file).length);
|
||||
|
||||
@@ -17,11 +17,24 @@ import {
|
||||
BACKGROUND_MAX_ZOOM,
|
||||
BACKGROUND_FOCUS_SPREAD,
|
||||
BACKGROUND_MAX_OVERSAMPLE,
|
||||
LOGO_SRC,
|
||||
LOGO_WIDTH,
|
||||
} from '/config.js';
|
||||
import { createPicker } from './motion.js';
|
||||
|
||||
const KEYS = Object.keys(BACKGROUNDS);
|
||||
|
||||
/**
|
||||
* Point the logo overlay at the configured file and size it against the
|
||||
* screen. The element is in the page from the start — only the two values that
|
||||
* belong to the config are set here.
|
||||
*/
|
||||
export function showLogo(element) {
|
||||
if (!element) return;
|
||||
element.src = LOGO_SRC;
|
||||
element.style.width = `${LOGO_WIDTH * 100}vw`;
|
||||
}
|
||||
|
||||
/**
|
||||
* A zoom level and the point of the image the crop closes in on, in percent.
|
||||
* The focal point is pulled toward the middle by BACKGROUND_FOCUS_SPREAD, so a
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
<body>
|
||||
<div id="backgrounds"></div>
|
||||
|
||||
<!-- The party's logo, centred over the poster. Its src and width come from
|
||||
the shared config, so the file can be swapped without touching this. -->
|
||||
<img id="logo" alt="" />
|
||||
|
||||
<!-- Frozen screenshots of the frame. A sibling, not a child, of #frameMover:
|
||||
these are positioned against the screen, not the moving frame. -->
|
||||
<div id="stills"></div>
|
||||
|
||||
@@ -42,6 +42,23 @@ body {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* The logo sits on the poster, not on the video: it shares the backdrop's
|
||||
layer so the frame and the stills still pass in front of it. Its width comes
|
||||
from LOGO_WIDTH, written onto the element by backdrop.js. */
|
||||
#logo {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
translate: -50% -50%;
|
||||
height: auto;
|
||||
/* Only bites on a screen too short for the width above — on the projector
|
||||
the width is what decides. */
|
||||
max-height: 70vh;
|
||||
object-fit: contain;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* Built and removed by the wash animation. Sits between the poster and the
|
||||
stills, and blends rather than covers, so the poster stays legible through
|
||||
whatever colour is passing over it. The gradient itself is written per frame
|
||||
|
||||
@@ -2,7 +2,7 @@ import { connect } from '/shared/socket.js';
|
||||
import { OVERLAP_SECONDS, HARD_CUT_SECONDS, AUTO_BACKGROUND, AUTO_ANIMATION } from '/config.js';
|
||||
import { createPlayer, loadApi, STATE } from './yt.js';
|
||||
import { startAnimationCycle } from './motion.js';
|
||||
import { startBackgroundCycle } from './backdrop.js';
|
||||
import { startBackgroundCycle, showLogo } from './backdrop.js';
|
||||
import { requestCapture } from './capture.js';
|
||||
|
||||
const TICK_MS = 250;
|
||||
@@ -25,6 +25,8 @@ const backgrounds = startBackgroundCycle(
|
||||
state.background,
|
||||
);
|
||||
|
||||
showLogo(document.getElementById('logo'));
|
||||
|
||||
// --- start gate ---------------------------------------------------------
|
||||
|
||||
const gate = document.getElementById('gate');
|
||||
|
||||
Reference in New Issue
Block a user