Skip to content

Commit 2cba835

Browse files
committed
rgc2ugb + rgc-lint: ugBASIC v1.18 keyword sweep + distribution proposal
Adds 18 v1.18-specific keywords to KEEP_UPPERCASE so they stay case-significant in transpiled output: MAX/MIN, FLASH, TRIANGLE, BITMAPADDRESS, RESET, ERROR, CHAIN, BEGIN/COPPER/MOVE/STORE (copper list directives), NUMBER, MSPRITE, ARRAY/CHECK/GET/PUT, REU. rules.json adds tier classifications for the same set (most portable, some conditional for target-specific copper / NUMBER / MSPRITE / CHAIN / BITMAPADDRESS). Also re-tiers TIMER from "modern" to "portable" since rgc2ugb now emits PARALLEL PROCEDURE for it. docs/distributables.md is a new proposal doc covering the .rgcpkg bytecode bundle format, three protection tiers (casual / medium / strong), monetisation tiers (Free / Pro / Studio / verticals), construction-kit verticals (RGC-SEUCK / RGC-ADV / RGC-RPG / RGC-PLATFORM / RGC-VN), the cross-platform compile-farm-as-a-service architecture, and Steam distribution requirements. Sin clustering bug confirmed reproducing in v1.18 — file upstream issue at github.com/spotlessmind1975/ugbasic with 11-line repro. LUT pipeline workaround stays in rgc2ugb.
1 parent 8ade43e commit 2cba835

3 files changed

Lines changed: 302 additions & 2 deletions

File tree

docs/distributables.md

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
# RGC-BASIC Distributables
2+
3+
Plan for packaging end-user RGC-BASIC programs into shippable binaries
4+
with code + asset protection. Status: **proposal / scoping doc**.
5+
6+
## Three protection tiers
7+
8+
### Tier 1 — Casual (deters peeping)
9+
- Minify + gzip the `.bas` source
10+
- Embed as binary blob in tauri/PyInstaller wrapper
11+
- Decompress in memory on launch
12+
- **Effort:** ~1 day
13+
- **Effectiveness:** stops `cat`, defeated by `strings`
14+
15+
### Tier 2 — Medium (recommended starting point)
16+
- Compile `.bas` → bytecode (AST → opcode stream)
17+
- Native interpreter ships VM, loads bytecode blob
18+
- Source never leaves dev machine
19+
- **Effort:** ~1–2 weeks (extend existing parser with emit + load)
20+
- **Effectiveness:** no instant `cat foo.bas`. Reverse-engineerable but
21+
takes real work. Side benefit: faster cold start (no re-parse).
22+
23+
### Tier 3 — Strong (paid/commercial)
24+
- Tier 2 + XOR/AES over bytecode + assets
25+
- Key bundled (still better than plaintext) or machine-bound
26+
- Periodic checksums detect tampering at runtime
27+
- **Effort:** ~3–4 weeks
28+
- **Effectiveness:** raises the bar significantly. Determined
29+
attacker still wins eventually, but mass piracy gets harder.
30+
31+
## Bundle format: `.rgcpkg`
32+
33+
Single file containing bytecode + every asset (sprites, music, data).
34+
35+
```
36+
[8B magic 'RGCPKG\0\0']
37+
[2B version]
38+
[4B TOC offset]
39+
[bytecode segment] <- compressed (zstd-19 or lz4)
40+
[asset segment] <- compressed
41+
[TOC: name → offset+len+type+compress_alg] <- XOR-scrambled
42+
```
43+
44+
### Wins
45+
- One file ships the whole program (code + `.png` + `.mod` + `.wav`)
46+
- zstd-19 ≈ 30–50 % smaller than raw + zip
47+
- Scrambled TOC blocks `unzip -l foo.rgcpkg` style ripping
48+
- Magic bytes ≠ ZIP/RAR/7z → `file foo.rgcpkg` reports "data"
49+
50+
### VFS integration
51+
rgc-basic mounts bundle as VFS root. `LOADIMAGE "logo.png"`
52+
bundle lookup → in-memory decode. **Zero changes** to `.bas` source.
53+
54+
### Cracking effort
55+
Still doable for determined attacker, but the easy attacks are blocked:
56+
- "drag `.png` out of zip" → blocked (custom format)
57+
- "open in hex editor and read text" → blocked (compressed + scrambled)
58+
- Music/sprite ripping by asset extractors (Game Extractor, etc.) → blocked
59+
60+
## Build chain
61+
62+
```
63+
foo.bas + assets/ rgc-pack foo.rgcpkg
64+
────────────► (CLI + IDE button) ──────────► ship to user
65+
66+
67+
rgc-basic --run foo.rgcpkg
68+
```
69+
70+
IDE adds **Build Distributable** action → generates either:
71+
- Bare `.rgcpkg` (run with installed rgc-basic CLI), or
72+
- Tauri-wrapped `.exe` / `.app` with `.rgcpkg` embedded as resource.
73+
74+
## Paid tier potential
75+
76+
Free tier could ship Tier 1 + bare `.rgcpkg`. Paid tier unlocks:
77+
- Tier 3 protection (encrypted bundle)
78+
- Tauri wrapper with custom icon/splash/about
79+
- Code signing for mac/windows (covers signing fees)
80+
- Steam-ready build pipeline (see below)
81+
- Auto-update via tauri updater
82+
83+
## Steam distribution
84+
85+
`.rgcpkg` + tauri wrapper alone is **not enough** for Steam. Steam
86+
expects native integration with Steamworks SDK and a specific build
87+
pipeline.
88+
89+
### Required for Steam
90+
| Item | What | Cost / Effort |
91+
|------|------|---------------|
92+
| Steam Direct fee | per-game | $100 USD per app ID |
93+
| Steamworks SDK | Steam APIs, depots, build upload | Free (Valve) — needs C/C++ FFI binding |
94+
| App ID | unique numeric ID for the game | obtained after Direct fee |
95+
| Depot | platform-specific build (win/mac/linux) | per-platform build pipeline |
96+
| `steamcmd` upload | CLI tool to push depots | free, scriptable |
97+
98+
### Recommended Steamworks features
99+
- **Achievements** — flat key/value, easy via `ISteamUserStats`
100+
- **Cloud saves** — Steam Auto-Cloud (no API needed) or Remote Storage
101+
- **Steam Input** — controller remap UI handled by Valve
102+
- **Rich Presence** — "Playing Level 3" status to friends
103+
- **Workshop** — user-generated content (later)
104+
105+
### Optional (avoid early)
106+
- Steam DRM wrapping — adds protection but complicates builds; usually
107+
not worth it for indie titles
108+
- Anti-cheat — heavy, only relevant for multiplayer
109+
- Multiplayer / lobbies / matchmaking
110+
111+
### Code signing fees (covered by paid tier?)
112+
- Apple Developer Program: $99 USD/year (mac signing + notarization)
113+
- Windows Authenticode: $200–$400 USD/year (varies by CA)
114+
- Linux: no signing required
115+
116+
### Integration approach
117+
Two options:
118+
119+
**A. FFI bindings** (purist, more work)
120+
- Generate C bindings from steam_api.h
121+
- Expose to rgc-basic via `STEAM.achievement_unlock(name)` calls
122+
- Same binary works on/off Steam (graceful no-op if SDK absent)
123+
124+
**B. Tauri shim** (pragmatic, less code)
125+
- Tauri host calls Steamworks SDK directly
126+
- Sends events (achievements, cloud save) via IPC to rgc-basic
127+
- rgc-basic stays Steam-agnostic; tauri layer handles platform
128+
129+
**Recommendation:** start with B. Cleaner separation. FFI later if
130+
specific features need direct rgc-basic access.
131+
132+
### Build pipeline sketch
133+
134+
```
135+
# CI per release
136+
1. rgc-pack foo.bas + assets → foo.rgcpkg
137+
2. tauri build --target x86_64-apple-darwin
138+
3. tauri build --target aarch64-apple-darwin
139+
4. tauri build --target x86_64-pc-windows-msvc
140+
5. tauri build --target x86_64-unknown-linux-gnu
141+
6. Sign mac (codesign + notarize)
142+
7. Sign windows (signtool)
143+
8. steamcmd run_app_build app_build_<APPID>.vdf
144+
9. Push to Steam beta branch → smoke test → promote to default
145+
```
146+
147+
## Compile farm as a service
148+
149+
Existing GitHub Actions already cross-builds rgc-basic native binaries.
150+
Same pattern can run server-side to compile **user games + assets →
151+
mac/win/linux/wasm `.zip`** on demand.
152+
153+
### Architecture
154+
155+
```
156+
IDE upload (.bas + assets) → POST api/distribute/build.php
157+
158+
queue + worker pool
159+
160+
┌─────────────────────┼─────────────────────┐
161+
▼ ▼ ▼
162+
linux worker win worker mac worker
163+
(docker, musl) (mingw or wine) (real m1/m2 HW)
164+
│ │ │
165+
└────────► sign ──────┴──────► rgc-pack bundle
166+
167+
s3/CDN + email link
168+
```
169+
170+
### Per-platform reality
171+
172+
| Platform | Cross-compile | Notes |
173+
|----------|---------------|-------|
174+
| Linux x64/arm64 | gcc + musl in docker | static link, zero user deps |
175+
| Windows x64 | mingw-w64 from linux | works. signtool needs windows or osslsigncode |
176+
| macOS arm64/x64 | **NO** — Apple licensing | needs real mac. Mac mini M2 ~$500 one-time, or MacStadium ~$50/mo |
177+
| WASM | emcc | already in CI |
178+
179+
### GitHub Actions vs self-hosted
180+
181+
| | GitHub Actions | Self-hosted (`makingpython`) |
182+
|---|---|---|
183+
| Setup | low (matrix yaml) | medium (worker mgmt) |
184+
| Cost | free public / paid private | electric + hardware |
185+
| Mac builds | real M1 runners ($0.16/min macOS) | local mac mini = unlimited |
186+
| Queue time | minutes | seconds |
187+
| Quotas | yes | no |
188+
189+
**Hybrid recommendation:** free tier hits GHA via API trigger; paid
190+
tier hits local farm. Reuses idle server capacity.
191+
192+
### Existing infra leverage
193+
194+
- `scripts/update-ugbasic-docker.sh` model → same pattern for
195+
cross-toolchain images: `rgc-build-linux:latest`,
196+
`rgc-build-win:latest`, `rgc-pack:latest`.
197+
- IDE already has compile-API pattern in `api/ugbasic/compile.php`.
198+
Add `api/distribute/build.php` mirroring it.
199+
- Job ID = sessionID style. Poll endpoint for status. Final = signed
200+
URL to bundle.
201+
202+
### Scope estimate
203+
204+
- Linux + WASM only farm: **1-2 weeks** (extend existing infra)
205+
- + Windows mingw + signing: **+1 week**
206+
- + Mac (needs real hardware): **+2 weeks**
207+
208+
## Monetisation tiers
209+
210+
| Tier | Price model | Includes |
211+
|------|-------------|----------|
212+
| Free | $0 | Tier 1 protection, bare `.rgcpkg`, Linux + WASM build |
213+
| Pro | one-off / Patreon $5/mo | Tier 2 bytecode, tauri wrapper, mac+win unsigned builds |
214+
| Studio | Patreon $20/mo or one-off | Tier 3 encryption, signed mac+win builds, Steam pipeline assist |
215+
| Verticals | per-kit licence | unlocks construction-kit packages (see below) |
216+
217+
Patreon-only releases of the desktop IDE itself are also a clean lever
218+
— web IDE stays free forever, native binaries gated by tier.
219+
220+
## Construction-kit verticals
221+
222+
Modern reincarnations of classic 8-bit construction kits. Each is a
223+
**curated rgc-basic project template** + asset library + bundled
224+
runtime, sold/gated separately:
225+
226+
### Shoot-em-up Construction Kit (RGC-SEUCK)
227+
- 80s SEUCK lineage. Vertical / horizontal scroller scaffold
228+
- Sprite sheets, enemy patterns, boss waves, bullet patterns
229+
- Drag-and-drop level editor in IDE
230+
- Output: `.rgcpkg` per game, ships as standalone exe via compile farm
231+
232+
### Adventure Creator (RGC-ADV)
233+
- GAC / Quill lineage. Text + parser-driven adventures
234+
- Room graph editor, vocabulary list, conditional logic blocks
235+
- Text + optional sprite illustration per room
236+
- Optional retro target via ugBASIC for actual Spectrum/C64 adventures
237+
238+
### RPG Creator (RGC-RPG)
239+
- RPG Construction Set / SCI lineage. Top-down 2D RPG
240+
- Tilemap editor, party/inventory/quest systems
241+
- Battle system templates (turn-based first, ATB later)
242+
- Music + portrait packs
243+
244+
### Platformer Kit (RGC-PLATFORM)
245+
- Mario/Sonic style sidescroller
246+
- Tile collision, animation states, enemy AI patterns
247+
- Power-ups, level transitions, save points
248+
249+
### Visual Novel Kit (RGC-VN)
250+
- Ren'Py lineage. Scripted dialogue trees + character art
251+
- Text-rendering w/ furigana / branching / autosave
252+
- Easiest vertical to ship — most logic is data not code
253+
254+
### Why verticals win
255+
256+
- Lower bar to entry — buyer doesn't need to learn rgc-basic, just
257+
edit content
258+
- Each kit is its own product/store page — discoverability
259+
- Asset pack add-ons = recurring revenue (sprite packs, music packs,
260+
background packs)
261+
- Power users can drop into raw rgc-basic to extend any kit
262+
- Each vertical's `.rgcpkg` runs on the same runtime — one VM, many
263+
products
264+
265+
### Prior art reality
266+
- GameMaker, RPG Maker, Construct 3 already do this on modern. Niche
267+
is **retro target output** + **portability across rgc-basic /
268+
ugBASIC retro hardware** in the same kit. SEUCK on a real C64 +
269+
modern desktop + WASM-in-browser from one project = unique angle.
270+
271+
## Open questions
272+
273+
- Bytecode format spec: stack VM vs register VM? Stack simpler, smaller.
274+
- Asset compression: zstd-19 (slow encode, fast decode) or lz4 (fast both, weaker)?
275+
- Bundle versioning: how do older `rgc-basic` runtimes handle newer bundles?
276+
Reject with version error vs forward-compat shim.
277+
- Reseller channels beyond Steam: itch.io (no fees), GOG (curated),
278+
Epic Games Store (12 % cut).
279+
280+
## See also
281+
- `working/compile.sh` — current ugBASIC retro compile path (different goal)
282+
- `api/ugbasic/compile.php` — IDE-side cross-compile API
283+
- Current native rgc-basic interpreter — already has parser + AST (foundation for bytecode emit)

tools/rgc2ugb/emit.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@
6363
"BLACK", "WHITE", "RED", "CYAN", "PURPLE", "GREEN", "BLUE",
6464
"YELLOW", "ORANGE", "BROWN", "PINK",
6565
"TRUE", "FALSE", "PI",
66+
# ugBASIC v1.18 additions
67+
"MAX", "MIN", "FLASH", "TRIANGLE", "BITMAPADDRESS",
68+
"RESET", "ERROR", "CHAIN",
69+
"BEGIN", "COPPER", "MOVE", "STORE",
70+
"NUMBER", "MSPRITE",
71+
"ARRAY", "CHECK", "GET", "PUT", "REU",
6672
})
6773

6874

tools/rgc_lint/rules.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@
176176
"HIDECURSOR": { "tier": "modern" },
177177
"SHOWCURSOR": { "tier": "modern" },
178178

179-
"TIMER": { "tier": "modern", "suggest": "ugBASIC EVERY ... DO ... is the closest analogue" },
179+
"TIMER": { "tier": "portable", "note": "transpiler maps to ugBASIC PARALLEL PROCEDURE + SPAWN; native rgc-basic uses real timer" },
180180

181181
"DOWNLOAD": { "tier": "modern" },
182182
"FILEEXISTS": { "tier": "modern" },
@@ -200,5 +200,16 @@
200200
"PLATFORM": { "tier": "modern" },
201201

202202
"ANTIALIAS": { "tier": "modern" },
203-
"SCREENCODES": { "tier": "modern" }
203+
"SCREENCODES": { "tier": "modern" },
204+
205+
"MAX": { "tier": "portable", "note": "v1.18: array max" },
206+
"MIN": { "tier": "portable", "note": "v1.18: array min" },
207+
"FLASH": { "tier": "conditional", "note": "v1.18: graphics; not all targets" },
208+
"TRIANGLE": { "tier": "portable", "note": "v1.18: graphics primitive" },
209+
"BITMAPADDRESS": { "tier": "conditional", "note": "v1.18: target-specific bitmap mem address" },
210+
"RESET": { "tier": "portable", "note": "v1.18: control" },
211+
"CHAIN": { "tier": "conditional", "note": "v1.18: load + run another .prg; retro only" },
212+
"NUMBER": { "tier": "conditional", "note": "v1.18: arbitrary-length int (127B big / 255B little)" },
213+
"MSPRITE": { "tier": "conditional", "note": "v1.18: multi-sprite TYPE field" },
214+
"COPPER": { "tier": "conditional", "note": "v1.18: copper lists; atari/atarixl/c64/c64reu/c128 only" }
204215
}

0 commit comments

Comments
 (0)