🌈️ apply a wallpaper based on the weather outside
0

Configure Feed

Select the types of activity you want to include in your feed.

feat(apply): initial implementation of multiple wallpapers

Angel Wang (Jun 26, 2026, 4:12 PM -0600) ae613862 2f4babd5

+48 -10
+21
src/utils.ts
··· 91 91 ) { 92 92 return func((number - min) / (max - min)) * (newMax - newMin) + newMin 93 93 } 94 + 95 + // Fisher-Yates Shuffle 96 + // deno-lint-ignore no-explicit-any 97 + export function shuffle(array: any[]) { 98 + let currentIndex = array.length 99 + 100 + // While there remain elements to shuffle... 101 + while (currentIndex != 0) { 102 + // Pick a remaining element... 103 + const randomIndex = Math.floor(Math.random() * currentIndex) 104 + currentIndex-- 105 + 106 + // And swap it with the current element. 107 + [array[currentIndex], array[randomIndex]] = [ 108 + array[randomIndex], 109 + array[currentIndex], 110 + ] 111 + } 112 + 113 + return array 114 + }
+10 -2
src/apply/application.ts
··· 12 12 lightnessRange: { night: number; dawn: number; noon: number } 13 13 chromaRange: { start: number; end: number } 14 14 targetSkyHue: number 15 + numberOfWallpapers: number 15 16 applyWallpaperCommand: string 16 17 } 17 18 ··· 28 29 start: 0, 29 30 end: 1, 30 31 }, 32 + numberOfWallpapers: 1, 31 33 targetSkyHue: 264, 32 34 applyWallpaperCommand: "hyprctl hyprpaper wallpaper , %s", 33 35 } ··· 79 81 } 80 82 } 81 83 82 - export function findMatchingImages(imagesData: ImageAnalysisData, targetColor: Colordx) { 84 + export function findMatchingImages(imagesData: ImageAnalysisData, targetColor: Colordx, numberOfImages: number) { 83 85 const matchingImages = [] 84 86 85 87 let targetDelta = 0.06 86 - while (matchingImages.length == 0) { 88 + while (matchingImages.length < numberOfImages) { 87 89 console.debug(`Finding matching image with delta E ${targetDelta.toFixed(2)}...`) 88 90 for (const image of imagesData.files) { 89 91 if (targetColor.delta(image.colour) <= targetDelta) { ··· 95 97 } 96 98 return matchingImages 97 99 } 100 + 101 + export function setWindowsWallpaper() { 102 + const user32 = Deno.dlopen("user32.dll", { 103 + SystemParametersInfoA: { parameters: ["u16", "u16", "pointer", "u16"], result: "void" } 104 + }) 105 + }
+17 -8
src/apply/index.ts
··· 1 1 import { colordx } from "@colordx/core" 2 2 import type { ImageAnalysisData } from "../analyze/analysis.ts" 3 - import { applyConfigPath, cachePath, chalkDebug, easeOutQuint, loadConfig, map, mapEased } from "../utils.ts" 3 + import { applyConfigPath, cachePath, chalkDebug, easeOutQuint, loadConfig, map, mapEased, shuffle } from "../utils.ts" 4 4 import { type ApplicationConfig, defaultConfig, findMatchingImages, getOpenMeteoData } from "./application.ts" 5 5 import * as SunCalc from "suncalc" 6 6 import "zx/globals" ··· 60 60 (x: number) => easeOutQuint(x), 61 61 ) 62 62 63 + console.log(hueValue) 63 64 const chromaValue = map( 64 65 100 - Number(openMeteoData.cloudCover), // gotta invert this one 65 66 0, ··· 68 69 config.chromaRange.end, 69 70 ) 70 71 71 - let lightnessValue = map( 72 + let lightnessValue = mapEased( 72 73 Number(openMeteoData.shortwaveRadiation), 73 74 0, 74 75 1000, 75 76 config.lightnessRange.dawn, 76 77 config.lightnessRange.noon, 78 + (x) => Math.pow(x, 1 / 4) 77 79 ) 78 80 79 81 // if the current sun altitude is less than that of dawn/dusk ··· 93 95 const imagesData = JSON.parse(cacheFile) as ImageAnalysisData 94 96 console.debug(chalkDebug(`Opened cache file ${cachePath}!`)) 95 97 96 - const matchingImages = findMatchingImages(imagesData, targetColour) 97 - const matchingImage = matchingImages[Math.floor(Math.random() * matchingImages.length)] 98 - console.info( 99 - `Found matching image ${matchingImage.path} with colour ${colordx(matchingImage.colour).toOklchString()}!`, 98 + const matchingImages = shuffle(findMatchingImages(imagesData, targetColour, config.numberOfWallpapers)).slice( 99 + 0, 100 + config.numberOfWallpapers, 100 101 ) 102 + 103 + matchingImages.forEach((image) => 104 + console.info( 105 + `Found matching image ${image.path} with colour ${colordx(image.colour).toOklchString()}!`, 106 + ) 107 + ) 108 + 109 + // TODO: implement setting more than one wallpaper. for ppl with multiple monitors 101 110 102 111 console.info(`Setting wallpaper...`) 103 112 104 113 if (Deno.build.os != "windows") { 105 - await $`eval ${config.applyWallpaperCommand.replace("%s", matchingImage.path)}` 114 + await $`eval ${config.applyWallpaperCommand.replace("%s", matchingImages[0].path)}` 106 115 } else { 107 116 const command = ` 108 117 $setwallpapersrc = @" ··· 122 131 "@ 123 132 Add-Type -TypeDefinition $setwallpapersrc 124 133 125 - [Wallpaper]::SetWallpaper("${matchingImage.path}") 134 + [Wallpaper]::SetWallpaper("${matchingImages[0].path}") 126 135 ` 127 136 usePowerShell() 128 137 // await $`Write-Host ${command}`