- Powered by Qloo:
- The brain
+ Taste data from the Qloo API:
+ The brain
of Busk Map
@@ -61,7 +57,7 @@ export default function BrainPage() {
- {`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}
diff --git a/src/app/brand/page.tsx b/src/app/brand/page.tsx
index 77143f18..416dbf61 100644
--- a/src/app/brand/page.tsx
+++ b/src/app/brand/page.tsx
@@ -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";
@@ -82,7 +82,7 @@ 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;
@@ -90,7 +90,7 @@ 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 = [
@@ -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"],
@@ -159,7 +159,6 @@ export default function BrandPage() {
{body}
- {title === "Qloo, our partner" ? : null}
))}
@@ -402,14 +401,8 @@ export default function BrandPage() {
))}
-
-
-
- Qloo's own logo, shown wherever Busk Map names Qloo as its partner. It always links to qloo.com in a new tab.
-
-
-
The pictures for the repository, the Devpost page and the video. Each uses the logo and Qloo's logo as drawn here; the screenshots are real captures of the app at 1440 and 390.
+
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.
diff --git a/src/app/globals.css b/src/app/globals.css
index d849adf5..bd481f5a 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -51,8 +51,8 @@
--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. */
@@ -60,7 +60,7 @@
--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;
@@ -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;
@@ -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;
@@ -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);
@@ -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); }
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 91ca8cf7..706db2c1 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -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");
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 3fb3cadb..c6384367 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,6 +1,5 @@
import Link from "next/link";
import { ExampleActCard } from "@/components/honeycomb/example-act-card";
-import { QlooLink } from "@/components/honeycomb/logo";
import { ScoreCell } from "@/components/honeycomb/score-cell";
import { Button } from "@/components/ui/button";
import { HexCell } from "@/components/honeycomb/hex-cell";
@@ -77,12 +76,11 @@ export default function Home() {
-
- {/* The halo keeps the purple legible when a glowing cell pulses behind it. */}
-
- Built with
+
+ {/* Plain text only: no Qloo logo, no partner wording. The halo keeps it legible when a glowing cell pulses behind it. */}
+
+ Taste data from the Qloo API
-
BrainMap, StatusCard, PageHeader and SiteFooter render full size on their own pages. Every state of every component is in the design system: Busk Map · Honeycomb.
diff --git a/src/components/brand/brand-tables.ts b/src/components/brand/brand-tables.ts
index f7dc8515..5ae5f170 100644
--- a/src/components/brand/brand-tables.ts
+++ b/src/components/brand/brand-tables.ts
@@ -2,7 +2,7 @@
export type ScreenRow = { name: string; route: string; shows: string; /** Drawn in the deck at 390, 768 and 1440; false until it is. Default true. */ drawn?: boolean };
export const SCREENS: ScreenRow[] = [
- { name: "Landing", route: "/", shows: "Main explains the product: hero, try an act, guesswork, what you get back, beyond buskers, Thanks to (Qloo as sponsor, then built with), the Brain and Honeycomb teasers, closing call." },
+ { name: "Landing", route: "/", shows: "Main explains the product: hero, try an act, guesswork, what you get back, beyond buskers, Thanks to (the Qloo taste data credit in plain text, then built with), the Brain and Honeycomb teasers, closing call." },
{ name: "Busks: plan your busk", route: "/busks", shows: "The form for your own act" },
{ name: "Repertoire", route: "/repertoire", shows: "Your songs: search, pick and suggested fill", drawn: true },
{ name: "Busks: plan again", route: "/busks?again=", shows: "Pre-filled from an earlier busk, date and hours left" },
diff --git a/src/components/honeycomb/artist-profile.tsx b/src/components/honeycomb/artist-profile.tsx
index c778799a..1905202b 100644
--- a/src/components/honeycomb/artist-profile.tsx
+++ b/src/components/honeycomb/artist-profile.tsx
@@ -17,7 +17,7 @@ export function formatFollowers(n: number): string {
return String(n);
}
-const qlooChip = "border-qloo text-qloo";
+const qlooChip = "border-slate text-slate";
/** "Your audience": the Qloo audience tags with the Qloo mark. One markup for the profile's inline use and the layout's `audience` slot. */
export function AudienceTags({ profile, className }: { profile: Pick | null; className?: string }) {
diff --git a/src/components/honeycomb/brain-sketch.tsx b/src/components/honeycomb/brain-sketch.tsx
index f33f21c0..563dd449 100644
--- a/src/components/honeycomb/brain-sketch.tsx
+++ b/src/components/honeycomb/brain-sketch.tsx
@@ -1,16 +1,18 @@
+import { callKinds, dataPointCount, featureCount } from "@/lib/qloo-map";
+
const HEX = "[clip-path:polygon(50%_0,100%_25%,100%_75%,50%_100%,0_75%,0_25%)]";
const LINK = "[clip-path:polygon(0_0,50%_0,100%_50%,50%_100%,0_100%)]";
/**
- * The landing's brain teaser sketch (user, impeccable live 17 Oct): the brain's real shape as dense bands of cells, 11 Qloo
- * calls, 16 data points and 8 parts of your busk, under big display labels and joined by the F30 half-hex links. A pulse runs
+ * The landing's brain teaser sketch (user, impeccable live 17 Oct): the brain's real shape as dense bands of cells, one per kind
+ * of Qloo call, data point and part of your busk (counted from lib/qloo-map, never typed in), under big display labels and joined by the F30 half-hex links. A pulse runs
* through every cell, calls to busk, on a loop that never stops (hc-flow in globals.css; still under reduced motion).
* A sketch, not data: hidden from screen readers (the teaser's numbers and copy carry the meaning).
*/
const COLUMNS = [
- { label: "Calls", n: 11, tone: (k: number) => (k % 3 === 1 ? "bg-primary" : "bg-qloo") },
- { label: "Data", n: 16, tone: (k: number) => (k % 4 === 0 ? "bg-muted" : "bg-primary") },
- { label: "Busk", n: 8, tone: (k: number) => (k % 2 === 0 ? "bg-primary" : "bg-muted") },
+ { label: "Calls", n: callKinds, tone: (k: number) => (k % 3 === 1 ? "bg-primary" : "bg-slate") },
+ { label: "Data", n: dataPointCount, tone: (k: number) => (k % 4 === 0 ? "bg-muted" : "bg-primary") },
+ { label: "Busk", n: featureCount, tone: (k: number) => (k % 2 === 0 ? "bg-primary" : "bg-muted") },
];
export function BrainSketch() {
diff --git a/src/components/honeycomb/hive-mark.tsx b/src/components/honeycomb/hive-mark.tsx
index f5f20fbc..d61b7d99 100644
--- a/src/components/honeycomb/hive-mark.tsx
+++ b/src/components/honeycomb/hive-mark.tsx
@@ -2,6 +2,7 @@
import { useEffect, useId, useState, useSyncExternalStore } from "react";
import { cn } from "cn";
+import { DATA_GLYPH } from "@/components/honeycomb/source-logo";
/**
* The Hive's mark: seven pointy-top cells in one comb. Ported 1:1 from the design project's HiveMark (Hive Identity): the
@@ -10,7 +11,7 @@ import { cn } from "cn";
*
* - `state="rest"`: all seven cells full (done, replayed, standing). `state="working"`: the centre is full and the outer cells
* move per `anim`. Reduced motion (checked live) and `motion={false}` hold the anim's fixed working frame.
- * - `source`: the centre cell takes the source's colour (tokens `--source-*`) and, from 20px up, its logo (larger below 40px: logoWidth). Outer cells keep
+ * - `source`: the centre cell takes the source's colour (tokens `--source-*`) and, from 20px up, its logo (Qloo: the neutral data glyph) (larger below 40px: logoWidth). Outer cells keep
* animating in Hive orange. Mixed-source steps omit it.
* - `muted`: the dashed plain hex used when the Hive didn't run (the design's engine-only state does not use the mark).
*/
@@ -67,17 +68,12 @@ const DIRS = [-60, 0, 60, 120, 180, 240];
type Cell = { points: string; fill: string; stroke: string; sw: number; op: number };
-/** The centre cell's logo per source, drawn in a nested viewBox: Qloo's ring and tail (the design's), Spotify's symbol (the official full logo's first path), Last.fm's "as". */
+/** The centre cell's logo per source, drawn in a nested viewBox: for Qloo the neutral data glyph (never Qloo's mark), Spotify's symbol (the official full logo's first path), Last.fm's "as". */
const LOGOS: Record = {
qloo: {
viewBox: "0 0 24 24",
ink: "var(--source-qloo-ink)",
- body: (
- <>
-
-
- >
- ),
+ body: {DATA_GLYPH},
},
spotify: {
viewBox: "11.8 3.2 218.8 218.8",
diff --git a/src/components/honeycomb/in-view.tsx b/src/components/honeycomb/in-view.tsx
deleted file mode 100644
index abad5836..00000000
--- a/src/components/honeycomb/in-view.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-"use client";
-
-import { useEffect, useRef, useState, type ReactNode } from "react";
-import { cn } from "cn";
-
-/**
- * Plays a one-shot CSS animation when its children first scroll on screen, not on page load far above them. Progressive:
- * the server renders no `data-inview`, so the children are fully visible with no JS, slow JS, crawlers and screenshots.
- * Once JS runs, an off-screen wrapper is marked `ready` (the CSS holds the animation at its first frame) and then `true`
- * when it enters view (the CSS plays it). A wrapper already on screen when JS runs stays as it is, with no animation.
- */
-export function InView({ children, className }: { children: ReactNode; className?: string }) {
- const ref = useRef(null);
- const [state, setState] = useState<"static" | "ready" | "true">("static");
- useEffect(() => {
- const el = ref.current;
- if (!el) return;
- const r = el.getBoundingClientRect();
- if (r.top < window.innerHeight && r.bottom > 0) return;
- const observer = new IntersectionObserver(
- (entries) => {
- if (entries.some((e) => e.isIntersecting)) {
- observer.disconnect();
- setState("true");
- }
- },
- { threshold: 0.4 },
- );
- // Marked ready from the observer's first callback, not synchronously in the effect.
- let first = true;
- const ready = new IntersectionObserver(() => {
- if (first) {
- first = false;
- ready.disconnect();
- setState((s) => (s === "static" ? "ready" : s));
- observer.observe(el);
- }
- });
- ready.observe(el);
- return () => {
- observer.disconnect();
- ready.disconnect();
- };
- }, []);
- return (
-
- {children}
-
- );
-}
diff --git a/src/components/honeycomb/info-tag.tsx b/src/components/honeycomb/info-tag.tsx
index 2b496e10..56e17ea2 100644
--- a/src/components/honeycomb/info-tag.tsx
+++ b/src/components/honeycomb/info-tag.tsx
@@ -7,8 +7,8 @@ import { Badge } from "@/components/ui/badge";
const tones = {
neutral: "border-input text-foreground",
- // Qloo purple only where Qloo is named ("Qloo", "Crowd by Qloo").
- qloo: "border-qloo text-qloo",
+ // Neutral slate for Qloo-sourced data, always with "Qloo" in the words ("Crowd by Qloo"); never a Qloo colour or logo.
+ qloo: "border-slate text-slate",
signal: "border-primary text-signal-text",
} as const;
@@ -26,7 +26,7 @@ export function InfoTag({
children?: ReactNode;
icon?: IconName;
tone?: keyof typeof tones;
- /** A data source: the tag is its logo only (Spotify, Last.fm, Qloo), the name in the accessible label. Replaces the words. */
+ /** A data source: Spotify and Last.fm as their icon, the name in the accessible label; Qloo as the neutral glyph plus the word "Qloo". Replaces the words. */
source?: MentionSource;
className?: string;
}) {
diff --git a/src/components/honeycomb/logo.tsx b/src/components/honeycomb/logo.tsx
index 6bbff804..95f50516 100644
--- a/src/components/honeycomb/logo.tsx
+++ b/src/components/honeycomb/logo.tsx
@@ -27,38 +27,3 @@ export function Logo({ size = 34, className, ground = "auto" }: LogoProps) {
);
}
-
-/** Qloo's wordmark: letters in the current colour, the bar in Qloo's purple. */
-function QlooSvg({ width = 48, className }: { width?: number; className?: string }) {
- return (
-
- );
-}
-
-/**
- * Every Qloo logo in the app is this link (F09): it goes to qloo.com in a new tab, with rel="noopener noreferrer", and its
- * name says that it opens in a new tab. The logo inside is decorative, so the link has one name, not two.
- */
-export function QlooWordmark({ width = 48, className, wordmarkClassName }: { width?: number; className?: string; wordmarkClassName?: string }) {
- return (
-
-
-
- );
-}
-
-/** Kept for callers that say "link": the Qloo wordmark is always the link. */
-export const QlooLink = QlooWordmark;
diff --git a/src/components/honeycomb/repertoire/repertoire-funnel.tsx b/src/components/honeycomb/repertoire/repertoire-funnel.tsx
index 9b52d88f..05e809d2 100644
--- a/src/components/honeycomb/repertoire/repertoire-funnel.tsx
+++ b/src/components/honeycomb/repertoire/repertoire-funnel.tsx
@@ -46,7 +46,7 @@ export function RepertoireFunnel({ totals, live, className }: { totals: Partial<
const name = n === 1 ? s.one : s.many;
items.push(
- 3 ? 10 : 12} className={cn(CELL, s.qloo && "text-qloo")} label={`${n} ${name} (${s.src})`}>
+ 3 ? 10 : 12} className={cn(CELL, s.qloo && "text-slate")} label={`${n} ${name} (${s.src})`}>
{text}
{name}
diff --git a/src/components/honeycomb/site-footer.tsx b/src/components/honeycomb/site-footer.tsx
index b43266f9..5da7ee8b 100644
--- a/src/components/honeycomb/site-footer.tsx
+++ b/src/components/honeycomb/site-footer.tsx
@@ -4,7 +4,7 @@ import Link from "next/link";
import { usePathname } from "next/navigation";
import { cn } from "cn";
import { HexCell } from "@/components/honeycomb/hex-cell";
-import { Logo, QlooWordmark } from "@/components/honeycomb/logo";
+import { Logo } from "@/components/honeycomb/logo";
import { OsmCredit } from "@/components/honeycomb/osm-credit";
import { VersionBadge } from "@/components/honeycomb/version-badge";
@@ -30,8 +30,8 @@ const SITE_LINKS = [
const LINK = "inline-flex min-h-tap items-center font-bold text-foreground underline underline-offset-3 hover:decoration-2";
/**
- * The footer on every page, in three parts: on the left the wordmark and the Qloo credit, in the centre Privacy, Brain and Brand,
- * on the right GitHub (an icon in a cell) and "Built by T04435" with the pixel critter, and on a line of its own at the bottom, centred, the running version (VersionBadge). At 390px the parts stack. The legal line
+ * The footer on every page, in three parts: on the left the wordmark and the map credit, in the centre Privacy, Brain and Brand,
+ * on the right GitHub (an icon in a cell) and "Built by T04435" with the pixel critter, and on a line of its own at the bottom, centred, the running version (VersionBadge), above it the Qloo taste-data credit and disclaimer in plain text. At 390px the parts stack. The legal line
* lives on /terms, which the footer links to. On the landing (`dark`) it continues the closing call to action's dark band, as in
* the deck; on every other page it sits on paper.
*/
@@ -48,9 +48,6 @@ export function SiteFooterView({ repo = REPO, dark = false, night = false }: { r
-
- with
-