recordlabel · mockindex

record.label · "the record label in your pocket" · UI spec (phase 1)

Name: the app is record.label (approved by 1982, 11 Nov 2026; formerly record.label). Always lowercase. In Inter 200 the period is drawn as the small red REC dot: record●label. Internal file and folder names (og-label-*, the-og-ios, hub paths) are unchanged.

Status: design + tappable prototype for 1982's approval. Rev 2 (11 Nov 2026): bottom tab bar, generic for any artist (no personal inboxes or accounts; every platform starts with a "connect your …" flow), two distribution routes. Nothing in the shipping iOS app (/Users/test/the-og-ios) or the live hub was changed, and nothing was published, posted, uploaded or connected. The widgets are on hold and untouched.

Prototype: proto/index.html (self-contained; serve the folder, e.g. python3 -m http.server -d proto). Generic sample data for any artist (sample takes and tracks, real device names, no real accounts).


Brand & domains

1. Visual system

token value source
background #000 (cards #0b0b0b, lines #1f1f1f / #2c2c2c) record.label black
ink #fff · dim #8e8e8e · dim2 #5c5c5c
red #ff452b (= Color(red: 1, green: 0.27, blue: 0.17) in OGWidgets.swift) REC dot, Grokbot, warnings, selection
type Inter variable, weight 200, all lowercase. Numbers are tabular. Small mono only for counters (position, timecode). Widgets/Fonts/Inter-Variable.ttf
corner radius widgets 22 pt, sheets 26 pt, pills full Apple widget feel
device art white line art on black: chassis #fff 0.715, controls/caps #fff 0.68, panels/holes #4d4d4d 0.39–0.52, non-scaling strokes, red REC dot fill. "Off" = same file with #9a9a9a. og-v41 art/*.svg grammar

Rules: white and red on black only. No neural web. No gradients except the faint red glow on Grokbot surfaces. One accent action per screen in red (REC, post, bump, connect).

Components (TE component kit for the design teammate):

2. Navigation: bottom tab bar

home · studio · video studio · tracks · account · ✦ grokbot

3. Home (never scrolls)

Widgets (after the brief's changes: Stems removed, Design + Marketing merged; Uploads holds private files and SP-1 exports, with no personal inboxes):

id size shows tap
connected device 2×2 live device line art, name, connection type, dots for several connected devices device sheet (all devices, connected lit white)
rec 1×1 big red dot (becomes rounded square while recording), timer, which device start/stop a take on that device
takes 1×1 count, last take tracks
studio 1×1 (2×1 on big grids) BPM, last session studio
finished 1×1 (2×1) count, live count tracks › finished
grokbot 1×1 (2×1) on/off, red glow grokbot
video studio 1×1 clip drafts video studio
uploads 1×1 private uploads + sp-1 exports uploads sheet
design + marketing 1×1 covers, clips, socials sheet
distribution 1×1 (2×1) mini bars + "connect soundcloud" / "soundcloud n live" · "dsp via distributor" tracks
sp-1 loader 1×1 state loader
socials 1×1 connected count 0/7 → "tap to connect" account › connect your platforms

Grid algorithm (layoutHome() in proto/app.js, port as a SwiftUI Layout):

  1. target tile = 150 pt on phones, otherwise clamp(172, min(w,h)/4.4, 236).
  2. cols = clamp(2, floor((w + gap) / (target + gap)), 6), square side from that.
  3. rows = max(2, floor((h + gap) / (side + gap))). Add one more row if rows can stay ≥ 72% of side tall.
  4. Pack widgets in order into pages of cols × rows cells (dense flow). If a page has ≥ 4 spare cells, promote studio/finished/grokbot/distribution/video/takes to 2×1 instead of leaving holes.
  5. Pages are swiped horizontally (pointer drag > 50 pt, arrow keys). Page dots sit under the grid, above the bottom tab bar.

Overflow check with the bottom tab bar: 26/26 pass (shots/home-overflow-check.json). Each size runs with simulated safe areas (iPhone notch 59 pt top / 34 pt home indicator in portrait, 21 pt in landscape; SE 20 / 0; Duo and iPad 24 / 20). It checks that the document doesn't scroll, every widget sits inside the page, no widget content overflows, there are no scrollable elements, the dots and pages sit above the tab bar, the tab bar is fully on screen with all 6 tabs, and no tab label is clipped.

device (pt) portrait grid · pages landscape grid · pages
iPhone SE 375×667 2×3 · 3 4×2 · 2
iPhone mini 375×812 2×4 · 2 5×2 · 2
iPhone 16 / 17 393×852 2×4 · 2 5×2 · 2
iPhone Plus 430×932 2×4 · 2 5×2 · 2
iPhone Pro Max 440×956 2×4 · 2 5×2 · 2
iPhone Duo outer 466×678* 2×3 · 3 4×2 · 2
iPhone Duo inner 669×951* 3×4 · 2 5×3 · 1
iPad mini 744×1133 4×6 · 1 6×4 · 1
iPad 10th 820×1180 4×6 · 1 6×4 · 1
iPad Air 11 820×1180 4×6 · 1 6×4 · 1
iPad Pro 11 834×1210 4×6 · 1 6×4 · 1
iPad Air 13 1024×1366 4×5 · 1 6×4 · 1
iPad Pro 13 1032×1376 4×5 · 1 6×4 · 1

*The Duo sizes are derived from the Duo simulator screenshots on the box (2007×2853 inner and 1398×2034 outer, at @3x). Apple should confirm the real point sizes.

4. Studio (the only scrolling page): GarageBand-style DAW

Aligned with Apple's plan: native SwiftUI. Other tabs can stay in the WebView hub at first.

Screen

Gestures (all working in the prototype; work/studio-test.txt shows every check passing)

gesture action
tap clip select (its track becomes selected)
drag clip body move, snapped to quarter notes. Drag vertically to move it to another lane.
drag clip left/right edge trim (non-destructive: changes sourceStart / sourceLength)
tap ruler or empty lane move the playhead (snapped). Applied when the finger lifts, so starting a pinch never moves the playhead.
pinch with both fingers on one lane track zoom: that track only (see Zoom below)
pinch on the ruler, the empty space under the lanes, or across two lanes project zoom: the shared timescale, 8–220 pt per beat, anchored at the pinch centre
double-tap a lane (empty part) toggle that track between 1× and 2.2×
double-tap the ruler or empty space · fit key fit to screen: whole song fits the width, every track back to 1×
ctrl/⌘-wheel or trackpad pinch over a lane = track zoom, elsewhere (or with ⇧) = project zoom
cut split the selected clip at the playhead (or at its middle if the playhead is outside it)
splice join with the next clip. If they're the same source and contiguous, they become one clip; otherwise the gap is closed.
copy / paste paste at the playhead on the selected track
duplicate copy placed right after the clip
keyboard (iPad) space play, B cut, J splice, ⌘C/⌘V/⌘D, ⌫ delete, ⌘Z / ⇧⌘Z

Zoom: two levels, one locked time grid (prototype + work/zoomtest.mjs, all checks pass on iPhone and Duo inner)

Engine and model (Apple's architecture, phases A–E)

5. Tracks (scroll allowed)

6. Video Studio

7. Account

Generic for any artist; nothing is pre-filled.

8. Grokbot connector (the superpower)

The tab

8a. record.label MCP server (what a Grok Bot connects to)

record.label runs its own remote MCP server. The artist adds it to their Grok Bot as a custom connector (URL + sign-in). The bot then calls record.label tools the same way it calls any other connector.

Transport and hosting

Auth

Outbound rule (hard rule, enforced on the server)

Tools

tool scope does notes
list_takes catalog:read takes, filterable by device, date, bpm; paged grouped by device like the Tracks tab
get_take catalog:read one take: name, device, bpm, length, notes, waveform peaks
list_tracks catalog:read finished tracks with per-destination status
get_track catalog:read one track: metadata, notes, credits, artwork, videos, ISRC, distribution
get_audio_preview catalog:read short-lived signed URL (15 min) to a low-bitrate preview lets the bot "listen" for a&r; never the master
rename_track catalog:write rename a take or finished track undoable in the app
set_notes catalog:write replace or append notes
set_artwork catalog:write set artwork from an uploaded image or a generated one (image URL or base64) previous artwork kept in history
attach_video catalog:write attach an exported Video Studio clip to a track
set_credits catalog:write title credits, roles, splits used by release drafts
bump_to_finished catalog:write move a take or studio bounce into Finished (distribution starts as draft) internal to record.label, not outbound, so no approval needed
get_distribution_status status:read per-destination state for a track (SoundCloud, Spotify, Apple Music), via, URL, last checked from §11 states
list_connections status:read which platforms and which distribution route are connected names only, never tokens
draft_post drafts:write create a post draft: clip or track, platforms, caption, schedule time status awaiting_approval; the app posts after approval
draft_release drafts:write create a release draft: track(s), title, credits, release date, target (SoundCloud upload and/or distributor handoff) builds the release kit; artist approves, then uploads/hands off
list_drafts / get_draft drafts:write the bot's drafts and their status (awaiting, approved, rejected, posted, failed)
update_draft / cancel_draft drafts:write edit or withdraw a draft while it is still awaiting approval
get_stats status:read plays and followers per connected platform, for the weekly report — where a platform doesn't report

Share links use https://1982.studio/t/<id> (planned, not live).

Also exposed as MCP resources (read-only): recordlabel://track/{id}, recordlabel://take/{id}, recordlabel://draft/{id}. Role toggles in the Grokbot tab map to tool groups (e.g. turning off social manager hides draft_post).

Not in v1: any publish/approve tool (never), editing Studio sessions (clips, mix) from the bot, and artist-to-artist actions.

9. Device line art

New SVGs in art/svg/ (<id>.svg and <id>-off.svg) and in proto/art/. Contact sheet with the reference fit checks: art/preview.png. They use the same grammar as the og-v41 art:

Pipeline: art/prim_dev.py + art/devices.json (re-runnable). Overlays: art/build/*-overlay.png.

device reference (official, straight-on) confidence
OP-1 (original) teenage.engineering asset 627cab62… (already in og-device-outlines/refs) high
OP-Z teenage.engineering 5bc066ec… (top view, 1024 px source upscaled; top edge rebuilt as a rounded rect) medium. The source is small and the top edge was cropped in the photo.
TX-6 66e88d84… high (knob rows and fader slots hand-placed on measured centres)
TP-7 66f277fd… high
CM-15 66e88dfe… (front, grille side) high for the outline. The mesh is drawn as a 34×32 square-hole grid (stylised weave), so it's medium for the grille.
EP-133 K.O. II (standard) 66a8e547… high
EP-1320 medieval 66b09bcb… high (same chassis as EP-133)
OB-4 64e4af8e… high for the body and cones. The handle and small grilles are approximate (medium).
PO-33 K.O! (pocket operator) 66211af6… high. Other POs share the chassis and differ in print.
Akai MPC Sample akaipro.com product image 7bd3ef0d… (slight perspective). Squashed to Akai's published 19.4 × 23.6 cm footprint, and the left edge was estimated because of a soft shadow. medium
EP-40 riddim, EP-2350 ting, OP-1 field / OP-XY / EP-133 Supreme — Not drawn. The EP-40 and EP-2350 have no clean top view on teenage.engineering. The OP-1 field, OP-XY and EP-133 Supreme already exist in og-v41 art/ and were reused, not redrawn.

Not drawn: the SP-1 (no reference found this pass). The hub's te.js still has a generic sampler glyph for it.

10. Data model

// Swift: Codable structs with the same fields
Device   { id: "op-xy"|"ep-133"|"op-1f"|"cm-15"|"mpc-sample"|…, name, maker, art: "op-xy.svg", usbMatch: RegExp, kind }
Source   { id, file: "audio/<uuid>.caf", sampleRate, frames, channels, peaks: "peaks/<uuid>.bin", recordedOn: Device.id, createdAt }   // immutable
Take     { id, name, sourceId, deviceId, bpm, durationSec, notes, createdAt }          // a raw recording, grouped by deviceId
Session  { id, name, tempoMap: [{ beat: 0, bpm: 92, meter: "4/4" }], tracks: [Track_], masterGain, createdAt, updatedAt }
Track_   { id, name, deviceId?, volume: 0…1.2, pan: -1…1, mute, solo,
           fx: { comp: {on, thresholdDb, ratio}, hp: {on, hz}, lp: {on, hz}, reverbSend: 0…1 }, clips: [Clip] }
Clip     { id, sourceId, sourceStart: samples, sourceLength: samples, timelineStart: beats, gain, fadeIn: beats, fadeOut: beats }
Finished { id, title, sessionId?, takeId?, bpm, durationSec, mixFile, artwork?, videos: [ClipExport.id], notes,
           isrc?, upc?, credits: [{name, role, split}], releaseDate?,
           distribution: { soundcloud: DestStatus, spotify: DestStatus, appleMusic: DestStatus } }
ClipExport { id, title, aspect: "9:16"|"1:1"|"16:9", lanes: { video: [VClip], audio: [VClip], files: [VClip] }, file?,
             posts: { instagram: PostStatus, youtube: PostStatus, tiktok: PostStatus, snapchat: PostStatus, x: PostStatus } }
DestStatus { state, remoteId?, url?, updatedAt, error?, via?: "native"|"handoff:<distributor>"|"catalog-poll"|"labelgrid" }
Distribution { route: null|"handoff"|"labelgrid" /* labelgrid = designed, inactive */, distributor?: "distrokid"|"too lost"|"cd baby"|"tunecore"|"amuse"|"other",
               labelgrid?: { accountRef, webhookSecretRef } /* reserved, unused in v1 */ }
PostStatus { state, remoteId?, url?, updatedAt, error?, via?: "native"|"ayrshare"|"buffer" }
Social   { platform, handle, connected: bool, accountType?, tokenRef (Keychain only), needs?: "creator-account"|"audit"|"allowlist"|"account" }
GrokbotLink { connected, botId?, roles: {anr, release, social, dist, report}, approvalRequired: true /* locked */ }
Profile  { name, handle, location, avatar?, banner?, label?, stats }
SessionView { ppb: 8…220, trackZoom: { [trackId]: 0.6…3 }, scrollX, scrollY }       // saved in session.json, not undoable
ClipView    { pps: number|null /* null = fit */, laneZoom: { video?, audio?, files?: 0.8…3 } }
BotDraft { id, kind: "post"|"release", payload, createdBy: "grokbot:<clientId>", status: "awaiting_approval"|"approved"|"rejected"|"posted"|"failed", approvedAt?, approvedBy? /* artist session only */ }
McpToken { id, kind: "oauth"|"pat", scopes: ["catalog:read","catalog:write","drafts:write","status:read"], createdAt, lastUsedAt, revokedAt? }   // empty for a new artist; set in edit profile

11. Status model and integrations

States shown as chips. This is based on XXX's research (/workspace/ogxy/marketing_connections.md, internal path unchanged); no platforms were re-researched.

Music destinations

destination path chip states how status is read
SoundCloud (P0) native upload API to the artist's own SoundCloud after they connect it. record.label registers one SoundCloud API app (Neo's existing app can serve as the dev app). OAuth 2.1 + PKCE, POST /tracks. not connected → draft → uploading → encoding → live (public or private) / failed · retry poll GET /tracks/:id until transcodings exist
Spotify via a distributor (no artist upload API), route below set up distribution → hand off · → watching catalogue · isrc → live / not found yet route 1: Spotify Web API search isrc: (catalogue poll; dev app). route 2 (later): LabelGrid webhooks.
Apple Music via a distributor, route below same as Spotify route 1: Apple Music API filter[isrc] (Apple Developer $99/yr + MusicKit key). route 2 (later): LabelGrid webhooks.

Distribution routes (Spotify + Apple Music). The artist picks one; record.label never signs up or pays for them.

  1. Your distributor: manual handoff + ISRC polling (default, built). Works with any consumer distributor the artist already uses: DistroKid ($24.99/yr), Too Lost ($19.99/yr), CD Baby, TuneCore, Amuse, others. None of these has an open API, so record.label exports a release kit (WAV master, artwork, title, credits/splits, ISRC/UPC fields), the artist uploads it on the distributor's site, then pastes the ISRC back. record.label polls the Spotify and Apple Music catalogues by ISRC (backoff: hourly for 2 days, then every 6 h up to 30 days) and flips each store to live with its URL when found. via: "handoff:<distributor>".
  2. LabelGrid Engine: API + webhooks (designed, inactive, "coming later"). For artists who run as a label: record.label would create releases through LabelGrid's API and get delivery and store status by webhook (states: sent → in review → delivered → live / rejected / taken down), no handoff. From $1,668/yr. Shown in the route picker as a dashed, disabled card with a coming later chip; the data model reserves route: "labelgrid". Not built in v1.

Social destinations (Video Studio)

platform path chip states (before connect: not connected → generic connect sheet)
YouTube (P0) Data API videos.insert, OAuth youtube.upload. Unverified projects are no longer forced private (as of 2 Nov 2026). Default 100 uploads/day. ≤3 min vertical becomes a Short. ready → uploading → processing → live / failed
X (P0) v2 chunked media upload + POST /2/tweets, OAuth 2.0 user context. Pay-per-use: $0.015/post, $0.20 if it has a URL. ready → uploading → posted / failed
Instagram (P0) Graph API Reels: container → status_code → media_publish. Instagram Login; the artist's account must be Creator or Business. needs creator account (if personal) → ready → processing → posted / error / expired
TikTok (P0, inbox) Content Posting API inbox upload (video.upload). Direct Post needs a TikTok app audit. ready · inbox → uploading → in tiktok inbox · tap publish in tiktok → posted / failed
Snapchat (later) Public Profile API is allowlist-only and needs a Business org + Public Profile. Or Ayrshare, or the Creative Kit share sheet. coming later
Aggregator option Ayrshare $149/mo covers all five (the only one with Snapchat). Buffer is cheaper but has no Snapchat. via: ayrshare

P0 order: SoundCloud → YouTube → X → Instagram → TikTok inbox → distribution route 1 (release kit + ISRC catalogue polling). LabelGrid (route 2) and Snapchat come later.

Only the artist can: pick and pay for their distributor, switch Instagram to Creator/Business, authorise each OAuth, and claim Spotify for Artists / Apple Music for Artists. Only 1982 (as the record.label owner) can: approve an aggregator or LabelGrid spend and own the platform dev apps and audits. Tokens go in the Keychain only.

Grok Bot connector: record.label's own MCP server, see §8a. Drafts only; the artist approves in the app.

12. Gestures summary

13. Phase 2 build order (SwiftUI native)

  1. Design tokens + TE component kit (design teammate, me guiding): colours, Inter 200, widget, pill, chip, sheet, transport keys, device-art views (SVG → PDF assets or SwiftUI Shapes from the same primitives).
  2. App shell + bottom tab bar + Home widget grid (Layout port of layoutHome(), paging TabView(.page)). Wire it to the existing DeviceBridge / NativeRecorder for live device art and REC. Apple.
  3. Studio A, foundations (Apple): StudioCore model + commands/undo, tempo map, session JSON + audio folder, AudioEngineKit graph, peak cache, Canvas timeline, TimelineView playhead.
  4. Studio B, editing: select, move, trim, cut, splice, copy/paste, duplicate, delete, snap, two-level zoom (project ppb + per-track zoom, pinch routed by touch hit-test, fit).
  5. Studio C, mixing: volume, pan, HP/LP, compressor, reverb aux, master limiter, track sheet.
  6. Studio D, record + export: record from the connected device into a new lane; offline render → bump → Finished.
  7. Tracks (can start in the WebView hub, then go native): takes grouped by device, finished, item sheet (rename, notes, artwork, video).
  8. Integrations P0 (XXX + Neo for the connections, Apple for the native OAuth UI): generic connect flows, then SoundCloud upload + status poll → YouTube → X → Instagram → TikTok inbox → distribution route 1 (release kit + ISRC polling). Status chips driven by the real states in §11.
  9. Video Studio: AVFoundation composition (video, audio, overlay lanes), export presets 9:16 / 1:1 / 16:9, post panel.
  10. Account banner, socials, finished pile. Grokbot: the MCP server (§8a) on the Cloudflare backend next to the hub sync, OAuth + PAT, drafts queue and in-app approval first, then the tools.
  11. Studio E polish; after that LabelGrid (route 2), Snapchat and artist-to-artist connect.

Ownership: Apple owns core, engine, timeline and native shell. XXX owns marketing and social connections (and status semantics). Neo owns the hub, the WebView tabs in the interim, and the existing SoundCloud app. Me (Brooklyn) coordinates, owns design and spec, and guides the team.

14. Open questions for 1982

  1. Ayrshare ($149/mo for all five platforms incl. Snapchat), or native APIs one by one (P0 order above)?
  2. Which of the new device drawings need a closer pass (OP-Z, MPC Sample, CM-15 grille are medium confidence)? Do you also want the EP-40 riddim / EP-2350 ting drawn?

15. Files