Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

An way to change the body background image?

edited February 2015 in Help! with 2.0
Is there any way to change the main background image mid-story?

Currently I'm using this setup in SugarCube to display a background image:

html {
background: [img[club.jpg]] fixed;
background-size: cover;
min-height: 100%;
height:100%;
}

body {
color: #111;
font-family: Georgia;
font-size: 16px;
background-color: transparent;
}

#ui-bar, #ui-body {
background-color: #222;
color: #e6e6e6;
background: hidden;
background-attachment: fixed;
background-color: transparent;
border-color: transparent;
}
This results in a body and ui bar that are completely see-through, leaving only the basic background and passage styling on top. Which is cool, but means I can't change the background image mid-story.


While using the body area to do this would be more responsive than the html area, the problem I was running into when I tried to do it in the body area is that it didn't fill out the whole screen like putting it in the html area does.

Comments

  • You can use SugarCube's addclass and removeclass macros and some class selector based CSS to achieve what you want.

    1. I am using a class of street to show the street.jpg background image, you can name the class and image whatever you like. Remember to add the following CSS later in your stylesheet than your existing html selector.

    html.street {
    background: [img[street.jpg]] fixed;
    }
    2. Add the following addclass macro to the first passage you want to start showing the new background image:

    <<addclass "html" "street">>
    The text of the passage.........
    3. Because people can use the browser back button to travel backwards through your story you will need to also add a removeclass macro to all passages that directly lead to the passage you added the addclass macro to in point 2.

    <<removeclass "html" "street">>
    The text of the passage directly before the one you changed to the new background image.
  • greyelf wrote:

    3. Because people can use the browser back button to travel backwards through your story you will need to also add a removeclass macro to all passages that directly lead to the passage you added the addclass macro to in point 2.


    Not in my story they can't!!!

    Thanks for the reply :)
  • Hmmm, is there a way to tell the browser to load these images before the game starts so they don't have a hitch while loading a 1mb image? I asked about the same topic regarding sounds not too long ago and got a good answer, so just wondering if the same is possible with images.

    Could I possibly do something silly like adding the <addclass>> macro with the images to the StoryInit passage or simply using the [img[image.jpg]] entry in StoryInit so that they're loaded in before game start, then remove them at the Start passage?
  • Claretta wrote:

    Could I possibly do something silly like [] simply using the [img[image.jpg]] entry in StoryInit so that they're loaded in before game start, then remove them at the Start passage?


    That might work, yes, though since StoryInit produces no output (technically, it discards all created output), there would be nothing to remove.  The only possible snags I foresee is that the created &lt;img&gt; elements may not live long enough to get their src cached or, if it takes a while to come across these images, they could be removed from the cache prematurely (those are both browser implementation details).  Regardless, I'd give it a try, since it's a simple solution (and I may be worrying over nothing).

    If that doesn't work for you, then programmatically creating &lt;img&gt; elements and simply not attaching them to the DOM (nor discarding them) would probably work.  For example: (preferably in your Story JavaScript)

    (function () {
    var sources = [
    "a_image.jpg",
    "b_image.png",
    "c_image.jpg"
    ],
    imgCache = window.TwineImgCache = {};
    sources.forEach(function (src) {
    if (!imgCache.hasOwnProperty(src)) {
    imgCache[src] = document.createElement("img");
    imgCache[src].src = src;
    }
    });
    }());
    n.b. I'd recommend only doing this for large and/or long lived images, however, as doing this for every image would be overkill.
  • TheMadExile wrote:

    Claretta wrote:

    Could I possibly do something silly like [] simply using the [img[image.jpg]] entry in StoryInit so that they're loaded in before game start, then remove them at the Start passage?


    That might work, yes, though since StoryInit produces no output (technically, it discards all created output), there would be nothing to remove.  The only possible snags I foresee is that the created &lt;img&gt; elements may not live long enough to get their src cached or, if it takes a while to come across these images, they could be removed from the cache prematurely (those are both browser implementation details).  Regardless, I'd give it a try, since it's a simple solution (and I may be worrying over nothing).



    This seems to work on my machine, with the interesting side effect that the screen just goes blank white and doesn't show any loading bar as the storyinit passage loads. Once it's finished loading the images, I get the load bar very briefly as it moves to load the first passage.

    Because of this I don't want to use it for too many images.
  • TheMadExile wrote:


    If that doesn't work for you, then programmatically creating &lt;img&gt; elements and simply not attaching them to the DOM (nor discarding them) would probably work.  For example: (preferably in your Story JavaScript)

    (function () {
    var sources = [
    "a_image.jpg",
    "b_image.png",
    "c_image.jpg"
    ],
    imgCache = window.TwineImgCache = {};
    sources.forEach(function (src) {
    if (!imgCache.hasOwnProperty(src)) {
    imgCache[src] = document.createElement("img");
    imgCache[src].src = src;
    }
    });
    }());



    I'm getting an error when I put this code into my story. I put it after the sound macros in my story java area and it results in the story refusing to recognise the sound macros.
  • As an even simpler solution, can I just put this in the start passage?

    <link rel="prefetch" href="images/armoury.jpg">
  • Claretta wrote:

    This seems to work on my machine, with the interesting side effect that the screen just goes blank white and doesn't show any loading bar as the storyinit passage loads. Once it's finished loading the images, I get the load bar very briefly as it moves to load the first passage.


    Ah, I believe I know what's going on there.  Something I'll have to publish a new release to address.


    Claretta wrote:

    I'm getting an error when I put this code into my story. I put it after the sound macros in my story java area and it results in the story refusing to recognise the sound macros.


    The code has been tested.  You likely broke something on copy or when populating the sources array.


    Claretta wrote:

    As an even simpler solution, can I just put this in the start passage?

    <link rel="prefetch" href="images/armoury.jpg">


    No, the &lt;link&gt; element is not legal outside of the &lt;head&gt; element (and you shouldn't be using the starting passage as an initialization dumping ground anyway).  That said, adding &lt;link&gt; elements to the document head during startup isn't terribly difficult.

    For example:

    (function () {
    var sources = [
    "images/armoury.jpg"
    ];
    sources.forEach(function (imgSrc) {
    var linkEl = document.createElement("link");
    linkEl.rel = "prefetch";
    linkEl.href = imgSrc;
    document.head.appendChild(linkEl);
    });
    }());
  • I know what I was doing wrong. When I added an extra image to the sources array, I forgot to add another comma to the end of the third image. Thanks for the tip.
  • It turns out all the preloading only semi-helps. There's still a weird delay before showing the images for the first time even with all 3 of the preloading methods in place.

    To get it to run smoothly on the first time the image is seen, I actually have to create a separate start passage for each image and go:

    <<addclass "html" "club">>
    <<timedcontinue 1s>>
    <<goto "Loading 3">>


    And that continues through to Loading 1, each "loading" passage adding a new image to the background, and when all 4 loading passages are cycled, the game switches to the proper start passage.

    So not ideal, but better than a weird hitch during the first image load. I could always try to make the images transparent maybe during this loading sequence so players don't get a brief preview of each image.
  • Claretta wrote:

    It turns out all the preloading only semi-helps. There's still a weird delay before showing the images for the first time even with all 3 of the preloading methods in place.


    Please, tell me you tried all three together only as a last resort.

    Just how large are these background images (in size and dimensions)?  Does this happen in all browsers or just one?  Are you using a WebKit/Blink-based browser?  Live example?
  • Yes. :P When I still got an issue with 1, I added another etc.

    I'm developing offline with chrome atm, and was originally using images 2mb each, but since optimised them down to about 300kb each. Images are 2560 x 1440.

    Still same issue, which is that the very first time you encounter the transition, there's a slight pause before the game activates the transition (I don't just switch upbuptly, but have a 1s fade between each image).


    But I don't actually mind my latest solution. It creates an interesting loading sequence of images so will probably just keep it on aesthetic grounds alone.
  • Claretta wrote:

    I'm developing offline with chrome atm, and was originally using images 2mb each, but since optimised them down to about 300kb each. Images are 2560 x 1440.


    The emphasized parts are your real problems.

    Raw file size matters during the loading of an image.  Once that's been accomplished, the next hurdle are the pixel dimensions.  To render an image onscreen, a bitmap must be created for it.  A 25601440 pixel bitmap takes a bit of processing (and memory), thus the delay you're noticing as the bitmap is initially created for the image.

    Common tricks, as we've been trying, are aimed mostly at caching the original image (I suppose that's my fault for not asking questions to begin with).  To solve the (let's call it) bitmap latency, you need to have the browser not only load the original image, but also create the onscreen bitmap for it.  In Firefox and IE, you could simply have the images rendered offscreen someplace (e.g. with a &lt;div&gt;, containing the images, fixed at a position far offscreen) or possibly even onscreen but invisible (e.g. same setup as before, but with hidden visibility or zero opacity, etc).  WebKit/Blink-based browsers make this more a pain than it should be, however, because they require the image to be both onscreen and visible before they'll create the bitmap.  Neither behavior is right/wrong, one is simply more of a pain in the neck.

    So, to resolve the bitmap latency for all browsers, you're going to need to have them rendered onscreen sometime before they're actually needed.  Your current monstrosity does that, so if you like it you could simply stick with it.

    Alternatively, you could do something like the following:

    JavaScript:

    (function () {
    var sources = [
    "images/armoury.jpg"
    ],
    docFrag = document.createDocumentFragment(),
    imgBox = document.createElement("div");
    imgBox.id = "imgloader-box";
    docFrag.appendChild(imgBox);
    sources.forEach(function (src) {
    var image = document.createElement("img");
    image.src = src;
    imgBox.appendChild(image);
    });
    document.body.appendChild(docFrag);
    }());
    CSS:

    #imgloader-box{position:fixed;left:0;top:0;width:2px;height:2px;overflow:hidden;z-index:0}
    #imgloader-box img{position:absolute;left:0;top:0;width:1px;height:1px}
    How it works: After the very first passage is rendered onscreen, the script creates a very small &lt;div&gt; (2px), layers the images inside it with fixed dimensions (1px), and then adds it to the page in a fixed position in the top left corner underneath the UI bar.  While the images are extremely tiny and hidden from player view (by being underneath the UI bar), they are actually completely visible, so WebKit/Blink will render the image bitmaps.


    Also, let me readdress something from earlier:

    Claretta wrote:

    This seems to work on my machine, with the interesting side effect that the screen just goes blank white and doesn't show any loading bar as the storyinit passage loads. Once it's finished loading the images, I get the load bar very briefly as it moves to load the first passage.


    The reason you're seeing the "blank white" bit is because of how Twine 2 spawns Play/Debug versions of your story.  For a published file (i.e. under normal use), you should only see the load screen.
  • Thanks for the detailed reply, I'll give it a shot.

    I'm aware that having such large images can give problems, but there are only 5 of them in my whole game, and it's not such a big deal to avoid having ones that look so good.
  • Put this into the game and it works perfectly, thank you.  Was a little worried it wouldn't since my ui-bar is ~also~ hidden (well, actually transparent), so wondered if there would be anything to hide the images under. But it works fine.

    I take it there's now no need for any of the other preloader methods?
  • Correct.  You can dispense with the others.
Sign In or Register to comment.