Writing stories

Story vs script mode, what dogs hear, pronouns, traits from an author angle, debugging.

Bark is a small esoteric language dressed up as short dog stories. It is meant to be ridiculous and fun, not practical or serious. You get assignments, branches, loops, stashes, piles, math, and tricks. That should also be enough for the usual "is this Turing complete?" thing that is apparently part of writing esoteric languages. At least, I think it does! Feel free to tell me I am wrong though. I did not deep dive into that topic, so it might as well not be true as well.

The idea: dogs hear blah name blah blah walk blah blah and only react to the words that they recognise. The rest gets ignored completely. Bark behaves the same. It ignores almost everything that is not a registered name, a keyword, or a value instead of throwing errors. You wrap real commands in filler if you want just so it reads nicer.

Story mode vs script mode

Two ways to write Bark programs.

StoryScript (no filler)Same meaning
her cookie jar holds "biscuit", "stick"cookie_jar holds "biscuit", "stick"fill a stash
she whimpers as she wants the first biscuit from her cookie jarwhimper first from cookie_jarprint first stash item
her cookie jar is emptycookie_jar emptyclear a stash
her cookie jar drops firstcookie_jar drops firstremove front slot
she woof how many toys she hasbark how many toys the labrador hasprint toy count
when she has 2 toys then she woofs "Ready."when labrador has 2 toys then bark "Ready."branch
for each treat from her cookie jar thenfor each treat from cookie_jar thenloop over stash
the labrador shares with the golden retrieverlabrador shares with golden_retrieversplit toys
the laundry basket holds "shirt", "sock"laundry_basket holds "shirt", "sock"fill a pile
I bark what is on top of the laundry basketbark top of laundry_basketpeek pile top

Story: spaces instead of underscores (cookie jar), optional filler (the, as she wants, even stash or pile if you like more technical jargon). None of that changes behaviour.

Script: registry names with underscores, heard keywords only, no filler. Do not write cookie_jar stash. The name cookie_jar is already enough. Use empty to clear a stash (or synonyms like starving). Useful for tests and scratch files.

Full script anti-patterns: Input and edge cases.

What the dogs hear

HeardNot heard (filler/glue)
Breeds, objects, stashes, piles from the registry filesBasically everything else: is, has, my, the, a, items, stash, pile, etc.
Keywords: when, bark, holds, shares, bury, …No separate ignore list. If it is not heard, it is filler.
memory / journal (two program-wide variables)
Strings, numbers, traits
I have a labrador.
She is 2.
She has 2 toys.
Her name is "Bimba".
she woofs how many toys she has

That prints 2. Meaning comes from where words sit on the line (who, what field, what value), not from filler like is or has.

A single breed on a line still registers it:

labrador
I have a labrador.
She is 2.              → age = 2
She has 2 toys.        → toys = 2
He is 5 years old      → age = 5
Her name is "Bimba".   → name
my corgi is loud       → loud trait
when she has 2 toys then …  → branch (when must start the line)

Filler never triggers behaviour by itself.

Debugging: --strict warns on lines that did nothing. --quiet hides the banner when you care about clean stdout.

One line per statement (mostly)

Each line is usually one command. Dogs are simple creatures.

Exceptions:

  • Multiline blocks after when / while / for each / tricks, closed with bury (or enough, goodnight, etc.)
  • One-liner branches like when she has 1 toy then she woofs "Hi" otherwise she woofs "Nope" with no bury

So a block is a bunch of lines between then and bury, not a free-form paragraph.

List slots: first, second, last

These are heard keywords. They pick a stash slot.

They only do something useful in stash/pile context (drops first, first from cookie jar, etc.). On a random story line they are just words that happen to be heard.

Not heard globally: spelled-out numbers used as slots (one, two, twenty third). Those still work in stash lines via the parser, but stay filler elsewhere so they do not collide with normal prose.

Dog fields (nine stored, many story words)

When you mention a breed (labrador, I have a beagle), you are registering a dog. The breed name is the handle from breeds.txt. It is not one of the nine stored fields. There is no breed counter.

Each dog keeps nine values. Story words are aliases. The parser maps toysitems, treatsfood, and so on.

Stored fieldTypeStory aliases (examples)
foodnumbertreat, snacks, cookie, biscuit. she steals a treat
itemsnumbertoy, toys, walk, nap, friend, squirrel. She has 2 toys
inventorytextbelongings, comma list (ball, stick)
agenumberShe is 2, labrador 5, years old
nametextname, nickname
descriptiontextowner, collar, tag, family
colortextcolor, species, gender
happyyes/nogoodboy, happy, trained, etc.
fedyes/nofed, groomed, washed

Full field table and every alias: Dog fields.

Treats vs toys

Dogs track food and items separately.

  • Food: treats, snacks, biscuits. she steals a treat adds to food.
  • Items: toys, walks, naps, squirrels, friends. She has 2 toys and she finds a toy touch items.

Greedy-trait logic only cares about food in some cases. See Traits.

World objects (ball, bone, etc.)

Names in objects.txt are world counters, not dog fields.

ball 5
I bark ball

Separate from a dog's inventory (comma list of what they carry). See Registries.

Comparisons in conditions

Less-than: sniffs + less. Greater-than: has more than.

You wantWrite
loop while toys < 8while she sniffs less toys than 8 then
branch when toys > 2when she has more than 2 toys then

Full grammar: Conditions.

Branches (when / if)

when is a real keyword, but only when it starts the line:

when she has 2 toys then she woofs "Ready."     → branch
bark "They left when the jar was empty."        → print only
The sun set when they reached the gate.         → story-only (--strict warns)
Where when isEffect
First word on the lineBranch
After otherwiseNext branch: otherwise when she has 1 toy then …
Inside "quotes"Printed text
Anywhere elseIgnored for control flow

Loops work the same: while, until, for each must lead the line. See Control flow.

Pronouns

WordResolves to
she / herLast dog you spoke about as she/her
he / him / hisLast dog as he/him/his
itLast stash, pile, or object
they / themFiller
I have a labrador.
She is 2.
I have a beagle.
she passes a toy to the beagle    → labrador gives, not beagle

Introducing another breed does not rebind she from the first dog. Full rules: Registering and pronouns.

Stash vs pile

Stash = ordered jar. Slots matter (first, second, last).

Story: her cookie jar holds "a", "b", "c", for each treat from her cookie jar thenbury

Script: cookie_jar holds "a", "b", "c", whimper first from cookie_jar, cookie_jar empty

Pile = stack (last in, first out).

Story: the laundry basket holds "a", I bark what is on top of the laundry basket

Script: laundry_basket holds "a", bark top of laundry_basket

Full grammar: Stashes and piles.

Synonyms

Learn one phrase, swap words when it sounds better.

IdeaStart hereAlso works
Equalsmatcheshas, is, are (assign)
Greatergrowls louder thanbigger, more
End blockburyenough, goodnight, done
Add toyfinds a toygets, fetches, collects
Add treatfeeds a treatfood verbs, not toy verbs
Lose toymisplaces a toytosses, hides
Eat treatgulps a treatnot toy verbs

Shortcuts

LineMeaning
the labrador shares with the beagle and huskySplit toys. Remainder stays with giver
the labrador passes a toy to the beagleOne toy, one friend
her cookie jar is emptyClear stash
bark bark barkPaw print easter egg

Traits (personality, not fields)

Traits are optional flags on a dog. Not part of the nine fields. They change interpreter behaviour.

Defaults in traits.json (60 breeds). You can set or clear in stories:

my corgi is loud
my beagle is greedy
my labrador is not greedy
TraitWhat it does
loudDog speaks → UPPERCASE. Narrator bark "…" stays normal.
greedyAfter 3 feed/gulp/share actions in a row, lose 1 treat from food. Counter resets after penalty.
lazywait sleeps twice as long.
wetwhine / whimper output doubled.
fetchySame print twice → proud fetch line on stdout, then prints again.
chaserEach loop tick adds +1 toy to items. Story word squirrels is the same field.
playfulDog speaks → characters reversed before formatting. Narrator unchanged.

Mood (no trait required):

  • Dog speaks (she barks, labrador woofs "…"): 0 toys → lowercase output. loud → uppercase.
  • Narrator (bark "…", I bark "…"): prints as written.

Full runtime detail: Traits and Runtime semantics.

Comments

// scene note
# act two

Debugging checklist

  1. bark --list-breeds and bark --list-objects
  2. Typos get fuzzy hints (Did you mean cookie jar?)
  3. Errors are dog-themed and prefer dog themed over usefulness. Sorry, not sorry.
  4. Short branches can live on one line. Longer scenes use bury
  5. Compare with tutorial.woof in the repo examples

Example to run

./bark examples/woof/tutorial.woof
./gradlew run --args="examples/woof/tutorial.woof"

tutorial.woof: Bimba at the park. Scratch work goes in examples/scratch/ (gitignored).