Error loading backgrouns in web export

Godot Version

4.4.1 Stable

Question

Hi, I’m pretty new to GODOT (less than a week :))

So i’ve written a small game that changes the background as progress through every level.

I’m on MacOS and it works fine every time during testing in dev in the editor.

I load and update my back ground on startup

# Load background sprite (assumed path)
bg_sprite = get_node("Background")
# Existing setup
GameState.level_changed.connect(_on_level_changed)
update_background_for_level(GameState.level)

Background is a Spriet2D
Bg folder is a child of res:// and contains jpg files 1 to 30.jpg

I update like this as the level goes higher:

func update_background_for_level(level: int):
var bg_path = “res://Bg/%d.jpg” % clamp(level, 1, 30)
var image_texture = ImageTexture.new()
var image = Image.load_from_file(bg_path)

if image != null:
	image_texture.set_image(image)
	var bg_sprite = get_node("Background")
	bg_sprite.texture = image_texture
	bg_image = image  # update for spawn logic
else:
	print("Failed to load background for level: ", level)

Again this all works fine in dev but when I export to Web (Runnable) the game still kinda works but the background won’t update.

Looking in the javascript console i’m getting this error:

OpenGL API OpenGL ES 3.0 (WebGL 2.0 (OpenGL ES 3.0 Chromium)) - Compatibility - Using Device: WebKit - WebKit WebGL
index.js:459 [GameState:<Node#23655875792>, MainScene:<Node2D#28705817811>]
index.js:474 ERROR: Error opening file ‘res://Bg/1.jpg’.
onPrintError @ index.js:474
put_char @ index.js:9
write @ index.js:9
write @ index.js:9
doWritev @ index.js:9
_fd_write @ index.js:9
$func65592 @ 0a6b2fda:0x25bf877
$func65715 @ 0a6b2fda:0x25c6529
$func65722 @ 0a6b2fda:0x25c71fd
$func53904 @ 0a6b2fda:0x2168b38
$func53902 @ 0a6b2fda:0x21688d8
$func53901 @ 0a6b2fda:0x2168878
$func53906 @ 0a6b2fda:0x2168cac
$func62846 @ 0a6b2fda:0x248365f
$func62848 @ 0a6b2fda:0x24837a0
$func53795 @ 0a6b2fda:0x214f026
$func53637 @ 0a6b2fda:0x213fc6f
$func12041 @ 0a6b2fda:0xac5848
$func5616 @ 0a6b2fda:0x626471
$func5468 @ 0a6b2fda:0x61833a
$func62092 @ 0a6b2fda:0x241c1dd
$func55355 @ 0a6b2fda:0x223ac90
$func5616 @ 0a6b2fda:0x62604f
$func5468 @ 0a6b2fda:0x61833a
$func17100 @ 0a6b2fda:0x12580ac
$func16382 @ 0a6b2fda:0x1225e94
$func62070 @ 0a6b2fda:0x24191e4
$func17129 @ 0a6b2fda:0x1259fd0
$func17129 @ 0a6b2fda:0x1259f83
$func17126 @ 0a6b2fda:0x1259e58
$func17470 @ 0a6b2fda:0x1274a22
$_Z14godot_web_mainiPPc @ 0a6b2fda:0xd278b
$__main_argc_argv @ 0a6b2fda:0xd6be5
(anonymous) @ index.js:9
callMain @ index.js:9
(anonymous) @ index.js:801
(anonymous) @ index.js:796
Promise.then
start @ index.js:775
(anonymous) @ index.js:834
Promise.then
startGame @ index.js:833
(anonymous) @ index.html:203
(anonymous) @ index.html:217Understand this error
index.js:474 at: load_image (core/io/image_loader.cpp:89)
onPrintError @ index.js:474
put_char @ index.js:9
write @ index.js:9
write @ index.js:9
doWritev @ index.js:9
_fd_write @ index.js:9
$func65592 @ 0a6b2fda:0x25bf877
$func65715 @ 0a6b2fda:0x25c6529
$func65722 @ 0a6b2fda:0x25c71fd
$func53904 @ 0a6b2fda:0x2168b38
$func53902 @ 0a6b2fda:0x21688d8
$func53901 @ 0a6b2fda:0x216889a
$func53906 @ 0a6b2fda:0x2168cac
$func62846 @ 0a6b2fda:0x248365f
$func62848 @ 0a6b2fda:0x24837a0
$func53795 @ 0a6b2fda:0x214f026
$func53637 @ 0a6b2fda:0x213fc6f
$func12041 @ 0a6b2fda:0xac5848
$func5616 @ 0a6b2fda:0x626471
$func5468 @ 0a6b2fda:0x61833a
$func62092 @ 0a6b2fda:0x241c1dd
$func55355 @ 0a6b2fda:0x223ac90
$func5616 @ 0a6b2fda:0x62604f
$func5468 @ 0a6b2fda:0x61833a
$func17100 @ 0a6b2fda:0x12580ac
$func16382 @ 0a6b2fda:0x1225e94
$func62070 @ 0a6b2fda:0x24191e4
$func17129 @ 0a6b2fda:0x1259fd0
$func17129 @ 0a6b2fda:0x1259f83
$func17126 @ 0a6b2fda:0x1259e58
$func17470 @ 0a6b2fda:0x1274a22
$_Z14godot_web_mainiPPc @ 0a6b2fda:0xd278b
$__main_argc_argv @ 0a6b2fda:0xd6be5
(anonymous) @ index.js:9
callMain @ index.js:9
(anonymous) @ index.js:801
(anonymous) @ index.js:796
Promise.then
start @ index.js:775
(anonymous) @ index.js:834
Promise.then
startGame @ index.js:833
(anonymous) @ index.html:203
(anonymous) @ index.html:217Understand this error
index.js:474 ERROR: Failed to load image. Error 7
onPrintError @ index.js:474
put_char @ index.js:9
write @ index.js:9
write @ index.js:9
doWritev @ index.js:9
_fd_write @ index.js:9
$func65592 @ 0a6b2fda:0x25bf877
$func65715 @ 0a6b2fda:0x25c6529
$func65722 @ 0a6b2fda:0x25c71fd
$func53904 @ 0a6b2fda:0x2168b38
$func53902 @ 0a6b2fda:0x21688d8
$func53901 @ 0a6b2fda:0x2168878
$func53906 @ 0a6b2fda:0x2168cac
$func62846 @ 0a6b2fda:0x248365f
$func62848 @ 0a6b2fda:0x24837a0
$func53637 @ 0a6b2fda:0x213fccd
$func12041 @ 0a6b2fda:0xac5848
$func5616 @ 0a6b2fda:0x626471
$func5468 @ 0a6b2fda:0x61833a
$func62092 @ 0a6b2fda:0x241c1dd
$func55355 @ 0a6b2fda:0x223ac90
$func5616 @ 0a6b2fda:0x62604f
$func5468 @ 0a6b2fda:0x61833a
$func17100 @ 0a6b2fda:0x12580ac
$func16382 @ 0a6b2fda:0x1225e94
$func62070 @ 0a6b2fda:0x24191e4
$func17129 @ 0a6b2fda:0x1259fd0
$func17129 @ 0a6b2fda:0x1259f83
$func17126 @ 0a6b2fda:0x1259e58
$func17470 @ 0a6b2fda:0x1274a22
$_Z14godot_web_mainiPPc @ 0a6b2fda:0xd278b
$__main_argc_argv @ 0a6b2fda:0xd6be5
(anonymous) @ index.js:9
callMain @ index.js:9
(anonymous) @ index.js:801
(anonymous) @ index.js:796
Promise.then
start @ index.js:775
(anonymous) @ index.js:834
Promise.then
startGame @ index.js:833
(anonymous) @ index.html:203
(anonymous) @ index.html:217Understand this error
index.js:474 at: load_from_file (core/io/image.cpp:2554)

If it’s in “res://” then the resource is often replaced and renamed/remapped with a compressed version on Export. Image.load_from_file only tries to load the exact specified path, but load will load packed resources even after mapping.

Try using load instead (assuming you are importing these as Texture2Ds)

func update_background_for_level(level: int):
    var bg_path = "res://Bg/%d.jpg" % clamp(level, 1, 30)
    var image_texture = load(bg_path)
    var image = image_texture.get_image()

Yes with a bit of tweaking that was what i needed to do using load instead. This now works

func update_background_for_level_old(level: int):
var bg_path = “res://Bg/%d.jpg” % clamp(level, 1, bg_image_count)

var image = Image.new()
var error = image.load(bg_path)
var tex = load(bg_path)  # ✅ Works at runtime
# Grab the image for pixel checking
if tex:
	bg_image = tex.get_image()
else:
	print("Failed to load texture for level: ", level)

Seems like you are still trying to load by explicit path with var error = image.load(bg_path), I don’t think that is helping you.

Yeah think that was some debug stuff I was using so i’ll just delete it. Cheers for that catch though probably just slowing it down. Not an AAA :slight_smile: just for my kids to teach them game dev.

Actually maybe i should open a new thread but this stopped working

func is_spawn_allowed(color: Color) → bool:
var excluded_colors = [
Color8(0x14, 0x9C, 0xB2), # Sky
Color8(0x73, 0x53, 0x6B), # Dark mountain
Color8(0xC9, 0x7E, 0x5E), # Sun mountain
Color8(0x6F, 0x7F, 0xB2), # Far dark mountain
Color8(0X6D, 0x7F, 0xB1), # Far dark mountains 2
Color8(0xFF, 0xC2, 0x62), # mountain tops
Color8(0xC4, 0xA5, 0x90), # Far sun mountain
Color8(0x2C, 0xC0, 0x8C), # Far tree
Color8(0x1B, 0x7D, 0xC4), # Sea
Color8(0xB6, 0x67, 0x46) # Cliffs
]

var tolerance = 0.10  # You can raise/lower this to fine-tune matching

for excluded in excluded_colors:
	var distance = sqrt(
		pow(color.r - excluded.r, 2) +
		pow(color.g - excluded.g, 2) +
		pow(color.b - excluded.b, 2)
	)
	if distance < tolerance:
		return false  # Too close to an excluded color

when i call this. not sure if something changed with the new code… RGB issue? or bg_image.get_pixel(px, py)?

while not crispy_spawned and attempts < max_attempts:
	attempts += 1
	var pos = Vector2(randf() * screen_size.x, randf() * screen_size.y)
	var local_pos = bg_sprite.to_local(pos)
	var px = int(local_pos.x)
	var py = int(local_pos.y)
	if px < 0 or py < 0 or px >= bg_image.get_width() or py >= bg_image.get_height():
		continue
	var color = bg_image.get_pixel(px, py)
	
	if is_spawn_allowed(color):
		crispy_instance = crispy_scene.instantiate()
		crispy_instance.position = pos