t27.aiРусский

The ship flies home

You will learn

Where the game draws a bee for each thing it is doing, and how a finished task ends on screen.

In the game at app.t27.ai/game each bee is a ship over the issue it works on. ship_mode in hive.t27 picks the place: parked at the entrance before a runner claims it, orbiting its cell while it is heard from, hovering when it has gone quiet, and waiting at its repository's portal until its cell is placed. When the bee leaves the feed it flies home, and ship_alpha fades it over DEPART_MS, 2400 ms: at 1200 ms it is at 500 of 1000.

Try it

Mark the bee as not heard from and see where it moves; then drag the time past 2400 ms.

Open the interactive lesson →

The game: where a bee flies and how it leaves
The game: where a bee flies and how it leaves ↗

Set what the bee is doing and where its cell stands: ship_mode puts it at the entrance, the portal, its cell or on the way home, and ship_alpha fades it out.

specs/queen/hive.t27

// SPDX-License-Identifier: Apache-2.0
; specs/queen/hive.t27 -- how the game draws the swarm: where each ship flies, what an event does to
; a cell, how a ship leaves, and how often the map may grow
; Owner, 2026-10-08 (translated): the bees fly over the GitHub issue each is working on, in the game
; (https://app.t27.ai/game); the ships come from the same 3D kit as the comb. Epic #7718, slice 4.
; What the game did before this card (gHashTag/trinity QueenCombBabylon, measured that day):
; - a bee that left the feed vanished in the frame it left: a finished task had no ending on screen.
; - a bee on an issue with no cell yet waited at the hive's entrance, in the middle of the map, far
;   from the repository it works for.
; - every newly running issue the atlas did not hold added one cell, and a new cell rebuilt the whole
;   scene: one rebuild for most bees that started.
; - nothing on the map answered an event: an accepted task, a lost lease and a cancel looked the same
;   as no news.
; The event kinds are control.t27's EV_* (index of a per-kind table here). Bee states arrive as two
; flags rather than tasks.t27's numbers, so no number is restated. The game runs this card as wasm.
; ASCII only (L3).
; phi^2 + 1/phi^2 = 3 | TRINITY

module QueenHive;

pub const HIVE_KINDS : u8 = 10;

; --- 1. Where a ship flies ---------------------------------------------------------------------------

/// Where its issue's cell stands: on the map, waiting for the next batch (section 4), or nowhere this
/// map can show (a repository with no region, or a task that is not an issue).
pub const CELL_PLACED : u8 = 0;
pub const CELL_PENDING : u8 = 1;
pub const CELL_NONE : u8 = 2;

/// PARK: in a row at the hive's entrance. ORBIT: circling its issue's rim. HOVER: still at the rim,
/// heard from too long ago to be drawn working. PORTAL: at its repository's portal, until its cell is
/// placed. HOME: flying back to the entrance, its task over.
pub const SM_PARK : u8 = 0;
pub const SM_ORBIT : u8 = 1;
pub const SM_HOVER : u8 = 2;
pub const SM_PORTAL : u8 = 3;
pub const SM_HOME : u8 = 4;

/// `queued`: not claimed yet. `working`: heard from lately (tasks.t27 bee_state). `departing`: no
/// longer in the feed.
pub fn ship_mode(queued: bool, working: bool, cell: u8, departing: bool) -> u8 {
    if (departing) { return SM_HOME; }
    if (queued) { return SM_PARK; }
    if (cell == CELL_PENDING) { return SM_PORTAL; }
    if (cell != CELL_PLACED) { return SM_PARK; }
    if (working) { return SM_ORBIT; }
    return SM_HOVER;
}

; --- 2. How a ship leaves ----------------------------------------------------------------------------

/// A ship whose bee left the feed flies home and fades out over DEPART_MS, instead of vanishing.
pub const DEPART_MS : u32 = 2400;

pub fn ship_kept(ms_since_left: u32) -> bool {
    return ms_since_left < DEPART_MS;
}

/// Opacity in thousandths: whole while its bee is in the feed, then falling to nothing.
pub fn ship_alpha(departing: bool, ms_since_left: u32) -> u32 {
    if (departing == false) { return 1000; }
    if (ms_since_left >= DEPART_MS) { return 0; }
    return 1000 - (ms_since_left * 1000) / DEPART_MS;
}

; --- 3. What an event does to a cell -----------------------------------------------------------------

/// FX_ACCEPT gold, FX_SEND_BACK amber, FX_LOST red (the lease expired: the bee went silent and the
/// task was taken back), FX_CANCEL grey (a person stopped it), FX_START white at the cell the bee is
/// headed for. task.ended draws nothing on the cell: its ship flies home, which says it.
pub const FX_NONE : u8 = 0;
pub const FX_START : u8 = 1;
pub const FX_ACCEPT : u8 = 2;
pub const FX_SEND_BACK : u8 = 3;
pub const FX_LOST : u8 = 4;
pub const FX_CANCEL : u8 = 5;

/// Per kind (control.t27 EV_*): created START, lease.expired LOST, reviewed ACCEPT or SEND_BACK by
/// its verdict, cancel CANCEL; everything else nothing.
pub const FX_OF_KIND : [10]u8 = [1, 0, 0, 4, 0, 2, 0, 5, 0, 0];

/// `accepted`: a review's verdict was an acceptance. Only a review reads it.
pub fn cell_effect(kind: u8, accepted: bool) -> u8 {
    if (kind >= HIVE_KINDS) { return FX_NONE; }
    let fx : u8 = FX_OF_KIND[kind];
    if (fx == FX_ACCEPT and accepted == false) { return FX_SEND_BACK; }
    return fx;
}

/// A flash rises at once and fades over FLASH_MS; an event older than that is not drawn.
pub const FLASH_MS : u32 = 1800;

pub fn flash_alpha(ms_since: u32) -> u32 {
    if (ms_since >= FLASH_MS) { return 0; }
    return 1000 - (ms_since * 1000) / FLASH_MS;
}

; --- 4. How often the map may grow -------------------------------------------------------------------

/// A running issue the atlas does not hold needs a cell, and a cell is part of the built scene: adding
/// one rebuilds it. So new cells are placed in batches, at most one batch every CELL_BATCH_SECONDS --
/// the same period a board takes a whole snapshot (events.t27 SNAPSHOT_EVERY_SECONDS) -- and all of
/// them at once when the page first opens. Until its cell is placed, a bee waits at its repository's
/// portal (SM_PORTAL), so where it is going is already true.
pub const CELL_BATCH_SECONDS : u32 = 300;

pub fn cells_due(pending: u32, placed_before: bool, seconds_since_batch: u32) -> bool {
    if (pending == 0) { return false; }
    if (placed_before == false) { return true; }
    return seconds_since_batch >= CELL_BATCH_SECONDS;
}

test a_ship_flies_where_its_bee_is {
    // queued: at the entrance, wherever its cell stands
    assert ship_mode(true, false, CELL_PLACED, false) == SM_PARK;
    assert ship_mode(true, true, CELL_PENDING, false) == SM_PARK;
    // claimed, its cell placed: orbit while heard, hover when quiet
    assert ship_mode(false, true, CELL_PLACED, false) == SM_ORBIT;
    assert ship_mode(false, false, CELL_PLACED, false) == SM_HOVER;
    // its cell not placed yet: at its repository's portal, working or not
    assert ship_mode(false, true, CELL_PENDING, false) == SM_PORTAL;
    assert ship_mode(false, false, CELL_PENDING, false) == SM_PORTAL;
    // no cell this map can show: back at the entrance
    assert ship_mode(false, true, CELL_NONE, false) == SM_PARK;
    // gone from the feed: home, whatever it was
    assert ship_mode(false, true, CELL_PLACED, true) == SM_HOME;
    assert ship_mode(true, false, CELL_NONE, true) == SM_HOME;
}

test a_ship_leaves_by_flying_home {
    assert ship_kept(0) == true;
    assert ship_kept(DEPART_MS - 1) == true;
    assert ship_kept(DEPART_MS) == false;
    assert ship_alpha(false, 0) == 1000;
    assert ship_alpha(false, 99999) == 1000;
    assert ship_alpha(true, 0) == 1000;
    assert ship_alpha(true, 1200) == 500;
    assert ship_alpha(true, DEPART_MS - 1) == 1;
    assert ship_alpha(true, DEPART_MS) == 0;
    assert ship_alpha(true, 4000000000) == 0;
}

test an_event_lights_its_cell {
    assert cell_effect(0, false) == FX_START;
    assert cell_effect(1, true) == FX_NONE;
    assert cell_effect(2, false) == FX_NONE;
    assert cell_effect(3, false) == FX_LOST;
    assert cell_effect(4, true) == FX_NONE;
    assert cell_effect(5, true) == FX_ACCEPT;
    assert cell_effect(5, false) == FX_SEND_BACK;
    assert cell_effect(6, true) == FX_NONE;
    assert cell_effect(7, false) == FX_CANCEL;
    assert cell_effect(8, false) == FX_NONE;
    assert cell_effect(9, true) == FX_NONE;
    // only a review reads the verdict
    assert cell_effect(3, true) == FX_LOST;
    assert cell_effect(HIVE_KINDS, true) == FX_NONE;
}

test a_flash_fades {
    assert flash_alpha(0) == 1000;
    assert flash_alpha(900) == 500;
    assert flash_alpha(FLASH_MS - 1) == 1;
    assert flash_alpha(FLASH_MS) == 0;
    assert flash_alpha(4000000000) == 0;
}

test the_map_grows_in_batches {
    assert cells_due(0, false, 0) == false;
    assert cells_due(0, true, 99999) == false;
    // the first answer places every cell at once
    assert cells_due(3, false, 0) == true;
    // after that, one batch a period
    assert cells_due(1, true, CELL_BATCH_SECONDS - 1) == false;
    assert cells_due(1, true, CELL_BATCH_SECONDS) == true;
}

invariant one_row_per_kind {
    assert HIVE_KINDS == 10;
    assert FX_OF_KIND[5] == FX_ACCEPT;
    assert FLASH_MS < DEPART_MS * 2;
    assert CELL_BATCH_SECONDS == 300;
}

Open the lesson's spec in the player ↗

All lessons