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 ASSET_DIR = join(dirname(fileURLToPath(import.meta.url)), 'assets');
|
||||||
const IMAGE_TYPES = new Set(['.jpg', '.jpeg', '.png', '.webp', '.avif']);
|
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() {
|
function readBackgrounds() {
|
||||||
let files;
|
let files;
|
||||||
try {
|
try {
|
||||||
@@ -125,7 +134,7 @@ function readBackgrounds() {
|
|||||||
|
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
files
|
files
|
||||||
.filter((file) => IMAGE_TYPES.has(extname(file).toLowerCase()))
|
.filter((file) => file !== LOGO_FILE && IMAGE_TYPES.has(extname(file).toLowerCase()))
|
||||||
.sort()
|
.sort()
|
||||||
.map((file) => {
|
.map((file) => {
|
||||||
const key = file.slice(0, -extname(file).length);
|
const key = file.slice(0, -extname(file).length);
|
||||||
|
|||||||
@@ -17,11 +17,24 @@ import {
|
|||||||
BACKGROUND_MAX_ZOOM,
|
BACKGROUND_MAX_ZOOM,
|
||||||
BACKGROUND_FOCUS_SPREAD,
|
BACKGROUND_FOCUS_SPREAD,
|
||||||
BACKGROUND_MAX_OVERSAMPLE,
|
BACKGROUND_MAX_OVERSAMPLE,
|
||||||
|
LOGO_SRC,
|
||||||
|
LOGO_WIDTH,
|
||||||
} from '/config.js';
|
} from '/config.js';
|
||||||
import { createPicker } from './motion.js';
|
import { createPicker } from './motion.js';
|
||||||
|
|
||||||
const KEYS = Object.keys(BACKGROUNDS);
|
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.
|
* 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
|
* The focal point is pulled toward the middle by BACKGROUND_FOCUS_SPREAD, so a
|
||||||
|
|||||||
@@ -9,6 +9,10 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="backgrounds"></div>
|
<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:
|
<!-- Frozen screenshots of the frame. A sibling, not a child, of #frameMover:
|
||||||
these are positioned against the screen, not the moving frame. -->
|
these are positioned against the screen, not the moving frame. -->
|
||||||
<div id="stills"></div>
|
<div id="stills"></div>
|
||||||
|
|||||||
@@ -42,6 +42,23 @@ body {
|
|||||||
opacity: 1;
|
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
|
/* 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
|
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
|
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 { OVERLAP_SECONDS, HARD_CUT_SECONDS, AUTO_BACKGROUND, AUTO_ANIMATION } from '/config.js';
|
||||||
import { createPlayer, loadApi, STATE } from './yt.js';
|
import { createPlayer, loadApi, STATE } from './yt.js';
|
||||||
import { startAnimationCycle } from './motion.js';
|
import { startAnimationCycle } from './motion.js';
|
||||||
import { startBackgroundCycle } from './backdrop.js';
|
import { startBackgroundCycle, showLogo } from './backdrop.js';
|
||||||
import { requestCapture } from './capture.js';
|
import { requestCapture } from './capture.js';
|
||||||
|
|
||||||
const TICK_MS = 250;
|
const TICK_MS = 250;
|
||||||
@@ -25,6 +25,8 @@ const backgrounds = startBackgroundCycle(
|
|||||||
state.background,
|
state.background,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
showLogo(document.getElementById('logo'));
|
||||||
|
|
||||||
// --- start gate ---------------------------------------------------------
|
// --- start gate ---------------------------------------------------------
|
||||||
|
|
||||||
const gate = document.getElementById('gate');
|
const gate = document.getElementById('gate');
|
||||||
|
|||||||
Reference in New Issue
Block a user