Compare commits
46
Commits
@@ -18,7 +18,7 @@ on:
|
|||||||
- .gitea/workflows/deploy.yml
|
- .gitea/workflows/deploy.yml
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PORTAL_RELEASE: v0.3.6
|
PORTAL_RELEASE: v0.3.36
|
||||||
INSTANCE: redoal-portal
|
INSTANCE: redoal-portal
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -57,6 +57,10 @@ jobs:
|
|||||||
KANIDM_URL=${{ vars.KANIDM_URL }}
|
KANIDM_URL=${{ vars.KANIDM_URL }}
|
||||||
OAUTH2_CLIENT_ID=${{ vars.OAUTH2_CLIENT_ID }}
|
OAUTH2_CLIENT_ID=${{ vars.OAUTH2_CLIENT_ID }}
|
||||||
OAUTH2_CLIENT_SECRET=${{ secrets.OAUTH2_CLIENT_SECRET }}
|
OAUTH2_CLIENT_SECRET=${{ secrets.OAUTH2_CLIENT_SECRET }}
|
||||||
|
# Onboarding from a desk (portal 0.3.40+, `invite:` alternatives): a
|
||||||
|
# Kanidm service-account token in idm_people_on_boarding. Empty
|
||||||
|
# means invites are not configured on this instance.
|
||||||
|
KANIDM_API_TOKEN=${{ secrets.KANIDM_API_TOKEN }}
|
||||||
PUBLIC_URL=${{ vars.PUBLIC_URL }}
|
PUBLIC_URL=${{ vars.PUBLIC_URL }}
|
||||||
COOKIE_SECURE=true
|
COOKIE_SECURE=true
|
||||||
# This repo is its own instance's content source; branding
|
# This repo is its own instance's content source; branding
|
||||||
|
|||||||
@@ -15,13 +15,18 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
# Same bare-metal runner/host as this repo's own Deploy workflow,
|
# iris (uhhm/iris) is the lint: it reads content with the portal
|
||||||
# which ships question_lint alongside the portal binary in every
|
# release it is pinned to, so IRIS_RELEASE should match the portal
|
||||||
# pinned release - so content is validated by the exact portal
|
# this site runs (PORTAL_RELEASE in deploy.yml).
|
||||||
# version this instance runs, not a hand-maintained yq/jq subset
|
|
||||||
# of the same rules.
|
|
||||||
- name: Lint questions
|
- name: Lint questions
|
||||||
run: /srv/app/redoal-portal/current/question_lint --path questions
|
env:
|
||||||
|
IRIS_RELEASE: v0.3.39
|
||||||
|
run: |
|
||||||
|
# The checkout is on a noexec mount for this runner; the cargo
|
||||||
|
# target dir is where it may run what it fetched.
|
||||||
|
bin="/var/local/cargo-target/iris-$IRIS_RELEASE"
|
||||||
|
[ -x "$bin" ] || { curl -sfL "${{ github.server_url }}/uhhm/iris/releases/download/$IRIS_RELEASE/iris" -o "$bin" && chmod +x "$bin"; }
|
||||||
|
"$bin" check --path questions
|
||||||
|
|
||||||
reload:
|
reload:
|
||||||
runs-on: bare
|
runs-on: bare
|
||||||
|
|||||||
@@ -14,3 +14,43 @@ aggregates:
|
|||||||
unsubscribed: { event: unsubscribed }
|
unsubscribed: { event: unsubscribed }
|
||||||
transitions:
|
transitions:
|
||||||
open: [unsubscribed]
|
open: [unsubscribed]
|
||||||
|
# Double opt-in: a watcher is pending until the address confirms from
|
||||||
|
# the mail n8n sends (redoal: confirm watching); only open watchers
|
||||||
|
# are told when something lands at their shape.
|
||||||
|
- bucket: redoal_watchers
|
||||||
|
initial: pending
|
||||||
|
states:
|
||||||
|
pending: { event: requested }
|
||||||
|
open: { event: confirmed }
|
||||||
|
unsubscribed: { event: unsubscribed }
|
||||||
|
transitions:
|
||||||
|
pending: [open, unsubscribed]
|
||||||
|
open: [unsubscribed]
|
||||||
|
# Reports on recordings. The relay watches this bucket: a record
|
||||||
|
# moved to "removed" deletes the recording from its store, the varde
|
||||||
|
# pin, and discovery. "kept" closes the report with the recording in
|
||||||
|
# place. Decisions are human, never automatic.
|
||||||
|
- bucket: redoal_reports
|
||||||
|
initial: open
|
||||||
|
states:
|
||||||
|
open: { event: reported }
|
||||||
|
removed: { event: removed }
|
||||||
|
kept: { event: kept }
|
||||||
|
transitions:
|
||||||
|
open: [removed, kept]
|
||||||
|
# TestFlight beta signups (index.yaml's "Test it on your iPhone").
|
||||||
|
# Attended by automation, not a human desk: a new "requested" signup
|
||||||
|
# is handed to the App Store Connect API to invite the Apple ID to the
|
||||||
|
# closed beta; "withdrawn" (the /joined-testers self-transition) drops
|
||||||
|
# them from the invite list.
|
||||||
|
- bucket: redoal_testers
|
||||||
|
attended_by: >
|
||||||
|
n8n TestFlight onboarding workflow — ops/n8n/testflight-onboarding
|
||||||
|
in redoal/redoal. Consumes NATS events.redoal_testers.* and calls
|
||||||
|
App Store Connect POST /v1/betaTesters.
|
||||||
|
initial: open
|
||||||
|
states:
|
||||||
|
open: { event: requested }
|
||||||
|
withdrawn: { event: withdrawn }
|
||||||
|
transitions:
|
||||||
|
open: [withdrawn]
|
||||||
|
|||||||
@@ -18,18 +18,27 @@
|
|||||||
//
|
//
|
||||||
// prefers-reduced-motion freezes the field fully drawn either way.
|
// prefers-reduced-motion freezes the field fully drawn either way.
|
||||||
|
|
||||||
import { makePaths, drawPaths } from './paths.js';
|
import { makePaths, drawPaths, OVERSCAN } from './paths.js';
|
||||||
|
|
||||||
const STYLE_ID = 'redoal-hero-style';
|
const STYLE_ID = 'redoal-hero-style';
|
||||||
const CYCLE_MS = 28000;
|
const CYCLE_MS = 28000;
|
||||||
const SEED = 7;
|
const SEED = 7;
|
||||||
const COUNT = 47;
|
const COUNT = 47;
|
||||||
|
|
||||||
|
const BLEED = `${((OVERSCAN - 1) / 2) * -100}%`;
|
||||||
|
|
||||||
const STYLE_TEXT = `
|
const STYLE_TEXT = `
|
||||||
|
/* The field bleeds 25% past the hero piece on every side. Sideways
|
||||||
|
it is clipped at the header box (clip, not hidden: no scroll
|
||||||
|
container, and overflow-y stays visible) - an element wider than
|
||||||
|
the viewport, even unscrollable, makes phones re-size the layout
|
||||||
|
viewport when it appears, which read as the page jumping as the
|
||||||
|
input loaded. Vertically it may run into the copy below. */
|
||||||
|
.hero-module { overflow-x: clip; overflow-y: visible; }
|
||||||
.redoal-paths {
|
.redoal-paths {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: ${BLEED};
|
||||||
overflow: hidden;
|
overflow: visible;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
--redoal-t: 0;
|
--redoal-t: 0;
|
||||||
--redoal-seed: ${SEED};
|
--redoal-seed: ${SEED};
|
||||||
|
|||||||
@@ -8,6 +8,11 @@
|
|||||||
// engine likes, and unseeded randomness would reshuffle the picture on
|
// engine likes, and unseeded randomness would reshuffle the picture on
|
||||||
// every repaint.
|
// every repaint.
|
||||||
|
|
||||||
|
// The field bleeds past its box: the painted element is this much
|
||||||
|
// larger than the hero piece on each axis (25% each side), and the
|
||||||
|
// drawing scales to the piece, not the element, so nothing grows.
|
||||||
|
export const OVERSCAN = 1.5;
|
||||||
|
|
||||||
export function mulberry32(seed) {
|
export function mulberry32(seed) {
|
||||||
let a = seed >>> 0;
|
let a = seed >>> 0;
|
||||||
return () => {
|
return () => {
|
||||||
@@ -118,7 +123,7 @@ const smooth = (u) => u * u * (3 - 2 * u);
|
|||||||
|
|
||||||
export function drawPaths(ctx, width, height, paths, t, colors) {
|
export function drawPaths(ctx, width, height, paths, t, colors) {
|
||||||
ctx.clearRect(0, 0, width, height);
|
ctx.clearRect(0, 0, width, height);
|
||||||
const s = Math.min(width, height) * 0.9;
|
const s = (Math.min(width, height) / OVERSCAN) * 0.9;
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(width / 2, height / 2);
|
ctx.translate(width / 2, height / 2);
|
||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 1;
|
||||||
|
|||||||
+22
-14
@@ -1,29 +1,37 @@
|
|||||||
# The group exhibition at Podium, connected to the conference: opens
|
# The group exhibition at Podium, part of Attac's «Big Tech må vekk»
|
||||||
# 21 October 2026 and runs for a month. Announced in every header
|
# 2026: opens 23 October 2026 at 19:00 and runs for a month. Announced
|
||||||
# while it runs (portal's event: window); afterwards a followup, and
|
# in every header while it runs (portal's event: window); afterwards a
|
||||||
# a "post what happened" task lands on /review.
|
# followup, and a "post what happened" task lands on /review.
|
||||||
name: Where can you see it in person?
|
name: Where can you see it in person?
|
||||||
description: >
|
description: >
|
||||||
redoal is part of the group exhibition at Podium, opening 21 October
|
redoal is part of the group exhibition at Podium, opening 23 October
|
||||||
and running for a month alongside the conference. Draw on the
|
and running for a month — the art strand of the conference
|
||||||
screens, leave a voice at a shape, hear who came before you.
|
«Big Tech må vekk». Draw on the screens, leave a voice at a shape,
|
||||||
|
hear who came before you.
|
||||||
event:
|
event:
|
||||||
starts: 2026-10-21T18:00:00+02:00
|
starts: 2026-10-23T19:00:00+02:00
|
||||||
duration: 31d
|
duration: 31d
|
||||||
place: Podium, Oslo
|
place: Podium, Hausmanns gate 34, Oslo
|
||||||
alternatives:
|
alternatives:
|
||||||
- name: Come draw on the wall
|
- name: See it in person at Podium
|
||||||
description: >
|
description: >
|
||||||
The installation runs the same code as this site, on screens
|
The installation runs the same code as this site, on screens
|
||||||
you can stand in front of together — the network at the scale
|
you can stand in front of together — the network at the scale
|
||||||
of a room.
|
of a room.
|
||||||
features:
|
features:
|
||||||
- name: Opening 21 October
|
- name: Opening 23 October, 19:00
|
||||||
description: >
|
description: >
|
||||||
The exhibition opens on the 21st and stays up for a month,
|
At [Podium](https://podium.enterprises/), Hausmanns gate 34,
|
||||||
within the conference programme. Come to the opening, or
|
and up for a month. Come to the opening, or any Saturday
|
||||||
any day after.
|
or Sunday after.
|
||||||
icon: lucide:calendar-days
|
icon: lucide:calendar-days
|
||||||
|
- name: Part of «Big Tech må vekk»
|
||||||
|
description: >
|
||||||
|
Attac's conference on digital counterculture returns to
|
||||||
|
Hausmania — the same building — on 31 October; the
|
||||||
|
exhibition is its art strand. Programme and details on
|
||||||
|
[attac.no](https://attac.no/arrangement/big-tech-ma-vekk-2026/).
|
||||||
|
icon: lucide:megaphone
|
||||||
- name: Draw, then listen
|
- name: Draw, then listen
|
||||||
description: >
|
description: >
|
||||||
Draw a shape on the touch screen and arrive at a place.
|
Draw a shape on the touch screen and arrive at a place.
|
||||||
|
|||||||
+108
-94
@@ -1,24 +1,123 @@
|
|||||||
id: /
|
id: /
|
||||||
name: What shapes us?
|
name: What is redoal, and what can you do here?
|
||||||
description: >
|
description: >
|
||||||
redoal is a gesture-addressed network. Draw a line and it becomes
|
redoal is a gesture-addressed network. Draw a line and it becomes
|
||||||
an address — the drawing itself, ready to use the moment your hand
|
an address — the drawing itself, ready to use the moment your hand
|
||||||
lifts. Similar drawings land near each other, and everything else
|
lifts. Similar drawings land near each other, and everything else
|
||||||
follows from that. Draw one below and see who's near.
|
follows from that. What it is comes first; the drawing is further
|
||||||
|
down the page.
|
||||||
responsible:
|
responsible:
|
||||||
name: Bendik Aagaard Lynghaug
|
name: Bendik Aagaard Lynghaug
|
||||||
contact: bl@uhhm.no
|
contact: bl@uhhm.no
|
||||||
alternatives:
|
alternatives:
|
||||||
|
# The opener: what redoal is, in two features and no button. The
|
||||||
|
# two people it exists for are the one who draws and the one who
|
||||||
|
# leaves a voice; both keep what they made.
|
||||||
|
- name: What redoal is
|
||||||
|
description: >
|
||||||
|
The one trick, and what it enables — the parts that run today,
|
||||||
|
said plainly.
|
||||||
|
features:
|
||||||
|
- name: A drawing is an address, and yours to use
|
||||||
|
description: >
|
||||||
|
The computer measures how your line curves, turns, and keeps
|
||||||
|
rhythm, and boils it down to a twenty-byte fingerprint.
|
||||||
|
Similar drawings get similar fingerprints — two spirals land
|
||||||
|
like two houses on the same street, and that closeness is
|
||||||
|
the whole network. Your machine asks the machines around it,
|
||||||
|
"has anyone been near this shape?", and your spiral finds my
|
||||||
|
spiral directly, peer to peer.
|
||||||
|
icon: lucide:map-pin
|
||||||
|
- name: A voice stays where you left it, sealed by your own hand
|
||||||
|
description: >
|
||||||
|
A drawing is a place, and places hold voices. Listen to the
|
||||||
|
recordings people left at a gesture, leave your own on top,
|
||||||
|
and when someone stands at the same drawing right now, just
|
||||||
|
talk. Every recording carries a signature from the leaver's
|
||||||
|
own machine: keep the key and you're recognized, delete it
|
||||||
|
and you were never here. A child, an elder, or a newcomer
|
||||||
|
still learning the local script arrives on the same terms.
|
||||||
|
icon: lucide:mic
|
||||||
|
|
||||||
|
# The look around: nothing to fill in.
|
||||||
|
- name: Have a look around first
|
||||||
|
description: >
|
||||||
|
The network as it runs right now, and where it is going.
|
||||||
|
features:
|
||||||
|
- name: The count so far
|
||||||
|
description: >
|
||||||
|
Live from the front-door relay — the running tally of what's
|
||||||
|
been left at places.
|
||||||
|
icon: lucide:activity
|
||||||
|
resource:
|
||||||
|
source:
|
||||||
|
kind: url
|
||||||
|
url: https://relay.redoal.com/pulse
|
||||||
|
public: true
|
||||||
|
# /pulse (redoal ADR-0023) returns { voices_echoed: N }; shape
|
||||||
|
# it into one card — the number as the heading, the phrase
|
||||||
|
# beneath. Emit a bare object, not a wrapped [ … ]: the portal
|
||||||
|
# collects the jq output stream into an array itself, so a
|
||||||
|
# wrapping [ ] nests it ([[{…}]]) and drops to a raw JSON dump.
|
||||||
|
jq: >
|
||||||
|
{ "name": (.voices_echoed | tostring),
|
||||||
|
"description": "voices echoed so far" }
|
||||||
|
empty: The first voice hasn't echoed yet.
|
||||||
|
- name: Releases
|
||||||
|
description: Run one of the desktop applications, free, no sign-up.
|
||||||
|
icon: lucide:package
|
||||||
|
resource:
|
||||||
|
source:
|
||||||
|
kind: gitea_releases
|
||||||
|
owner: redoal
|
||||||
|
repo: redoal
|
||||||
|
public: true
|
||||||
|
empty: Nothing released yet — the first cut lands here.
|
||||||
|
# url pinned to null while the repo is private - a private
|
||||||
|
# release's html_url 404s for anonymous visitors, and the
|
||||||
|
# card renders an unlinked heading instead (same lesson as
|
||||||
|
# uhhm/questions 9b7162f).
|
||||||
|
jq: >
|
||||||
|
.[] | {name: .name, description: .body, tag: .tag_name,
|
||||||
|
published: .published_at, url: null}
|
||||||
|
- name: The iPhone app, in beta
|
||||||
|
description: >
|
||||||
|
The iPhone build rides TestFlight (Apple's beta program) —
|
||||||
|
[join the redoal testers](https://testflight.apple.com/join/eR9dvHkz)
|
||||||
|
with one tap on your iPhone; no invitation, no email, no
|
||||||
|
waiting on us.
|
||||||
|
icon: lucide:smartphone
|
||||||
|
- name: Carried by iroh, through varde
|
||||||
|
description: >
|
||||||
|
What is left at a place is kept and mirrored by
|
||||||
|
[varde](https://project.uhhm.no/uhhm/varde), a small
|
||||||
|
daemon that moves bytes between consenting machines over
|
||||||
|
[iroh](https://iroh.computer) — verified, rate-limited, and
|
||||||
|
legible to the network it runs on. Recordings travel that way,
|
||||||
|
with no company carrying them.
|
||||||
|
icon: lucide:waypoints
|
||||||
|
- name: Built in the open at UHHM
|
||||||
|
description: >
|
||||||
|
[UHHM](https://uhhm.no) builds and carries the gesture math,
|
||||||
|
the relay, and the portal this page runs on — and hosts the
|
||||||
|
network's first node. It is a prototype and an artwork before
|
||||||
|
it is a product: what you can touch is real and running, the
|
||||||
|
transport that reaches across the internet is being built
|
||||||
|
now, and the rough edges are where the interesting questions
|
||||||
|
live. A client, a relay, an instrument — if you want to put
|
||||||
|
the network on a surface it isn't on yet, say so through the
|
||||||
|
path below.
|
||||||
|
icon: lucide:anvil
|
||||||
|
|
||||||
|
# The offers.
|
||||||
- name: Draw a path and see who's near
|
- name: Draw a path and see who's near
|
||||||
description: >
|
description: >
|
||||||
By associating similar movements while facilitating discourse we
|
By associating similar movements while facilitating discourse we
|
||||||
discover signal within chaos. Draw a path — the network answers
|
discover signal within chaos. Draw a path — the network answers
|
||||||
with the shapes it heard nearby.
|
with the shape it heard, and with the places kept nearby. Pick
|
||||||
action: /shape
|
one of those and it becomes your address.
|
||||||
# Announced, not yet open: the network answers with echoes today,
|
action: /shape/{curve.key}
|
||||||
# what follows a shape is still being built.
|
consequence: [Go to the place]
|
||||||
disabled: true
|
|
||||||
consequence: [Find what follows]
|
|
||||||
record_as: redoal_gestures
|
record_as: redoal_gestures
|
||||||
encouragements:
|
encouragements:
|
||||||
- What you don't know — your collaborators will.
|
- What you don't know — your collaborators will.
|
||||||
@@ -36,93 +135,8 @@ alternatives:
|
|||||||
type: gesture
|
type: gesture
|
||||||
relay: wss://relay.redoal.com
|
relay: wss://relay.redoal.com
|
||||||
optional: true
|
optional: true
|
||||||
- name: email
|
|
||||||
label: Email, if the echoes should reach you later
|
|
||||||
type: email
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
- name: Meet a network you carry in your hand
|
- name: Get a note when something lands
|
||||||
description: >
|
|
||||||
The one trick, and what it enables — the parts that run today,
|
|
||||||
said plainly.
|
|
||||||
features:
|
|
||||||
- name: A drawing is an address
|
|
||||||
description: >
|
|
||||||
The computer measures how your line curves, turns, and keeps
|
|
||||||
rhythm, and boils it down to a twenty-byte fingerprint.
|
|
||||||
Similar drawings get similar fingerprints — two spirals land
|
|
||||||
like two houses on the same street, and that closeness is
|
|
||||||
the whole network.
|
|
||||||
icon: lucide:map-pin
|
|
||||||
- name: Your machine asks the room
|
|
||||||
description: >
|
|
||||||
To find someone, your machine asks the machines around it:
|
|
||||||
"has anyone been near this shape?" Your spiral finds my
|
|
||||||
spiral directly, peer to peer. The whole directory is the
|
|
||||||
shapes people know, passed along on a napkin.
|
|
||||||
icon: lucide:users
|
|
||||||
- name: Voices stay where you left them
|
|
||||||
description: >
|
|
||||||
A drawing is a place, and places hold voices. Listen to the
|
|
||||||
recordings people left at a gesture, leave your own on top,
|
|
||||||
and when someone stands at the same drawing right now, just
|
|
||||||
talk — live, machine to machine.
|
|
||||||
icon: lucide:mic
|
|
||||||
- name: Sealed by your own hand
|
|
||||||
description: >
|
|
||||||
Every recording and every stored stroke carries a signature
|
|
||||||
from the leaver's own machine — proof that it arrived
|
|
||||||
intact and that the same hand made the same things. The key
|
|
||||||
lives only with you: keep it and you're recognized, delete
|
|
||||||
it and you were never here.
|
|
||||||
icon: lucide:stamp
|
|
||||||
- name: Draw and speak, and you're in
|
|
||||||
description: >
|
|
||||||
The primitives are the drawn line and the human voice. A
|
|
||||||
child, an elder, or a newcomer still learning the local
|
|
||||||
script arrives on the same terms as everyone else — that is
|
|
||||||
the whole entry requirement.
|
|
||||||
icon: lucide:hand
|
|
||||||
- name: Young, and honest about it
|
|
||||||
description: >
|
|
||||||
A prototype and an artwork before it is a product. The
|
|
||||||
gesture math, the fingerprints, the voice recordings, and the
|
|
||||||
machine-to-machine fetching are real and running; the
|
|
||||||
transport that reaches across the internet is being built
|
|
||||||
now. The edges are rough, and the edges are where the
|
|
||||||
interesting questions live.
|
|
||||||
icon: lucide:sprout
|
|
||||||
|
|
||||||
- name: Follow the build as it lands
|
|
||||||
description: >
|
|
||||||
The network as it is being built — and we need collaborators on
|
|
||||||
every new surface it grows.
|
|
||||||
features:
|
|
||||||
- name: Communicate
|
|
||||||
description: >
|
|
||||||
A client, a relay, an instrument — if you want to put the
|
|
||||||
network on a surface it isn't on yet, say so through the
|
|
||||||
path above and we'll find each other.
|
|
||||||
icon: lucide:message-circle
|
|
||||||
- name: Releases
|
|
||||||
description: Start exploring by running one of our applications.
|
|
||||||
icon: lucide:package
|
|
||||||
resource:
|
|
||||||
source:
|
|
||||||
kind: gitea_releases
|
|
||||||
owner: redoal
|
|
||||||
repo: redoal
|
|
||||||
public: true
|
|
||||||
empty: Nothing released yet — the first cut lands here.
|
|
||||||
# url pinned to null while the repo is private - a private
|
|
||||||
# release's html_url 404s for anonymous visitors, and the
|
|
||||||
# card renders an unlinked heading instead (same lesson as
|
|
||||||
# uhhm/questions 9b7162f).
|
|
||||||
jq: >
|
|
||||||
.[] | {name: .name, description: .body, tag: .tag_name,
|
|
||||||
published: .published_at, url: null}
|
|
||||||
|
|
||||||
- name: Hear from us when it matters
|
|
||||||
description: >
|
description: >
|
||||||
Notes from the build — sent only when there is something worth
|
Notes from the build — sent only when there is something worth
|
||||||
saying.
|
saying.
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
id: /joined-testers
|
||||||
|
route: ^/joined-testers
|
||||||
|
followup: true
|
||||||
|
name: What happens next?
|
||||||
|
description: >
|
||||||
|
You asked for a place in the closed beta — here's the shape of it.
|
||||||
|
alternatives:
|
||||||
|
- name: Your invite is on its way
|
||||||
|
description: ""
|
||||||
|
features:
|
||||||
|
- name: Check your mail
|
||||||
|
description: >
|
||||||
|
A TestFlight invite goes to the Apple ID you left. Tap it on
|
||||||
|
your iPhone, install TestFlight if you don't have it, and
|
||||||
|
redoal lands on your home screen.
|
||||||
|
icon: lucide:mail
|
||||||
|
- name: It's rough on purpose
|
||||||
|
description: >
|
||||||
|
A beta, and an artwork before a product — the networked edges
|
||||||
|
are where the interesting questions live. Tell us what breaks.
|
||||||
|
icon: lucide:hammer
|
||||||
|
|
||||||
|
- name: Withdraw from the beta
|
||||||
|
description: >
|
||||||
|
Changed your mind? Confirm below and we'll drop your Apple ID from
|
||||||
|
the invite list.
|
||||||
|
self_transition:
|
||||||
|
bucket: redoal_testers
|
||||||
|
to: withdrawn
|
||||||
|
label: Remove me from the beta
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# One recording, held up for human review: /report/<digest>. Reached
|
||||||
|
# from the place page's per-recording link. Filing creates an open
|
||||||
|
# record in redoal_reports; the desk decides, and a removal decision
|
||||||
|
# deletes the recording from the relay, varde, and discovery.
|
||||||
|
name: Should this stay?
|
||||||
|
description: >
|
||||||
|
Every voice here was left by a person, and a person looks at every
|
||||||
|
report. Tell us what you heard and why it needs eyes on it — the
|
||||||
|
recording stays reachable until someone has listened and decided.
|
||||||
|
alternatives:
|
||||||
|
- name: Ask for a review
|
||||||
|
description: >
|
||||||
|
Goes straight to the review desk. If the recording breaks
|
||||||
|
something — a person's privacy, the law, basic decency — it is
|
||||||
|
removed everywhere this network keeps it.
|
||||||
|
action: /reported
|
||||||
|
consequence: [Send it to review]
|
||||||
|
record_as: redoal_reports
|
||||||
|
encouragements:
|
||||||
|
- A person will listen.
|
||||||
|
features:
|
||||||
|
- name: What you heard
|
||||||
|
description: >
|
||||||
|
A sentence or two is plenty. Leave an email if you want to
|
||||||
|
hear what was decided.
|
||||||
|
icon: lucide:flag
|
||||||
|
requirements:
|
||||||
|
- name: digest
|
||||||
|
label: Recording
|
||||||
|
type: hidden
|
||||||
|
value: "{digest}"
|
||||||
|
- name: reason
|
||||||
|
label: Why
|
||||||
|
type: textarea
|
||||||
|
placeholder: What is wrong with this recording?
|
||||||
|
- name: email
|
||||||
|
label: Email
|
||||||
|
type: email
|
||||||
|
optional: true
|
||||||
|
- name: Go back to listening
|
||||||
|
description: >
|
||||||
|
The place you came from holds the rest of its voices.
|
||||||
|
features:
|
||||||
|
- name: Nothing sent
|
||||||
|
description: >
|
||||||
|
Leaving this page files nothing — only the button does.
|
||||||
|
icon: lucide:undo-2
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# Landing after filing a report.
|
||||||
|
followup: true
|
||||||
|
name: What happens now?
|
||||||
|
description: >
|
||||||
|
Your report is on the review desk. A person listens, decides, and
|
||||||
|
the decision acts everywhere this network keeps the recording.
|
||||||
|
alternatives:
|
||||||
|
- name: Draw another
|
||||||
|
description: >
|
||||||
|
The paper keeps listening.
|
||||||
|
action: /
|
||||||
@@ -38,6 +38,70 @@ alternatives:
|
|||||||
- to: unsubscribed
|
- to: unsubscribed
|
||||||
label: Unsubscribe
|
label: Unsubscribe
|
||||||
|
|
||||||
|
- name: Voices
|
||||||
|
description: >
|
||||||
|
Recordings left through the web, one answer per upload: the
|
||||||
|
address, the digest, the length. The audio itself lives in the
|
||||||
|
relay's node and in varde.
|
||||||
|
features:
|
||||||
|
- name: ""
|
||||||
|
description: ""
|
||||||
|
resource:
|
||||||
|
source:
|
||||||
|
kind: kv
|
||||||
|
bucket: redoal_voices
|
||||||
|
requires_group: owners
|
||||||
|
|
||||||
|
- name: Reports
|
||||||
|
description: >
|
||||||
|
Recordings a visitor asked a person to listen to. "Remove it"
|
||||||
|
acts for real: the relay watches this bucket and deletes the
|
||||||
|
recording from its store, the varde pin, and discovery. "Keep
|
||||||
|
it" closes the report with the voice in place.
|
||||||
|
action: /review
|
||||||
|
consequence: [Decide]
|
||||||
|
features:
|
||||||
|
- name: ""
|
||||||
|
description: ""
|
||||||
|
resource:
|
||||||
|
source:
|
||||||
|
kind: kv
|
||||||
|
bucket: redoal_reports
|
||||||
|
requires_group: owners
|
||||||
|
transitions:
|
||||||
|
- from: open
|
||||||
|
to: removed
|
||||||
|
label: Remove it
|
||||||
|
- from: open
|
||||||
|
to: kept
|
||||||
|
label: Keep it
|
||||||
|
|
||||||
|
- name: Watchers
|
||||||
|
description: >
|
||||||
|
Who asked to hear from one exact address. Unsubscribing is
|
||||||
|
theirs (the link in their receipt); the desk can retire an
|
||||||
|
address that bounces.
|
||||||
|
action: /review
|
||||||
|
consequence: [Confirm]
|
||||||
|
features:
|
||||||
|
- name: ""
|
||||||
|
description: ""
|
||||||
|
resource:
|
||||||
|
source:
|
||||||
|
kind: kv
|
||||||
|
bucket: redoal_watchers
|
||||||
|
requires_group: owners
|
||||||
|
transitions:
|
||||||
|
- from: pending
|
||||||
|
to: open
|
||||||
|
label: Confirm by hand
|
||||||
|
- from: pending
|
||||||
|
to: unsubscribed
|
||||||
|
label: Drop
|
||||||
|
- from: open
|
||||||
|
to: unsubscribed
|
||||||
|
label: Unsubscribe
|
||||||
|
|
||||||
- name: Announced pages
|
- name: Announced pages
|
||||||
description: >
|
description: >
|
||||||
Pages with an `event:` window, kept here by portal itself. When a
|
Pages with an `event:` window, kept here by portal itself. When a
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
id: /shape
|
|
||||||
route: ^/shape
|
|
||||||
followup: true
|
|
||||||
name: Where does the path lead?
|
|
||||||
description: >
|
|
||||||
Your shape is in the room now. Echoes of it reach whoever draws
|
|
||||||
nearby — and theirs reach you, whenever you come back to draw again.
|
|
||||||
alternatives:
|
|
||||||
- name: What just happened
|
|
||||||
description: ""
|
|
||||||
features:
|
|
||||||
- name: An address, not an upload
|
|
||||||
description: >
|
|
||||||
The stroke became a 20-byte gesture key — a compressed
|
|
||||||
encoding of its shape. Similar shapes land on nearby keys;
|
|
||||||
that proximity is the whole network.
|
|
||||||
- name: Nothing to undo
|
|
||||||
description: >
|
|
||||||
A drawn path is a fact, not an account. There is no profile
|
|
||||||
behind it unless you left an email.
|
|
||||||
- name: What arrives here next
|
|
||||||
description: >
|
|
||||||
In the full network a drawing is a place that holds voices —
|
|
||||||
recordings left by whoever came before, and live talk with
|
|
||||||
whoever is standing here now. On this site it holds echoes
|
|
||||||
today; the voices follow.
|
|
||||||
|
|
||||||
- name: Draw another
|
|
||||||
description: >
|
|
||||||
The network gets more interesting with every shape it hears.
|
|
||||||
action: /
|
|
||||||
consequence: [Back to the canvas]
|
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
# The place a drawn (or picked) path leads to: /shape/<gesture key>.
|
||||||
|
# Reached through the landing alternative's templated action
|
||||||
|
# (/shape/{curve.key}); the key is the URL. What is kept here comes
|
||||||
|
# from the relay - the first redoal node - over its /place endpoint,
|
||||||
|
# and a voice left here goes back the same way (ADR-0015 in redoal).
|
||||||
|
name: Where does the path lead?
|
||||||
|
description: >
|
||||||
|
This is a place: the 20-byte address your path became — or the one
|
||||||
|
you picked from what the network keeps nearby. Voices left here play
|
||||||
|
here, for whoever draws their way to this shape. What you see on
|
||||||
|
this site is a preview of the app: the same network, reached
|
||||||
|
through a relay instead of your own machine.
|
||||||
|
alternatives:
|
||||||
|
- name: Listen to what was left here
|
||||||
|
description: ""
|
||||||
|
features:
|
||||||
|
- name: ""
|
||||||
|
description: ""
|
||||||
|
icon: lucide:ear
|
||||||
|
resource:
|
||||||
|
source:
|
||||||
|
kind: url
|
||||||
|
url: "https://relay.redoal.com/place/{key}"
|
||||||
|
public: true
|
||||||
|
empty: Nothing has been left at this address yet — yours could be the first voice here.
|
||||||
|
jq: >
|
||||||
|
.recordings[] | {name: ((.duration_ms / 1000 | round | tostring) + " seconds of voice"),
|
||||||
|
description: ("sealed by " + .author[0:8] + "… · [have it reviewed](/report/" + .digest + ")"),
|
||||||
|
audio: ("https://relay.redoal.com" + .audio)}
|
||||||
|
|
||||||
|
- name: Leave your voice here
|
||||||
|
description: >
|
||||||
|
A preview of what the app will give you in full. Record in your
|
||||||
|
browser, listen back, and press *Keep it here* — nothing leaves
|
||||||
|
your phone before that. The relay, the network's first node,
|
||||||
|
keeps it at exactly this address and mirrors it on, sealed with
|
||||||
|
its own key on your behalf; a key of your own comes with the app.
|
||||||
|
action: /shape/{voice.key}
|
||||||
|
consequence: [Keep it here]
|
||||||
|
record_as: redoal_voices
|
||||||
|
encouragements:
|
||||||
|
- It stays where you left it.
|
||||||
|
features:
|
||||||
|
- name: ""
|
||||||
|
description: >
|
||||||
|
Up to a minute. Record, listen back, record again if you like
|
||||||
|
— it is sealed as it is once you keep it.
|
||||||
|
icon: lucide:mic
|
||||||
|
requirements:
|
||||||
|
- name: voice
|
||||||
|
label: Voice
|
||||||
|
type: voice
|
||||||
|
relay: wss://relay.redoal.com
|
||||||
|
value: "{key}"
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
- name: Get a note when a voice lands here
|
||||||
|
description: >
|
||||||
|
The fallback for a phone without the app: one note when
|
||||||
|
something is left at exactly this shape — and nothing about
|
||||||
|
anywhere else.
|
||||||
|
action: /subscribed
|
||||||
|
consequence: [Watch this address]
|
||||||
|
record_as: redoal_watchers
|
||||||
|
encouragements:
|
||||||
|
- Your shape now has a listener.
|
||||||
|
features:
|
||||||
|
- name: Where the note goes
|
||||||
|
description: >
|
||||||
|
The note is about one exact address, so it needs one exact
|
||||||
|
place to land. One mail comes first, asking you to confirm —
|
||||||
|
nothing is sent before you do, and at most one note a day
|
||||||
|
after.
|
||||||
|
icon: lucide:mail
|
||||||
|
requirements:
|
||||||
|
- name: email
|
||||||
|
label: Email
|
||||||
|
type: email
|
||||||
|
- name: key
|
||||||
|
label: Address
|
||||||
|
type: hidden
|
||||||
|
value: "{key}"
|
||||||
|
|
||||||
|
- name: What your drawing became
|
||||||
|
description: ""
|
||||||
|
features:
|
||||||
|
- name: An address, not an upload
|
||||||
|
description: >
|
||||||
|
The stroke became a 20-byte gesture key — an ordered chain of
|
||||||
|
headings, drawn back for you under the stroke. Similar shapes
|
||||||
|
land on nearby keys; picking a kept place makes its key yours.
|
||||||
|
- name: Nothing to undo
|
||||||
|
description: >
|
||||||
|
A drawn path is a fact, not an account. There is no profile
|
||||||
|
behind it unless you asked to hear from an address.
|
||||||
|
|
||||||
|
- name: Draw another
|
||||||
|
description: >
|
||||||
|
The network gets more interesting with every shape it hears.
|
||||||
|
action: /
|
||||||
|
consequence: [Back to the canvas]
|
||||||
@@ -21,3 +21,12 @@ alternatives:
|
|||||||
bucket: redoal_subscribers
|
bucket: redoal_subscribers
|
||||||
to: unsubscribed
|
to: unsubscribed
|
||||||
label: Unsubscribe me
|
label: Unsubscribe me
|
||||||
|
|
||||||
|
- name: Stop watching an address
|
||||||
|
description: >
|
||||||
|
Using the link from a note about a shape? Confirm below and that
|
||||||
|
address goes quiet for you.
|
||||||
|
self_transition:
|
||||||
|
bucket: redoal_watchers
|
||||||
|
to: unsubscribed
|
||||||
|
label: Stop watching
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Landing page of the confirmation mail: /watching?chain=<record>&email=<address>.
|
||||||
|
# A followup - never in the nav; the record id in the link is the only
|
||||||
|
# way here, and it plus the matching email is what authorizes the
|
||||||
|
# transition (portal's self_transition).
|
||||||
|
followup: true
|
||||||
|
name: Are you watching this address?
|
||||||
|
description: >
|
||||||
|
Someone asked to hear from a shape on redoal with your address. Say
|
||||||
|
yes and you get one note when something is left there — nothing
|
||||||
|
else, ever. Say it wasn't you and the request is dropped.
|
||||||
|
alternatives:
|
||||||
|
- name: Yes, watch it
|
||||||
|
description: >
|
||||||
|
One note per day at most, only when a recording or a program
|
||||||
|
lands at exactly this shape.
|
||||||
|
self_transition:
|
||||||
|
bucket: redoal_watchers
|
||||||
|
to: open
|
||||||
|
label: Yes, watch it
|
||||||
|
|
||||||
|
- name: That wasn't me
|
||||||
|
description: >
|
||||||
|
The request is dropped and the address stays unused.
|
||||||
|
self_transition:
|
||||||
|
bucket: redoal_watchers
|
||||||
|
to: unsubscribed
|
||||||
|
label: Drop it
|
||||||
@@ -4,3 +4,4 @@ wordmark: https://project.uhhm.no/redoal/questions/raw/branch/main/wordmark.svg
|
|||||||
hero:
|
hero:
|
||||||
kind: module
|
kind: module
|
||||||
module: hero.js # this repo's sine-swings piece, served at /site/hero.js
|
module: hero.js # this repo's sine-swings piece, served at /site/hero.js
|
||||||
|
wordmark_invert: true
|
||||||
|
|||||||
Reference in New Issue
Block a user