creatordesign system
GitHub
Collections
Collections · Creator Design System

Collections

A collection is a kind of thing you publish. Five routes, one section vocabulary, and one rule: it is the same design system arranged for a different subject.

A collection is a kind of thing you publish — travel, courses, a video series, a shop. Each one gets a folder holding the routes it needs, the sections those routes are built from, and one stylesheet written entirely in the system's tokens.

The point of doing it this way: a collection is not a new design. It is the same tokens, the same cards and the same type scale, arranged for a different subject. If a collection needs a colour or a spacing the system does not have, that is a question about the system — not a licence to invent one locally.

The five routes every collection has

Every collection answers the same five questions, so every collection has the same five routes. The names change; the shape does not.

RouteThe question it answers
Indexwhat is here?
travel: /travel
Groupwhat is here, of this kind?
travel: /travel/asia
Placewhat is here about this one thing?
travel: /travel/japan
Serieswhat is here, in order?
travel: /travel/india-2026
Postthe thing itself
travel: /travel/the-train-south

Series is the one worth being careful about. A series is an ordered set of posts made as one body of work — a trip, a course, a season. A group is an unordered set that share an attribute — a region, a subject, a tag. They look similar and behave differently: a series has a first and a last and a progress through it; a group has none of those. That is why the series route gets a spine and the group route gets a grid.

What a collection folder holds

text
collection/
  README.md          the shared contract
  collection.css     the col- vocabulary - every section, once
  collection.js      the linked filters - the only thing CSS cannot do
  shell.py           the head, navbar and footer every route shares

  _default/          the starting point: cp -r it and rename
    build.py         five routes with no subject in them
    *.html

  travel/
    travel.css       only what travel needs: globe, flight line, palm
    build.py
    *.html           index, region, country, trip, post, components

  blog/
    build.py         no CSS of its own - which is the test
    *.html           index, post

  course/
    course.css       the syllabus scene, the level meter, the quiz, the cert
    build.py
    *.html           index, track, topic, course, lesson, components

four collections, and only two of them need a stylesheet

Blog has no CSS of its own, and that is deliberate. If a second collection cannot be built out of the shared vocabulary, the vocabulary was really just the first collection wearing a general-sounding prefix. Travel keeps 44 lines — the globe, the flight line and the palm — because those genuinely belong to travel.

Course is the other direction. Its post route has a video in it rather than prose, and five sections were missing for that. They went into the shared sheet, not into course.css, because a podcast season and a video series want every one of them — and what a collection keeps for itself is the test of whether that split was honest.

The rules

RuleWhy
Tokens onlyevery value is a var(--…). A collection that hard-codes a colour cannot be rebranded, and has quietly left the system
Prefix onceshared sections are col-; a collection's own extras take its name (trv-). Anything useful twice graduates from one to the other
Reuse before addinga place card is a card. If a section is 90% an existing component, it is that component with a modifier
JS is additivethe filters degrade to showing everything. Every route must be readable and navigable with the script blocked
State in ARIAaria-pressed on a filter, aria-current on the current item. Never an .active class

Starting a new one

The default collection exists to be copied. It has five working routes and nothing subject-specific in them, so the first thing you see is the shape rather than somebody else's content.

bash
cp -r collection/_default collection/podcast
python3 collection/podcast/build.py

change the six lists at the top of build.py and the collection is yours

Auditing the rule

"Reuse before adding" is easy to agree with and hard to obey — the failure mode is not malice, it is not knowing the thing already exists. Two ways to check, both cheap enough to run on every build.

1 · Find classes used but never defined. A phantom class is worse than a missing style, because the markup looks right and renders as unstyled HTML. Two were found this way: .quote, used in five collections and defined nowhere — it only looked correct because those blockquotes sit inside .content, which styles blockquote directly — and .spec-table in the reusable docs template, which existed only in this repo's own docs stylesheet, so any project copying the template got an unstyled table.

2 · Find components defined but never used. This is where the reuse rule actually gets broken. The guides collection shipped its own .guide-cover while .book sat unused in 12-frame.css — already carrying a spine, a page edge, and a .book-shelf that tilts every second cover, with a doc comment naming the guides as what it was for. Every collection also hand-rolled a two-line footer while the real .footer — brand column, link columns, sign-off row — went unused, which meant the one place a sitemap gets to be exhaustive was a single sentence.

CheckWhat it catches
Used but undefinedgrep every class="…" in the built HTML against every .selector in the compiled CSS. Should always be empty
Defined but unusedthe same two sets, inverted. Will never be empty — utilities exist to be optional — but a whole family at zero is a component nobody knows about
The tella collection writing CSS for something the foundation already draws. If a new class describes a thing rather than a subject, it probably already exists