Token导航 LogoToken导航TokenDH.com
待分类权限需确认github未标认证来源可访问许可证需确认审计通过

godot-genre-rhythm戈多流派节奏

Agent Skill

godot-genre-rhythm 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

1,599

周安装

68

GitHub Stars

137

下载量

560
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:godot-genre-rhythm(戈多流派节奏)
来源仓库:https://github.com/thedivergentai/gd-agentic-skills
仓库路径:skills/godot-genre-rhythm
安装命令:
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-genre-rhythm
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-genre-rhythm

简介

godot-genre-rhythm 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中围绕仓库状态、代码变更或协作事项进行整理。
  • 通过 npx skills add 命令从指定仓库安装并使用该技能。
  • 安装前需确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

Genre: Rhythm

Expert blueprint for rhythm games emphasizing audio-visual synchronization and flow state.

NEVER Do (Expert Anti-Patterns)

Audio Sync & Logic

  • NEVER use Time.get_ticks_msec() for rhythm sync; strictly use AudioServer.get_time_since_last_mix() combined with latency offsets for sub-frame accuracy.
  • NEVER process song logic in _process(); strictly use _physics_process() or a conductor loop to ensure deterministic timing regardless of render frames.
  • NEVER use _process() to capture hit inputs; strictly use _input(event) to record the exact timestamp of the button press event.
  • NEVER scale engine time_scale for song speed; strictly use AudioStreamPlayer.pitch_scale to adjust speed and avoid globally breaking physics logic.
  • NEVER ignore Audio Latency Calibration; strictly provide a manual offset menu to compensate for varied hardware (Bluetooth vs Wired).
  • NEVER use yield or await for beat timing; strictly use a sample-accurate Delta Accumulator tied to the audio clock.
  • NEVER assume a constant BPM; strictly build your conductor to handle a Tempo Map for complex track changes.

Feedback & Performance

  • NEVER judge inputs based on world position (pixels); strictly judge against the Song's Elapsed Time (ms) to ensure consistency across resolutions.
  • NEVER play hit sounds with static pitch; strictly add ±5% Random Pitch Variation to hit sounds to avoid the "machine gun" effect.
  • NEVER use tight timing windows (e.g., <25ms) for all players; strictly use Wider Windows for Beginners to prevent immediate frustration.
  • NEVER instantiate note nodes every beat; strictly use Object Pooling to recycle note instances and prevent GC spikes during dense tracks.
  • NEVER use standard Area2D signals for rhythmic hits; strictly Poll Inputs in the conductor loop to compare against target timestamps.
  • NEVER calculate FFT for visualization on the main thread; strictly use AudioEffectSpectrumAnalyzerInstance for optimized engine-side analysis.
  • NEVER allow note spamming/mashing; strictly penalize misses or break combos to maintain the game's integrity.
  • NEVER use load() dynamically during gameplay; strictly use ResourceLoader.load_threaded_request() to avoid thread stalling.
  • NEVER forget to pause the conductor/ highway; strictly sync with the audio player's pause state to prevent notes from scrolling while the music is stopped.

🛠 Expert Components (scripts/)

Original Expert Patterns

Modular Components


Core Loop

Music Plays → Notes Appear → Player Inputs → Timing Judged → Score/Feedback → Combo Builds

Skill Chain

godot-project-foundations, godot-input-handling, sound-manager, animation, ui-framework


Audio Synchronization

THE most critical aspect - notes MUST align perfectly with audio.

Music Time System

class_name MusicConductor
extends Node

signal beat(beat_number: int)
signal measure(measure_number: int)

@export var bpm := 120.0
@export var music: AudioStream

var seconds_per_beat: float
var song_position: float = 0.0  # In seconds
var song_position_in_beats: float = 0.0
var last_reported_beat: int = 0

@onready var audio_player: AudioStreamPlayer

func _ready() -> void:
    seconds_per_beat = 60.0 / bpm
    audio_player.stream = music

func _process(_delta: float) -> void:
    # Get precise audio position with latency compensation
    song_position = audio_player.get_playback_position() + AudioServer.get_time_since_last_mix()

    # Convert to beats
    song_position_in_beats = song_position / seconds_per_beat

    # Emit beat signals
    var current_beat := int(song_position_in_beats)
    if current_beat > last_reported_beat:
        beat.emit(current_beat)
        if current_beat % 4 == 0:
            measure.emit(current_beat / 4)
        last_reported_beat = current_beat

func start_song() -> void:
    audio_player.play()
    song_position = 0.0
    last_reported_beat = 0

func beats_to_seconds(beats: float) -> float:
    return beats * seconds_per_beat

func seconds_to_beats(secs: float) -> float:
    return secs / seconds_per_beat

Note System

Note Data Structure

class_name NoteData
extends Resource

@export var beat_time: float  # When to hit (in beats)
@export var lane: int  # Which input lane (0-3 for 4-key, etc.)
@export var note_type: NoteType
@export var hold_duration: float = 0.0  # For hold notes (in beats)

enum NoteType { TAP, HOLD, SLIDE, FLICK }

Chart/Beatmap Loading

class_name ChartLoader
extends Node

func load_chart(chart_path: String) -> Array[NoteData]:
    var notes: Array[NoteData] = []
    var file := FileAccess.open(chart_path, FileAccess.READ)

    while not file.eof_reached():
        var line := file.get_line()
        if line.is_empty() or line.begins_with("#"):
            continue

        var parts := line.split(",")
        var note := NoteData.new()
        note.beat_time = float(parts[0])
        note.lane = int(parts[1])
        note.note_type = NoteType.get(parts[2]) if parts.size() > 2 else NoteType.TAP
        note.hold_duration = float(parts[3]) if parts.size() > 3 else 0.0
        notes.append(note)

    notes.sort_custom(func(a, b): return a.beat_time < b.beat_time)
    return notes

Note Highway / Receptor

class_name NoteHighway
extends Control

@export var scroll_speed := 500.0  # Pixels per second
@export var hit_position_y := 100.0  # From bottom
@export var note_scene: PackedScene
@export var look_ahead_beats := 4.0

var active_notes: Array[NoteVisual] = []
var chart: Array[NoteData]
var next_note_index: int = 0

func _process(_delta: float) -> void:
    spawn_upcoming_notes()
    update_note_positions()

func spawn_upcoming_notes() -> void:
    var look_ahead_time := MusicConductor.song_position_in_beats + look_ahead_beats

    while next_note_index < chart.size():
        var note_data := chart[next_note_index]
        if note_data.beat_time > look_ahead_time:
            break

        var note_visual := note_scene.instantiate() as NoteVisual
        note_visual.setup(note_data)
        note_visual.position.x = get_lane_x(note_data.lane)
        add_child(note_visual)
        active_notes.append(note_visual)
        next_note_index += 1

func update_note_positions() -> void:
    for note in active_notes:
        var beats_until_hit := note.data.beat_time - MusicConductor.song_position_in_beats
        var seconds_until_hit := MusicConductor.beats_to_seconds(beats_until_hit)

        # Note scrolls down from top
        note.position.y = (size.y - hit_position_y) - (seconds_until_hit * scroll_speed)

        # Remove if too far past
        if note.position.y > size.y + 100:
            if not note.was_hit:
                register_miss(note.data)
            note.queue_free()
            active_notes.erase(note)

Timing Judgment

class_name JudgmentSystem
extends Node

signal note_judged(judgment: Judgment, note: NoteData)

enum Judgment { PERFECT, GREAT, GOOD, BAD, MISS }

# Timing windows in milliseconds (symmetric around hit time)
const WINDOWS := {
    Judgment.PERFECT: 25.0,
    Judgment.GREAT: 50.0,
    Judgment.GOOD: 100.0,
    Judgment.BAD: 150.0
}

func judge_input(input_time: float, note_time: float) -> Judgment:
    var difference := abs(input_time - note_time) * 1000.0  # ms

    if difference <= WINDOWS[Judgment.PERFECT]:
        return Judgment.PERFECT
    elif difference <= WINDOWS[Judgment.GREAT]:
        return Judgment.GREAT
    elif difference <= WINDOWS[Judgment.GOOD]:
        return Judgment.GOOD
    elif difference <= WINDOWS[Judgment.BAD]:
        return Judgment.BAD
    else:
        return Judgment.MISS

func get_timing_offset(input_time: float, note_time: float) -> float:
    # Positive = late, Negative = early
    return (input_time - note_time) * 1000.0

Scoring System

class_name RhythmScoring
extends Node

signal score_changed(new_score: int)
signal combo_changed(new_combo: int)
signal combo_broken

const JUDGMENT_SCORES := {
    Judgment.PERFECT: 100,
    Judgment.GREAT: 75,
    Judgment.GOOD: 50,
    Judgment.BAD: 25,
    Judgment.MISS: 0
}

const COMBO_MULTIPLIER_THRESHOLDS := {
    10: 1.5,
    25: 2.0,
    50: 2.5,
    100: 3.0
}

var score: int = 0
var combo: int = 0
var max_combo: int = 0

func register_judgment(judgment: Judgment) -> void:
    if judgment == Judgment.MISS:
        if combo > 0:
            combo_broken.emit()
        combo = 0
    else:
        combo += 1
        max_combo = max(max_combo, combo)

    var base_score := JUDGMENT_SCORES[judgment]
    var multiplier := get_combo_multiplier()
    var earned := int(base_score * multiplier)

    score += earned
    score_changed.emit(score)
    combo_changed.emit(combo)

func get_combo_multiplier() -> float:
    var mult := 1.0
    for threshold in COMBO_MULTIPLIER_THRESHOLDS:
        if combo >= threshold:
            mult = COMBO_MULTIPLIER_THRESHOLDS[threshold]
    return mult

Input Processing

class_name RhythmInput
extends Node

@export var lane_actions: Array[StringName] = [
    &"lane_0", &"lane_1", &"lane_2", &"lane_3"
]

var held_notes: Dictionary = {}  # lane: NoteData for hold notes

func _input(event: InputEvent) -> void:
    for i in lane_actions.size():
        if event.is_action_pressed(lane_actions[i]):
            process_lane_press(i)
        elif event.is_action_released(lane_actions[i]):
            process_lane_release(i)

func process_lane_press(lane: int) -> void:
    var current_time := MusicConductor.song_position
    var closest_note := find_closest_note_in_lane(lane, current_time)

    if closest_note:
        var note_time := MusicConductor.beats_to_seconds(closest_note.beat_time)
        var judgment := JudgmentSystem.judge_input(current_time, note_time)

        if judgment != Judgment.MISS:
            hit_note(closest_note, judgment)
            if closest_note.note_type == NoteType.HOLD:
                held_notes[lane] = closest_note

func process_lane_release(lane: int) -> void:
    if held_notes.has(lane):
        var hold_note := held_notes[lane]
        var hold_end_time := hold_note.beat_time + hold_note.hold_duration
        var current_beat := MusicConductor.song_position_in_beats

        # Check if released at correct time
        if abs(current_beat - hold_end_time) < 0.25:  # Quarter beat tolerance
            complete_hold_note(hold_note)
        else:
            drop_hold_note(hold_note)

        held_notes.erase(lane)

Visual Feedback

func show_judgment_splash(judgment: Judgment, position: Vector2) -> void:
    var splash := judgment_sprites[judgment].instantiate()
    splash.position = position
    add_child(splash)

    var tween := create_tween()
    tween.tween_property(splash, "scale", Vector2(1.2, 1.2), 0.1)
    tween.tween_property(splash, "scale", Vector2(1.0, 1.0), 0.1)
    tween.tween_property(splash, "modulate:a", 0.0, 0.3)
    tween.tween_callback(splash.queue_free)

func pulse_receptor(lane: int, judgment: Judgment) -> void:
    var receptor := lane_receptors[lane]
    receptor.modulate = judgment_colors[judgment]

    var tween := create_tween()
    tween.tween_property(receptor, "modulate", Color.WHITE, 0.15)

Common Pitfalls

PitfallSolution
Audio desyncUse AudioServer.get_time_since_last_mix() latency compensation
Unfair judgmentGenerous windows at low difficulty, offset calibration
Notes bunched visuallyAdjust scroll speed or spawn timing
Hold notes jankySeparate hold body and tail rendering
Frame drops cause missesDecouple input from framerate

Godot-Specific Tips

  1. Audio latency: Calibrate with AudioServer and custom offset
  2. Input polling: Use _input not _process for precise timing
  3. Shaders: UV scrolling for note highways
  4. Particles: Use GPUParticles2D for hit effects

Reference

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

35.38%
按下载量换算198

Claude

27.81%
按下载量换算156

Cursor

19.07%
按下载量换算107

Gemini CLI

8.37%
按下载量换算47

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

权限需确认

当前来源未能明确判断权限范围,默认进入异常复核队列。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills