diff --git a/package-lock.json b/package-lock.json index b4e1a19..ff0da3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1666,6 +1666,12 @@ "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", "dev": true }, + "@types/luxon": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.4.tgz", + "integrity": "sha512-H9OXxv4EzJwE75aTPKpiGXJq+y4LFxjpsdgKwSmr503P5DkWc3AG7VAFYrFNVvqemT5DfgZJV9itYhqBHSGujA==", + "dev": true + }, "@types/minimist": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", @@ -4189,6 +4195,11 @@ "yallist": "^4.0.0" } }, + "luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==" + }, "magic-string": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", diff --git a/package.json b/package.json index 2d98818..ba151d6 100644 --- a/package.json +++ b/package.json @@ -21,14 +21,15 @@ "@emotion/styled": "^11.3.0", "@mui/material": "^5.11.4", "@pixi/filter-bevel": "^4.2.0", + "@pixi/filter-crt": "^4.2.0", "@pixi/filter-drop-shadow": "^4.2.0", "@pixi/filter-outline": "^4.2.0", - "@pixi/filter-crt": "^4.2.0", "clone": "^2.1.2", "currency-to-abbreviation": "^2.0.1", "events": "^3.3.0", "gsap": "^3.11.4", "lodash": "^4.17.21", + "luxon": "^3.4.4", "object-path": "^0.11.8", "pixi-projection": "^0.4.4", "pixi.js": "^6.5.9", @@ -49,6 +50,7 @@ "@types/clone": "^2.1.1", "@types/events": "^3.0.0", "@types/lodash": "^4.14.191", + "@types/luxon": "^3.3.4", "@types/object-path": "^0.11.1", "@types/obs-studio": "^2.17.0", "@types/react": "^17.0.21", diff --git a/src/channels/desert-bus/daytime.ts b/src/channels/desert-bus/daytime.ts new file mode 100644 index 0000000..7ed784c --- /dev/null +++ b/src/channels/desert-bus/daytime.ts @@ -0,0 +1,50 @@ +import { DateTime } from 'luxon'; + +const timezone = nodecg.Replicant('timezone', { + defaultValue: 'America/New_York', +}); + +/** + * These times are based on Pittsburgh, January 14th 2024. + * Change times to reflect event location and time before event. + */ + +const Times: [number, 'night' | 'dawn' | 'day' | 'dusk'][] = [ + [(17 * 60 + 46) * 60, 'night'], // 5:46pm + [(17 * 60 + 16) * 60, 'dusk'], // 5:16pm + [(7 * 60 + 41) * 60, 'day'], // 7:41am + [(7 * 60 + 11) * 60, 'dawn'], // 7:11am + [0, 'night'], // Midnight +]; + +/** + * This time is based on the scheduled time for Day 7 recap. + * i.e. The Checkpoint. + * Change time to reflect event schedule before event. + */ +const OmegaShift = [2024, 1, 20, 21, 7, 0] as const; + +export function dayTime() { + const datetime = DateTime.local({ zone: timezone.value }); + const seconds = datetime.toSeconds() - datetime.startOf('day').toSeconds(); + + for (const Time of Times) { + if (seconds > Time[0]) return Time[1]; + } + + return Times[0][1]; +} + +export function shiftTime(): 'zeta' | 'dawn' | 'alpha' | 'night' | 'omega' { + const omegaShiftStart = DateTime.local(...OmegaShift, { zone: timezone.value }); + const datetime = DateTime.local({ zone: timezone.value }); + + if (datetime.toSeconds() > omegaShiftStart.toSeconds()) return 'omega'; + + const hour = datetime.hour; + + if (hour > 18) return 'night'; + if (hour > 12) return 'alpha'; + if (hour > 6) return 'dawn'; + return 'zeta'; +} diff --git a/src/channels/desert-bus/images/bus.png b/src/channels/desert-bus/images/bus.png deleted file mode 100644 index a08c3a9..0000000 Binary files a/src/channels/desert-bus/images/bus.png and /dev/null differ diff --git a/src/channels/desert-bus/images/dawn/bus-stop.png b/src/channels/desert-bus/images/dawn/bus-stop.png new file mode 100644 index 0000000..744a920 Binary files /dev/null and b/src/channels/desert-bus/images/dawn/bus-stop.png differ diff --git a/src/channels/desert-bus/images/dawn/bus.png b/src/channels/desert-bus/images/dawn/bus.png new file mode 100644 index 0000000..00d4cad Binary files /dev/null and b/src/channels/desert-bus/images/dawn/bus.png differ diff --git a/src/channels/desert-bus/images/dawn/light_sand_texture.png b/src/channels/desert-bus/images/dawn/light_sand_texture.png new file mode 100644 index 0000000..597051f Binary files /dev/null and b/src/channels/desert-bus/images/dawn/light_sand_texture.png differ diff --git a/src/channels/desert-bus/images/dawn/numbers_white.png b/src/channels/desert-bus/images/dawn/numbers_white.png new file mode 100644 index 0000000..82788fd Binary files /dev/null and b/src/channels/desert-bus/images/dawn/numbers_white.png differ diff --git a/src/channels/desert-bus/images/dawn/sand_texture.png b/src/channels/desert-bus/images/dawn/sand_texture.png new file mode 100644 index 0000000..a9d77d5 Binary files /dev/null and b/src/channels/desert-bus/images/dawn/sand_texture.png differ diff --git a/src/channels/desert-bus/images/dawn/wheel1.png b/src/channels/desert-bus/images/dawn/wheel1.png new file mode 100644 index 0000000..b2cae1e Binary files /dev/null and b/src/channels/desert-bus/images/dawn/wheel1.png differ diff --git a/src/channels/desert-bus/images/dawn/wheel2.png b/src/channels/desert-bus/images/dawn/wheel2.png new file mode 100644 index 0000000..3775ffd Binary files /dev/null and b/src/channels/desert-bus/images/dawn/wheel2.png differ diff --git a/src/channels/desert-bus/images/dawn/wheel3.png b/src/channels/desert-bus/images/dawn/wheel3.png new file mode 100644 index 0000000..fba5712 Binary files /dev/null and b/src/channels/desert-bus/images/dawn/wheel3.png differ diff --git a/src/channels/desert-bus/images/dawn/wheel4.png b/src/channels/desert-bus/images/dawn/wheel4.png new file mode 100644 index 0000000..f0e4266 Binary files /dev/null and b/src/channels/desert-bus/images/dawn/wheel4.png differ diff --git a/src/channels/desert-bus/images/day/alpha-flight.png b/src/channels/desert-bus/images/day/alpha-flight.png new file mode 100644 index 0000000..3c96dd3 Binary files /dev/null and b/src/channels/desert-bus/images/day/alpha-flight.png differ diff --git a/src/channels/desert-bus/images/day/bus-stop.png b/src/channels/desert-bus/images/day/bus-stop.png new file mode 100644 index 0000000..4bbe9ad Binary files /dev/null and b/src/channels/desert-bus/images/day/bus-stop.png differ diff --git a/src/channels/desert-bus/images/day/bus.png b/src/channels/desert-bus/images/day/bus.png new file mode 100644 index 0000000..713006e Binary files /dev/null and b/src/channels/desert-bus/images/day/bus.png differ diff --git a/src/channels/desert-bus/images/day/dawn-guard.png b/src/channels/desert-bus/images/day/dawn-guard.png new file mode 100644 index 0000000..5c3c0af Binary files /dev/null and b/src/channels/desert-bus/images/day/dawn-guard.png differ diff --git a/src/channels/desert-bus/images/day/light_sand_texture.png b/src/channels/desert-bus/images/day/light_sand_texture.png new file mode 100644 index 0000000..64e1c57 Binary files /dev/null and b/src/channels/desert-bus/images/day/light_sand_texture.png differ diff --git a/src/channels/desert-bus/images/day/night-watch.png b/src/channels/desert-bus/images/day/night-watch.png new file mode 100644 index 0000000..fbcc14e Binary files /dev/null and b/src/channels/desert-bus/images/day/night-watch.png differ diff --git a/src/channels/desert-bus/images/day/numbers_white.png b/src/channels/desert-bus/images/day/numbers_white.png new file mode 100644 index 0000000..be51b9c Binary files /dev/null and b/src/channels/desert-bus/images/day/numbers_white.png differ diff --git a/src/channels/desert-bus/images/day/omega-shift.png b/src/channels/desert-bus/images/day/omega-shift.png new file mode 100644 index 0000000..257a95e Binary files /dev/null and b/src/channels/desert-bus/images/day/omega-shift.png differ diff --git a/src/channels/desert-bus/images/day/sand_texture.png b/src/channels/desert-bus/images/day/sand_texture.png new file mode 100644 index 0000000..2ccd1ed Binary files /dev/null and b/src/channels/desert-bus/images/day/sand_texture.png differ diff --git a/src/channels/desert-bus/images/day/wheel1.png b/src/channels/desert-bus/images/day/wheel1.png new file mode 100644 index 0000000..5242b0c Binary files /dev/null and b/src/channels/desert-bus/images/day/wheel1.png differ diff --git a/src/channels/desert-bus/images/day/wheel2.png b/src/channels/desert-bus/images/day/wheel2.png new file mode 100644 index 0000000..b737cae Binary files /dev/null and b/src/channels/desert-bus/images/day/wheel2.png differ diff --git a/src/channels/desert-bus/images/day/wheel3.png b/src/channels/desert-bus/images/day/wheel3.png new file mode 100644 index 0000000..0f74e18 Binary files /dev/null and b/src/channels/desert-bus/images/day/wheel3.png differ diff --git a/src/channels/desert-bus/images/day/wheel4.png b/src/channels/desert-bus/images/day/wheel4.png new file mode 100644 index 0000000..66157d3 Binary files /dev/null and b/src/channels/desert-bus/images/day/wheel4.png differ diff --git a/src/channels/desert-bus/images/day/zeta-shift.png b/src/channels/desert-bus/images/day/zeta-shift.png new file mode 100644 index 0000000..ddf9af2 Binary files /dev/null and b/src/channels/desert-bus/images/day/zeta-shift.png differ diff --git a/src/channels/desert-bus/images/dusk/bus-stop.png b/src/channels/desert-bus/images/dusk/bus-stop.png new file mode 100644 index 0000000..f0b550e Binary files /dev/null and b/src/channels/desert-bus/images/dusk/bus-stop.png differ diff --git a/src/channels/desert-bus/images/dusk/bus.png b/src/channels/desert-bus/images/dusk/bus.png new file mode 100644 index 0000000..0e19279 Binary files /dev/null and b/src/channels/desert-bus/images/dusk/bus.png differ diff --git a/src/channels/desert-bus/images/dusk/light_sand_texture.png b/src/channels/desert-bus/images/dusk/light_sand_texture.png new file mode 100644 index 0000000..3c5752f Binary files /dev/null and b/src/channels/desert-bus/images/dusk/light_sand_texture.png differ diff --git a/src/channels/desert-bus/images/dusk/sand_texture.png b/src/channels/desert-bus/images/dusk/sand_texture.png new file mode 100644 index 0000000..4ee24a8 Binary files /dev/null and b/src/channels/desert-bus/images/dusk/sand_texture.png differ diff --git a/src/channels/desert-bus/images/light_sand_texture.png b/src/channels/desert-bus/images/light_sand_texture.png deleted file mode 100644 index fa86ed6..0000000 Binary files a/src/channels/desert-bus/images/light_sand_texture.png and /dev/null differ diff --git a/src/channels/desert-bus/images/line1.png b/src/channels/desert-bus/images/line1.png index 07fa9a2..97e2226 100644 Binary files a/src/channels/desert-bus/images/line1.png and b/src/channels/desert-bus/images/line1.png differ diff --git a/src/channels/desert-bus/images/line2.png b/src/channels/desert-bus/images/line2.png index da2a148..c2fd17e 100644 Binary files a/src/channels/desert-bus/images/line2.png and b/src/channels/desert-bus/images/line2.png differ diff --git a/src/channels/desert-bus/images/line3.png b/src/channels/desert-bus/images/line3.png index a3154be..5428db7 100644 Binary files a/src/channels/desert-bus/images/line3.png and b/src/channels/desert-bus/images/line3.png differ diff --git a/src/channels/desert-bus/images/line4.png b/src/channels/desert-bus/images/line4.png index ae3a00f..abdfd1d 100644 Binary files a/src/channels/desert-bus/images/line4.png and b/src/channels/desert-bus/images/line4.png differ diff --git a/src/channels/desert-bus/images/line5.png b/src/channels/desert-bus/images/line5.png index f5ac1f6..b683932 100644 Binary files a/src/channels/desert-bus/images/line5.png and b/src/channels/desert-bus/images/line5.png differ diff --git a/src/channels/desert-bus/images/line6.png b/src/channels/desert-bus/images/line6.png index e614db8..bba4bdc 100644 Binary files a/src/channels/desert-bus/images/line6.png and b/src/channels/desert-bus/images/line6.png differ diff --git a/src/channels/desert-bus/images/line7.png b/src/channels/desert-bus/images/line7.png index 652c503..85571ea 100644 Binary files a/src/channels/desert-bus/images/line7.png and b/src/channels/desert-bus/images/line7.png differ diff --git a/src/channels/desert-bus/images/night/bus-stop.png b/src/channels/desert-bus/images/night/bus-stop.png new file mode 100644 index 0000000..adc35e8 Binary files /dev/null and b/src/channels/desert-bus/images/night/bus-stop.png differ diff --git a/src/channels/desert-bus/images/night/bus.png b/src/channels/desert-bus/images/night/bus.png new file mode 100644 index 0000000..09ee54e Binary files /dev/null and b/src/channels/desert-bus/images/night/bus.png differ diff --git a/src/channels/desert-bus/images/night/headlights.png b/src/channels/desert-bus/images/night/headlights.png new file mode 100644 index 0000000..bbe1143 Binary files /dev/null and b/src/channels/desert-bus/images/night/headlights.png differ diff --git a/src/channels/desert-bus/images/night/light_sand_texture.png b/src/channels/desert-bus/images/night/light_sand_texture.png new file mode 100644 index 0000000..f8c8561 Binary files /dev/null and b/src/channels/desert-bus/images/night/light_sand_texture.png differ diff --git a/src/channels/desert-bus/images/night/numbers_white.png b/src/channels/desert-bus/images/night/numbers_white.png new file mode 100644 index 0000000..bfc8ce0 Binary files /dev/null and b/src/channels/desert-bus/images/night/numbers_white.png differ diff --git a/src/channels/desert-bus/images/night/sand_texture.png b/src/channels/desert-bus/images/night/sand_texture.png new file mode 100644 index 0000000..6906b70 Binary files /dev/null and b/src/channels/desert-bus/images/night/sand_texture.png differ diff --git a/src/channels/desert-bus/images/night/wheel1.png b/src/channels/desert-bus/images/night/wheel1.png new file mode 100644 index 0000000..cc11f74 Binary files /dev/null and b/src/channels/desert-bus/images/night/wheel1.png differ diff --git a/src/channels/desert-bus/images/night/wheel2.png b/src/channels/desert-bus/images/night/wheel2.png new file mode 100644 index 0000000..eb8fb09 Binary files /dev/null and b/src/channels/desert-bus/images/night/wheel2.png differ diff --git a/src/channels/desert-bus/images/night/wheel3.png b/src/channels/desert-bus/images/night/wheel3.png new file mode 100644 index 0000000..ee168d8 Binary files /dev/null and b/src/channels/desert-bus/images/night/wheel3.png differ diff --git a/src/channels/desert-bus/images/night/wheel4.png b/src/channels/desert-bus/images/night/wheel4.png new file mode 100644 index 0000000..a2fc705 Binary files /dev/null and b/src/channels/desert-bus/images/night/wheel4.png differ diff --git a/src/channels/desert-bus/images/numbers_white.png b/src/channels/desert-bus/images/numbers_white.png deleted file mode 100644 index bedd30d..0000000 Binary files a/src/channels/desert-bus/images/numbers_white.png and /dev/null differ diff --git a/src/channels/desert-bus/images/sand_texture.png b/src/channels/desert-bus/images/sand_texture.png deleted file mode 100644 index 837820b..0000000 Binary files a/src/channels/desert-bus/images/sand_texture.png and /dev/null differ diff --git a/src/channels/desert-bus/images/wheel1.png b/src/channels/desert-bus/images/wheel1.png deleted file mode 100644 index 03d67c1..0000000 Binary files a/src/channels/desert-bus/images/wheel1.png and /dev/null differ diff --git a/src/channels/desert-bus/images/wheel2.png b/src/channels/desert-bus/images/wheel2.png deleted file mode 100644 index afbddc3..0000000 Binary files a/src/channels/desert-bus/images/wheel2.png and /dev/null differ diff --git a/src/channels/desert-bus/images/wheel3.png b/src/channels/desert-bus/images/wheel3.png deleted file mode 100644 index 62f600d..0000000 Binary files a/src/channels/desert-bus/images/wheel3.png and /dev/null differ diff --git a/src/channels/desert-bus/images/wheel4.png b/src/channels/desert-bus/images/wheel4.png deleted file mode 100644 index 0baaf43..0000000 Binary files a/src/channels/desert-bus/images/wheel4.png and /dev/null differ diff --git a/src/channels/desert-bus/index.tsx b/src/channels/desert-bus/index.tsx index a6f36ee..c0f124b 100644 --- a/src/channels/desert-bus/index.tsx +++ b/src/channels/desert-bus/index.tsx @@ -11,32 +11,28 @@ import styled from '@emotion/styled'; import { useListenFor, useReplicant } from 'use-nodecg'; import { usePIXICanvas } from '@gdq/lib/hooks/usePIXICanvas'; import * as PIXI from 'pixi.js'; -import { TilingSprite2d } from 'pixi-projection'; - -import bus from './images/bus.png'; -import tree from './images/tree.gif'; -import wheel1 from './images/wheel1.png'; -import wheel2 from './images/wheel2.png'; -import line1 from './images/line1.png'; -import line2 from './images/line2.png'; -import line3 from './images/line3.png'; -import line4 from './images/line4.png'; -import line5 from './images/line5.png'; -import line6 from './images/line6.png'; -import line7 from './images/line7.png'; - -import numbersBlack from './images/numbers_black.png'; -import numbersWhite from './images/numbers_white.png'; - -import sand from './images/sand_texture.png'; -import lightSand from './images/light_sand_texture.png'; -import mask from './images/sand_banks_mask.png'; - -import bug from './images/bug.png'; -import splat from './images/splat.png'; +import { Sprite2d, TilingSprite2d } from 'pixi-projection'; import TweenNumber from '@gdq/lib/components/TweenNumber'; import { useActive } from '@gdq/lib/hooks/useActive'; +import { + Sprites, + bug, + headlights, + line1, + line2, + line3, + line4, + line5, + line6, + line7, + numbersBlack, + splat, + tree, +} from './sprites'; +import { useObjects } from './useObjects'; +import { Palettes } from './palettes'; + registerChannel('Desert Bus', 17, DesertBus, { handle: 'VodBox', position: 'bottomRight', @@ -69,6 +65,7 @@ export function DesertBus(_: ChannelProps) { const frame = useRef(0); const busRef = useRef(null); + const headlightsRef = useRef(null); const wheelRef = useRef(null); const speedoRef = useRef(null); const odometerRef = useRef(null); @@ -76,8 +73,6 @@ export function DesertBus(_: ChannelProps) { const speed = useRef(firstBus.value ? 45 : -10); const left = useRef(10); const steer = useRef(1); - const objects = useRef | null>(null); - const textures = useRef | null>(null); if (active) firstBus.value = true; @@ -90,43 +85,44 @@ export function DesertBus(_: ChannelProps) { const background = objects.current.background as PIXI.Graphics; background.clear(); - background.beginFill(0x42cfce); + background.beginFill(Palettes[timeDay].sky); background.drawRect(0, 0, 546, 166); background.endFill(); - background.beginFill(0x8cefce); + background.beginFill(Palettes[timeDay].horizonSky); background.drawRect(0, 43, 546, 1); background.endFill(); - background.beginFill(0xceaa8c); + background.beginFill(Palettes[timeDay].horizonSky); background.drawRect(0, 44, 546, 1); background.endFill(); - background.beginFill(0xce8a21); + background.beginFill(Palettes[timeDay].ground); background.drawRect(0, 46, 546, 120); background.endFill(); const x = 442 + left.current * 20; const desert = objects.current.desert as TilingSprite2d; - desert.tilePosition.y = distance * 500; - desert.tileScale.x = 0.5; - desert.tileScale.y = 0.1; + desert.tilePosition.y = (distance * 275 * 0.75) % 166; + desert.tileScale.x = 2; + desert.tileScale.y = 0.05; + desert.width = 2048; desert.proj.mapSprite(desert, [ { - x: 182 + left.current - 100, + x: 182 + left.current - 5, y: 46, }, { - x: 182 + left.current + 100, + x: 182 + left.current + 5, y: 46, }, { - x: x + 2300, + x: x + 100, y: 166, }, { - x: x - 2680, + x: x - 480, y: 166, }, ]); @@ -134,7 +130,7 @@ export function DesertBus(_: ChannelProps) { const road = objects.current.road as PIXI.Graphics; road.clear(); - road.beginFill(0x636563); + road.beginFill(Palettes[timeDay].road); road.drawPolygon([182 + left.current, 46, x + 10, 166, x - 490, 166]); road.endFill(); @@ -144,8 +140,8 @@ export function DesertBus(_: ChannelProps) { ); const sandPits = objects.current.sandPits as TilingSprite2d; - sandPits.tilePosition.y = distance * 330; - sandPits.tileScale.y = 0.04; + sandPits.tilePosition.y = (distance * 275 * 0.75) % 166; + sandPits.tileScale.y = 0.02; sandPits.alpha = 1; sandPits.proj.mapSprite(sandPits, [ { @@ -169,8 +165,8 @@ export function DesertBus(_: ChannelProps) { const meridian = objects.current.meridian as PIXI.Graphics; meridian.clear(); - meridian.beginFill(0xefcf42); - meridian.drawPolygon([182 + left.current, 46, x - 230, 166, x - 250, 166]); + meridian.beginFill(Palettes[timeDay].meridian); + meridian.drawPolygon([182 + left.current, 46, x - 232, 166, x - 248, 166]); meridian.endFill(); const meridianMask = objects.current.meridianMask as PIXI.Graphics; @@ -179,75 +175,31 @@ export function DesertBus(_: ChannelProps) { meridianMask.beginFill(0xffffff); for (let i = 0, l = 14; i < l; ++i) { - const d = Math.pow(((distance * 60) / 4 + i / l) % 1, 6); - meridianMask.drawRect(0, 46 + d * 120, 546, d * 35); + const d = Math.pow(((distance * 50 * 0.85) / 4 + i / l) % 1, 6); + if (timeDay === 'night') meridianMask.drawRect(0, 56 + d * 120, 546, d * 15); + else meridianMask.drawRect(0, 46 + d * 120, 546, d * 35); } meridianMask.endFill(); - }); - useEffect(() => { - if (!app) return; - - textures.current = { - sandMask: PIXI.Texture.from(mask), - sand: PIXI.Texture.from(sand), - lightSand: PIXI.Texture.from(lightSand), - }; - - objects.current = { - background: new PIXI.Graphics(), - desert: new TilingSprite2d(textures.current.lightSand, 546, 166), - road: new PIXI.Graphics(), - sandPitsMask: new PIXI.Sprite(textures.current.sandMask), - sandPits: new TilingSprite2d(textures.current.sand, 546, 166), - lights: new PIXI.Graphics(), - meridianMask: new PIXI.Graphics(), - meridian: new PIXI.Graphics(), - }; - - //(objects.current.sandPits as TilingSprite2d).convertTo2s(); - - const container = new PIXI.Container(); - const filter = new PIXI.filters.AlphaFilter(1); - filter.resolution = 0.5; - - container.filters = [filter]; - - container.addChild(objects.current.background); - container.addChild(objects.current.desert); - container.addChild(objects.current.road); - container.addChild(objects.current.sandPits); - container.addChild(objects.current.sandPitsMask); - container.addChild(objects.current.lights); - container.addChild(objects.current.meridian); - container.addChild(objects.current.meridianMask); - - objects.current.sandPits.mask = objects.current.sandPitsMask as PIXI.Graphics; - objects.current.meridian.mask = objects.current.meridianMask as PIXI.Graphics; - - app.current?.stage.addChild(container); - - container.setTransform(0, 0, 2, 2); - - return () => { - for (const key in objects.current) { - const obj = objects.current[key]; - if (!obj.destroyed) obj.destroy(true); - } - for (const key in textures.current) { - const tex = textures.current[key]; - tex.destroy(true); - } + const dStop = Math.pow(((distance * 20 * 0.85) / 4) % 3, 6); + const busStop = objects.current.busStop as Sprite2d; + busStop.position.x = (184 + left.current) * (1 - dStop) + dStop * (x + 145); + busStop.position.y = 46 + dStop * 120; + busStop.scale.set(dStop * 1.6); + + const dBanner = Math.pow((((distance + 1) * 20 * 0.85) / 4) % 3, 6); + const banner = objects.current.banner as Sprite2d; + banner.position.x = (184 + left.current) * (1 - dBanner) + dBanner * (x + 145); + banner.position.y = 46 + dBanner * 120; + banner.scale.set(dBanner * 1.6); + }); - filter.destroy(); - if (!container.destroyed) container.destroy(true); - }; - }, [app]); + const { timeDay, objects } = useObjects(app); useRafLoop(() => { if (!busRef.current || !wheelRef.current || !speedoRef.current || !odometerRef.current) return; - const t = distance * 60; + const t = distance * 50; const p = 1; speed.current = Math.min(speed.current + 0.05, 45); @@ -265,6 +217,10 @@ export function DesertBus(_: ChannelProps) { speedoRef.current.style.transform = 'translate(-4px, 4px) scale(-1, -1)'; } + if (headlightsRef.current) { + headlightsRef.current.style.animationDuration = 46.35 - speed.current + 's'; + } + const prevDistance = distanceRep.value ?? 0; const prevDistanceStr = (Math.floor(prevDistance) + '').padStart(4, '0'); @@ -279,29 +235,29 @@ export function DesertBus(_: ChannelProps) { if (speed.current < 10) { steer.current = 1; - wheelRef.current.src = wheel1; + wheelRef.current.src = Sprites[timeDay].wheel1; wheelRef.current.style.transform = ''; } else if (r < 0.015) { steer.current = -4; - wheelRef.current.src = wheel1; + wheelRef.current.src = Sprites[timeDay].wheel1; wheelRef.current.style.transform = 'translate(42px, 0) scale(-1, 1)'; } else if (r < 0.02) { steer.current = 4; - wheelRef.current.src = wheel2; + wheelRef.current.src = Sprites[timeDay].wheel2; wheelRef.current.style.transform = ''; } else if (r < 0.05) { steer.current = 1; - wheelRef.current.src = wheel1; + wheelRef.current.src = Sprites[timeDay].wheel1; wheelRef.current.style.transform = ''; } if (left.current > 10) { steer.current = 1; - wheelRef.current.src = wheel1; + wheelRef.current.src = Sprites[timeDay].wheel1; wheelRef.current.style.transform = ''; } else if (left.current < -5) { steer.current = -4; - wheelRef.current.src = wheel1; + wheelRef.current.src = Sprites[timeDay].wheel1; wheelRef.current.style.transform = 'translate(42px, 0) scale(-1, 1)'; } @@ -368,25 +324,56 @@ export function DesertBus(_: ChannelProps) { + {timeDay === 'night' && } $ - + - - - - - + + + + + - + ); } +const Headlights = styled.img` + opacity: 0.5; + position: absolute; + top: 170px; + left: 260px; + + animation: anim 1s steps(2, end) infinite; + @keyframes anim { + 0% { + transform: translate(0, 0); + } + + 20% { + transform: translate(2px, 4px); + } + + 40% { + transform: translate(0, 8px); + } + + 60% { + transform: translate(-2px, 4px); + } + + 80% { + transform: translate(0, 0); + } + } +`; + const TotalText = styled.div` font-family: gdqpixel; font-size: 46px; @@ -449,7 +436,7 @@ const Speedo = styled.img` transform-origin: top right; `; -const Odometer = styled.div` +const Odometer = styled.div<{ timeDay: 'night' | 'dawn' | 'day' | 'dusk' }>` position: absolute; top: 294px; left: 361px; @@ -457,7 +444,13 @@ const Odometer = styled.div` width: 54px; height: 16px; - background: linear-gradient(to right, black 0px, black 42px, white 42px, white 54px); + background: linear-gradient( + to right, + black 0px, + black 42px, + ${(p) => (p.timeDay === 'dawn' ? '#88aaaa' : p.timeDay === 'night' ? '#002244' : 'white')} 42px, + ${(p) => (p.timeDay === 'dawn' ? '#88aaaa' : p.timeDay === 'night' ? '#002244' : 'white')} 54px + ); overflow: hidden; diff --git a/src/channels/desert-bus/palettes.ts b/src/channels/desert-bus/palettes.ts new file mode 100644 index 0000000..c2b2042 --- /dev/null +++ b/src/channels/desert-bus/palettes.ts @@ -0,0 +1,46 @@ +type Palette = { + sky: number; + horizonSky: number; + ground: number; + horizonGround: number; + road: number; + meridian: number; +}; + +export const Palettes = { + day: { + sky: 0x44cccc, + horizonSky: 0x88eecc, + ground: 0xcc8822, + horizonGround: 0xccaa88, + road: 0x666666, + meridian: 0xeecc44, + } satisfies Palette, + + dusk: { + sky: 0xcc88aa, + horizonSky: 0xeeaacc, + ground: 0xcc8866, + horizonGround: 0xeeaa66, + road: 0x444444, + meridian: 0xeecc44, + } satisfies Palette, + + night: { + sky: 0x000000, + horizonSky: 0x000000, + ground: 0x000000, + horizonGround: 0x000000, + road: 0x000000, + meridian: 0xeeee00, + } satisfies Palette, + + dawn: { + sky: 0x222266, + horizonSky: 0x442266, + ground: 0x664444, + horizonGround: 0xaa6644, + road: 0x000000, + meridian: 0xccaa44, + } satisfies Palette, +}; diff --git a/src/channels/desert-bus/sprites.ts b/src/channels/desert-bus/sprites.ts new file mode 100644 index 0000000..eafc27c --- /dev/null +++ b/src/channels/desert-bus/sprites.ts @@ -0,0 +1,125 @@ +type SpritePaths = { + bus: string; + + wheel1: string; + wheel2: string; + + numbersWhite: string; + + sand: string; + lightSand: string; + + busStop: string; +}; + +export const Sprites = { + day: { + bus: busDay, + wheel1: wheel1Day, + wheel2: wheel2Day, + numbersWhite: numbersWhiteDay, + sand: sandDay, + lightSand: lightSandDay, + busStop: busStopDay, + } satisfies SpritePaths, + dusk: { + bus: busDusk, + wheel1: wheel1Day, + wheel2: wheel2Day, + numbersWhite: numbersWhiteDay, + sand: sandDusk, + lightSand: lightSandDusk, + busStop: busStopDusk, + } satisfies SpritePaths, + night: { + bus: busNight, + wheel1: wheel1Night, + wheel2: wheel2Night, + numbersWhite: numbersWhiteNight, + sand: sandNight, + lightSand: lightSandNight, + busStop: busStopNight, + } satisfies SpritePaths, + dawn: { + bus: busDawn, + wheel1: wheel1Dawn, + wheel2: wheel2Dawn, + numbersWhite: numbersWhiteDawn, + sand: sandDawn, + lightSand: lightSandDawn, + busStop: busStopDawn, + } satisfies SpritePaths, +}; + +import busDay from './images/day/bus.png'; +import wheel1Day from './images/day/wheel1.png'; +import wheel2Day from './images/day/wheel2.png'; +import sandDay from './images/day/sand_texture.png'; +import lightSandDay from './images/day/light_sand_texture.png'; +import numbersWhiteDay from './images/day/numbers_white.png'; +import busStopDay from './images/day/bus-stop.png'; + +import busNight from './images/night/bus.png'; +import wheel1Night from './images/night/wheel1.png'; +import wheel2Night from './images/night/wheel2.png'; +import sandNight from './images/night/sand_texture.png'; +import lightSandNight from './images/night/light_sand_texture.png'; +import numbersWhiteNight from './images/night/numbers_white.png'; +import busStopNight from './images/night/bus-stop.png'; + +import busDusk from './images/dusk/bus.png'; +import sandDusk from './images/dusk/sand_texture.png'; +import lightSandDusk from './images/dusk/light_sand_texture.png'; +import busStopDusk from './images/dusk/bus-stop.png'; + +import busDawn from './images/dawn/bus.png'; +import wheel1Dawn from './images/dawn/wheel1.png'; +import wheel2Dawn from './images/dawn/wheel2.png'; +import sandDawn from './images/dawn/sand_texture.png'; +import lightSandDawn from './images/dawn/light_sand_texture.png'; +import numbersWhiteDawn from './images/dawn/numbers_white.png'; +import busStopDawn from './images/dawn/bus-stop.png'; + +import zetaShiftBanner from './images/day/zeta-shift.png'; +import dawnGuardBanner from './images/day/dawn-guard.png'; +import alphaFlightBanner from './images/day/alpha-flight.png'; +import nightWatchBanner from './images/day/night-watch.png'; +import omegaShiftBanner from './images/day/omega-shift.png'; + +import tree from './images/tree.gif'; +import line1 from './images/line1.png'; +import line2 from './images/line2.png'; +import line3 from './images/line3.png'; +import line4 from './images/line4.png'; +import line5 from './images/line5.png'; +import line6 from './images/line6.png'; +import line7 from './images/line7.png'; + +import numbersBlack from './images/numbers_black.png'; + +import bug from './images/bug.png'; +import splat from './images/splat.png'; +import mask from './images/sand_banks_mask.png'; + +import headlights from './images/night/headlights.png'; + +export { + tree, + line1, + line2, + line3, + line4, + line5, + line6, + line7, + numbersBlack, + bug, + splat, + mask, + headlights, + zetaShiftBanner, + dawnGuardBanner, + alphaFlightBanner, + nightWatchBanner, + omegaShiftBanner, +}; diff --git a/src/channels/desert-bus/useObjects.ts b/src/channels/desert-bus/useObjects.ts new file mode 100644 index 0000000..2cb3565 --- /dev/null +++ b/src/channels/desert-bus/useObjects.ts @@ -0,0 +1,130 @@ +import * as PIXI from 'pixi.js'; +import { AFFINE, Container2d, TilingSprite2d } from 'pixi-projection'; +import { MutableRefObject, useEffect, useRef, useState } from 'react'; + +import { + alphaFlightBanner, + dawnGuardBanner, + mask, + nightWatchBanner, + Sprites, + zetaShiftBanner, + omegaShiftBanner, +} from './sprites'; +import { dayTime, shiftTime } from './daytime'; +import { useHarmonicIntervalFn } from 'react-use'; + +export function useObjects(app: MutableRefObject) { + const [timeDay, setTimeDay] = useState<'night' | 'dawn' | 'day' | 'dusk'>('day'); + const [shift, setShift] = useState<'zeta' | 'dawn' | 'alpha' | 'night' | 'omega'>('night'); + const objects = useRef | null>(null); + const textures = useRef | null>(null); + + useHarmonicIntervalFn(() => { + const currentTime = dayTime(); + if (timeDay !== currentTime) setTimeDay(currentTime); + const currentShift = shiftTime(); + if (shift !== currentShift) setShift(currentShift); + }, 1000); + + useEffect(() => { + if (!app.current) return; + + textures.current = { + sandMask: PIXI.Texture.from(mask), + sandday: PIXI.Texture.from(Sprites.day.sand), + lightSandday: PIXI.Texture.from(Sprites.day.lightSand), + busStopday: PIXI.Texture.from(Sprites.day.busStop), + }; + + objects.current = { + background: new PIXI.Graphics(), + desert: new TilingSprite2d(textures.current.lightSand, 546, 166), + road: new PIXI.Graphics(), + sandPitsMask: new PIXI.Sprite(textures.current.sandMask), + sandPits: new TilingSprite2d(textures.current.sandday, 546, 166), + lights: new PIXI.Graphics(), + meridianMask: new PIXI.Graphics(), + meridian: new PIXI.Graphics(), + busStop: new PIXI.Sprite(textures.current.busStopday), + banner: new PIXI.Sprite(textures.current.bannernight), + container: new Container2d(), + }; + + //(objects.current.sandPits as TilingSprite2d).convertTo2s(); + + const container = objects.current.container as Container2d; + const filter = new PIXI.filters.AlphaFilter(1); + filter.resolution = 0.5; + + container.filters = [filter]; + + container.addChild(objects.current.background); + container.addChild(objects.current.desert); + container.addChild(objects.current.road); + container.addChild(objects.current.sandPits); + container.addChild(objects.current.sandPitsMask); + container.addChild(objects.current.lights); + container.addChild(objects.current.meridian); + container.addChild(objects.current.meridianMask); + container.addChild(objects.current.busStop); + container.addChild(objects.current.banner); + + (objects.current.busStop as PIXI.Sprite).anchor.set(0.5, 1.0); + (objects.current.banner as PIXI.Sprite).anchor.set(0.5, 1.0); + (objects.current.desert as TilingSprite2d).anchor.set(0.5, 0.0); + (objects.current.desert as TilingSprite2d).proj.affine = AFFINE.NONE; + + objects.current.sandPits.mask = objects.current.sandPitsMask as PIXI.Graphics; + objects.current.meridian.mask = objects.current.meridianMask as PIXI.Graphics; + + app.current?.stage.addChild(container); + + container.setTransform(0, 0, 2, 2); + + return () => { + for (const key in objects.current) { + const obj = objects.current[key]; + if (!obj.destroyed) obj.destroy(true); + } + for (const key in textures.current) { + const tex = textures.current[key]; + tex.destroy(true); + } + + filter.destroy(); + if (!container.destroyed) container.destroy(true); + }; + }, [app]); + + useEffect(() => { + if (!app.current || !textures.current || !objects.current) return; + + if (!textures.current[`sand${timeDay}`]) { + textures.current[`sand${timeDay}`] = PIXI.Texture.from(Sprites[timeDay].sand); + } + + if (!textures.current[`lightSand${timeDay}`]) { + textures.current[`lightSand${timeDay}`] = PIXI.Texture.from(Sprites[timeDay].lightSand); + } + + if (!textures.current[`busStop${timeDay}`]) { + textures.current[`busStop${timeDay}`] = PIXI.Texture.from(Sprites[timeDay].busStop); + } + + if (!textures.current[`banner${shift}`]) { + if (shift === 'zeta') textures.current[`bannerzeta`] = PIXI.Texture.from(zetaShiftBanner); + else if (shift === 'dawn') textures.current[`bannerdawn`] = PIXI.Texture.from(dawnGuardBanner); + else if (shift === 'alpha') textures.current[`banneralpha`] = PIXI.Texture.from(alphaFlightBanner); + else if (shift === 'night') textures.current[`bannernight`] = PIXI.Texture.from(nightWatchBanner); + else if (shift === 'omega') textures.current[`banneromega`] = PIXI.Texture.from(omegaShiftBanner); + } + + (objects.current.desert as TilingSprite2d).texture = textures.current[`lightSand${timeDay}`]; + (objects.current.sandPits as TilingSprite2d).texture = textures.current[`sand${timeDay}`]; + (objects.current.busStop as PIXI.Sprite).texture = textures.current[`busStop${timeDay}`]; + (objects.current.banner as PIXI.Sprite).texture = textures.current[`banner${shift}`]; + }, [app, timeDay, shift]); + + return { timeDay, objects, textures }; +} diff --git a/src/test/app.tsx b/src/test/app.tsx index 48e3ccf..5bfdbe6 100644 --- a/src/test/app.tsx +++ b/src/test/app.tsx @@ -16,6 +16,7 @@ const totalRep = nodecg.Replicant('total', { export function App() { const [breakChannel, setBreakChannel] = usePreloadedReplicant('break-channel', 0); + const [timeZone, setTimeZone] = usePreloadedReplicant('timezone', 'America/New_York'); return ( <> @@ -88,6 +89,15 @@ export function App() { Next + + + ); } @@ -101,6 +111,40 @@ function formatCurrency(amount: number, fractionDigits?: number) { }); } +const timeZones = [ + 'America/Adak', + 'America/Anchorage', + 'America/Boise', + 'America/Chicago', + 'America/Denver', + 'America/Detroit', + 'America/Indiana/Knox', + 'America/Indiana/Marengo', + 'America/Indiana/Petersburg', + 'America/Indiana/Tell_City', + 'America/Indiana/Vevay', + 'America/Indiana/Vincennes', + 'America/Indiana/Winamac', + 'America/Indianapolis', + 'America/Juneau', + 'America/Kentucky/Monticello', + 'America/Los_Angeles', + 'America/Louisville', + 'America/Menominee', + 'America/Metlakatla', + 'America/New_York', + 'America/Nome', + 'America/North_Dakota/Beulah', + 'America/North_Dakota/Center', + 'America/North_Dakota/New_Salem', + 'America/Phoenix', + 'America/Sitka', + 'America/Yakutat', + 'Pacific/Honolulu', + 'Australia/Melbourne', + 'Europe/London', +] as const; + const Row = styled.div` display: flex; gap: 10px; diff --git a/src/test/index.tsx b/src/test/index.tsx index 762e50f..52b0af6 100644 --- a/src/test/index.tsx +++ b/src/test/index.tsx @@ -29,6 +29,10 @@ const currentEventRep = nodecg.Replicant('currentEvent', { }, }); -NodeCG.waitForReplicants(breakChannel, totalRep, currentEventRep).then(() => { +const timezone = nodecg.Replicant('timezone', { + defaultValue: 'America/New_York', +}); + +NodeCG.waitForReplicants(breakChannel, totalRep, currentEventRep, timezone).then(() => { ReactDOM.render(, document.getElementById('root')); });