# pncdsl-demo — Morning Coffee

A short point-and-click adventure built on the
[`pncdsl`](https://git.teletypegames.org/games/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).

```bash
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:

```bash
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:

```bash
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 `var`s — one struct value
per file, no constructor functions. `main.go` only calls `lib.Run()`.

```
main.go                       embeds assets/ (go:embed) and calls 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.

The `assets/` tree is compiled into the binary via `go:embed` and
handed to the framework through `pncdsl.AssetFS`, so the js/wasm build
(`make wasm`) ships with working art. Native builds read from the same
embedded copy — changing a PNG requires a rebuild. Files listed in
`lib/assets.go` but missing from `assets/` still fall back to the
framework's colored placeholders.

## 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:

```go
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`](LICENSE.md). Copyright © 2026 Teletype Games.
