Crusty Studio is a focused desktop studio for building small retro-computer programs with crustyBASIC. It brings source editing, project files, native toolchains, build output, emulator launching, and pixel-and-sound workshops into one place.
This guide explains the complete workflow: how projects are organised, how the editor decides what to build, which tools work with which targets, and how the asset workshops feed data back into your game.
.crusty manifest name./Volumes/Data2/Programming when that folder exists; on other machines the default is a Programming folder inside Documents.Crusty Studio creates the project folder, a src folder containing main.cbs, and folders for sprites, charsets, tiles, sound, music, generated, and build. The project is remembered and restored the next time the desktop app opens.
The browser preview can demonstrate the interface and a simulated C64 build, but native file browsing, real compilation, and emulator launching require the installed desktop application.
The app is divided into four working areas:
| Area | What it does |
|---|---|
| Menu bar | Project, file, edit, run, tools, and help commands. |
| Project Explorer | Open source tabs, project assets, target information, and tool status. |
| Code editor | Monaco-based crustyBASIC editor with syntax colours, completion, diagnostics, and tabs. |
| Output and Problems | Build messages, compiler output, warnings, errors, and clickable source locations. |
| Search | Project-wide text search results, one row per matching line, each one clickable. |
The sidebar and bottom panel are resizable. Drag the vertical divider between the Explorer and editor, or the horizontal divider above Output, to give a panel more room. Both panels scroll internally, so increasing the interface scale does not hide their contents.
The source editor has a two-row header. The top row contains the Project, File, Edit, Run, Tools, and Help menus. The row below keeps the build target, Options, Build, and Build and run controls together, followed by the independent Edit toolbar and the Go to procedure picker. Menu and Options popovers stay attached to their controls and are repositioned to remain visible inside the window. When the window is narrow, the Edit toolbar scrolls independently; its thin scrollbar appears when you hover over that toolbar, so the Target and build controls do not move with it.
The status bar shows the current build phase, target, encoding, runtime, the editor code size, and the version of the build at the far right. Select the Code Npx indicator to reset the code editor to its default size.
The Explorer mirrors the project on disk:
My Game/
├── My Game.crusty project manifest
├── src/
│ ├── main.cbs main source file
│ └── other.cbi optional include/source file
├── sprites/ C64, NES, or Apple II graphics assets
├── charsets/ C64 character sets
├── tiles/ C64 and NES tile-map projects
├── sound/ sound recipes
├── music/ SID music projects
├── generated/ generated include data
└── build/ build products and intermediate files
Double-click a source file to edit it. Double-click a recognised asset to open its workshop. Right-click a file for Edit, Rename, or Delete. Renames update the project manifest when the asset is part of the current project.
.crusty project manifestThe manifest is a small JSON file that records the project identity and asset locations. A typical manifest looks like this:
{
"format": "crusty-project",
"version": 1,
"name": "My Game",
"target": "c64",
"main": "src/main.cbs",
"assets": {
"sprites": [],
"charsets": [],
"tilemaps": [],
"sounds": [],
"music": []
}
}
Paths in assets are relative to the project folder. You normally do not need to edit this file by hand: creating, saving, importing, renaming, and deleting assets keeps it in sync.
main.cbs filesrc/main.cbs is the default entry source file. It is not a special language dialect; it is simply the source file named by the project manifest and shown first when a project opens. You can create additional .cbs, .cbi, or .bas files and switch between them using editor tabs.
The first lines normally declare the target:
@OPTION TARGET c64
@OPTION TARGET (or the compatible @OPTION SYSTEM) controls the target label, target-aware workshop availability, emulator adapter, and default launch behaviour. The editor reads this directive live, so changing it changes the target card in the Explorer.
You can also select an output format:
@OPTION OUTPUT_TYPE crt
When present, Crusty Studio passes that output type to the compiler. Without it, crustyBASIC chooses its normal default for the selected target.
The code editor is powered by Monaco and is aware of the crustyBASIC language.
/* … */ and /' … '/) are highlighted across their whole span, including blocks nested inside each other. They are also understood rather than merely coloured: procedures, constants, labels, calls, and @INCLUDE lines inside one stay out of the outline, the include graph, and the problems list, and the formatter leaves the comment text exactly as written. A block is only ended by the delimiter that opened it, matching the compiler. Block comments need a crustyBASIC build that supports them./* and */, and removes them again when the selection already carries them. Line comments keep using '.@OPTION and @INCLUDE.PROC, IF, FOR, WHILE, REPEAT, and SELECT CASE blocks.PROC and FUNCTION declarations in the current editor file. It is deliberately compact and does not add file names to the picker entries.↻ beside the tab name and on the Explorer row, next to the amber ● that means unsaved edits. Both can show at once, and the … tab menu gains Reload N changed files while any are waiting.Use the … button at the right side of the tab strip for tab management:
The tab scrollbar is separate from the code editor scrollbar. The Edit toolbar also has its own horizontal scroll area when the window is too narrow for all of its buttons. Hover over that toolbar to reveal the thin scrollbar and reach actions such as indent, outdent, duplicate line, delete line, and Find.
The lightweight live checker catches common mistakes immediately, such as an untyped DIM declaration. After a short pause, the desktop app also asks crustyBASIC to check the current source and reports compiler diagnostics.
Use .cbs for a normal source file and .cbi for reusable include data or generated declarations. @INCLUDE is handled by crustyBASIC; the Studio does not rewrite your source. Asset workshops can generate include-style data for workflows that need byte arrays in code.
Procedure navigation understands include paths relative to the source file, including nested includes and target-specific paths such as machine/{target}.cbi. This means a declaration opened in an include file can find its calls in main.cbs, and a call in main.cbs can return to the correct declaration in an included file. When more than one target or file provides the same procedure name, choose the intended definition from the chooser.
Choose Build in the top toolbar or Run → Build. Crusty Studio:
@OPTION OUTPUT_TYPE and the current target.If Generated assembly is enabled in Settings, the compiler receives --emit-asm and writes an .asm file into an assembly folder beside the source.
The Options control beside Target opens common crustyBASIC build parameters. Optimization, array indexing, and video region use --set; Debug mode, warnings, timings, and the size report add their matching compiler flags. Unchanged options are left out so the compiler keeps its normal defaults. These choices are remembered locally for future builds.
Choose Run or Run → Build and run. A successful build is followed by target-aware emulator selection. If another emulator is running, Crusty Studio stops the previous process before launching the new artifact.
The Stop button ends a tracked emulator process. Fujisan on macOS is reused through its local service when possible, so Stop cannot terminate it in the same way as a child process.
The target is taken from the first matching @OPTION TARGET or @OPTION SYSTEM directive. The family is the text before a dot, so c64.demo still uses the C64 adapter.
| Target family | Adapter | Executable names searched | Launch behaviour |
|---|---|---|---|
c64 |
VICE C64 | x64sc, x64 |
-autostart for normal images; -cartcrt for .crt. |
c128 |
VICE C128 | x128 |
VICE autostart. |
plus4 |
VICE Plus/4 | xplus4 |
VICE autostart. |
vic20 |
VICE VIC-20 | xvic |
VICE autostart. |
atari800 |
Atari 8-bit | atari800, Fujisan |
Atari800 launch; Fujisan uses its local TCP service on macOS. |
atari5200 |
Atari 5200 | atari800, Fujisan |
Adds the 5200 mode and cartridge flags for .car/.a52. |
atari2600 |
Atari 2600 | stella |
Direct artifact launch. |
apple2 |
Apple II | linapple, applewin, microM8 |
Direct launch; microM8 receives its Apple II profile. |
coco |
Color Computer | xroar |
Direct artifact launch. |
nes |
Nintendo Entertainment System | mesen, fceux, nestopia, tetanes |
Direct artifact launch. |
The Target menu contains each target and its detected emulators as child options. If exactly one compatible emulator is found, it is selected automatically; when several are available, choose one beneath the target. The selection is remembered per target family. Choose Automatic to use the first detected emulator.
The target list in New Project contains the supported project choices. Additional crustyBASIC target IDs can still be edited in source, but Run needs a matching adapter and emulator.
Open Tools → Settings or select the gear in the Explorer. Settings has two sections.
Interface size scales the complete UI: text, controls, spacing, menus, and panels. Presets are Default (100%), Comfortable (115%), Large (130%), and Extra large (150%). The preview is immediate; choose Save settings to persist it.
The code editor has an independent zoom. Hold Command or Control while scrolling over the code editor. On macOS, Command is the recommended modifier; ⌘+, ⌘−, and ⌘0 are reliable keyboard fallbacks. On Windows and Linux use the equivalent Control shortcuts.
Highlight colour changes the accent used across the studio: the active tab, the build and run buttons, badges, selection outlines, editor caret, and the highlighted panels in every asset workshop. Drag the wheel's outer ring to choose a hue and the inner square to set how strong and how bright it is, type a hex value, or pick one of the presets. The change is previewed immediately; Reset returns to the stock amber and Save settings keeps the choice. The default amber is used until a custom colour is saved.
PATH.assembly/<source>.asm.Select Check installation to refresh the green, yellow, and missing tool indicators. The desktop app does not bundle crustyBASIC, VASM, emulators, ROMs, or games; install those separately and point Settings at them.
On macOS, Gatekeeper can quarantine downloaded compiler helper tools. The tool check and build output explain the exact helper that needs to be reviewed and cleared if this occurs.
Workshops are opened from Tools or by double-clicking a recognised asset in the Explorer. Each workshop has its own scrollable panels and a Back to code action. In the desktop app, New and Save write into the current project; in browser preview, Save downloads a JSON project file.
Availability follows the target in the active source file, not the project manifest. A target family is the text before the dot in an @OPTION TARGET or @OPTION SYSTEM value, so c64.demo still counts as C64-family.
| Tools menu entry | Enabled for | What opens |
|---|---|---|
| Sprite Editor | C64 family, NES, Apple II | C64 Sprite Workshop for the C64 family, NES Sprite Workshop for NES, Apple II Graphics Workshop for Apple II. |
| Charset Editor | C64 family | The C64 charset editor (standard and multicolour character sets). |
| Tile Workshop | C64 family, NES | C64 tile-map editor for the C64 family, NES tile-map editor for NES. |
| Sound Editor | C64 family, NES | The sound editor, adapting to SID or the NES 2A03 according to the target. |
| Music Workshop | Every target | The portable four-lane tracker, which uses the target-neutral CrustyBasic sound API. |
| SID Music Workshop | C64 family | The three-voice SID tracker with chip-model, filter, and PAL/NTSC controls. |
Where a menu entry is disabled the Explorer shows the note that workshops are available for C64-family, NES, and Apple II targets. Disabling is only about creating a new asset for the current target: opening an existing asset from the Explorer always works, because the saved asset records the platform it was authored for. A NES tile map opened from a C64 project still opens in the NES tile editor.
Sound follows the same split, and it is worth knowing what each family actually gets. The C64, C128, and Plus/4 use the MOS 6581/8580 SID with three voices, a shared multimode filter, and PAL or NTSC timing; the Sound Editor and SID Music Workshop configure those registers directly. NES uses the 2A03 APU with two pulse channels, a triangle, and noise, which is what the Sound Editor's NES controls map onto. Every other target has only the portable Music Workshop and the generic CrustyBasic sound API, resolved by the target's own runtime — there is no chip-specific editor for Atari, Apple II, CoCo, or the other targets.
Nothing here is available in the browser preview beyond drawing and downloading a project file; saving into the project, importing binaries, and exporting includes are desktop-only.
Available for the C64, C128, and Plus/4 targets in the current Tools menu. It edits a VIC-II sprite as one or more animation frames.
.c64sprite.json format and are stored in sprites/.Available for NES targets. It edits 8 × 8 indexed tiles with two bitplanes.
.nessprite.json project. There is no image import, so NES artwork is drawn in the editor, imported as project data, or produced by the tooling that generates sprite tables..nessprite.json and live in sprites/.Available for Apple II targets. It provides Apple II-oriented graphics presets and pixel editing for low-resolution and high-resolution sprite-style assets. The preview is an editing guide; composite colour for hi-res art also depends on the screen X position when the program runs.
Apple II graphics assets use .apple2graphics.json or .apple2lores.json and are stored with other sprite assets in sprites/. Open and Save read and write those project files; there is no image import.
Opened from Tools → Tile Workshop, or by double-clicking a tile map in the Explorer. The C64 tile editor opens for the C64 family and the NES tile editor opens for NES, but the workflow is the same three layers in both:
| C64 | NES | |
|---|---|---|
| Atomic tile | An 8 × 8 glyph from the charset you load for the map | An 8 × 8 CHR pattern edited in the workshop, with pixel values 0–3 (the two CHR bitplanes, not fixed colours) |
| Colour | Comes from the charset the map refers to | Four background sub-palettes you edit from the complete 64-entry PPU colour table; palette slot 0 is the shared universal background colour |
| Metatile meaning | Collision (Empty, Solid, One way, Ladder, Hazard) and Gameplay role (Platform, Wall, Floor, Ceiling, Pickup, Checkpoint, Spawn, Goal, Decoration) | An attribute palette of 0–3 |
| Default map size | 40 × 25 metatiles, matching one character-mode screen at 1 × 1; editable up to 160 × 100 | 32 × 30 metatiles, matching one nametable screen at 1 × 1; editable up to 256 × 120 |
| Exported include | Metatile arrangements, map values, collision values, and gameplay-role values, as <NAME>_MAP, _COLLISION, _ROLE, _METATILE_OFFSETS, and _METATILE_CELLS |
CHR pattern bytes, the four background palettes as 16 PPU colour bytes, the map table, attribute bytes, and a generated LOAD_<NAME>_CHR procedure |
Metatile sizes come from a fixed menu of 1 × 1, 2 × 1, 1 × 2, 2 × 2, 3 × 2, 2 × 3, and 4 × 2 tiles in both editors. Delete a metatile and every map cell using it is cleared, with no confirmation and no undo. The C64 starter project ships Empty, Solid, and Pickup; the NES one ships Blank, Solid, Edge, and Corner. Paint an Empty or Blank metatile over a cell to clear it, and remember that an untouched cell and an Empty cell both export as metatile 0, so your renderer should treat metatile 0 as nothing.
Three consequences are worth planning for:
$00–$3F). It changes only when a project file is loaded, so treat the exported CHR range as fixed by the file you started from rather than as an editor setting. Importing a map whose chrStart is not zero re-saves it from zero.Both editors scroll their own canvas with zoom buttons, a Fit action, and a Grid toggle; there is no pan tool and no undo, so save before reshaping a map. Resizing discards any cells that fall outside the new bounds.
Tile maps use .c64tilemap.json or .nestilemap.json and are stored in tiles/. Both editors open the editor's own JSON project only — neither imports PNG or binary graphics, and the C64 charset is chosen from the charsets already in the project. Help → Tile Workshop Guide covers the step-by-step workflow and the NES attribute-grid behaviour in more depth.
Available for the C64, C128, and Plus/4 targets. It edits the computer's character memory as 256 glyphs, each 8 × 8 pixels, and it is a C64-family tool throughout: the palette it writes names VIC-II registers, so the same asset is expected on a C128 or Plus/4 as on a C64. The NES equivalent is the CHR editor inside the NES Tile Workshop; there is no charset editor for Apple II or the other targets.
Choose Standard or Multicolour before drawing, because the two modes are different shapes:
Switching mode converts all 256 glyphs at once, and the conversion is lossy: standard to multicolour keeps only whether a pixel pair was lit, and multicolour to standard loses which of colours 1, 2, or 3 each cell used. There is no undo, so choose the mode before investing in art.
$hex, or 0x values separated by commas or spaces, applying them when you leave the field. Copy glyph bytes puts that text on the clipboard.Import. Open charset accepts a classic C64 .64c binary dump or a saved charset project. A binary's two-byte load address is read and shown, eight bytes per glyph are decoded, and a shorter set is padded to 256 glyphs with blanks. The parser rejects anything under one glyph, data that is not a whole number of eight-byte records, and more than 256 glyphs, each with its own message. A binary is converted into an editable .c64charset.json project rather than being edited in place, and the load address is not kept in the project. The editor's Open dialog decodes a binary in the mode you are currently in, while importing the same file from the Explorer or by dropping it always decodes as standard, so set the mode first if you are importing a multicolour dump. Charset projects require exactly 256 glyphs; a hand-edited file with fewer will be rejected as invalid.
Export. Export charset include writes a .cbi into the project's src/ folder for the glyph range you choose. The defaults are glyphs 64 to 127, and the help beside the fields explains why the range matters: exporting all 256 would blank the letters and digits the ROM font still supplies. The generated file starts with the asset marker, then one CONST <SYM>_GLYPH_<n>(7) AS U8 line per glyph in range, then <SYM>_INSTALL_CHARSET, which calls CHARSET_COPY_DEFAULT and stamps each exported glyph with CHARSET_DEFINE. Multicolour charsets additionally get the stored palette as _COLOR_BACKGROUND, _COLOR_1, _COLOR_2, and _COLOR_CELL constants plus palette and colour-RAM routines; a standard charset emits no palette block, because its two colours come from the screen registers.
Assets use .c64charset.json and are stored in charsets/. Help → Charset Editor Guide covers the drawing workflow, the screen palette, the .64c import, and how to choose an export range in more depth.
Available for the C64 family and NES. One project is one sound effect, and the editor adapts its controls to the sound hardware of the current target, which the header names: C64 SID for the C64 family or NES APU for NES. The target is not switchable inside the editor, and opening a sound asset adopts the editor's target, so a C64 recipe opened in an NES project is treated as an NES sound.
APU.SOUND call per step; the C64 sequence is a header plus SID.GATE_OFF, SID.ADSR, SID.PULSE_WIDTH, SID.FREQ, and SID.CTRL calls per step.SFX_PLAY_<NAME> procedure behind shared SFX_PLAYER_INIT, SFX_PLAYER_STOP, SFX_PLAYER_APPLY, and SFX_PLAYER_UPDATE routines, and each row has a ▶ button so you can audition a sound from the export list. A player holds a single target family, so C64 and NES sounds cannot be mixed in one include, and the export refuses that with a message. On C64 the player also carries per-tick frequency and pulse-width tables plus a SFX_PLAYER_MODULATE routine that applies the patch's modulation; on NES each step is a single APU.SOUND call with no tables.Import reads the editor's own JSON project only — .c64sound.json or .nessound.json. There is no .sid, GoatTracker, or raw-binary import here. Fields missing from an older file are filled with defaults, so it loads rather than failing, and an invalid file reports Invalid sound project file.
Assets use .nessound.json for NES or .c64sound.json for C64 and are stored in sound/. Only the JSON forms are editable projects: a dropped .c64sound, .sound, or .sfx file is copied into the folder and listed in the manifest, but it does not open in the editor.
Available from Tools → Music Workshop for every target, because it is a portable four-lane tracker built around the generic CrustyBasic sound API rather than one machine's sound chip. That is also its limit: only the SFX player and the two chip-specific editors get at real hardware registers.
A47, V26, U12, D12, T24, and W23. Effects and the instrument envelope shape the preview and are a written record of intent, but the exported player carries note, lane, waveform shape, and volume per event — it does not emit the ADSR, gate, duty, arpeggio, vibrato, or tremolo settings, and the Fx column is not exported at all. Keep a note of the patch settings you rely on..txt) and converts 2A03 pulse, triangle, and noise material into portable lanes, reporting each unsupported feature it dropped — expansion-chip data, DPCM, and effects it could not map. There is no ProTracker .mod import: a dropped .mod is stored in music/ but not converted..crustymusic.json into music/. Export player include writes a MUSIC_* player into src/, with the same include-name and overwrite rules as the other workshops.The portable song can be tested against NES, C64, and other CrustyBasic targets. The separate SID Music Workshop remains the place for full SID register authoring, filter design, and chip-model-specific composition. Help → Music Workshop Guide walks through building a song here, its imports, and what the exported player carries.
Available for the C64, C128, and Plus/4 targets. It is a three-voice tracker designed around the SID's musical workflow, and it is the only editor here that writes real SID register behaviour.
C-4.Axy, Vxy, Uxx, Dxx, and Fxx, and the instrument tab lists what each does.src/: an asset marker, a commented quick-start block showing the @INCLUDE and the SIDM_INIT/SIDM_TICK calls, then SIDM_ROWS, SIDM_SPEED, SIDM_LOOP, the per-voice note, instrument, effect, and parameter arrays, the per-instrument tables, a frequency table for the project's clock, the enabled-voice table, and the SIDM_INIT, SIDM_START_ROW, SIDM_MODULATE, and SIDM_TICK procedures. Your game calls the player each frame; the include is data plus routine, not a finished game soundtrack driver. The dialog names the include after the file the tune was opened from — caverns-theme.c64music.json suggests caverns-theme.cbi, so a re-export lands on the same file — and lists the project's existing music includes so one can be selected and replaced, the same list-and-replace contract the other editors use. Only generated includes carrying a CrustyStudio music marker are offered..sng file. Only the first subtune is converted, the file's own tempo and speed are not imported, and the status message lists every feature that needed approximation — wavetable and pulse-table commands, filter modulation, per-row ADSR and waveform changes, portamento, and anything past the pattern or row limits. Import → MIDI converts in the same spirit: every instrument is replaced by one of four fixed patches and notes are ranked by pitch into the three voices, with the same 64-pattern ceiling. Importing always starts a new asset, so Save asks for a name rather than replacing the original tune.A project is data plus a player; your game still has to include and call the player routine. The companion technical notes in docs/SID_MUSIC_WORKSHOP.md explain the hardware model and player design in more depth, and Help → SID Music Guide is the step-by-step tutorial.
Every workshop that writes crustyBASIC data writes it into src/ as a .cbi include, and they all share one safety rule. A generated include starts with a marker comment such as:
' @crusty-asset kind=tilemap name=platform.cbi target=c64
When you export over an existing .cbi, Crusty Studio reads that marker and decides:
That rule exists because a generated include once overwrote a hand-written level.cbi. If you want to own a file by hand, use a name you never export to. Refusals are reported in Output rather than inside the workshop, so look there if an export appears to do nothing.
This walkthrough makes a short original tune called Neon Patrol. It uses the same practical ideas associated with classic C64 players—small reusable patches, three-channel counterpoint, rapid arpeggios, and parameter motion—without copying a commercial melody or data.
Before touching the tracker, decide what each voice must contribute:
| Voice | Job | Register | Rhythmic idea |
|---|---|---|---|
| 1 | Bass and occasional kick | C-2 to A-2 | Root on beats, rests between phrases |
| 2 | Lead | C-4 to A-4 | Four-note call and answer |
| 3 | Harmony, echo, and percussion | C-3 to G-4 | Chord stabs on alternate rows |
Set the tune to 125 BPM, Speed 6, PAL, and start with the 6581 model. Use a 32-row pattern as one phrase. The important constraint is not to fill every cell: rests make room for transients and make the three lines readable.
sid-tune.c64music.json name or enter neon-patrol.c64music.json.Neon Patrol, add your name in Author, set BPM to 125, and set Speed to 6.neon-patrol-starter.c64music.json from the Explorer.Select Instrument 1 and set:
Neon Bass$480 (a narrower pulse is brighter than the square midpoint)0, Decay: 4, Sustain: 9, Release: 25 ticks180, Motion speed: 1.5 HzSelect Audition patch. If the note is too soft, raise sustain; if it blurs into the next note, lower gate length or release. The pulse motion is the animated part of the patch—keep it subtle on bass so the rhythm remains solid.
Select Instrument 2 and choose:
Neon Lead2, Decay: 6, Sustain: 10, Release: 46 ticks0,4,7 for a major colour12¢, Vibrato speed: 6 HzAudition the patch again. Vibrato is deliberately delayed by the instrument's vibrato-delay setting, so the start of a note stays clear before the pitch begins to move.
Select Instrument 3, choose Noise, and make it short:
Noise Snap0, Decay: 2, Sustain: 0, Release: 12 ticks0:noise, 1:pulseThe wave program turns the noise transient into a pulse almost immediately. That is a compact way to imply a drum without spending another oscillator or importing a sample.
In the tracker, each row has a note, instrument number, and optional effect for each of the three voices. The following is a useful first phrase; use the controls to enter the notes and instrument numbers, leaving unlisted cells as rests (···).
Row Voice 1 Voice 2 Voice 3
00 C-2 · 1 C-4 · 2 C-3 · 3
04 G-2 · 1 E-4 · 2 G-4 · 3
08 A#2 · 1 G-4 · 2 A47 ··· · 3
0C G-2 · 1 E-4 · 2 C-4 · 3
10 C-2 · 1 C-4 · 2 ··· · 3
14 G-2 · 1 D-4 · 2 G-4 · 3
18 A#2 · 1 G-4 · 2 V26 ··· · 3
1C G-2 · 1 E-4 · 2 C-4 · 3
The table shows the accented rows. Fill the rows between them with rests first, then add passing notes only when the phrase needs more motion. A47 means a rapid root/major-third/perfect-fifth arpeggio on the lead; V26 adds a modest vibrato override to one longer note.
Voice 3 does not need to play harmony continuously. Put the chord stabs on rows 00, 04, 0C, 14, 1C, then use short noise snaps on rows 08, 18, and 1E. This is the time-sharing principle: the ear hears a chord, then a drum, while the chip still has only three voices at any instant.
If the arrangement feels crowded, delete notes before changing instruments. Silence is an arrangement tool, not an unfinished cell.
Choose + Pattern, rename it Neon Patrol B, and duplicate the phrase's bass and lead. Make three changes:
D-2 and A-2 passing notes to the bass on rows 06 and 16.The new pattern is appended to Song order automatically. The current UI gives one order entry per pattern you create or duplicate; to repeat an earlier pattern, duplicate it or edit the order array in the saved JSON project. Turn Loop on while composing; turn it off when you want the generated player to stop and call SID.ALL_OFF at the end.
Open the SID chip tab. Start with Low-pass, cutoff around 1180, resonance 7, and master volume 13–15. Only instruments with Route through filter participate in the filtered signal. Raise cutoff for a brighter chorus; lower it for an intro or a darker bass.
Switch between MOS 6581 and MOS 8580 while the song plays. The 6581 preview is warmer and more nonlinear; the 8580 is cleaner and more predictable. If the melody only works at one exact cutoff, simplify it—the physical chips vary.
Choose Play song and listen for three things: can you follow the bass pulse, does the lead answer itself, and does the third voice add colour without masking the melody? Use Audition patch while a cell is selected to fix an instrument without replaying the whole tune.
Save the tune to the project's music/ folder. The .c64music.json file stores notes, pattern order, instruments, effects, filter settings, chip model, clock, and loop state. Saving also adds the relative asset path to the .crusty manifest.
Choose Export .cbi. The generated include contains the flattened song arrays and a small player:
@INCLUDE "neon-patrol.cbi"
PROC MAIN
SIDM_INIT
WHILE 1 = 1
SIDM_TICK
DELAY 1
ENDWHILE
ENDPROC
Call SIDM_INIT once. Call SIDM_TICK at the target's display refresh cadence—50 Hz for PAL or 60 Hz for NTSC, as noted in the generated file. The include writes SID.FREQ, SID.ADSR, SID.CTRL, SID.PULSE_WIDTH, gate, filter, and master-volume values. Your game loop decides when to tick the player and when to pause it for menus, sound effects, or gameplay events.
Play the song in both chip models, then test it beside the game's sound effects. Leave space in the arrangement for priority sounds. A good game cue has a recognisable contour after one listen, a strong rhythm even with the lead muted, and a safe ending when its loop is disabled.
The SID is three oscillators plus a shared filter, but a player can rewrite those registers every refresh. Classic composers used that time dimension as part of the instrument: a patch could change waveform, pitch, pulse width, envelope, or filter after the note began. The Workshop exposes those decisions directly so you can design the player behaviour and the note data together.
For further reading, compare the Workshop's controls with the Commodore 64 Programmer's Reference Guide sound chapter, Rob Hubbard's April 1986 Electronics & Music Maker interview, and Martin Galway's released Wizball music source. These references explain the hardware and historical player techniques; Neon Patrol and the Workshop's starter arrangement are original.
Saving an asset updates the manifest so it appears in the Explorer. The compiler does not automatically draw every asset just because it exists: source code must load, include, or reference the generated data according to the target's crustyBASIC APIs.
One C64 compatibility path is built in for the Space Invaders asset set. When the expected C64 sprite and charset files exist, a build can generate generated/space-invaders-3-assets.cbi containing byte arrays for those assets. Other projects can copy the same idea with their own include files and code.
The Project menu remembers the ten most recently opened or saved projects. Choose one from Recent projects to reopen it; dirty files are still protected by the normal save-before-switching prompt. Rename project… changes the project's display name, which is stored in the manifest and shown in the Explorer and the recent-projects list; it does not rename the project folder or the .crusty file. The project title in the Explorer can also be double-clicked to rename it.
The magnifier in the Explorer heading searches the whole project; see the crustyBASIC editor for the results workflow.
In the desktop app, choose File → Import into project or drop files onto the editor. Source files and .cbi includes are copied into src/ and open as tabs. Recognised assets are copied into the appropriate project folder and opened in their workshop. Other files are copied to the project root.
Recognised source extensions are .cbs, .cbi, and .bas. Everything else is routed by extension into the matching project folder and opened in its workshop where there is one:
| Family | Extensions accepted | Destination |
|---|---|---|
| C64 sprites | .c64sprite.json, .c64sprite, .sprite.json, .sprite |
sprites/ |
| NES sprites | .nessprite.json, .nessprite |
sprites/ |
| Apple II graphics | .apple2graphics.json, .apple2graphics, .apple2lores.json, .apple2lores |
sprites/ |
| C64 charsets | .64c, .c64charset.json, .c64charset, .charset.json, .charset |
charsets/ |
| Tile maps | .c64tilemap.json, .c64tilemap, .nestilemap.json, .nestilemap, .tilemap.json, .tilemap |
tiles/ |
| Sound | .c64sound.json, .c64sound, .nessound.json, .sound, .sfx |
sound/ |
| Music | .crustymusic.json, .c64music.json, .c64music, .music, .mod, .sng |
music/ |
| Source | .cbs, .cbi, .bas |
src/ |
| Anything else | project root |
A file that is already inside the project keeps its path; an imported file from elsewhere is copied to the destination folder under its own name. Sprite, charset, and tile-map imports then open in their workshop, so you can carry on editing straight away. Two kinds of file are converted on the way in: a C64 .64c charset binary becomes an editable .c64charset.json project with its load address read and its glyphs padded to 256, and a sound or music file is copied as it is and listed in the manifest — the GoatTracker .sng conversion is a separate step performed from inside the SID Music Workshop.
When switching projects, the app asks whether dirty source files should be saved first. The Explorer rescans every project subfolder, so files added externally appear automatically; source files added under folders such as src/includes/ are available as editor tabs. If an open file changes outside the app, the editor offers a choice to reload the disk version or keep the current in-app version, and the tab is marked with a blue ↻ while the choice is outstanding. Files that are not open are compared against the project as it was when it was opened, so an external edit to a text file such as crustybasic.config.toml or an .asm listing is marked in the Explorer too; opening or reloading the file clears the mark. The app's own saves, exports and builds never count as external changes, and hidden files such as the compiler's transient check sources are ignored.
| Action | macOS | Windows/Linux |
|---|---|---|
| New file | ⌘N |
Ctrl+N |
| Open file | ⌘O |
Ctrl+O |
| Save file | ⌘S |
Ctrl+S |
| Close tab | ⌘W |
Ctrl+W |
| Undo | ⌘Z |
Ctrl+Z |
| Redo | ⇧⌘Z |
Ctrl+Shift+Z |
| Find | ⌘F |
Ctrl+F |
| Settings | ⌘, |
Ctrl+, |
| Build | ⌘B |
Ctrl+B |
| Build and run | ⌘R |
Ctrl+R |
| Format casing | ⌘⇧U or ⌘⇧P |
Ctrl+Shift+U or Ctrl+Shift+P |
| Go to declaration or usages | Hold ⌘ and click, or F12 |
Hold Ctrl and click, or F12 |
| Increase code size | ⌘+ or ⌘= |
Ctrl+Plus or Ctrl+= |
| Decrease code size | ⌘− |
Ctrl+− |
| Reset code size | ⌘0 |
Ctrl+0 |
You can also hold Command or Control and scroll over the code editor to zoom code without changing the rest of the interface. The status bar's Code Npx button shows the current editor size and resets it when clicked.
Help → Crusty Studio Guide opens this guide in an editor tab. Four companion guides cover one workshop each in depth:
.64c import, and choosing an export range.Headings in each guide are clickable through the table of contents, and the help tab has its own scroll area. Help → Crusty Basic Help opens the language documentation shipped beside the configured compiler. Use the Studio Guide for app workflow and the Crusty Basic reference for language syntax and runtime APIs.
Open Tools → Settings → Toolchain, choose the compiler executable, and run Check installation. If the compiler is installed beside the project tools, leave the field empty and let the automatic search try common locations and PATH.
Install vasm6502_oldstyle 2.x and select its executable. Crusty Studio rejects versions below the supported 2.x line.
Add the folder containing the emulator in Emulator folders, not only a shortcut or unrelated ROM folder. Nested folders are searched. Confirm that the target directive matches the emulator you installed; for example, C64 uses VICE while NES uses Mesen, FCEUX, or Nestopia.
Check the first @OPTION TARGET or @OPTION SYSTEM line in the active source. The value is case-insensitive, and the part before a dot determines the family. Save the file if you want the project manifest and future sessions to retain the intended target.
Workshops are target-aware, and the Tools menu disables an entry that does not match the target in the active source. C64 Sprite, Charset, Tile (C64 editor), Sound (SID), and SID Music are for the C64, C128, and Plus/4 targets; NES Sprite, Tile (NES editor), and Sound (2A03) are for NES; Apple II Graphics is for Apple II; the Music Workshop is portable and is offered for every target. Change the source target, or open an asset directly from the Explorer, which always works because a saved asset records the platform it was authored for.
That is the generated-include check working. Crusty Studio only replaces a .cbi that carries the @crusty-asset marker line with a matching kind; anything else is treated as hand-written source and left alone. Export to a different name, or delete the file after checking its contents. The refusal message appears in Output, not in the workshop.
The C64 Sprite Workshop is the only asset editor with an undo history. The tile, charset, sound, and music editors do not, and neither does the NES sprite or Apple II graphics editor. Saving before a large change is the practical safety net, and a workshop auto-saves an asset that was opened from the project. Deleting a metatile clears the map cells that used it, resizing a tile map discards what falls outside the new bounds, and switching a charset between standard and multicolour converts every glyph.
Use Tools → Settings → Appearance for the complete interface. For code only, hold Command or Control while scrolling over the editor, or use the code-size keyboard shortcuts. Larger panels scroll internally, and the sidebar and Output panel can be resized.
Confirm that the declaration and the calling source are part of the same project and that the include path is written relative to the including file. Target-specific include patterns are supported; if several target files define the same procedure, Crusty Studio may show a chooser. Navigation removes the declaration itself and duplicate path representations, but it does not treat an unrelated source file containing the same text as a valid reference.
The tool check reports when Gatekeeper has quarantined a helper. Review that download and follow the exact command shown in the diagnostic to clear the quarantine attribute, then run Check installation again.
Browser preview is intentionally safe and limited: it uses simulated tool checks and a simulated C64 build, keeps files in browser memory or downloads workshop assets, and cannot launch native emulators. Use the desktop app for the complete filesystem and toolchain workflow.
For a small retro game, this sequence works well:
src/main.cbs as the entry point and split reusable routines into additional source or include files.The Studio is the organiser and feedback loop around your game. crustyBASIC remains the language and runtime, the assembler turns the compiler's output into machine code, and the emulator provides the target machine's final test.