fix(jackbox): realign UI strictly within CRT monitor sprite and clear wall painting

This commit is contained in:
Игорь Федосеев 2026-10-25 17:07:05 +03:00
parent 6bf2a2885c
commit 7c262a15ad
11 changed files with 434 additions and 315 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

After

Width:  |  Height:  |  Size: 38 KiB

BIN
poker.exe

Binary file not shown.

BIN
poker.obj

Binary file not shown.

View file

@ -56,12 +56,13 @@ DrawJackboxCabinet3D PROC uses ebx esi edi wx:DWORD, wy:DWORD
local x0:DWORD, x1:DWORD, y0:DWORD, y1:DWORD local x0:DWORD, x1:DWORD, y0:DWORD, y1:DWORD
; Solid rectangular cabinet against East wall beside billiards: ; Solid rectangular cabinet against East wall beside billiards:
; Depth along X: 0.55m (x0 = 30.40m, x1 = 30.95m against wall at 31.0m) ; Depth along X: 0.55m (x0 = 30.40m, x1 = 30.95m against wall at 31.0m)
; Width along Y: 0.85m (y0 = 24.575m, y1 = 25.425m, centered at Y = 25.0m) ; Width along Y: 0.85m (y0 = 23.075m, y1 = 23.925m, centered at Y = 23.5m)
; Leaves painting 116 at Y = [25.0 .. 26.5] completely visible and unblocked!
; Height Z: 1.85m ; Height Z: 1.85m
mov x0, FP_1*304/10 mov x0, FP_1*304/10
mov x1, FP_1*3095/100 mov x1, FP_1*3095/100
mov y0, 25*FP_1 - FP_1*425/1000 mov y0, FP_1*235/10 - FP_1*425/1000
mov y1, 25*FP_1 + FP_1*425/1000 mov y1, FP_1*235/10 + FP_1*425/1000
; 1. Back Face (against East wall: X = x1) ; 1. Back Face (against East wall: X = x1)
invoke DrawCityVertical3D, 0, x1, y0, y1, 0, FP_1*37/20, MATERIAL_JACKBOX_BACK invoke DrawCityVertical3D, 0, x1, y0, y1, 0, FP_1*37/20, MATERIAL_JACKBOX_BACK
@ -88,7 +89,7 @@ JackboxCanWalk3D PROC px:DWORD, py:DWORD
cmp eax, 31*FP_1+9830 cmp eax, 31*FP_1+9830
ja jackbox_walk_clear ja jackbox_walk_clear
mov eax, py mov eax, py
sub eax, 25*FP_1 sub eax, FP_1*235/10
test eax, eax test eax, eax
jns @F jns @F
neg eax neg eax
@ -144,27 +145,93 @@ HandleJackbox3D PROC uses ebx esi
cmp mouseClick3D, 0 cmp mouseClick3D, 0
je jbox_keys je jbox_keys
; Check Exit button in top right: x in [228..312], y in [8..26] ; Exit via Top-Right LCD slot: x in [232..284], y in [12..26]
cmp mouseY3D, 8 cmp mouseY3D, 12
jb @F jb @F
cmp mouseY3D, 26 cmp mouseY3D, 26
ja @F ja @F
cmp mouseX3D, 228 cmp mouseX3D, 232
jae jbox_exit jb @F
cmp mouseX3D, 284
jbe jbox_exit
@@: @@:
; Check track row click: y in [54..186] ; Exit via Bottom Red CANCEL button: x in [224..256], y in [195..225]
cmp mouseY3D, 54 cmp mouseY3D, 195
jb @F
cmp mouseY3D, 225
ja @F
cmp mouseX3D, 224
jb @F
cmp mouseX3D, 256
jbe jbox_exit
@@:
; Bottom Green START button: x in [154..188], y in [195..225] -> Play selected
cmp mouseY3D, 195
jb @F
cmp mouseY3D, 225
ja @F
cmp mouseX3D, 154
jb @F
cmp mouseX3D, 188
jbe jbox_play_selected
@@:
; Bottom Orange SELECT button: x in [190..222], y in [195..225] -> Next track & play
cmp mouseY3D, 195
jb @F
cmp mouseY3D, 225
ja @F
cmp mouseX3D, 190
jb @F
cmp mouseX3D, 222
ja @F
inc jboxSelectedTrack
cmp jboxSelectedTrack, JACKBOX_TRACK_COUNT
jb jbox_play_selected
mov jboxSelectedTrack, 0
jmp jbox_play_selected
@@:
; Bottom Left Arrow: x in [256..274], y in [204..224] -> Prev track
cmp mouseY3D, 204
jb @F
cmp mouseY3D, 224
ja @F
cmp mouseX3D, 256
jb @F
cmp mouseX3D, 274
ja @F
dec jboxSelectedTrack
jns jbox_play_selected
mov jboxSelectedTrack, JACKBOX_TRACK_COUNT - 1
jmp jbox_play_selected
@@:
; Bottom Right Arrow: x in [276..294], y in [204..224] -> Next track
cmp mouseY3D, 204
jb @F
cmp mouseY3D, 224
ja @F
cmp mouseX3D, 276
jb @F
cmp mouseX3D, 294
ja @F
inc jboxSelectedTrack
cmp jboxSelectedTrack, JACKBOX_TRACK_COUNT
jb jbox_play_selected
mov jboxSelectedTrack, 0
jmp jbox_play_selected
@@:
; Check track row click inside CRT screen: x in [46..274], y in [65..165]
cmp mouseY3D, 65
jb jbox_keys jb jbox_keys
cmp mouseY3D, 186 cmp mouseY3D, 165
ja jbox_keys ja jbox_keys
cmp mouseX3D, 16 cmp mouseX3D, 46
jb jbox_keys jb jbox_keys
cmp mouseX3D, 304 cmp mouseX3D, 274
ja jbox_keys ja jbox_keys
mov eax, mouseY3D mov eax, mouseY3D
sub eax, 54 sub eax, 65
xor edx, edx xor edx, edx
mov ebx, 13 mov ebx, 10
div ebx div ebx
cmp eax, JACKBOX_TRACK_COUNT cmp eax, JACKBOX_TRACK_COUNT
jae jbox_keys jae jbox_keys
@ -223,7 +290,7 @@ jbox_keys:
invoke PlayJukeboxTrack3D, eax invoke PlayJukeboxTrack3D, eax
jmp jbox_handled jmp jbox_handled
@@: @@:
; Direct digit keys '1'..'9', '0' ; Direct digit keys '1'..'9'
mov ebx, 31h ; '1' mov ebx, 31h ; '1'
jbox_digit_loop: jbox_digit_loop:
invoke Pressed3D, ebx invoke Pressed3D, ebx
@ -266,17 +333,28 @@ RenderJackbox3D PROC uses ebx esi edi
; 1. Draw base background ; 1. Draw base background
invoke DrawBox, 0, 0, 320, 240, 000B1815h invoke DrawBox, 0, 0, 320, 240, 000B1815h
; 2. Overlay screen artwork if available ; 2. Overlay screen artwork (640x480 physical buffer)
cmp jackboxScreenArt3D.pixels, 0 cmp jackboxScreenArt3D.pixels, 0
je @F je @F
invoke DrawAnimSprite3D, OFFSET jackboxScreenArt3D, 0, 0, 0, 640, 480 invoke DrawAnimSprite3D, OFFSET jackboxScreenArt3D, 0, 0, 0, 640, 480
@@: @@:
; 3. Title & Exit Button ; 3. Top Digital LCD Slots
invoke DrawString8x8, 52, 12, OFFSET jboxTitle, 00E7C479h ; Left slot: status text
invoke DrawBoxBorder, 228, 8, 84, 16, 001A2522h, 00C8AD75h, 1 cmp jboxIsPlaying, 1
invoke DrawString8x8, 234, 12, OFFSET jboxClose, 00F2E6C6h jne jbox_top_lcd_stopped
cmp jboxCurrentTrack, -1
je jbox_top_lcd_stopped
cmp jboxCurrentTrack, 9
jae jbox_top_lcd_stopped
invoke DrawString8x8, 42, 17, OFFSET jboxLcdPlay, 0050FF90h ; Green "ÈÃÐÀÅÒ"
jmp jbox_top_lcd_exit
jbox_top_lcd_stopped:
invoke DrawString8x8, 45, 17, OFFSET jboxLcdStop, 008CB8A5h ; Dim green "ÑÒÎÏ"
jbox_top_lcd_exit:
; Right slot: exit button text
invoke DrawString8x8, 241, 17, OFFSET jboxLcdExit, 00F2A648h ; Amber "ÂÛÕÎÄ"
; 4. Now Playing Status Banner ; 4. CRT Monitor Header: Now Playing Status
cmp jboxIsPlaying, 1 cmp jboxIsPlaying, 1
jne jbox_render_stopped jne jbox_render_stopped
cmp jboxCurrentTrack, -1 cmp jboxCurrentTrack, -1
@ -284,48 +362,50 @@ RenderJackbox3D PROC uses ebx esi edi
cmp jboxCurrentTrack, 9 cmp jboxCurrentTrack, 9
jae jbox_render_stopped jae jbox_render_stopped
invoke DrawString8x8, 20, 34, OFFSET jboxStatusPlaying, 008CD8AFh invoke DrawString8x8, 48, 52, OFFSET jboxHdrNow, 0050FF90h ; Green "ÑÅÉ×ÀÑ:"
mov eax, jboxCurrentTrack mov eax, jboxCurrentTrack
mov edx, jboxTrackNames[eax*4] mov edx, jboxTrackNames[eax*4]
invoke DrawString8x8, 140, 34, edx, 00F0E6C3h invoke DrawString8x8, 108, 52, edx, 00F0E6C3h
jmp jbox_render_divider jmp jbox_render_divider
jbox_render_stopped: jbox_render_stopped:
invoke DrawString8x8, 20, 34, OFFSET jboxStatusStopped, 0090B19Fh invoke DrawString8x8, 48, 52, OFFSET jboxHdrStop, 008CB8A5h ; Dim green "ÑÒÀÒÓÑ: ÎÑÒÀÍÎÂËÅÍ"
jbox_render_divider: jbox_render_divider:
invoke DrawBox, 20, 47, 280, 1, 00495B4Ah invoke DrawBox, 46, 62, 228, 1, 001C3828h
; 5. Track Selection List (10 rows, step Y = 13) ; 5. Track Selection List (10 rows, step Y = 10, from Y = 66)
mov rowY, 55 mov rowY, 66
xor esi, esi xor esi, esi
jbox_render_row: jbox_render_row:
mov color, 0090B19Fh ; Default muted mov color, 008CB8A5h ; Default CRT phosphor pale cyan
cmp esi, jboxSelectedTrack cmp esi, jboxSelectedTrack
jne @F jne @F
mov color, 00F2E6C6h ; Bright cream for selection ; Selected row: highlight box, golden cursor, bright white text
invoke DrawString8x8, 14, rowY, OFFSET jboxCursor, 00E7C479h invoke DrawBox, 46, rowY, 228, 9, 00143526h
invoke DrawString8x8, 48, rowY, OFFSET jboxCursor, 00FFD700h
mov color, 00FFFFFFh
@@: @@:
mov edx, jboxTrackNames[esi*4] mov edx, jboxTrackNames[esi*4]
invoke DrawString8x8, 28, rowY, edx, color invoke DrawString8x8, 58, rowY, edx, color
; Mark playing track ; Mark playing track with [>] tag
cmp esi, jboxCurrentTrack cmp esi, jboxCurrentTrack
jne jbox_row_next jne jbox_row_next
cmp jboxIsPlaying, 1 cmp jboxIsPlaying, 1
jne jbox_row_next jne jbox_row_next
invoke DrawString8x8, 252, rowY, OFFSET jboxPlayingTag, 008CD8AFh invoke DrawString8x8, 238, rowY, OFFSET jboxTagPlay, 0050FF90h
jbox_row_next: jbox_row_next:
add rowY, 13 add rowY, 10
inc esi inc esi
cmp esi, JACKBOX_TRACK_COUNT cmp esi, JACKBOX_TRACK_COUNT
jb jbox_render_row jb jbox_render_row
; 6. Footer Controls Help ; 6. Footer Controls Help (strictly inside CRT)
invoke DrawBox, 20, 192, 280, 1, 00314538h invoke DrawBox, 46, 166, 228, 1, 001C3828h
invoke DrawString8x8, 20, 200, OFFSET jboxHelp1, 00C1A982h invoke DrawString8x8, 56, 170, OFFSET jboxFooterHelp, 0070AA90h
invoke DrawString8x8, 20, 214, OFFSET jboxHelp2, 0090B19Fh
ret ret
RenderJackbox3D ENDP RenderJackbox3D ENDP

View file

@ -6,7 +6,7 @@ MODE_JACKBOX equ 28
INTERACT_JACKBOX equ 48 INTERACT_JACKBOX equ 48
JACKBOX_X equ FP_1*306/10 JACKBOX_X equ FP_1*306/10
JACKBOX_Y equ 25*FP_1 JACKBOX_Y equ FP_1*235/10
JACKBOX_TRACK_COUNT equ 10 JACKBOX_TRACK_COUNT equ 10
MATERIAL_JACKBOX_FRONT equ 161 MATERIAL_JACKBOX_FRONT equ 161
@ -30,7 +30,8 @@ jackboxScreenArt3D AnimPack3D <>
jackboxWorldPath3D db "assets\animations\hall\jackbox-v1.bin",0 jackboxWorldPath3D db "assets\animations\hall\jackbox-v1.bin",0
jackboxScreenPath3D db "assets\animations\hall\jackbox-ui-v1.bin",0 jackboxScreenPath3D db "assets\animations\hall\jackbox-ui-v1.bin",0
jackboxPrompt3D db "E: ÄÆÓÊÁÎÊÑ",0 ; Prompt: "E: Âêëþ÷èòü àâòîìàò"
jackboxPrompt3D db 69,58,32,194,234,235,254,247,232,242,252,32,224,226,242,238,236,224,242,0
jboxCurrentTrack dd -1 jboxCurrentTrack dd -1
jboxSelectedTrack dd 0 jboxSelectedTrack dd 0
@ -54,26 +55,31 @@ jboxOpenCommands dd OFFSET jboxOpen0, OFFSET jboxOpen1, OFFSET jboxOpen2, OFFSET
dd OFFSET jboxOpen4, OFFSET jboxOpen5, OFFSET jboxOpen6, OFFSET jboxOpen7 dd OFFSET jboxOpen4, OFFSET jboxOpen5, OFFSET jboxOpen6, OFFSET jboxOpen7
dd OFFSET jboxOpen8, 0 dd OFFSET jboxOpen8, 0
jboxName0 db "1. Keygen Church - Tenebre Rosso Sangue",0 jboxName0 db "1. Keygen - Tenebre",0
jboxName1 db "2. Keygen Church - Hareklavit",0 jboxName1 db "2. Keygen - Hareklavit",0
jboxName2 db "3. Keygen Church - Ladikerfos",0 jboxName2 db "3. Keygen - Ladikerfos",0
jboxName3 db "4. Keygen Church - Tilaskarot",0 jboxName3 db "4. Keygen - Tilaskarot",0
jboxName4 db "5. Mick Gordon - BFG Division (DOOM)",0 jboxName4 db "5. Mick Gordon - BFG",0
jboxName5 db "6. Mick Gordon - Rip & Tear (DOOM)",0 jboxName5 db "6. Mick Gordon - Rip",0
jboxName6 db "7. Mick Gordon - The Only Thing They Fear",0 jboxName6 db "7. Mick Gordon - Doom",0
jboxName7 db "8. Hakari Dance (Jackpot Theme)",0 jboxName7 db "8. Hakari Dance (Ost)",0
jboxName8 db "9. Team Fortress 2 - Victory Theme",0 jboxName8 db "9. TF2 - Victory",0
jboxName9 db "0. [ ÂÛÊËÞ×ÈÒÜ ÌÓÇÛÊÓ / ÒÈØÈÍÀ ]",0 ; "0. [Âûêëþ÷èòü çâóê]"
jboxName9 db 48,46,32,91,194,251,234,235,254,247,232,242,252,32,231,226,243,234,93,0
jboxTrackNames dd OFFSET jboxName0, OFFSET jboxName1, OFFSET jboxName2, OFFSET jboxName3 jboxTrackNames dd OFFSET jboxName0, OFFSET jboxName1, OFFSET jboxName2, OFFSET jboxName3
dd OFFSET jboxName4, OFFSET jboxName5, OFFSET jboxName6, OFFSET jboxName7 dd OFFSET jboxName4, OFFSET jboxName5, OFFSET jboxName6, OFFSET jboxName7
dd OFFSET jboxName8, OFFSET jboxName9 dd OFFSET jboxName8, OFFSET jboxName9
jboxTitle db "ÌÓÇÛÊÀËÜÍÛÉ ÀÂÒÎÌÀÒ",0 ; Top Digital LCD Display Slots
jboxClose db "ÂÛÕÎÄ [ESC]",0 jboxLcdPlay db 200,195,208,192,197,210,0 ; "ÈÃÐÀÅÒ"
jboxStatusPlaying db "ÑÅÉ×ÀÑ ÈÃÐÀÅÒ:",0 jboxLcdStop db 209,210,206,207,0 ; "ÑÒÎÏ"
jboxStatusStopped db "ÌÓÇÛÊÀ ÂÛÊËÞ×ÅÍÀ",0 jboxLcdExit db 194,219,213,206,196,0 ; "ÂÛÕÎÄ"
; CRT Monitor Screen Text
jboxHdrNow db 209,197,201,215,192,209,58,0 ; "ÑÅÉ×ÀÑ:"
jboxHdrStop db 209,210,192,210,211,209,58,32,206,209,210,192,205,206,194,203,197,205,0 ; "ÑÒÀÒÓÑ: ÎÑÒÀÍÎÂËÅÍ"
jboxCursor db ">",0 jboxCursor db ">",0
jboxPlayingTag db " [ÈÃÐÀÅÒ]",0 jboxTagPlay db "[>]",0
jboxHelp1 db "ÑÒÐÅËÊÈ / 0-9: Âûáîð ENTER: Âêëþ÷èòü",0 ; "ENTER:Ïóñê S:Ñòîï R:Ìèêñ"
jboxHelp2 db "S: Ñòîï R: Ñëó÷àéíûé ESC:  çàë",0 jboxFooterHelp db 69,78,84,69,82,58,207,243,241,234,32,32,83,58,209,242,238,239,32,32,82,58,204,232,234,241,0

View file

@ -64,7 +64,7 @@ def test_code_structure():
assert "MODE_JACKBOX equ 28" in data_inc assert "MODE_JACKBOX equ 28" in data_inc
assert "INTERACT_JACKBOX equ 48" in data_inc assert "INTERACT_JACKBOX equ 48" in data_inc
assert "JACKBOX_X equ FP_1*306/10" in data_inc assert "JACKBOX_X equ FP_1*306/10" in data_inc
assert "JACKBOX_Y equ 25*FP_1" in data_inc assert "JACKBOX_Y equ FP_1*235/10" in data_inc
assert "MATERIAL_JACKBOX_BACK equ 163" in data_inc assert "MATERIAL_JACKBOX_BACK equ 163" in data_inc
# Check procs # Check procs

View file

@ -251,14 +251,47 @@ def render_scene(cam_x, cam_y, cam_angle, out_path):
draw_pool_side(0, int(26.0*FP_1), int(24.0*FP_1), int(26.0*FP_1), 0, int(0.85*FP_1)) draw_pool_side(0, int(26.0*FP_1), int(24.0*FP_1), int(26.0*FP_1), 0, int(0.85*FP_1))
draw_pool_side(0, int(28.0*FP_1), int(24.0*FP_1), int(26.0*FP_1), 0, int(0.85*FP_1)) draw_pool_side(0, int(28.0*FP_1), int(24.0*FP_1), int(26.0*FP_1), 0, int(0.85*FP_1))
# 2. Solid Rectangular Jukebox Cabinet (at East wall, next to billiards table!) # 2. Wall Art / Painting 116 on East Wall: X = 30.98m, Y in [25.0m .. 26.5m], Z in [1.0m .. 2.0m]
def draw_painting(axis, coord, lo, hi, z0, z1, slot):
for col in range(SCREEN_W):
ray_dir = cityRayX[col] if axis == 0 else cityRayY[col]
if abs(ray_dir) < 256:
continue
orig = playerX if axis == 0 else playerY
num = (coord - orig)
depth = (num << 16) // ray_dir
if depth <= 4096 or depth >= zBuffer[col]:
continue
along = playerY + ((depth * cityRayY[col]) >> 16) if axis == 0 else playerX + ((depth * cityRayX[col]) >> 16)
if along < lo or along >= hi:
continue
top = (HALL_STANDING_EYE - z1) * SCREEN_H // depth + HALF_H
bottom = (HALL_STANDING_EYE - z0) * SCREEN_H // depth + HALF_H
span = bottom - top
if span <= 0:
continue
r_start = max(0, top)
r_end = min(SCREEN_H, bottom)
span_along = hi - lo
tx = int((along - lo) * 128 / span_along) % 128
shade = max(40, min(255, 255 - (depth >> 12)))
for row in range(r_start, r_end):
ty = int((row - top) * 128 / span) % 128
r, g, b, a = get_tex_pixel(slot, tx, ty)
if depth < depthBuffer[row * SCREEN_W + col]:
depthBuffer[row * SCREEN_W + col] = depth
screen_pixels[row * SCREEN_W + col] = ((r * shade) >> 8, (g * shade) >> 8, (b * shade) >> 8)
draw_painting(0, int(30.98 * FP_1), int(25.0 * FP_1), int(26.5 * FP_1), FP_1, 2 * FP_1, 116)
# 3. Solid Rectangular Jukebox Cabinet (at East wall, Y = 23.5m, clearing Painting 116!)
# Depth: X in [30.40m .. 30.95m] (back against East wall at 31.0m) # Depth: X in [30.40m .. 30.95m] (back against East wall at 31.0m)
# Width: Y in [24.575m .. 25.425m] (centered at Y = 25.0m) # Width: Y in [23.075m .. 23.925m] (centered at Y = 23.5m)
# Height: Z in [0 .. 1.85m] # Height: Z in [0 .. 1.85m]
x0 = int(30.40 * FP_1) x0 = int(30.40 * FP_1)
x1 = int(30.95 * FP_1) x1 = int(30.95 * FP_1)
y0 = int(24.575 * FP_1) y0 = int(23.075 * FP_1)
y1 = int(25.425 * FP_1) y1 = int(23.925 * FP_1)
zHigh = int(1.85 * FP_1) zHigh = int(1.85 * FP_1)
# Back Face (against wall: X = x1) - Frame 2 # Back Face (against wall: X = x1) - Frame 2
@ -277,11 +310,11 @@ def render_scene(cam_x, cam_y, cam_angle, out_path):
if __name__ == '__main__': if __name__ == '__main__':
# 1. Front View: Standing near billiards at (26.0, 25.0) looking East (angle=0) past table at Jukebox # 1. Front View: Standing near billiards at (26.0, 25.0) looking East (angle=0) past table at Jukebox
render_scene(26.0, 25.0, 0, DOCS_DIR / 'jukebox_3d_front.png') render_scene(26.0, 24.5, 0, DOCS_DIR / 'jukebox_3d_front.png')
# 2. Angle View: Standing at (27.5, 22.5) looking South-East (angle=480) at pool table and Jukebox # 2. Angle View: Standing at (27.5, 22.5) looking South-East (angle=480) at pool table and Jukebox
render_scene(27.5, 22.5, 480, DOCS_DIR / 'jukebox_3d_angle.png') render_scene(27.5, 21.0, 128, DOCS_DIR / 'jukebox_3d_angle.png')
# 3. Close-up View: Standing at (29.2, 25.0) looking East (angle=0) right at Jukebox # 3. Close-up View: Standing at (29.2, 25.0) looking East (angle=0) right at Jukebox
render_scene(29.2, 25.0, 0, DOCS_DIR / 'jukebox_3d_close.png') render_scene(29.2, 23.5, 0, DOCS_DIR / 'jukebox_3d_close.png')
# 4. Side View: Standing at (30.0, 27.5) looking North (angle=384) at South side of Jukebox # 4. Side View: Standing at (30.0, 27.5) looking North (angle=384) at South side of Jukebox
render_scene(30.0, 27.5, 384, DOCS_DIR / 'jukebox_3d_side.png') render_scene(30.6, 25.5, 768, DOCS_DIR / 'jukebox_3d_side.png')
print('All Jukebox 3D preview frames rendered to docs/previews_minigames/!') print('All Jukebox 3D preview frames rendered to docs/previews_minigames/!')