Skip to content

Toast

ss-gameforge-toast lets you display temporary, non-intrusive notifications in your game. It supports 5 predefined styles, 9 screen positions, stacking, custom themes, and animated icons.

  1. Download ss-gameforge-toast from the releases page.
  2. Copy addons/ss-gameforge-toast/ into your project’s res://addons/.
  3. Enable ss-gameforge-singleton and ss-gameforge-toast in Project Settings → Plugins.

Add this to your main scene or autoload:

func _enter_tree() -> void:
SingletonNode.ensure_for(ToastService, get_tree().root, "ToastService")
# Show different toast types
ToastService.i.info("Server is under maintenance")
ToastService.i.success("Game saved successfully!")
ToastService.i.danger("Connection lost")
ToastService.i.loader("Loading data...")
# Custom options on any toast
ToastService.i.info("Custom notification", {
"duration": 5.0,
"font_size": 18,
"position": ToastConstants.ToastPosition.TOP_CENTER,
"background_color": Color("#FF6B6B"),
"text_color": Color("#FFFFFF")
})
MethodStyleDefault colorUse for
info(text, overrides)INFOBlue #2D9CDBGeneral messages
success(text, overrides)SUCCESSGreen #27AE60Completed operations
danger(text, overrides)DANGERRed #EB5757Errors and warnings
custom(text, overrides)CUSTOMDark gray #333333Custom styling
loader(text, overrides)LOADERBlue (spinning icon)Async operations
show(text, style, overrides)AnyGeneric entry point
# Generic show() with explicit style
ToastService.i.show("Message", ToastConstants.ToastStyle.SUCCESS, {"duration": 3.0})

Nine positions are available via ToastConstants.ToastPosition:

enum ToastPosition {
TOP_LEFT, TOP_CENTER, TOP_RIGHT,
CENTER_LEFT, CENTER, CENTER_RIGHT,
BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT # default
}
ToastService.i.success("Top right", {
"position": ToastConstants.ToastPosition.TOP_RIGHT
})
# Custom margin from screen edges
ToastService.i.info("With margin", {
"position": ToastConstants.ToastPosition.TOP_RIGHT,
"position_margin": Vector2(50, 50)
})

Pass any of these keys in the overrides dictionary:

KeyTypeDefaultDescription
background_colorColorStyle defaultToast background
text_colorColorStyle defaultText color
font_sizeint14Font size in pixels
iconTexture2DStyle defaultIcon texture
icon_colorColorColor.WHITEIcon tint
icon_sizefloat18.0Icon size in pixels
icon_spinboolfalseEnable icon rotation
icon_spin_speedfloat1.5Rotation speed (rad/s)
paddingfloat10.0Internal padding
corner_radiusfloat10.0Corner radius
positionToastPositionBOTTOM_CENTERScreen position
position_marginVector2Vector2(16, 16)Distance from screen edges
durationfloat2.0Visible time in seconds
@export var theme: ToastTheme # Global visual theme
@export var max_queue: int = 50 # Maximum queued toasts
@export var stack_toasts: bool = true # Stack vs. single mode
@export var max_visible: int = 4 # Maximum visible at once
@export var stack_spacing: float = 8.0 # Pixels between stacked toasts

Multiple toasts are visible simultaneously, stacked at their position.

ToastService.i.stack_toasts = true
ToastService.i.max_visible = 5
ToastService.i.stack_spacing = 10.0
ToastService.i.info("Toast 1")
ToastService.i.info("Toast 2")
ToastService.i.info("Toast 3") # All visible at once

Stack direction follows position:

  • TOP positions → stack downward
  • BOTTOM positions → stack upward
  • CENTER positions → stack downward

Each position maintains an independent stack:

# Each group stacks independently
ToastService.i.info("Center 1", {"position": ToastConstants.ToastPosition.CENTER})
ToastService.i.info("Center 2", {"position": ToastConstants.ToastPosition.CENTER})
ToastService.i.success("Right 1", {"position": ToastConstants.ToastPosition.CENTER_RIGHT})

One toast at a time. The next waits for the current to finish.

ToastService.i.stack_toasts = false

Define a reusable ToastTheme resource to style all toasts consistently.

Right-click in the FileSystem → New Resource → select ToastTheme. Configure:

  • Duration, font_size, icon_size, corner_radius, padding, position_margin
  • Per-style: info_background_color, info_text_color, info_icon, and equivalents for success_, danger_, custom_, loader_
var my_theme = ToastTheme.new()
my_theme.duration = 3.0
my_theme.font_size = 16
my_theme.corner_radius = 8.0
my_theme.position = ToastConstants.ToastPosition.TOP_CENTER
my_theme.info_background_color = Color("#3498DB")
my_theme.success_background_color = Color("#2ECC71")
my_theme.danger_background_color = Color("#E74C3C")
func _ready() -> void:
ToastService.i.theme = preload("res://themes/my_toast_theme.tres")
func unlock_achievement(name: String, description: String) -> void:
ToastService.i.success("Achievement Unlocked!", {
"duration": 5.0,
"font_size": 18,
"icon": preload("res://icons/trophy.svg"),
"icon_color": Color.GOLD,
"position": ToastConstants.ToastPosition.TOP_CENTER,
})
await get_tree().create_timer(0.5).timeout
ToastService.i.info(description, {
"duration": 4.0,
"position": ToastConstants.ToastPosition.TOP_CENTER
})
func show_damage(amount: int, is_critical: bool) -> void:
var msg := "%d damage" % amount
var opts := { "position": ToastConstants.ToastPosition.CENTER, "duration": 1.5 }
if is_critical:
msg = "CRITICAL! " + msg
opts["background_color"] = Color("#FF0000")
opts["text_color"] = Color.YELLOW
ToastService.i.danger(msg, opts)
func show_heal(amount: int) -> void:
ToastService.i.success("+%d HP" % amount, {
"position": ToastConstants.ToastPosition.CENTER,
"duration": 1.5,
"font_size": 20,
})
func _on_autosave() -> void:
ToastService.i.loader("Saving...", {
"position": ToastConstants.ToastPosition.BOTTOM_RIGHT,
"duration": 1.0
})
await perform_save()
ToastService.i.success("Game saved", {
"position": ToastConstants.ToastPosition.BOTTOM_RIGHT
})

Toasts don’t appear

  • Confirm ensure_for(ToastService, ...) is called before any toast.
  • Confirm both ss-gameforge-singleton and ss-gameforge-toast are enabled in Plugins.

Icons appear blank

  • Check the icon file path and verify the .import file exists.
  • Use assert(preload("res://...") != null) to catch missing resources early.

Performance with many toasts

  • Keep max_visible between 3–5.
  • Reduce max_queue if you don’t need large queues.
  • Use shorter durations.