moonn.
Gather the moonlight from the tree, and return it to the moon.
Exploration
What if collecting changed the world instead of a score?
There is no counter on screen. The only sign of progress is the sky. Every catch makes the background darker and the tree brighter, so collecting slowly turns the day into night.
Narrative exploration
The moonlight has ended up in a tree. The player’s job is to shake it loose and give it back. Giving it back is a feeling, not a place on screen.
Each drop of light floats slowly upward as it fades, as if it already knows where it is going.
Collecting light makes the world darker. The more you gather, the closer it comes to night, the hour that belongs to the moon.
The player is a go-between. The light belongs to the moon and is caught in the tree. The player owns none of it and is only there to help it go home.
The story is a single task that takes the length of a day. Its progress is told by light: every return makes it later. The ending is not a message on screen but the moment the sky has gone fully dark.
Moonlight in a tree
Something borrowed and not yet given back. A debt of light.
The branching tree
Patience and searching. The light hides in the finest twigs.
Day turning to night
Giving back costs the day. The world grows darker as the debt is paid.
- 01
Searching
A pale, bright day and a dark tree. The player looks closely for where to click.
- 02
Rhythm
Some clicks shake light loose and some don’t. The player settles into a quiet back and forth with the tree.
- 03
Night
The sky is dark and the tree glows. The light has all gone up, and nothing is left to do but look.
Result and iteration
Gathering turned into a slow change of time. After thirty catches the day is gone and the tree glows on its own. The feeling that came out of it is giving back, not taking.
Hit distance · 12 px
Clicks have to land on a branch, so the player looks closely at the tree.
Chance · 50%
Half the clicks give nothing. The tree feels alive, not like a dispenser.
Thirty catches to night
Long enough to feel the light change, short enough to finish in one sitting.
Code
setup()- Grows the tree once with drawTree() and stores every branch as a line segment.
drawTree()- Recursive: each branch splits into 2–3 children, turning up to 60° and shrinking to 60–85% of its length, until branches are shorter than 6 px.
mousePressed()- Measures the click’s distance to each branch segment with distToSegment(), then rolls the 50% chance.
draw()- Maps the number of catches to sky and tree colour, then moves each drop of light up and fades it.
function draw() {
// 0 → 30 catches: the sky goes from day (250) to night (80)
let bgBase = map(lightCount, 0, 30, 250, 80, true);
background(bgBase, bgBase - 10, bgBase - 20);
// ...and the tree brightens as the sky darkens
let treeBrightness = map(lightCount, 0, 30, 40, 180, true);
for (let b of branches) {
strokeWeight(b.w);
stroke(treeBrightness, treeBrightness - 10, treeBrightness - 30, b.alpha);
line(b.x1, b.y1, b.x2, b.y2);
}
// each drop of light rises slowly and fades
for (let i = lights.length - 1; i >= 0; i--) {
let l = lights[i];
l.y -= 0.3;
l.alpha -= 0.8;
fill(255, 240, 180, l.alpha);
noStroke();
ellipse(l.x, l.y, l.size);
if (l.alpha <= 0) lights.splice(i, 1);
}
}Comments added for reading. Two map() calls replace a score display: the same counter drives the sky and the tree in opposite directions.
Full source on OpenProcessing ↗The embedded sketch above also has a Code tab with the complete source.
Method
Let the world keep score
Progress is a colour change, not a number, so the player watches the world instead of the HUD.
Misses are part of the voice
A 50% chance makes the tree feel like it is choosing.
Let things leave
Light that rises and fades is returned rather than owned.
还月光.
收集树上的月光,把它还给月亮。
探索
如果收集改变的不是分数,而是整个世界?
画面上没有计数器,唯一的进度提示是天空。每收集一次,背景就暗一点,树就亮一点,收集这件事慢慢把白天变成了夜晚。
叙事探索
月光落在了一棵树上。玩家要做的,是把它摇下来,还回去。“还给月亮”是一种感觉,不是画面上的某个地方。
每一滴光都会一边淡去,一边慢慢往上飘,好像它已经知道要去哪里。
收集光会让世界变暗。收得越多,天就越接近夜晚,那是属于月亮的时刻。
玩家是一个中间人:光属于月亮,被树留住了。玩家什么也不拥有,只是帮它回家。
故事是一件需要一整天来完成的事。它的进展由光来讲述:每归还一次,天就晚一点。结尾不是屏幕上的一句话,而是天空完全暗下来的那一刻。
树上的月光
借来还没还的东西,一笔光的债。
分叉的树
耐心与寻找。光藏在最细的枝丫里。
白天变成黑夜
归还要付出白天。债越还越清,世界也越来越暗。
- 01
寻找
明亮苍白的白天,一棵深色的树。玩家仔细地找可以点的地方。
- 02
节奏
有的点击能摇下光,有的不能。玩家和树之间慢慢有了一来一回的节奏。
- 03
夜晚
天黑了,树亮着。光都已经飘上去,剩下的只有看。
结果与迭代
收集变成了时间缓慢的流转。收满三十次,白天就过去了,树自己亮了起来。由此得到的感受是“归还”,而不是“拿走”。
点击判定 · 12 px
点击必须落在树枝上,玩家会仔细地看这棵树。
成功率 · 50%
一半的点击什么也得不到,树显得是活的,而不是一台出货机器。
三十次入夜
长到能感觉光在变化,短到一次就能玩完。
代码解读
setup()- 用 drawTree() 一次性长出整棵树,把每根枝条存成一条线段。
drawTree()- 递归:每根枝条分出 2–3 根子枝,偏转最多 60°,长度缩到 60–85%,直到短于 6 px。
mousePressed()- 用 distToSegment() 算出点击到每根枝条的距离,再掷一次 50% 的概率。
draw()- 把收集次数映射成天空和树的颜色,再让每滴光上升、淡去。
function draw() {
// 0 → 30 catches: the sky goes from day (250) to night (80)
let bgBase = map(lightCount, 0, 30, 250, 80, true);
background(bgBase, bgBase - 10, bgBase - 20);
// ...and the tree brightens as the sky darkens
let treeBrightness = map(lightCount, 0, 30, 40, 180, true);
for (let b of branches) {
strokeWeight(b.w);
stroke(treeBrightness, treeBrightness - 10, treeBrightness - 30, b.alpha);
line(b.x1, b.y1, b.x2, b.y2);
}
// each drop of light rises slowly and fades
for (let i = lights.length - 1; i >= 0; i--) {
let l = lights[i];
l.y -= 0.3;
l.alpha -= 0.8;
fill(255, 240, 180, l.alpha);
noStroke();
ellipse(l.x, l.y, l.size);
if (l.alpha <= 0) lights.splice(i, 1);
}
}注释为方便阅读而加。两个 map() 取代了分数显示:同一个计数同时驱动天空和树,方向相反。
在 OpenProcessing 查看完整源码 ↗上方嵌入的速写里也有 Code 标签,可以查看完整源码。
方法
让世界来计分
进展是颜色的变化,不是数字,玩家看的是世界,而不是界面。
落空也是一种声音
50% 的概率让树显得像在做选择。
让东西离开
会上升、会淡去的光是被归还,而不是被拥有。