pncdsl-demo — Morning Coffee
A short point-and-click adventure built on the
pncdsl framework. Two scenes,
three items, one NPC dialog and an ending cutscene — small on purpose,
designed as an end-to-end reference for someone learning the library.
Running it
The library is fetched as a regular Go module. Prerequisites: Go 1.24+
and SSH access to git.teletypegames.org (the private host that serves the
pncdsl repo).
git clone ssh://git@git.teletypegames.org:2222/games/pncdsl-demo
cd pncdsl-demo
go mod tidy # fetches git.teletypegames.org/games/pncdsl
go run .
A 1280×800 window opens.
Pointing Go at the private host
If go mod tidy can't reach git.teletypegames.org over HTTPS, ask Go to
clone via SSH instead. One-time setup:
git config --global \
url."ssh://git@git.teletypegames.org:2222/".insteadOf "https://git.teletypegames.org/"
export GOPRIVATE=git.teletypegames.org/*
(Add GOPRIVATE=git.teletypegames.org/* to your shell profile to make it
permanent.)
Local-development override
While iterating on the framework and the demo in parallel, point Go at a
local checkout of pncdsl with a temporary replace directive:
go mod edit -replace=git.teletypegames.org/games/pncdsl=../pncdsl
go mod tidy
Remove the replace line before pushing.
Project layout
Game content lives in lib/ as package-level vars — one struct value
per file, no constructor functions. main.go only calls lib.Run().
main.go func main() { lib.Run() }
lib/
setup.go Run() and Build(); the only wiring code
assets.go var Assets []pncdsl.Asset
flags.go flag-name constants
character.player.go var Player
character.cat.go var Cat
item.key.go / beans / mug var Key, Beans, Mug
scene.bedroom.go var Bedroom
scene.kitchen.go var Kitchen
script.intro.go var IntroScript
script.victory.go var VictoryScript
dialog.cat_morning.go var CatMorning
theme.go var MorningCoffeeTheme + var Chat
widget.gamechat.go GameChat — demo-only chat widget
widget.savekeys.go SaveKeys — F5/F9 save/load
Adding new content means creating one file with one var, and adding
one Register(...) line in lib/setup.go. No registrar functions, no
indirection.
Custom theme and chat widget
The demo ships with a game-specific theme (morning-coffee, warm coffee
browns over deep espresso) registered alongside the framework's preset
themes and activated in Build(). It is registered the same way as any
other entity:
g.ThemeManager.Register(MorningCoffeeTheme)
g.UseTheme("morning-coffee")
The chat strip at the bottom of the screen is not the framework's
built-in ChatLog. It is GameChat, a demo-only widget defined in
lib/widget.gamechat.go: click to focus (border highlights), type a
message, press Enter to send. The widget responds with a random canned
line — independent of the game state, just a playful HUD element. The
framework's ChatLog is removed and GameChat is registered in its
place during Build().
GameChat is intentionally kept inside the demo. If another game wants
the same panel, copy the file in; the framework stays free of any
gameplay-flavoured chatter.
Controls
| Action | Effect |
|---|---|
| left click on a hotspot/UI button | run the active verb |
| left click on an inventory item | select it (cursor picks it up) |
| left click on a hotspot with item selected | use-with |
| right click on a hotspot | open the verb coin |
| right click elsewhere | deselect held item, or reset verb to Look |
| left click on the chat panel | focus chat input |
| type + Enter (chat focused) | send message, receive a random reply |
| Esc | unfocus chat |
| click during dialog | advance line / pick choice |
| F1 | toggle hotspot debug overlay |
| F5 / F9 | save / load slot 0 |
License
MIT — see LICENSE.md. Copyright © 2026 Teletype Games.