Concept Sketchbook · 01 · Pull

Gravity.

引力

Stars so distant they’ve lost their starlight, trapped by their own gravity. Use your gravity to communicate with the stars.

Date
July 20, 2025
Input
Move the cursor near the stars
Built with
p5.js · OpenProcessing
Status
Sketch · playable
Live sketch · Move the cursor near the starsOpen on OpenProcessing ↗
(01)

Exploration

The feeling · Pull

Can a cursor feel like it has weight?

Most cursors point and click. Here the player is a small gravity well. There is nothing to click and nothing to choose. The only thing the player has is presence, and the sky answers to how close it comes.

(02)

Narrative exploration

The sketch starts from one image: stars so far away that their light no longer reaches anyone, each held in place by its own gravity.

The player is the one thing in that sky that can still pull. To “talk” to a star is to come close enough that it starts to move toward you.

There are no words. The conversation is the motion itself: a star leaves its small orbit and follows, then goes home when you leave.

Point of view

The player is never named and never shown. They are a force, not a character: the one presence in the sky that still has pull. The stars are the ones with a story, and the player is the listener.

Narrative structure

There is no text, no beginning and no end. The narrative is a single situation that can be repeated: loneliness, contact, return. It works more like a poem than a plot, and each player writes it again with the path of their cursor.

Motifs

Lost starlight

Something that still exists but can no longer reach anyone.

Gravity

Being held in place by yourself. The same force that traps the stars is what lets the player reach them.

The small orbit

Home. Every star has a place to return to, so contact never becomes possession.

Emotional arc
  1. 01

    Arrival

    A still, dark sky. Nothing asks for attention.

  2. 02

    Contact

    A few dim stars lean toward the cursor. The player realises they are being answered.

  3. 03

    Letting go

    Moving away, the stars drift home. The sky is as it was, and the player is the one who has changed.

Mechanic as meaning
ActionMeaning
Coming close→Starting a conversation
Stars following→Being answered
Stars returning home→The conversation ends, and nothing is taken
(03)

Result and iteration

What came out of it

The pull turned out to be gentle and temporary. Stars come when you are near and go back when you leave. The feeling that came out of it is closer to company than to control.

Decisions in the code

Pull radius · 120 px

Big enough to catch a few stars at once, small enough that the player has to go to them.

Pull strength · 0.09

Stars close 9% of the gap each frame. They ease in rather than snap, so following feels willing.

Two layers of stars

800 fixed stars only blink. 120 dimmer ones wander and can be pulled. The sky stays calm while a few stars respond.

(04)

Code

Structure
setup()
Fills the window with 800 Star objects and 120 FloatingMeteor objects.
Star
Fixed points that blink on a sine wave. Background only.
FloatingMeteor
Each one wanders in a small circle around its starting point and checks its distance to the cursor every frame.
draw()
Clears the frame, then updates and draws both layers.
windowResized()
Keeps the canvas full-window.
FloatingMeteor.update(): the pullp5.js
update() {
  let attractionRadius = 120;
  let attractionStrength = 0.09;

  // where the star would drift on its own: a small circle around home
  let wanderTargetX = this.initialX + cos(this.wanderAngle) * this.wanderMagnitude;
  let wanderTargetY = this.initialY + sin(this.wanderAngle) * this.wanderMagnitude;

  // close to the cursor? follow it. otherwise, go home.
  let d = dist(this.x, this.y, mouseX, mouseY);
  let tx = d < attractionRadius ? mouseX : wanderTargetX;
  let ty = d < attractionRadius ? mouseY : wanderTargetY;

  // ease 9% of the way there each frame
  this.x = lerp(this.x, tx, attractionStrength);
  this.y = lerp(this.y, ty, attractionStrength);
  this.wanderAngle += this.wanderSpeed;
}

Lightly condensed from the original for reading. One target switch and one lerp do all the work: the same line that pulls a star in also brings it home.

Full source on OpenProcessing ↗The embedded sketch above also has a Code tab with the complete source.

(05)

Method

What this sketch taught me about the method
01

Let presence be the input

No click needed. Being near is enough, which makes the cursor feel like a body rather than a pointer.

02

Make it reversible

Stars return home, so the player can’t break the sky. That freedom is what makes it calm.

03

Two layers, one voice

A quiet background and a small responsive layer keep the answer readable.

See the method behind the series →

概念速写本 · 01 · 牵引

引力.

Gravity

远到失去星光的星星,被困在自己的引力里。用你的引力去和星星交流。

日期
2025 年 7 月 20 日
操作
把光标移近星星
工具
p5.js · OpenProcessing
状态
速写 · 可试玩
在线试玩 · 把光标移近星星在 OpenProcessing 打开 ↗
(01)

探索

感受 · 牵引

光标能不能让人感觉到“重量”?

大多数光标只负责指和点。这里的玩家是一个小小的引力源:没有可点的东西,也没有可选的东西。玩家唯一拥有的是“在场”,天空回应的是你靠得有多近。

(02)

叙事探索

这个速写从一个画面开始:星星远到光已经照不到任何人,每一颗都被自己的引力困在原地。

在这片天空里,玩家是唯一还能“拉动”什么的存在。和星星“交流”,就是靠得足够近,让它开始向你移动。

这里没有一个字。对话就是运动本身:一颗星离开它小小的轨道跟上来,你走开后,它又回到原处。

视角

玩家没有名字,也不出现在画面上。玩家是一种力,不是一个角色:天空里唯一还有引力的存在。有故事的是星星,玩家是那个倾听者。

叙事结构

这里没有文字,没有开头,也没有结尾。叙事是一个可以反复发生的情境:孤独、接触、回归。它更像一首诗而不是一段情节,每个玩家都用光标的轨迹把它重新写一遍。

意象

失去的星光

仍然存在,却再也照不到任何人的东西。

引力

被自己困在原地。困住星星的是引力,让玩家触到它们的也是引力。

小小的轨道

家。每颗星都有可以回去的地方,所以接触永远不会变成占有。

情绪曲线
  1. 01

    到来

    一片安静、黑暗的天空,什么也不催促你。

  2. 02

    接触

    几颗暗星向光标靠过来,玩家意识到自己得到了回应。

  3. 03

    放手

    离开后,星星漂回原处。天空和原来一样,改变的是玩家自己。

机制即意义
动作含义
靠近→开始一段对话
星星跟随→得到回应
星星回到原处→对话结束,什么也没有被带走
(03)

结果与迭代

得到了什么

最后得到的引力是温柔的、短暂的:你靠近时星星过来,你离开时它们回去。由此得到的感受更接近“陪伴”,而不是“控制”。

代码里的决定

引力半径 · 120 px

大到一次能牵动几颗星,又小到玩家得主动走过去。

引力强度 · 0.09

星星每一帧拉近 9% 的距离,是慢慢靠过来,不是一下吸住,跟随显得是自愿的。

两层星星

800 颗固定的星只会闪烁,120 颗更暗的星会游荡、能被牵动。天空保持安静,只有少数星星回应。

(04)

代码解读

结构
setup()
铺满窗口:800 个 Star 对象和 120 个 FloatingMeteor 对象。
Star
按正弦波闪烁的固定点,只做背景。
FloatingMeteor
每一颗都绕着自己的起点小幅游荡,每一帧检查和光标的距离。
draw()
清空画面,再更新并绘制两层星星。
windowResized()
让画布始终铺满窗口。
FloatingMeteor.update():引力p5.js
update() {
  let attractionRadius = 120;
  let attractionStrength = 0.09;

  // where the star would drift on its own: a small circle around home
  let wanderTargetX = this.initialX + cos(this.wanderAngle) * this.wanderMagnitude;
  let wanderTargetY = this.initialY + sin(this.wanderAngle) * this.wanderMagnitude;

  // close to the cursor? follow it. otherwise, go home.
  let d = dist(this.x, this.y, mouseX, mouseY);
  let tx = d < attractionRadius ? mouseX : wanderTargetX;
  let ty = d < attractionRadius ? mouseY : wanderTargetY;

  // ease 9% of the way there each frame
  this.x = lerp(this.x, tx, attractionStrength);
  this.y = lerp(this.y, ty, attractionStrength);
  this.wanderAngle += this.wanderSpeed;
}

为方便阅读略作精简。一个目标切换加一个 lerp 完成了全部工作:把星星拉过来的同一行代码,也负责把它送回家。

在 OpenProcessing 查看完整源码 ↗上方嵌入的速写里也有 Code 标签,可以查看完整源码。

(05)

方法

这个速写对方法的启发
01

让“在场”成为输入

不需要点击,靠近就够了,光标因此更像一个身体,而不是一个指针。

02

让它可以复原

星星会回家,玩家不会弄乱天空。正是这种自由让它显得安静。

03

两层,一个声音

安静的背景加上少量会回应的星星,让回应清晰可读。

查看整个系列的方法 →