Skip to content

Commit 232eca7

Browse files
committed
fix(release): use versionless SFX asset and publish draft after upload so latest link never 404s
1 parent 2924fd1 commit 232eca7

4 files changed

Lines changed: 90 additions & 59 deletions

File tree

.claude/skills/release/SKILL.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ changelog, no mod asset, no new tag.
5959

6060
```bash
6161
source .env # sets CUE_SFX_SOURCE_DIR
62-
python3 bin/build_sfx_asset.py "$CUE_SFX_SOURCE_DIR" --out "/tmp/renpy_cue_sfx_<ver>.zip"
62+
python3 bin/build_sfx_asset.py "$CUE_SFX_SOURCE_DIR" --out "/tmp/cue_sfx.zip"
6363
```
6464
Verify `test_bad` is not in the zip.
6565

@@ -78,7 +78,11 @@ changelog, no mod asset, no new tag.
7878
- Swap in the categorized notes:
7979
`gh release edit v<ver> --notes-file <notes-file>`
8080
- Upload the SFX asset:
81-
`gh release upload v<ver> /tmp/renpy_cue_sfx_<ver>.zip --clobber`
81+
`gh release upload v<ver> /tmp/cue_sfx.zip --clobber`
82+
- Publish the release (CI created it as a draft; drafts are invisible to
83+
`releases/latest`, so the stable SFX link never 404s before the pack is
84+
attached):
85+
`gh release edit v<ver> --draft=false`
8286

8387
11. **Report.** Print the release URL and confirm both assets are attached.
8488

@@ -101,7 +105,7 @@ Standalone: never touches the full-release steps above.
101105
3. **Build the pack.**
102106

103107
```bash
104-
python3 bin/build_sfx_asset.py "$CUE_SFX_SOURCE_DIR" --out "/tmp/renpy_cue_sfx_<ver>.zip"
108+
python3 bin/build_sfx_asset.py "$CUE_SFX_SOURCE_DIR" --out "/tmp/cue_sfx.zip"
105109
```
106110

107111
4. **Verify the zip** has the category folders and no `test_bad`.
@@ -115,7 +119,7 @@ Standalone: never touches the full-release steps above.
115119
7. **Upload** (in-place overwrite of the existing pack):
116120

117121
```bash
118-
gh release upload <tag> /tmp/renpy_cue_sfx_<ver>.zip --clobber
122+
gh release upload <tag> /tmp/cue_sfx.zip --clobber
119123
```
120124

121125
8. **Report.** Print the release URL and confirm the SFX asset is attached.
@@ -125,5 +129,11 @@ Standalone: never touches the full-release steps above.
125129
- The SFX asset comes from the local machine (its source is not in git), so the
126130
skill uploads it after CI creates the release. The mod zip is CI-built.
127131
- First-release detection: `git tag --list 'v*'` is empty, or no prior release.
128-
- `/release sfx` overwrites `renpy_cue_sfx_<ver>.zip` in place — users must
132+
- `/release sfx` overwrites `cue_sfx.zip` in place — users must
129133
re-download the pack from the same release page to pick up the change.
134+
- The SFX asset name is deliberately versionless so the README link
135+
`https://github.com/guanzo/renpy-cue/releases/latest/download/cue_sfx.zip`
136+
stays stable across releases. `releases/latest` resolves only to published
137+
releases, not drafts. The release workflow creates each release as a draft
138+
and the full flow publishes it after the SFX upload, so the link never
139+
resolves to a release missing the pack.

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,5 @@ jobs:
7979
gh release create "$GITHUB_REF_NAME" \
8080
--title "Ren'Py Cue $GITHUB_REF_NAME" \
8181
--generate-notes \
82+
--draft \
8283
"renpy_cue_${GITHUB_REF_NAME#v}.zip"

README.md

Lines changed: 73 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,99 @@
1+
<p align="center">
2+
<img src="./cue_lib/images/branding/cue-wordmark.png" alt="Ren'Py Cue" width="200">
3+
</p>
4+
15
# Ren'Py Cue
26

3-
Ren'Py Cue lets you add your own sound effects, music, and video effects to [Ren'Py](https://www.renpy.org/) visual novels while you play — without editing the game's scripts.
7+
Ren'Py Cue lets you add your own sound effects, music, and video effects to [Ren'Py](https://www.renpy.org/) visual novels while you play, without editing the game's scripts.
8+
49

5-
Open Cue over the game, add sounds to the current image, dialogue, video, or other trigger, and Cue remembers your setup and plays them automatically when that trigger happens again.
10+
**Need help, want to share your setup, or just hang out? [Join the Cue Discord](https://discord.gg/kAVtFGcQYm)**
611

7-
<sub>Cue was built with AVNs in mind, and the official SFX pack contains NSFW audio. Cue itself works the same on any Ren'Py game, and you can load your own SFX instead if you'd rather keep things SFW.</sub>
12+
## Contents
13+
14+
* [Getting Started](#getting-started)
15+
* [How Cue Works](#how-cue-works)
16+
* [What You Can Do](#what-you-can-do)
17+
* [Video Speed & Effects](#video-speed--effects)
18+
* [Intensity Groups](#intensity-groups)
19+
* [Using Cue With Multiple Games](#using-cue-with-multiple-games)
20+
* [Settings and Your Data](#settings-and-your-data)
21+
* [Requirements](#requirements)
22+
* [For Developers](#for-developers)
823

924
## Getting Started
1025

1126
### 1. Install Cue
1227

13-
1. Download and extract Cue.
14-
2. Open the game's `game` folder.
15-
3. Copy the `renpy_cue` folder into it.
28+
1. Download and extract the [latest release](https://github.com/guanzo/renpy-cue/releases/latest).
29+
2. Drop the `renpy_cue` folder into the game's `game` folder.
1630

1731
```text
1832
Your Game/
19-
└── game/
20-
└── renpy_cue/
21-
└── cue_lib/
33+
└─ game/
34+
└─ renpy_cue/
2235
```
2336

2437
### 2. Add some sounds
2538

26-
Cue needs sound files before it can play anything. Download the Cue SFX pack and extract it. Then open Cue, go to **SFX Library**, and click **Open SFX Folder**. Copy the extracted audio files into the folder that opens.
39+
Cue needs sound files before it can play anything. You can start with either of these:
2740

28-
### 3. Add your first sound effect
41+
- **[Cue NSFW SFX Pack](https://github.com/guanzo/renpy-cue/releases/latest/download/cue_sfx.zip)**: A curated collection selected for Cue.
42+
- **[OPENNSFW](https://opennsfw.carrd.co/)**: High quality SFX + Voice Pack. Contains Free and Paid versions.
2943

30-
1. Play until you reach an image where you want a sound.
31-
2. Press `` ` `` (backtick) or `Shift+Alt+E` to open Cue.
32-
3. Find a sound in **SFX Library**.
33-
4. Click the **+** button.
34-
5. If the current image doesn't have a pool yet, Cue creates one automatically.
44+
Download and extract the pack you want to use. Then run the game, open Cue, go to **SFX Library**, and click **Open SFX Folder**. Copy the extracted audio files into the folder that opens.
3545

36-
**[Screenshot: the game with the Cue overlay open, sitting on an image.]** Annotate ① the Image SFX pool / active pool, and ② the SFX Library panel.
46+
Cue was built with AVNs in mind, but Cue itself works the same on any Ren'Py game.
3747

38-
### 4. Keep playing
48+
### 3. Add your first sound effect
3949

40-
Close Cue and continue playing. When the same image appears again, Cue plays sounds from its pool automatically.
50+
1. Start a replay and play until you reach an image where you want a sound.
51+
2. Press `` ` `` (backtick) or `Shift+Alt+E` to open Cue.
52+
3. Find a sound in **SFX Library** and click the **+** button.
53+
4. The next time this image appears on screen, your chosen sound will play.
4154

4255
## How Cue Works
4356

4457
Cue attaches **SFX pools** to triggers in a game.
4558

4659
A pool is a collection of sound files and folders. When its trigger occurs, Cue plays from that pool. A trigger can be:
4760

48-
- an image
49-
- a dialogue line
50-
- a video timestamp
51-
- a repeating loop
52-
- a screen shake
61+
* an image
62+
* a dialogue line
63+
* a video timestamp
64+
* a repeating loop
65+
* a screen shake
66+
67+
A trigger can have more than one pool.
5368

54-
A trigger can have more than one pool. The **active pool** is the one you're currently editing and the one new sounds are added to.
69+
Pools can overlap when they play. More than one sound can play at once, and each pool can be set to overlap freely, cross-fade, or wait for a quiet moment before playing. This is an advanced setting you can leave alone until you need it.
5570

56-
Pools can also overlap when they play — more than one sound can sound at once, and each pool can be set to overlap freely, cross-fade, or wait for a quiet moment before playing. This is an advanced setting you can leave alone until you need it.
71+
<b>You can add individual files to a pool, but folders are recommended.</b> Any changes you make to a folder's contents are automatically reflected in the pool, so you can add or remove files later without updating the pool itself.
72+
73+
Some games simulate video using sequences of images rather than actual video files. These sequences cannot currently be used as triggers, but support is planned for a future version.
5774

5875
## What You Can Do
5976

60-
- **Add sound effects** to images, dialogue, videos, loops, and screen shakes.
61-
- **Build reusable SFX pools** from your own files and folders, and save common setups as **presets**.
62-
- **Customize replay music** with your own music or the game's existing tracks.
63-
- **Add sounds to videos** with draggable timeline markers.
64-
- **Create video speed variants** and switch or sequence between speeds while playing.
65-
- **Reuse your setup across games** with shared audio, music, presets, and configuration.
77+
* **Add sound effects** to triggers.
78+
* **Build reusable SFX pools** from your own files and folders, and save common setups as **presets**.
79+
* **Customize replay music** with your own music or the game's existing tracks.
80+
* **Create video speed variants** and switch or sequence between speeds while playing.
81+
* **Reuse your setup across games** with shared audio, music, presets, and configuration.
82+
* **Export and import** your Cue setup to share it with others or move it to different machines.
6683

6784
## Video Speed & Effects
6885

6986
**Requires ffmpeg.**
7087

71-
Cue can pre-render slow-motion or fast-motion copies of any movie, then let you switch speeds while playing — including multi-speed sequences and procedural **auto-speed** rhythms (roller_coaster, build_up, edge, tease, and more) that vary each playthrough.
88+
Cue can create slow-motion or fast-motion copies of any movie, then let you switch speeds while playing. You can also create multi-speed sequences and use procedural **auto-speed** rhythms such as `roller_coaster`, `build_up`, `edge`, and `tease` that vary each playthrough.
89+
90+
You only need to place Video SFX markers once, on the original video. When you switch to a speed variant, Cue automatically scales every marker's timestamp to match, so there's no need to re-time or re-place anything for each speed.
91+
92+
## Intensity Groups
93+
94+
Intensity Groups tie your sound effects to video speed. As a video speeds up or slows down, Cue automatically swaps in sounds that match, so slower speeds can use softer, sparser sounds while faster speeds use louder and more frequent ones.
95+
96+
It's the feature that brings everything together: video SFX, loop SFX, loop SFX frequency, and volume can all react alongside video speed instead of feeling like separate effects layered on top of each other.
7297

7398
## Using Cue With Multiple Games
7499

@@ -83,31 +108,26 @@ If you have Cue installed in several games and want one copy of the code to serv
83108
<game2>/game/renpy_cue/cue_lib -> <your shared copy of cue_lib>
84109
```
85110

86-
An update to the shared copy then propagates to every game at once. On Windows, use a directory junction (`mklink /J …`). Your **data** — markers, presets, audio, music — is already shared machine-wide through the data directory below, so only the code needs the symlink.
87-
88-
## Settings and Your Data
89-
90-
Press `` ` `` (backtick) or `Shift+Alt+E` to open the Cue overlay. **Settings** is where you can:
111+
An update to the shared copy then propagates to every game at once. On Windows, use a directory junction (`mklink /J …`).
91112

92-
- relocate the **Cue Data Directory**;
93-
- view, rebind, or reset every hotkey.
113+
Your **data** (markers, presets, audio, music, and other configuration) is already shared machine-wide through Cue's data directory, so only the code needs to be shared.
94114

95-
Cue keeps your SFX and music, pools and markers, presets, and generated video variants in one shared data folder, used by every game where Cue is installed.
115+
## Cue Data Folder
96116

97-
Cue also keeps **automatic hourly and manual backups** as zip files, and supports **undo/redo** (up to 20 steps) and **copy/paste** of a pool's configuration, so you can experiment without losing your setup.
117+
Cue keeps your SFX and music, pools and markers, presets, and generated video variants in one shared data folder used by every game where Cue is installed.
98118

99119
### Default locations
100120

101-
- **Windows**: `%APPDATA%\renpy_cue`
102-
- **macOS**: `~/Library/Application Support/renpy_cue`
103-
- **Linux**: `$XDG_DATA_HOME/renpy_cue`, or `~/.local/share/renpy_cue`
121+
* **Windows:** `%APPDATA%\renpy_cue`
122+
* **macOS:** `~/Library/Application Support/renpy_cue`
123+
* **Linux:** `$XDG_DATA_HOME/renpy_cue`, or `~/.local/share/renpy_cue`
104124

105-
You can also override the location with the `RENPY_CUE_DIR` environment variable.
125+
You can change the data folder location in Cue's settings, or override it with the `RENPY_CUE_DIR` environment variable.
106126

107127
## Requirements
108128

109-
- **Ren'Py 7.4 or newer** works on both the 7.x (Python 2) and 8.x (Python 3) engine generations.
110-
- **ffmpeg 5 or newer** only required for creating video speed variants. Must be on `PATH`, or pointed to with the `RENPY_CUE_FFMPEG` / `RENPY_CUE_FFPROBE` environment variables.
129+
* **Ren'Py 7.4 or newer:** works on both the 7.x (Python 2) and 8.x (Python 3) engine generations.
130+
* **ffmpeg 5 or newer:** only required for creating video speed variants. It must be on `PATH`, or pointed to with the `RENPY_CUE_FFMPEG` and `RENPY_CUE_FFPROBE` environment variables.
111131

112132
## For Developers
113133

@@ -121,15 +141,15 @@ You can also override the location with the `RENPY_CUE_DIR` environment variable
121141

122142
### Compatibility
123143

124-
Code must work on **Ren'Py 7.4.x and up**, which means both the 7.x (Python 2) and 8.x (Python 3) engine generations. The 7.x constraint forbids f-strings, type hints, and other Python 3-only syntax in `.py` files. The full rules are in `CLAUDE.md`.
144+
Code must work on **Ren'Py 7.4.x and up**both the 7.x (Python 2) and 8.x (Python 3) engine generations. The 7.x constraint forbids f-strings, type hints, and other Python 3-only syntax in `.py` files. Full rules are in `CLAUDE.md`.
125145

126146
### Tooling
127147

128148
- `bin/lint.sh` — runs pyright on `cue_lib/` plus a 120-character line-length check. Prints `CLEAN` or exits nonzero.
129-
- `bin/test.sh``poetry run pytest tests/ -q` (headless unit tests against the mock runtime).
130-
- `bin/test_harness.sh <sdk>/renpy.sh` — runs the in-engine testcases harness against a real Ren'Py SDK (screen/engine code that pytest's mock can't drive). Picks `testcases_modern.rpy` (8.x) or `testcases_legacy.rpy` (7.x) based on the SDK version.
149+
- `bin/test.sh``poetry run pytest tests/ -q`, the headless unit suite against the mock runtime.
150+
- `bin/test_harness.sh <sdk>/renpy.sh` — runs the in-engine testcase harness against a real Ren'Py SDK, for screen/engine code the pytest mock can't drive. Picks `testcases_modern.rpy` (8.x) or `testcases_legacy.rpy` (7.x) based on the SDK version.
131151

132-
CI runs the harness against pinned Ren'Py **7.4.10** and **8.5.3** SDKs, plus lint and pytest on every push/PR.
152+
CI runs the harness against pinned Ren'Py **7.4.10** and **8.5.3** SDKs, plus lint and pytest, on every push and pull request.
133153

134154
### Local Setup
135155

@@ -143,4 +163,4 @@ bin/test.sh
143163

144164
## License
145165

146-
MIT — see [LICENSE](LICENSE).
166+
MIT. See [LICENSE](LICENSE).

bin/build_sfx_asset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def main():
4040
if not os.path.isdir(args.src):
4141
sys.exit(f"source dir not found: {args.src}")
4242
if args.out is None:
43-
args.out = "renpy_cue_sfx.zip"
43+
args.out = "cue_sfx.zip"
4444
print(f"built {build_zip(args.src, args.out, set(args.exclude))} (excluded {', '.join(args.exclude)})")
4545

4646

0 commit comments

Comments
 (0)