GF

godot-fun/godot-framework

Developer tools
91 stars 품질 85 트렌드 85

A lightweight Godot framework + agent skills for building and shipping games

개요

A lightweight Godot framework + agent skills for building and shipping games

README

godot-framework

A lightweight Godot framework + agent skills for building and shipping games

Quick start

  1. Copy the zfoo/ folder into your Godot project.

  2. Register the framework scene as an Autoload (Project → Project Settings → Autoload):

    Name Path
    GodotFramework res://zfoo/GodotFramework.tscn
  3. That’s it — have fun!


Usage

AI — OpenAI-compatible chat

# Set OPENAI_API_KEY env, or override OpenAiClient.api_key / base_url / model
var reply := await OpenAiClient.async_chat("hello", "you are a helpful assistant")

# Multi-turn
var messages: Array[ChatMessage] = []
messages.append(ChatMessage.new(ChatMessage.ROLE_USER, "hello"))
var reply2 := await OpenAiClient.async_chat_messages(messages)

Alert — Floating toast messages

Alert.alert("Saved successfully", Colors.success)
Alert.alert("Network error", Colors.error)

Audio — play music, sound, voice,SoundEffect

# Single track or playlist (auto cross-fade near end of track)
Audio.play_music("res://audio/bgm.mp3")
Audio.play_musics(["res://audio/a.mp3", "res://audio/b.mp3"])

# One-shot sound / voice
await Audio.play_voice("res://audio/narration.mp3")

# Multi-channel SFX (overlapping sounds on SoundEffect bus)
Audios.play("res://audio/click.mp3", 0.8)

Animation

# plays a one-shot sprite sheet animation and removes itself when finished. Multi-row sheet: 4 columns × 4 rows, scale 0.5, 13 fps
EffectAnimation2D.spawn(Vector2(500, 200), self, "res://effects/attack.png", Vector2i(4, 4), 0.5, 13)

Unit tests

  • Attach zfoo/gdtest/UnitTest.gd to a scene; it scans .gd files in the scene’s folder.
  • In each file, every no-arg method whose name starts or ends with test (case-insensitive) is run as a unit test.

Integration tests

  • Attach zfoo/gdtest/IntegrationTest.gd to a scene; it scans the scene’s folder for .tscn whose name starts or ends with test, then runs them one by one.
  • Each finished test scene must emit gdf.events.test_passed (UnitTest does this automatically).

HotUpdate

  • Godot PCK Hot Update for single pck
  • Workflow: Launch App → Check Version → Download PCK → Verify MD5 → Load PCK → Enter Game

Http

# GET request
var response := await HttpHelper.async_get("https://api.example.com/data")
if response.success:
    Log.info(response.get_body_string())

Log

  • file logger at {user_data}/logs/godot.log
Log.info("player login uid:[{}]", user_id)
Log.error("load failed path:[{}] err:[{}]", path, err)

Network

  • support TcpClient, TcpClientThread, WebsocketClient, WebsocketClientThread
# Create a network seesion
# `ICodec` for encode/decode
var session: Session = TcpClient.new(Codec.new(), "127.0.0.1:80")

# Register receiver (typically at login / session init)
Router.register_receiver(LoginResponse, func(packet: LoginResponse) -> void: on_login_response(packet))

# Send message is Fire-and-forget
Router.send(session, SomeRequest.new())

# Request–response (waits for matching reply or timeout)
var reply: LoginResponse = await Router.async_ask(session, LoginRequest.new())

ResourceHelper — async loading

  • Avoid blocking the main thread when loading large assets.
var texture: Texture2D = await ResourceHelper.async_load("res://assets/icon.svg")
var scene: PackedScene = await ResourceHelper.async_load("res://scene/Level.tscn")

SceneHelper — scenes & nodes

# Switch scene with fade transition (default: RectTransitionFade)
await SceneHelper.async_change_scene_to_file("res://scene/Main.tscn")

# Custom slide transition
await SceneHelper.async_change_scene_to_file("res://scene/Main.tscn", RectTransitionSlide.new())

# Instantiate a scene as child of a node
var node := SceneHelper.add_scene_to_node(load("res://scene/Popup.tscn"), self)

# Safe queue_free
SceneHelper.queue_free(old_node)

SchedulerBus — delayed & periodic tasks

var sw := StopWatch.new() # sw.cost_seconds()

# Run once after 1000 ms
SchedulerBus.schedule(func() -> void: do_something(), 1000)

# Run every 2000 ms (optional timer name, optional sub-thread)
SchedulerBus.schedule_at_fixed_rate(func() -> void: poll_status(), 2000)

Setting — persistent user config

Setting.set_bool("sound_enabled", true)
Setting.set_string("nickname", "player1")
Setting.save()

var enabled := Setting.get_bool("sound_enabled", false)
var name := Setting.get_string("nickname", "")

Utils — common helpers

  • Also available: ArrayUtils, CollectionUtils, NumberUtils, NetUtils, HttpUtils, IdUtils, RateLimitUtils.
# StringUtils
var msg := StringUtils.format("score:[{}] name:[{}]", score, name)
if StringUtils.is_blank(text):
    return

# TimeUtils
var ts := TimeUtils.now()              # cached ms timestamp (updated each second)
var now_str := TimeUtils.date()        # "yyyy-mm-dd hh:mm:ss"

# JsonUtils — plain objects with public fields
var obj = JsonUtils.json_to_object('{"name":"test","age":10}', Student)
var json := JsonUtils.object_to_json(obj)

# FileUtils
FileUtils.write_string_to_file("user://log.txt", content)
var text := FileUtils.read_file_to_string("user://log.txt")
FileUtils.delete_file("user://log.txt")

# RandomUtils
var n := RandomUtils.random_int_limit(100)
var item = RandomUtils.random_ele(items)

# ThreadUtils — non-blocking wait on main thread
await ThreadUtils.async_sleep(500)

# NodeUtils
var node := NodeUtils.load_and_instantiate("res://scene/Popup.tscn")

GodotFramework — gdf

The Autoload node runs GodotFramework.gd, whose global class name is gdf.

# Defer a callable to the main thread (useful from network / worker callbacks)
gdf.callable_deferred(func() -> void: refresh_ui())

# Graceful exit (waits a few frames before quit)
await gdf.quit()

Agent Support

Shared: root AGENTS.md, .cursor/skills/. For Codex / Claude: copy, then replace every .cursor path in the copied tree with that platform’s directory.

Agent Setup
Cursor Native Support
OpenCode Native Support — opencode.json
Codex Keep root AGENTS.md. Copy .cursor/skills → .agents/skills, then replace .cursor with .agents in skills/
Claude Copy root AGENTS.md → CLAUDE.md. Copy .cursor/skills → .claude/skills, then replace .cursor with .claude in skills/

Agent Skills

Batch asset tools in .cursor/skills/. Run from repo root; use each skill’s script; never overwrite sources. Commands and flags: see each skill’s SKILL.md.

Category Pipeline Skills
AI Text-to-speech 1 skill
Audio to-wav → trim → loudness → export 9 skills
Image to-png → watermark → split → background → trim / resize 8 skills
Video watermark → mute / wav → 4K → merge → compress / OGV 9 skills
Storyboard Storyboard → HTML preview / VO / video → AV mix → merge → publish 4 skills
Other Naming, commits 2 skills

Sync framework into your project

Use sync-godot-framework.ps1 to pull the latest zfoo/, .cursor/, AGENTS.md, and opencode.json from godot-fun/godot-framework into a game project.

  1. Copy sync-godot-framework.ps1 into your Godot project root (same level as project.godot).
  2. From that root, run:
.\sync-godot-framework.ps1

What it does:

  • Shallow-clones the framework repo into a temp folder
  • Overlays .cursor/ (skills) onto your project
  • Replaces zfoo/, root AGENTS.md, and opencode.json with the upstream copies
  • Deletes the temp clone when finished

Requires Git and PowerShell. Review the diff after sync before committing.

View this README on GitHub

추천 도구

다른 키워드를 입력하거나 필터를 제거해 보세요.

설치

npx skillfish add godot-fun/godot-framework