Wallpaper Engine

Wallpaper Engine

Not enough ratings
Easy backgrounds w/ slideshows for Webwallpapers
By Squee
Some code to easily implement some background features with JS with a class to automatically handle your settings from the project.json
   
Award
Favorite
Favorited
Unfavorite
Introduction
I've been asked several times to update my wallpapers to include a slideshow option. For that I wanted one simple way to update the different wallpapers ( Currently also implemented in a few of my wallpapers as initial trial ). I thought that code would be useful to others so here is a guide where to get it and implement it.

The code is for webwallpaper that use a transparent canvas and want to use html/css for their background options. The code can also automatically handle your settings from the project.json and apply the necessary CSS to the html elements of your choice, all you need to do is some setup work and tell the class what the name of the properties are. But you can always manually set values from JS too.

I know the guide might seem long, but its pretty much 4 steps of copy & paste and then configuring the settings you want to use in project.json. The rest is just trying to explain and detail things.

If wanted I can also add some callbacks so you can handle the image changes yourself, for example to get an event for each time the background image changes.

Currently in the guide
  • Where to find the code, and how to make a canvas transparent.
  • Setting it up in a way that it automatically processes the settings for you
  • Some interesting functions you can use for controlling the background from js ( or if you want to manage the settings yourself )
  • Changes in setup needed up for transitions
  • Some example settings stolen from the related wallpaper

If you have questions just ask via the comment section.
If you found bugs let me know via the comment section.
If you would like to see some feature let me know via the comment section.
If you have tips to make the guide more clear let me know via the comment section. ( i'm chaotic when writing non-code )


Currently Supported Options
  • file setting
  • folder setting ( load all filenames )
  • ondemand setting ( as alternative to folder setting )
  • image sizing ( css contain/cover )
  • image opacity
  • image interval for the slideshow
  • 1-5 colors
  • linear/radial gradients
  • has basic slideshow implementation
  • transitions ( see special chapter about those )
  • slideshow using folder settings will randomize files internally and when for example only 2 images are in the folder it wont play the same image in a row twice but toggle between the two.
  • default uses preload setup via hidden image to avoid flickering which can occur otherwise.

Currently Planned Settings:
  • Checkbox in settings to control play/pause.
  • Linear gradient direction ( horizontal/vertical/diagonal gradients )
  • Blur options ( are implemented but still buggy and doubt anyone will use it but why not )

Known issues to be worked on
  • Lack of control over colors options when using the BackgroundSettingsProxy class as it maintains its own backup of the settings. Would like to create functions to be able to cooperate
    with the class instead of have to use one or the either
Where to get the code
I've put the code in a wallpaper, so that you will keep getting updated, as well as having an example wallpaper where the code is used:
https://steamhost.cn/steamcommunity_com/sharedfiles/filedetails/?id=858730156

The files will be located in:
%steam%\steamapps\workshop\content\431960\858730156

Some automatically generated documentation on the 4 classes can be found in:
%steam%\steamapps\workshop\content\431960\858730156\docs\index.html

All important classes are in background.js and is the only file you have to include.


Making your canvas transparent
To be able to see the background through the canvas your canvas needs to be transparent. If you don't know how to make your canvas transparent, have some code ;)

context.globalCompositeOperation = 'destination-out'; context.fillStyle = 'rgba(0,0,0,1)'; context.fillRect(0, 0, canvas.width, canvas.height); context.globalCompositeOperation = 'source-over';

For a 3d context, you might have to change the clearing color or something and when creating the context you can use alpha:true as option:
context = canvas.getContext('webgl',{alpha:true}) // ( by head )
Implementing in your wallpaper
This bit explains how to setup with all settings being automatically processed for you. You can still control and set the settings without this bit of automation if you want, nor do you have to use all settings.

After you did this you do still need to setup the settings yourself ( examples included at the bottom ) and assign them correctly. Currently its not clearly documented how to tie each individual setting, but thats basically the bit where we create the BackgroundSettingsProxy in the code.

The steps to implement:
  • Decide which HTML element you want to use
  • Include the javascript
  • Setup the necessary code
  • Forward wallpaper engines property events


Deciding what HTML elements to use
First we will need to decide which html element will we use to apply the settings on. I perfer the body element myself.

Then we need to decide if we want to allow the image to be transparent, for example to darken or tint the image . In that case we will need an extra html element. One will display the color/gradient. On top of that will be an element displaying the image.

For the wallpaper, to demonstrate transparency, that means my HTML is structured like so:
<head> <style> html, body { width: 100%; height: 100%; margin: 0; overflow: hidden; } #background-image { width: 100%; height: 100%; position: fixed; top: 0; left: 0;} canvas { position: fixed; top: 0; left: 0;} </style> <!-- js includes here --> </head> <body> <div id="background-image"></div> <!-- canvas here --> </body>

Required JS File(s)
Copy the background.js and include it in your html:

<!-- background.js : required : contains the background handling code --> <script src="background.js"></script>


Setting up an instance of the Background and BackgroundSettingsProxy classes
Now that we know which element or elements will we use for the css, we can setup our code within the window.onload function.

First lets create a background element:
var IDesperatelyNeedToUseOpacity = true; // for demonstrating the code var bg; // our background class instance if( IDesperatelyNeedToUseOpacity ) { bg = new Background( document.body, document.getElementById('background-image') ); } else { // if you dont need opacity, then dont use 2 elements .. bg = new Background( document.body ); } // delay initialisation until we got the first properties // ( will be called in applyUserProperties callback below ) var fnInitSlideshow = function() { bg.play(true); // start the slideshow loop fnInitSlideshow= null; // avoid this being called again }

The next thing we will use is this proxy class which handles the property changes and calls the correct functions on the background instance. I will assume you have set up your settings already or will do so after. I have included the settings from my wallpaper below if you want some easy copy/paste stuff.

// property names used below ( like bgFile ) are the property names of those found in project.json // leave a property out if you dont use it or set it to null, i just set the complete list to show all options // new BackgroundSettingsProxy( bgInstance, settings ) // config values ( bgFile, bgFolder etc ) all property names found in project.json var bgSettingsProxy = new BackgroundSettingsProxy( bg, { 'image-file': 'bgFile', // setting of type file 'image-ondemand': 'bgRandomFile', // setting of type ondemand 'image-folder': 'bgFolder', // setting of type directory 'image-size': 'bgSize', // setting of type combo with options 'contain' | 'cover' 'image-opacity': 'bgOpacity', // setting of type slider/combo with values 0 - 100 'image-blend': 'bgBlendMode',// setting of type combo ( values must match css background-blend-mode values ) 'slideshow-interval': 'bgInterval', // setting of type slider/combo with int values 'slideshow-interval-multiply': 'bgIntervalMultiplier', // setting of type slider/combo with int values 'gradient-type': 'bgColGradientType', // setting of type combo with options 'radial' | 'linear' 'color-count': 'bgColCount', // setting of type slider/combo with values 1 - 5 'color-1': 'bgCol1', // setting of type color ( or combo if values are color notation ) 'color-2': 'bgCol2', // setting of type color ( or combo if values are color notation ) 'color-3': 'bgCol3', // setting of type color ( or combo if values are color notation ) 'color-4': 'bgCol4', // setting of type color ( or combo if values are color notation ) 'color-5': 'bgCol5' // setting of type color ( or combo if values are color notation ) });

Remember, only set those you need .. You don't have to use everything.

Let me detail those config options a bit more:
  • 'image-file': Use for a single file selection option
  • 'image-ondemand': This is used for a slideshow by requesting a new image from WE
  • 'image-folder': This is a directory type setting is used for a randomized slideshow
  • 'image-size': This is an option to allow users to fit a wallpaper instead of cover the full screen. For some reason some people like that.
  • 'image-opacity': This option can be used for example in combination with black color to dark an image
  • 'image-blend': equivalent to background-blend-mode values
  • 'slideshow-interval': this value multiplied with slideshow-interval-multiply determines the interval in seconds
  • 'slideshow-interval-multiply': this value multiplied with slideshow-interval determines the interval in seconds
  • 'gradient-type': setting for type of gradient
  • 'color-count': amount of colors to use
  • 'color-1': color 1
  • 'color-2': color 2
  • 'color-3': color 3
  • 'color-4': color 4
  • 'color-5': color 5

You can use the different file options together. It will try to get/set a new image for the slideshow by using the settings in in this order: ondemand, folder, (single)file ..

Another tip:
if you just want users to set their interval with a single slider and just want it to represent seconds, minutes or hours, then dont use the 'slideshow-interval-multiply' setting but apply the multiple via code like so:
bg.setIntervalMultiplier( 1 ); // interval value will now be seconds bg.setIntervalMultiplier( 60 ); // interval value will now be minutes bg.setIntervalMultiplier( 3600 ); // interval value will now be hours

Hook into the wallpaper engines property callbacks
And finally the tie-in with wallpaper engine:
// hook into wallpaper engins callback functions window.wallpaperPropertyListener = { applyUserProperties: function( p ) { bgSettingsProxy.applyUserProperties( p ); if( fnInitSlideshow ) fnInitSlideshow(); }, userDirectoryFilesAddedOrChanged: function( propertyName, changedFiles ) { bgSettingsProxy.userDirectoryFilesAddedOrChanged( propertyName, changedFiles ); }, userDirectoryFilesRemoved: function(propertyName, removedFiles) { bgSettingsProxy.userDirectoryFilesRemoved( propertyName, removedFiles ); } };

After setting up the settings you are done.
Interesting Functions
Not needed, but if wanted you can control the slideshow you can use the following function:
bg.play( bool ); // when bool is true, instantly update background, when false wait for timeout bg.pause(); // hope i dont have to explain this bg.setInterval( 5000 ); // set 5 second interval .. will reset interval if used bg.setIntervalMultiplier( 60 ); // set interval to represent minutes

Some background color options
bg.gradient.setSolidColor( 'red' ); // css color notations bg.gradient.setSolidColor( 'rgb(255,0,0)' ); bg.gradient.setSolidColor( '#f00' ); // color stops are [ perc, color ], perc being a value between 0 and 1 bg.gradient.setLinearGradient( 'up', [ [ 0, 'red' ], [ 0.5, 'green' ], [ 1, 'blue'] ] ); bg.gradient.setLinearGradient( '45deg', [ [ 0, 'red' ], [ 0.5, 'green' ], [ 1, 'blue'] ] ); bg.gradient.setRadialGradient( 'center center', '50px 50px', [ [ 0, 'red' ], [ 0.5, 'green' ], [ 1, 'blue'] ] );

Some image options
bg.image.setImageSize( 'cover' ); bg.image.setImageSize( 'contain' ); bg.image.setBlendMode( 'darken' ); bg.image.setImageOpacity( 0.5 ); bg.image.setSingleImage( filename ); bg.image.setSingleImage( null ); bg.image.setFilelist( arrayOfFiles ); bg.image.setFilelist( [] );
Changes in setup needed up for transitions
Transitions will use the necessary cpu and gpu for the animations. It's not horribly bad, but is something that you might want to consider before using them. You can shorten the transition time to also limit the time

For transitions we need a few extra things:
  • Html/Css changes
  • Include the animation css
  • Settings you can use

Html/Css changes

This is I guess the "best" setup..

To explain, the extra html is mostly for 2 things. 1, when the z-index changes for transitions it shouldn't interfere with the rest of your html. The other is the 2 extra "wrapper" which are used to be able to support opacity and blending .

<head> <style> html, body { width: 100%; height: 100%; margin: 0; overflow: hidden; } #background-wrapper { position: fixed; width: 100%; height: 100%; top: 0; left: 0; } #background-image1 { position: absolute; width: 100%; height: 100%; top: 0; left: 0; } #background-image2 { position: absolute; width: 100%; height: 100%; top: 0; left: 0; } #background-image1-wrapper { position: absolute; width: 100%; height: 100%; top: 0; left: 0; } #background-image2-wrapper { position: absolute; width: 100%; height: 100%; top: 0; left: 0; } </style> </head> <body> <div id="background-wrapper"> <div id="background-image1-wrapper"><div id="background-image1"></div></div> <div id="background-image2-wrapper"><div id="background-image2"></div></div> </div> <!-- your canvas here --> </body>

Also be sure to put your canvas over that, so it might require "position: fixed" too. I kind of forgot the rules when it came to z-index and the different positioning options. Sorry :s

If you don't need opacity or blending you can also use this for transitions.
<head> <style> html, body { width: 100%; height: 100%; margin: 0; overflow: hidden; } #background-wrapper { position: absolute; width: 100%; height: 100%; top: 0; left: 0; } #background-image1 { position: absolute; width: 100%; height: 100%; top: 0; left: 0; } #background-image2 { position: absolute; width: 100%; height: 100%; top: 0; left: 0; } </style> </head> <body> <div id="background-wrapper"> <div id="background-image1"></div> <div id="background-image2"></div> </div> <!-- your canvas here --> </body>


Include the css for transitions
For transitions you MUST have the animations included. Without the animations some events will not trigger.

For the animations you can use background-anim.css and then just include it in your index.html like so:
<link href="background-anim.css" rel="stylesheet" type="text/css">


Code changes in the setup
Before you might have used this code to create the Background object and you want to replace this:
bg = new Background( document.body ) // or bg = new Background( document.body, document.getElementById('background-image' ) )

And replace it with this. This line will work with both setups for transitions, because if the wrappers don't exist they are not set either..
bg = new Background( document.body, document.getElementById('background-image1' ), document.getElementById('background-image2' ), document.getElementById('background-image1-wrapper' ), document.getElementById('background-image2-wrapper' ) );

.. and with that you transitions should now use transitions...

Settings options
there are 2 new settings that can be used in combination with the BackgroundSettingsProxy class:

var bgSettingsProxy = new BackgroundSettingsProxy( bg, { .. your other settings here .. // setting of type bool/combo with true/false ( numeric values 0 and 1 should work too ) 'slideshow-use-transitions': 'bgUseTransitions', // setting of type slider/combo with values 0 to 3600 ( 1 hour ). value is in seconds. 'slideshow-transition-duration': 'bgTransitionDuration', });

Direct control
You can also toggle transition or change the timing by code with:
bg.setUseTransitions( bool ); bg.setTransitionDuration( seconds );
Examples settings for Project.json
Some examples for image settings.
"bgFile" : { "order" : 10, "text" : "File", "type" : "file" }, "bgFolder" : { "mode" : "fetchall", "order" : 11, "text" : "Folder", "type" : "directory" }, "bgOpacity" : { "max" : 100, "min" : 0, "order" : 21, "text" : "Background Opacity (%)", "type" : "slider", "value" : 100 }, "bgRandomFile" : { "mode" : "ondemand", "order" : 12, "text" : "On Demand", "type" : "directory" }, "bgSize" : { "options" : [ { "label" : "Cover Screen", "value" : "cover" }, { "label" : "Fit Screen", "value" : "contain" } ], "order" : 20, "text" : "Background Size", "type" : "combo", "value" : "cover" }, }, "bgBlendMode" : { "options" : [ { "label" : "normal", "value" : "normal" }, { "label" : "multiply", "value" : "multiply" }, { "label" : "screen", "value" : "screen" }, { "label" : "overlay", "value" : "overlay" }, { "label" : "darken", "value" : "darken" }, { "label" : "lighten", "value" : "lighten" }, { "label" : "color-dodge", "value" : "color-dodge" }, { "label" : "color-burn", "value" : "color-burn" }, { "label" : "hard-light", "value" : "hard-light" }, { "label" : "soft-light", "value" : "soft-light" }, { "label" : "difference", "value" : "difference" }, { "label" : "exclusion", "value" : "exclusion" }, { "label" : "hue", "value" : "hue" }, { "label" : "saturation", "value" : "saturation" }, { "label" : "color", "value" : "color" }, { "label" : "luminosity", "value" : "luminosity" } ], "order" : 22, "text" : "Blend Mode", "type" : "combo", "value" : "luminosity" }, "bgBlur" : { "max" : 10, "min" : 0, "order" : 23, "text" : "Blur", "type" : "slider", "value" : 0 }, "bgInterval" : { "max" : 120, "min" : 1, "order" : 30, "text" : "Image Interval", "type" : "slider", "value" : 5 }, "bgIntervalMultiplier" : { "options" : [ { "label" : "seconds", "value" : 1 }, { "label" : "minutes", "value" : 60 }, { "label" : "hour", "value" : 3600 } ], "order" : 30, "text" : "Image Interval Units", "type" : "combo", "value" : 1 },

Some examples for background gradient/color
"bgCol1" : { "order" : 60, "text" : "Background Color 1", "type" : "color", "value" : "0 0 1" }, "bgCol2" : { "order" : 61, "text" : "Background Color 2", "type" : "color", "value" : "0 1 0" }, "bgCol3" : { "order" : 62, "text" : "Background Color 3", "type" : "color", "value" : "0.5 0 1" }, "bgCol4" : { "order" : 63, "text" : "Background Color 4", "type" : "color", "value" : "1 1 0" }, "bgCol5" : { "order" : 64, "text" : "Background Color 5", "type" : "color", "value" : "1 0 0" }, "bgColCount" : { "max" : 5, "min" : 1, "order" : 51, "text" : "Use # Colors", "type" : "slider", "value" : 5 }, "bgColGradientType" : { "options" : [ { "label" : "Linear", "value" : "linear" }, { "label" : "Radial", "value" : "radial" } ], "order" : 52, "text" : "Gradient Type", "type" : "combo", "value" : "linear" },
Class Definitions
Some automatically generated documentation on the 5 classes can be found in:
%steam%\steamapps\workshop\content\431960\858730156\docs\index.html

The 5 classes are:
  • Background - a javscript way of setting backgrounds with basic slideshow implementation on an html element ( contains an instance of the BackgroundImage and BackgroundGradient classes )
  • BackgroundImage - manages the selected files and determining based on the settings what the next image in the slideshow will be
  • BackgroundGradient - class to easily change gradient/color settings
  • BackgroundTransition - basic css animation controller used by the background class. not to be used directly
  • BackgroundSettingsProxy - a class that works as intermediary between wallpaper engine and the classes above and handles the property changes of your settings.
5 Comments
Nightwalker 11 Oct, 2023 @ 11:30am 
The ability to add music to the slideshow would be cool
Squee  [author] 9 Feb, 2017 @ 1:05pm 
Also update the setup. The line starting the slideshow now waits for until the first properties are set.
Squee  [author] 9 Feb, 2017 @ 12:34pm 
Updated
- Added CSS based transitions

Will update the docs on how to use those soon. Using them requires a bit more html so will probably create a new chapter for that.
Squee  [author] 7 Feb, 2017 @ 2:07pm 
Updated ..
- Images now are unset if the user deselects and image/folder.
- There is a blend/blur and timeout settings possible, documentation to be updated soon. Blur has it's problems so wont document those until I can explain how to patch the html/css for that issue.
fug4life 7 Feb, 2017 @ 12:26am 
Thanks for sharing!