Having trouble pushing Kaboom.js project to prod

I followed THIS tutorial to create a new portfolio with Kaboom.js that I plan to host on my personal website. I got it working great locally but am running into an issue pushing it to my live site. I suspect the issue is with the asynchronous nature of loading assets in Kaboom.js but so far I’ve been unsuccessful in resolving it.

The code:

import { dialogData, scaleFactor } from “./constants”;
import { k } from “./kaboomCtx”;
import { displayDialog, setCamScale, openContactForm, closeContactForm } from “./utils”;

document.addEventListener(“DOMContentLoaded”, () => {

console.log('import.meta.url:', import.meta.url);

console.log('Spritesheet URL:', new URL('../spritesheet.png', import.meta.url));
k.loadSprite ("spritesheet", new URL ('../spritesheet.png', import.meta.url), {

    sliceX: 39,
    sliceY: 31,
    anims: {
        "idle-down": 936,
        "walk-down": { from: 936, to: 939, loop: true, speed: 8 },
        "idle-side": 975,
        "walk-side": { from: 975, to: 978, loop: true, speed: 8 },
        "idle-up": 1014,
        "walk-up": { from: 1014, to: 1017, loop: true, speed: 8 },
        "bag-open": 128,
    },
});

console.log('Map sprite URL:', new URL('../map.png', import.meta.url));
k.loadSprite ("map", new URL ('../map.png', import.meta.url));

k.load(() => {

    k.setBackground (k.Color.fromHex ("#311047"));

    // Creating a scene
    k.scene ("main", async () => {
        
        const mapJsonUrl = new URL('../map.json', import.meta.url);
        console.log('Map JSON URL:', mapJsonUrl);
        const mapData = await (await fetch(mapJsonUrl)).json();
        console.log('Map data:', mapData);
        const layers = mapData.layers;
        console.log('Layers:', layers);

        const map = k.add ([
            k.sprite ("map"),
            k.pos (0, 0),
            // Controls the scale size of the map -- see constants.js
            k.scale (scaleFactor)
        ]);

        const player = k.make ([
            k.sprite ("spritesheet", { anim: "idle-down" }),
            k.area ({ 
                shape: new k.Rect (k.vec2(0, 3), 10, 10),
            }),
            k.body (),
            k.anchor ("center"),
            k.pos (),
            k.scale (scaleFactor),
            {
                speed: 250,
                direction: "down",
                isInDialog: false,
            },
            "player",
        ]);

        for (const layer of layers) {
            if (layer.name == "Boundaries") {
                for (const boundary of layer.objects) {
                    map.add ([
                        k.area ({
                            shape: new k.Rect (k.vec2(0), boundary.width, boundary.height),
                        }),
                        k.body ({isStatic: true}),
                        k.pos (boundary.x, boundary.y),
                        boundary.name,
                    ]);

                    if (boundary.name) {
                        player.onCollide(boundary.name, () => {
                            player.isInDialog = true;

                            displayDialog(
                                dialogData[boundary.name],
                                () => (player.isInDialog = false)
                            );
                        });
                    }
                }
                
                continue;
            }

            if (layer.name == "Spawnpoint") {
                for (const entity of layer.objects) {
                    if (entity.name == "player") {
                        player.pos = k.vec2(
                            (map.pos.x + entity.x) * scaleFactor,
                            (map.pos.y + entity.y) * scaleFactor
                        );
                        k.add(player);
                        continue;
                    }
                }
            }
        }

        setCamScale(k)

        k.onResize(() => {
            setCamScale(k);
        });

        k.onUpdate(() => {
            k.camPos(player.pos.x, player.pos.y + 100);
        });

        // Player movement
        k.onMouseDown((mouseBtn) => {
            if (mouseBtn !== "left" || player.isInDialog)
                return;

            const worldMousePos = k.toWorld(k.mousePos());
            player.moveTo(worldMousePos, player.speed);

            const mouseAngle = player.pos.angle(worldMousePos);
            const lowerBound = 50;
            const upperBound = 125;

            // Up
            if (mouseAngle > lowerBound && 
                mouseAngle < upperBound && 
                player.curAnim() !== "walk-up") {

                player.play("walk-up");
                player.direction = "up";
                return;
            }

            // Down
            if (mouseAngle < -lowerBound &&
                mouseAngle > -upperBound &&
                player.curAnim() !== "walk-down") {

                player.play("walk-down");
                player.direction = "down";
                return;
                }

            // Right
            if (Math.abs(mouseAngle) > upperBound) {
                player.flipX = false;

                if (player.curAnim() !== "walk-side") {
                    player.play("walk-side");
                    player.direction = "right";
                    return;
                }
            }

            // Left
            if (Math.abs(mouseAngle) < lowerBound) {
                player.flipX = true;

                if (player.curAnim() !== "walk-side") {
                    player.play("walk-side");
                    player.direction = "left";
                    return;
                }
            }
        });

        // Stops walking animation
        k.onMouseRelease(() => {
            if (player.direction === "down") {
                player.play("idle-down");
                return;
            }

            if (player.direction === "up") {
                player.play("idle-up");
                return;
            }

            player.play("idle-side");
        });

        k.go ("main");
    });
});

});

// Wait for the DOM to load before querying elements
window.addEventListener(‘DOMContentLoaded’, (event) => {

// Closes the contact form when the page loads
closeContactForm();

// Gets contact form buttons
const openButton = document.querySelector('.ui-popup-button');
const closeButton = document.querySelector('#closeContactFormButton');

// Check if the elements exist before adding event listeners
if (openButton) {
    openButton.addEventListener('click', openContactForm);
} else {
    console.error("Element with class '.ui-popup-button' not found");
}

if (closeButton) {
    closeButton.addEventListener('click', closeContactForm);
} else {
    console.error("Element with id 'closeContactFormButton' not found");
}

});

And here is the error from the Chrome console:

Uncaught TypeError: Failed to execute ‘drawImage’ on ‘CanvasRenderingContext2D’: The provided value is not of type ‘(CSSImageValue or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or OffscreenCanvas or SVGImageElement or VideoFrame)’.
at b.add (index-DfV-Wg4v.js:1:51115)
at SpriteData.fromImage (index-DfV-Wg4v.js:1:66115)
at Object.loadSprite (index-DfV-Wg4v.js:1:69732)
at HTMLDocument. (index-DfV-Wg4v.js:1:136855)

A few things to note:

  1. The contact form functionality works. It’s the map and sprites that won’t show.
  2. As you can see in the code, I’ve added console.log code to check the status of certain variables. Only import.meta.url and spritesheet url fire in the console.
  3. I’ve tried window.onload and defer.
  4. If I take the assets and plug my website name into the path they load in the browser so I know the issue isn’t there.
  5. It did work fine testing locally but as usual, it’s a different ballgame when it comes to hosting.

Thanks for any help!

Hello, your on track code is exexuting before the sprites etc… are loading in other asynchronous issues. What ide are you using is there a link to anything other than the code. If it works fine on one and not the other like in web browser it can take some time to figure this out, document.addEventListener("DOMContentLoaded", () => { ... }) to load assets. Are you actually pushing this to your domain if so you need to find the out the issues surrounding this. Good luck
note: Uncaught error means there is no error listed in js to define your issue.

I’m sorry I can’t help you as my JS is still only basics but I wanted to thank you for showing me Kaboom.js - it looks like a really cool library.
Happy coding!

1 Like

I’m using Visual Studio Code for this project. The code itself is for sure being pushed to my domain because the code for anything unrelated to the map and sprites is loading and working correctly. Since I’ve already used DOMContentLoaded in the code I provided I’m not sure what else I should do to load the assets so they appear.