flocks 0.1.0
flocks: ^0.1.0 copied to clipboard
Flocks — a Flutter design system built on widgets.dart: design tokens, theme and brand (white-label).
Changelog #
Every relevant change to this package. The format follows Keep a Changelog, and the numbering follows SemVer.
On the numbering. Nothing below
[0.1.0]was ever published. Those versions are internal migration milestones from the monorepo — they ran from0.1.0to1.5.0while the pubspec still said1.0.0, so they never agreed with it in the first place. The component catalog used to carry the same milestones in asince:field; it was dropped for that reason.The public line starts at
0.1.0, on purpose.1.0.0on pub.dev is a promise about the future, and this package has not yet met an external consumer. In0.x, SemVer makes the minor the breaking slot, so^0.1.0pins adopters to>=0.1.0 <0.2.0and the churn cannot reach them by surprise. It graduates to1.0.0once the API holds still through a few outside adopters.
0.1.0 - 2026-08-05 #
Added #
AppBrandTypography— a brand now picks its display and body families. It closes the last white-label gap: color, radius, motion, style, glass and icon already belonged to the brand; typography was pinned in the package.AppIconToken— the contract of 55 icons the components use, and that every provider has to know how to serve. It is anextension typeoverString, so it is accepted anywhere aStringalready is.AppIconProvideras a theme axis, with two implementations:AppAssetIconProvider(the default, bundled SVGs, no network) andAppNetworkIconProvider(a CDN, with the base URL injected).AppIllustrationToken,AppIllustrationProviderand theAppIllustrationThemeaxis — the last corner where the package took a third-party licensed asset. The bundledemptycomes from Open Peeps under CC0, which (unlike unDraw/ManyPixels/Storyset) does not forbid redistributing it in a package.AppThemeScope(iconProvider:, illustrationProvider:)— the seam through which the APP picks the icon set. The brand cannot declare it: a large set lives in a sibling package, and the core does not depend on those.- Sibling packages
flocks_phosphor(1,512 icons × 6 weights, withPhosphorWeightas an axis) andflocks_material(the reference implementation, which proves the zero-Material thesis from outside). - The
flocksbrand — the whole palette derived from a seed throughswatchFromSeed, with Space Grotesk on display. It is the living proof of the white-label. (It used to be the only brand that worked with no network at all; sincecdnBaseUrlleftAppBrandConfig, every brand does.) neutralSwatchFromSeed— the neutral ramp needs a tone ladder of its own: the theme uses stop 300 assurfaceand 600 asoutline, and on the chromatic ladder those two sit 30 tones apart (a ratio of 2.79, below the 3.0 floor). Without it, every seed-generated brand would fail the contrast gate, in the same place.AppTextTheme.copyWithandAppBrandConfig.copyWith, which did not exist.LICENSE(MIT), thisCHANGELOGand a realREADME.tool/golden_triage.py— it builds contact sheets per family for reviewing golden failures.- The catalog freshness gate (
test/architecture/catalog_freshness_test.dart).doc/mcp/catalog.jsondrifted twice in three days because regenerating it was a manual step, and the site reads that file to publish the component count — each drift became a false number in the wild. The test runs in every PR'sflutter testand also requires that the hand-written numbers in the README match the code.
Changed #
- The catalog's prose is bilingual.
summary,description,whenToUse,whenNotToUse,props[].description,examples[].title/description,do,dontanda11ynow carryLocalizedText/LocalizedList(en+pt), anddoc/mcp/catalog.jsonemits{"en": …, "pt": …}for each of them. Both languages are required by the constructor, so no component can ship half-translated;test/architecture/catalog_language_test.dartalso fails when anenfield is left carrying Portuguese. Breaking for anyone readingAppComponentMetaor the JSON. statesandvariantsare a closed English vocabulary. They name API surface (an enum's value, an interaction state), so they are not localized; they are checked against the allow-list intest/architecture/catalog_vocabulary.dart.- The
.doc.mdfiles and this README are in English. The package is international from publication onward. The Portuguese lives on in the catalog'sptside, which is what the site publishes on its PT routes. Poppins-SemiBoldenters, and thetitle*styles now render at the weight they ask for. They had declaredw600all along and fell back to 500 because there was no 600 file on disk — the design system's "semibold" never existed. 161 goldens rebaselined.- The whole type scale is Poppins. The
display*andlabel*styles were Neutrek. Thelabel*ones move up to weight 500: Neutrek's regular read much heavier than Poppins', and keeping them at 400 erased the separation between label and body. AppIconsstores slugs, not URLs. Translating a name into an address is the brand's provider's job. Thejotapeandzxtrackbrands point at the CDN; the package's default resolves from the bundled assets.- The illustration's default accent became neutral (it was
secondary). An illustration's fill is the AREA — skin, clothing, surface — not a detail: painting it with the brand color left the whole figure monochrome in that color. It changes how the illustrations look in all 4 apps. AppIllustrationsstores slugs, not URLs, andAppIllustrationlost its own loading — the provider is what loads.AppIconbecame aStatelessWidget. The loading moved inside the provider, which also resolved a trap: the download was born ininitState, where reading the theme is unsafe — and the provider comes from the theme.swatchFromSeednow generates 11 stops (50–950), like the hand-written brands.AppBrandbuilds the registry asfinal, notconst, because theflocksbrand derives its palette at runtime.AppAuthSplitLayouttakeswebsiteUrlas a parameter. It used to readAppBrand.current.websiteUrl— the one place inlib/srcthat reached for the global brand singleton, for a string that already had sibling parameters (brandTitle,brandSubtitle,logoUrl) right next to it. A component that reads a static registry cannot be tested without it, cannot render two brands on one screen, and forces the package to have an opinion about where the data lives.nullkeeps the logo and drops only the link. Breaking only in the sense that the link now needs to be asked for.
Removed #
-
AppBrandConfigis theme configuration, and nothing else. Gone:appName,brandSubtitle,websiteUrl,cdnBaseUrl(with its seven derived asset getters andprecacheUrls),videoBasePath,playStoreUrlandpoweredByLabel. What stays isclientSlug, the palette, the six theme axes andtypography.None of the removed fields were read by
lib/src— the package carried them only so the app could read them back. The cost was never their weight: the derived getters (splashLogoUrl,otpLogoUrl,railExpandedUrland company) asserted an app architecture — that there is a splash screen, an OTP flow, a profile page, a nav rail, an auth background, and a Play Store listing. A design system that asserts that has an opinion about someone else's product, which is the same coupling this package refuses when it declines to reuseCardandScaffold.clientSlugstayed: with the asset path gone it is pure identity — the registry key, and the label that names the goldens and scopes the contrast reports. Breaking for anyone constructing anAppBrandConfig; the fix is to delete the arguments and keep that identity wherever your app already keeps its own. -
The Neutrek font. It is licensed "Personal Use Only"; in an MIT repository, using it would amount to redistribution. It was what blocked publishing the package.
Fixed #
- The OFL fonts were being redistributed without the license text, which the
SIL Open Font License requires. There is now an
OFL.txtbeside each family. AppIcons.mail,.plusand.refreshwere cited in dartdoc but did not exist. They exist now, as part of the contract.
Security #
- The package's default path no longer depends on a private CDN or on a licensed icon set (Streamline Ultimate). The default is offline and MIT.
- A brand can no longer point anywhere.
cdnBaseUrlwas first made optional, so that an adopter with nowhere to host was not pushed into copyingflocksBrand's value — which pointed at the site's own CDN, putting our infra and our logo inside their product. Removing the field settles it by absence: there is no URL to copy and no network for the package to reach.
1.0.0 #
The first consolidated version of the design system inside the monorepo: tokens,
theme, per-brand white-label, the global axes (AppStyle, AppRadiusMode,
glass, motion, transparency) and 131 components across atoms/molecules/organisms,
each with a .doc.md, a preview, a Widgetbook case and a test.