Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ colors:
night-card: "#182025"
night-ink: "#f2ede4"
honey: "#ffcf3a"
qloo-purple: "#8C8CC8"
qloo-ink: "#5b5ba3"
slate: "#45596b"
slate-night: "#a9bccb"
zone-pink: "#e0337a"
destructive: "#b0152f"
taste-3: "#f28644"
Expand Down Expand Up @@ -89,7 +89,7 @@ components:
- **Signal orange** (#ff5a1f by day, #ff6a2b at night): the one accent. It's for the primary action, the selected or top item, the pitch ring, and the taste cells. It is never used for body text; text in the accent tone uses **signal text** (#b13a00) for contrast.

### Secondary
- **Qloo purple** (#8C8CC8 brand bar, #5b5ba3 for text): only where Qloo is named or its data shows (the Brain page, Qloo calls, the Qloo wordmark).
- **Slate** (#45596b day, #a9bccb night): neutral ink for data from a named source (the Brain page, Qloo calls, Qloo-sourced chips), always beside the word "Qloo". No Qloo colour or logo anywhere.

### Neutral
- **Paper** (#f2eee6) ground with **paper card** (#fbf9f5) surfaces; **bluestone** (#141c21) ink, rules and the night header; **muted ink** (#56606a) for secondary text; a **hairline** (#cfc7b8) for quiet dividers.
Expand Down
4 changes: 2 additions & 2 deletions PRODUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Taste-matched pitches: who is actually out there at that hour, and what they lik

## Operating Context

Built for the Qloo Agentic Hackathon 2026; submission is due 30 Oct. The live judge path is landing → plan a busk → the plan page → Repertoire → Brain (how Qloo powers it).
Built for the Qloo Agentic Hackathon 2026; submission is due 30 Oct. The live judge path is landing → plan a busk → the plan page → Repertoire → Brain (how Qloo taste data feeds it).

## Capabilities and Constraints

Expand All @@ -34,7 +34,7 @@ Built for the Qloo Agentic Hackathon 2026; submission is due 30 Oct. The live ju

- The name is Busk Map, and the visual identity is Honeycomb (the published design system is the reference; the app is the source of truth for component code).
- The logo is the lockup: the hex mark beside the wordmark.
- Every Qloo logo links to qloo.com.
- Qloo is named in plain text only: no Qloo logo, no partner or sponsor wording. Busk Map is not affiliated with or endorsed by Qloo.
- Busk Map never confirms a pitch is legal: it tells buskers to check their permit conditions.
- No text glyphs as icons (arrows, chevrons, checks); icons are the design system's Icon set.
- One keyboard focus ring, never two.
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

Know where to play, and what to play there.

Busk Map is an agent for street performers. Pick a city and a time slot, and it finds the pitches whose crowd matches your music, near busy places that are open at that hour. It then builds a setlist for each pitch from the songs you can play. It is built with [Qloo](https://qloo.com) for the [Qloo Agentic Hackathon](https://qloo.devpost.com/). Live at https://buskmap.app.
Busk Map is an agent for street performers. Pick a city and a time slot, and it finds the pitches whose crowd matches your music, near busy places that are open at that hour. It then builds a setlist for each pitch from the songs you can play. Taste data from the Qloo API. Built for the [Qloo Agentic Hackathon](https://qloo.devpost.com/). Live at https://buskmap.app.

Busk Map is not affiliated with or endorsed by Qloo.

## Hive, the agent

Expand Down Expand Up @@ -46,7 +48,7 @@ pnpm test:e2e # builds and starts an offline server, then runs the judg
`pnpm purge:spotify` deletes or nulls the Spotify data stored in Postgres (cover images, Spotify years and durations, artist profile snapshots, research snapshots, learn-run steps, cached runs, Spotify pacer rows). It keeps the Spotify IDs and our own data, and it is safe to run twice. Run it once on 10 Nov 2026 against production (Spotify Developer Terms IV.3). Before that date it refuses unless you pass `--force`. It uses the same main-database guard as the other scripts.

## Data
- [Qloo](https://qloo.com) taste API (16 kinds of call, see the /brain page; a local mock without a key)
- Taste data from the Qloo API, used under Qloo's Terms of Use (18 kinds of call, see the /brain page; a local mock without a key)
- OpenStreetMap public spaces and venue names (© OpenStreetMap contributors, ODbL)
- City of Melbourne busking locations (CC BY)
- Ticketmaster Discovery API, Last.fm, Open-Meteo
Expand Down
2 changes: 1 addition & 1 deletion docs/qloo-city-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Run on 2026-10-17 against the live Qloo hackathon API (`https://hackathon.api.qloo.com`). Qloo only, no model calls.
Script: `scripts/probe-qloo-cities.mjs` (re-run with `node --env-file=.env.local scripts/probe-qloo-cities.mjs`).
It prints aggregates only. Qloo responses are cached privately server-side (Qloo Support confirmed this is allowed). No Qloo response data is kept in this repo: no locality ids, counts or artist names from live responses.
It prints aggregates only. Qloo responses are cached privately server-side. No Qloo response data is kept in this repo: no locality ids, counts or artist names from live responses.

## Method

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "busk-map",
"version": "1.2.0",
"version": "1.2.1",
"private": true,
"scripts": {
"dev": "node scripts/copy-maplibre-worker.mjs && next dev",
Expand Down
Binary file modified public/brand/kit/features/02-repertoire.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/brand/kit/features/03-brain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/brand/kit/github-social-preview-1280x640.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/brand/kit/readme-hero-1600x640.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/brand/kit/screenshot-desktop-1500x1000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/brand/kit/video-end-1920x1080.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/brand/kit/video-lower-third-1920x1080.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/brand/kit/video-title-1920x1080.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/brand/social/devpost-cover-1200x800.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/brand/social/og-image-1200x630.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion public/partners/qloo-icon-ink.svg

This file was deleted.

1 change: 0 additions & 1 deletion public/partners/qloo-icon-white.svg

This file was deleted.

14 changes: 5 additions & 9 deletions src/app/brain/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import type { Metadata } from "next";
import Link from "next/link";
import { BrainMap } from "@/components/brain/brain-map";
import { QlooWordmark } from "@/components/honeycomb/logo";
import { Icon } from "@/components/honeycomb/icon";
import { MeetTheHive } from "@/components/honeycomb/meet-the-hive";
import { NoteCard } from "@/components/honeycomb/note-card";
import { StatStrip } from "@/components/honeycomb/stat-strip";
import { callKinds, facts, next, QUOTA } from "@/lib/qloo-map";
import { callKinds, facts, next, quotaNote } from "@/lib/qloo-map";

export const metadata: Metadata = {
title: "The brain of Busk Map",
Expand All @@ -27,13 +26,10 @@ export default function BrainPage() {
<main id="main" data-theme="dark" className="bm-grain flex-1 bg-background text-foreground" style={{ backgroundImage: `${LATTICE}, radial-gradient(color-mix(in oklab, var(--foreground) 9%, transparent) 0.8px, transparent 1.2px)`, backgroundSize: "56px 100px, 4px 4px" }}>
<div className="mx-auto flex w-full max-w-[1360px] flex-col gap-8 px-4 pt-8 pb-16 md:px-6 md:pt-16">
<header className="flex max-w-[900px] flex-col gap-[18px]">
<span className="inline-flex flex-wrap items-center gap-3.5 font-display text-[clamp(24px,4vw,36px)] leading-none font-extrabold text-qloo uppercase">
Powered by
<QlooWordmark width={200} className="w-[clamp(120px,26vw,200px)]" wordmarkClassName="h-auto w-full text-foreground" />
</span>
<span className="font-display text-[clamp(24px,4vw,36px)] leading-none font-extrabold text-slate uppercase">Taste data from the Qloo API</span>
<h1 className="m-0 font-display text-[clamp(56px,9vw,128px)] leading-[0.86] font-extrabold uppercase">
<span className="sr-only">Powered by Qloo: </span>
The <span className="text-qloo">brain</span>
<span className="sr-only">Taste data from the Qloo API: </span>
The <span className="text-slate">brain</span>
<br />
of Busk Map
</h1>
Expand Down Expand Up @@ -61,7 +57,7 @@ export default function BrainPage() {
</NoteCard>
<NoteCard title="Light on the quota">
<p className="m-0" data-testid="quota-note">
{`Answers are cached for ${QUOTA.cacheHours} hours. Qloo allows ${QUOTA.requestsPerSecond} calls a second; Busk Map paces itself to ${QUOTA.pacedPerSecond}, because bursts of 4 drew rate-limit errors. One key's ${QUOTA.requestsPerMonth.toLocaleString("en-AU")} calls a month cover roughly 270–360 new busks, and reruns are free.`}
{quotaNote}
</p>
</NoteCard>
<NoteCard variant="next">
Expand Down
17 changes: 5 additions & 12 deletions src/app/brand/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { PhoneFold } from "@/components/brand/phone-fold";
import { HexCell } from "@/components/honeycomb/hex-cell";
import { Icon } from "@/components/honeycomb/icon";
import { Spinner } from "@/components/ui/spinner";
import { Logo, QlooWordmark } from "@/components/honeycomb/logo";
import { Logo } from "@/components/honeycomb/logo";
import { ScoreCell } from "@/components/honeycomb/score-cell";
import { RankTile } from "@/components/honeycomb/rank-tile";
import { DURATIONS, EASINGS, RADII, SHADOWS, SIZES, SPACE, STROKES, TOKENS, WORDS, type ScaleRow } from "@/lib/brand-data";
Expand Down Expand Up @@ -82,15 +82,15 @@ const PRINCIPLES = [
["Bluestone and paper", "Bluestone is the ink and the night ground; warm paper is the day ground. Both themes pass AA everywhere."],
["Condensed caps", "Big Shoulders shouts the headings. Sentences stay in Atkinson Hyperlegible Next; data and numbers in JetBrains Mono."],
["Print texture", "2px rules instead of soft shadows, hard offsets on things that float, a halftone grain on night grounds, a stencil wordmark."],
["Qloo, our partner", "Qloo is credited with its own wordmark wherever its data changes the answer, and has its own purple (`qloo`) only for Qloo facts and the Brain."],
["Credit in words", "Qloo's taste data is credited in plain text wherever it changes the answer: the word Qloo, never a logo, in the neutral `slate`."],
["Honest numbers", "Every number names its source. Estimates are labelled; planned work is labelled \"Next · not built yet\"; nothing is invented."],
] as const;

const VOICE = [
["Pitch, busk", "A pitch is one place to play. A busk is the whole outing: three pitches, their suggested sets, one link."],
["Plain words", "Say what the research found, never the tool behind it."],
["Honest numbers", "Every number names its source. Estimates are labelled, and nothing is invented."],
["Qloo first", "Taste data is the heart of every busk. Credit Qloo wherever its data changed the answer."],
["Name the data", "Taste data is the heart of every busk. Name Qloo, in plain text, wherever its data changed the answer."],
] as const;

const COLOURS = [
Expand All @@ -99,7 +99,7 @@ const COLOURS = [
["Paper", "--card", "cards, panels"],
["Ground", "--background", "the page"],
["Honey", "--honey", "hidden gems"],
["Qloo", "--qloo", "Qloo, our partner"],
["Slate", "--slate", "data from a named source"],
["Event blue", "--event", "events"],
["Zone pink", "--zone-pink", "no-busking zones"],
["Footfall", "--footfall", "activity estimate"],
Expand Down Expand Up @@ -159,7 +159,6 @@ export default function BrandPage() {
<span>
<Rich>{body}</Rich>
</span>
{title === "Qloo, our partner" ? <QlooWordmark width={96} className="self-start" /> : null}
</li>
))}
</ul>
Expand Down Expand Up @@ -402,14 +401,8 @@ export default function BrandPage() {
</ul>
</PhoneFold>
))}
<PhoneFold heading="Qloo's logo" headingClassName="m-0 font-display text-[26px] leading-none font-extrabold uppercase">
<div className="flex flex-wrap items-center gap-4 border-2 border-rule bg-card p-5">
<QlooWordmark width={160} />
<span className="max-w-md text-sm text-muted-foreground">Qloo&apos;s own logo, shown wherever Busk Map names Qloo as its partner. It always links to qloo.com in a new tab.</span>
</div>
</PhoneFold>
<PhoneFold heading="Submission and video kit" count={KIT.length} headingClassName="m-0 font-display text-[26px] leading-none font-extrabold uppercase">
<p className="m-0 max-w-3xl">The pictures for the repository, the Devpost page and the video. Each uses the logo and Qloo&apos;s logo as drawn here; the screenshots are real captures of the app at 1440 and 390.</p>
<p className="m-0 max-w-3xl">The pictures for the repository, the Devpost page and the video. Each uses the logo as drawn here and names Qloo in plain text only; the screenshots are real captures of the app at 1440 and 390.</p>
<TableFrame label="Submission and video kit" min={640}>
<thead>
<tr>
Expand Down
29 changes: 6 additions & 23 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,16 @@
--bluestone: #141c21;
--honey: #ffcf3a;
--honey-deep: #d99a00;
--qloo: #5b5ba3;
--qloo-brand: #8C8CC8;
/* Slate: the neutral ink for data from a named source (a Qloo-sourced chip, tag or stat), always with the source's name in words. */
--slate: #45596b;
--signal-text: #b13a00;
/* The Hive mark (Hive Identity): signal-text by day, signal at night. The day and night values and the board's day paper are
the same in both themes, so a specimen can show the day mark inside a night panel. */
--hive-day: #b13a00;
--hive-night: #ff6a2b;
--hive-paper: #f7f3ec;
--hive: var(--hive-day);
/* Source colours for the Hive mark's centre cell (single-source steps): Qloo's bluestone with a white mark, Spotify's green with a black mark, Last.fm's red with a white mark. Brand colours, the same in both themes. */
/* Source colours for the Hive mark's centre cell (single-source steps): Qloo steps on Busk Map's own bluestone with the white neutral data glyph (no Qloo mark), Spotify's green with a black mark, Last.fm's red with a white mark. Brand colours, the same in both themes. */
--source-qloo: #141c21;
--source-qloo-ink: #ffffff;
--source-spotify: #1ed760;
Expand Down Expand Up @@ -122,8 +122,7 @@
--bluestone: #141c21;
--honey: #ffcf3a;
--honey-deep: #d99a00;
--qloo: #8C8CC8;
--qloo-brand: #8C8CC8;
--slate: #a9bccb;
--signal-text: #ff7f45;
--hive: var(--hive-night);
--zone-pink: #ff5c9d;
Expand Down Expand Up @@ -180,8 +179,7 @@
--bluestone: #141c21;
--honey: #ffcf3a;
--honey-deep: #d99a00;
--qloo: #8C8CC8;
--qloo-brand: #8C8CC8;
--slate: #a9bccb;
--signal-text: #ff7f45;
--hive: var(--hive-night);
--zone-pink: #ff5c9d;
Expand Down Expand Up @@ -292,8 +290,7 @@
--color-bluestone: var(--bluestone);
--color-honey: var(--honey);
--color-honey-deep: var(--honey-deep);
--color-qloo: var(--qloo);
--color-qloo-brand: var(--qloo-brand);
--color-slate: var(--slate);
--color-signal-text: var(--signal-text);
--color-hive: var(--hive);
--color-hive-paper: var(--hive-paper);
Expand Down Expand Up @@ -440,20 +437,6 @@ html { scroll-padding-bottom: var(--bottom-nav); }
@media (prefers-reduced-motion: reduce) { .hc-flow-cell, .hc-flow-link { animation: none; } }
/* The landing's one pause control (MotionPause) holds every loop where it is (WCAG 2.2.2): the ticker, the hero glow, the brain pulse. */
:root[data-motion="paused"] :is(.hc-ticker, .hc-glow, .hc-flow-cell, .hc-flow-link) { animation-play-state: paused; }
/* The sponsor's Qloo wordmark assembles once, when it scrolls into view (impeccable live, 17 Oct; progressive). Paths: 1 l, 2 Q, 3 and 4 the o's, 5 the purple bar. */
@keyframes hc-qloo-rise { 0% { opacity: 0; transform: translateY(60%) scaleY(0.6); } 100% { opacity: 1; transform: none; } }
@keyframes hc-qloo-bar { 0% { transform: scaleX(0); } 100% { transform: scaleX(1); } }
/* Progressive: with no JS (or before it runs) there is no data-inview and no animation, so the logo is always visible. InView marks an
off-screen wordmark "ready" (held at its first frame) and then "true" when it scrolls into view (it plays). */
[data-inview] .hc-qloo-rise path { transform-box: fill-box; transform-origin: 50% 100%; animation: hc-qloo-rise 0.6s cubic-bezier(.2,.8,.2,1) both; }
[data-inview] .hc-qloo-rise path:nth-child(2) { animation-delay: 0.05s; }
[data-inview] .hc-qloo-rise path:nth-child(1) { animation-delay: 0.17s; }
[data-inview] .hc-qloo-rise path:nth-child(4) { animation-delay: 0.29s; }
[data-inview] .hc-qloo-rise path:nth-child(3) { animation-delay: 0.41s; }
[data-inview] .hc-qloo-rise path:nth-child(5) { transform-origin: 0 50%; animation: hc-qloo-bar 0.5s cubic-bezier(.2,.8,.2,1) 0.75s both; }
[data-inview="ready"] .hc-qloo-rise path { animation-play-state: paused; }
/* Reduced motion: no rise, no bar; the nth-child(5) rule is named too, or its higher specificity would keep the bar animating. */
@media (prefers-reduced-motion: reduce) { [data-inview] .hc-qloo-rise path, [data-inview] .hc-qloo-rise path:nth-child(5) { animation: none; } }

.hc-cell { transform-box: fill-box; transform-origin: center; animation: hc-cell-in 520ms var(--ease-out, ease) backwards; animation-delay: var(--d, 0ms); }
.hc-cell-hot { animation: hc-cell-in 520ms var(--ease-out, ease) backwards, hc-breathe 3.6s ease-in-out infinite; animation-delay: var(--d, 0ms), calc(var(--d, 0ms) + 2400ms); }
Expand Down
2 changes: 1 addition & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const mono = JetBrains_Mono({ subsets: ["latin"], weight: ["400", "500", "700"],

const TITLE = "Busk Map";
const DESCRIPTION =
"Know where to play, and what to play there. A taste-aware pitch planner for street performers, powered by Qloo.";
"Know where to play, and what to play there. A taste-aware pitch planner for street performers, with taste data from the Qloo API.";

/** Absolute URLs for the social images: the production domain on Vercel, localhost elsewhere. */
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL ?? (process.env.VERCEL_PROJECT_PRODUCTION_URL ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}` : "http://localhost:3000");
Expand Down
Loading
Loading