Constellation sky links
A sky is a map of skills for one activity: each skill is a star, and lines between stars say what to learn first. Constellation is an iPhone app for tracking practice this way, and a sky can also live entirely inside a link, at https://sky.alexhumphreys.me/s/#…. Everything after the # is the sky. The page that opens it runs in the browser and never sends the sky to a server.
This page explains the format, for people and for AI assistants. If someone asked you to make them a sky, the next section is all you need.
Making a sky for someone
Write JSON in this shape:
{
"version": 2,
"title": "Bouldering basics",
"practices": [{ "name": "Bouldering" }],
"stars": [
{ "name": "Straight arms" },
{ "name": "Quiet feet" },
{ "name": "Flagging", "prereqs": ["Straight arms"] },
{ "name": "Drop knee", "prereqs": ["Quiet feet"] },
{ "name": "Heel hook", "prereqs": ["Flagging"], "softPrereqs": ["Drop knee"],
"notes": ["Pull with the hamstring, not the arms."] },
{ "name": "Dyno", "prereqs": ["Heel hook"] }
]
}
Then give it to them in one of two ways:
- As a link:
https://sky.alexhumphreys.me/s/#followed by the JSON, percent-encoded (what JavaScript'sencodeURIComponentproduces). Tapping it opens the sky, ready to edit. - As JSON to paste: on the sky page, the menu has Paste a sky. It accepts your whole answer and finds the JSON inside it, code fences and all.
Guidelines that make a sky useful:
- Name stars after real, specific skills in the activity's own words ("Heel hook", not "Intermediate technique 3").
- **
prereqsmeans "learn this first".** A star stays locked until all its prereqs are landed. UsesoftPrereqsfor "helps with, but not required". Don't make loops. - Start where they are. If the person says what they can already do ("I know my open chords", "I can already stand up on a surfboard"), include those skills as stars with
"landed": true, so the sky opens with their next steps lit. - Start small: 6 to 30 stars. Long links break in some messaging apps, and a short sky is easier to start on.
- Leave positions out. The page lays the sky out on first open.
- Don't invent links. Only add a
linksentry for a URL you know exists; otherwise leave links out. - Say it's a draft. Progressions for an activity you know second-hand may be plausible but wrong; the person will fix the order as they go.
Every line is drawn on the sky, so a sky with fewer, truer lines reads better. When choosing prereqs:
- List only direct prereqs. If "Harness basics" needs "Control power", and "Control power" needs "Neutral stance", don't also list "Neutral stance" for "Harness basics". It's already implied, and the extra line crosses the whole sky.
- Test every hard prereq: could someone learn this star without ever having done that one? If they could, it isn't a prereq. Use
softPrereqswhen it genuinely helps, and leave it out when the two are merely related, often practised together, or usually taught in that order. - Most stars need one prereq, a few need two, and three or more is rare. When every new star depends on several earlier ones, the sky turns into a tangle instead of a map.
- Separate tracks can stay separate. Unconnected groups (say, footwork drills and finger strength) are drawn side by side. Don't tie them together with a catch-all star like "Basics" or "Warm-up" unless it really has to come first.
- Watch for pairs that share both prereqs. If two stars each need the same two earlier stars, check whether both lines are true. Four lines between two pairs always cross.
- Keep names short: one to four words, under about 25 characters. Names sit beside their stars, and long ones crowd each other out.
Names in prereqs, softPrereqs, from and to can be star names, as above, or ids. Anything the page can't use is dropped and listed, never an error.
Fields
Top level:
version:2.title: optional. The sky's heading, in your own words.practices: the activities in the sky, each{ "name": "…" }, optionally with atintcolour as"#rrggbb".stars: the skills.
Each star:
name: required.practice: the practice's name or id. Defaults to the first practice.prereqs,softPrereqs: stars this one needs, by name or id.landed:trueif the person can already do it. Omit otherwise.notes: a list of plain-text notes.[[Star name]]inside a note links to that star.links: a list of{ "url": "https://…", "title": "…" }. Onlyhttpslinks are kept.kind:"transition"for a named move that bridges two stars, withfromandto.id: optional. Short,[A-Za-z0-9_-]. The page adds ids when they're missing.x,y: optional position in a 2400 × 1600 sky, origin top left. Both or neither.
Unknown fields are kept and ignored, so links made by newer versions still open.
Reading a link you were given
Take everything after the #.
- **If it starts with
{or%7B**, it's JSON: percent-decode it and parse it. - Otherwise it's compressed. Base64url-decode it to bytes:
- byte 0: container version,
2; - byte 1: flags; if bit 0 is set, the body is raw DEFLATE (no zlib header);
- bytes 2 to 5: CRC-32 of the uncompressed JSON, big-endian;
- the rest: the body. Inflate it if the flag is set; the result is the JSON above.
- byte 0: container version,
In Python:
import base64, json, zlib
frag = link.split("#", 1)[1]
raw = base64.urlsafe_b64decode(frag + "=" * (-len(frag) % 4))
body = zlib.decompress(raw[6:], -15) if raw[1] & 1 else raw[6:]
sky = json.loads(body)
This link holds a two-star sky; decode it to check your reader:
https://sky.alexhumphreys.me/s/#AgHoVDm3bZHBTsMwDIZfxTLXdCpDYmJXLkhw23HqITReG5YmJXG3VdMkXoPX40lwBmObxCWKrN-_v9_eo_W1GwwlnC_R6TEMjAp9YKlUCkO0jfU4x1WIneai1w0VSXe9I5H1Udds62PzHq0RXZtyu-5I_k_am8T5kRpbz1K7ma3MvS7xIOaRNji_VSiaeGGx1c6dTR5bSlxwKHIZ2uDMH58QL-yOR0hUB5mioM3DILVhcIZisbWGWwWvJPQEHEfrG9CwtvW6GPpJDniKcELfCdG0LBWOOH8oy4P6hco9Z6jnH4dLkpfBN6TABP_18cnwNnT9BBYiB2c9gU6wXOYIVfXv3D5SpPej0zF_dY0yuyvzxtiyu9os5N3li20oJhvkUtPDNw
Privacy
The sky lives in the link, not on a server: the part after # is never sent when a page loads. The page counts visits with GoatCounter: it sends the page's path (/ or /s/), the site you came from, and a ?from= tag if the link has one, and nothing else. No cookies, and never the sky. Anyone with a link can read the whole sky, notes included, so share it the way you'd share the text inside it.