Feedback that arrives, and a reason to dig

The Orbit2D signal log showing nine objectives and recovered log entries

Written by

in

Two things went in this week, and they belong in the same entry because they are the same
idea from opposite ends: the game now asks the player what they think, and it finally tells the
player what they are doing here.

Part one: a feedback form that actually delivers

There is a panel on the title screen now. Four tags — Bug, Idea, Too hard, Loved it — a
message box, and an optional email if you want a reply.

The feedback panel on the Orbit2D title screen, with Bug, Idea, Too hard and Loved it tags

The part worth writing down is what every message carries with it. A player who says “it
broke” has told you almost nothing. So each message automatically arrives with the world number
and name, the level and how many pieces were placed, the build version, the viewport size, and
whether the session was touch or pointer. That is the difference between a complaint and a bug
report, and it costs the player nothing.

Then the interesting failure. The obvious implementation is to have the endpoint email me
directly, and that is what I built first. It did not work — and it did not work in the worst
possible way, which is silently. PHP’s mail() returned success and nothing arrived,
because the domain’s SPF record does not list the web server, so every message failed
authentication and was dropped before it reached an inbox. Had I trusted the return value, I
would have shipped a form that swallowed feedback for weeks and concluded nobody had any.

The fix separates storing from sending. The endpoint’s only job is to validate and append the
message to a file outside the document root, which either works or fails loudly. Delivery is a
separate scheduled job that reads anything new over a token-protected endpoint and emails it
from an address that passes authentication, keeping a cursor so nothing is sent twice and nothing
is lost if a send fails. Store first, deliver second, and never let the delivery layer be the
thing that owns the data.

Housekeeping, since this is a public form: a honeypot field, a five-per-hour cap per address,
a 1,400-character limit, control characters stripped, and IP addresses hashed rather than stored.
My email address is not in the page source, so it cannot be scraped out of the game.

Part two: the game now has a story

Orbit2D had a premise sitting unread in its own scenery. There is a Signal Monolith described
as the source of a carrier tone. There is a derelict hauler captioned “someone was here first”.
You wake up in a crash pod. None of it went anywhere, and a new player’s honest reaction to the
first two minutes was: dig what, and why?

The Orbit2D signal log showing nine objectives and recovered log entries

The answer is deliberately not a cutscene. It is two layers.

Nine objectives, satisfied by playing

One objective is shown at a time, on a pill under the readouts: break ground, make it yours,
see the first dawn, seal and heat a room, get the current up, cook a hot meal, dig under the
slate, find who came first, answer the tone.

Every one of them is checked against live game state rather than a scripted trigger. “Seal and
heat a room” reads the same shelter calculation the HUD displays, so what you see is what the
objective reads. “Get the current up” asks the power grid whether a generator is running and a
machine is actually drawing from it. Nothing is a trigger volume. A player who never looks at
the objective list completes it anyway by playing well, which is the only version of this I am
willing to ship — the objectives describe the game, they do not fence it.

They also fix a real structural problem. The reward curve runs to level 30 and the back half
of it had nothing pointing at it. The spine is weighted so that finishing it carries a player to
somewhere around rank 18, which means the late ranks are now the reward for a journey rather
than a grind with no destination.

Nine log entries you have to earn

The other layer is the reading. Nine written fragments — the lander’s final entry, survey
notes from the geyser and the grove, personal logs from the first night and the first working
generator, the recovered crew log of the hauler Kestrel Ash, and what is waiting on the
ridge. They unlock from reaching landmarks and from passing milestones, so exploring and
progressing feed the same log.

They are written as documents, not exposition. The survey note about the geyser observes that
it vents on a fifty-one second cycle and remarks that nothing geological is that tidy. The note
from the fungal basin observes that every stalk leans toward the ridge, and admits the writer is
trying not to use the word “cultivated” in an official log. The hauler’s log is nineteen people
who landed intact, dug in, ate well, lasted eleven months, and then walked to the ridge one at a
time. Its last line is the thesis of the whole game: the tone is not a distress call, because
distress calls do not wait.

One small interaction detail I am pleased with. Completing an objective can push a level, and
a level opens the talent picker — which meant a modal could slam over a log entry mid-sentence.
The picker now waits until you have closed the log. Interrupting someone reading is a worse sin
than delaying a reward by four seconds.

What is next

The third layer is consequence: making the ending respond to how the colony was actually
built — how deep, how sealed, how well fed, and at what rank you arrived. The groundwork is in,
because the game now tracks the things that would need to be read.

Until then: nine objectives, nine entries, twenty worlds, thirty ranks, and a form on the
title screen that genuinely reaches me. Play it, then tell me what dragged.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *