Doop
Doop: 오픈소스 멀티플레이어 디자인 캔버스 및 AI 에이전트용 MCP
Province of British Columbia의 공식 로고 세 가지를 내려받습니다
Generate the three official Province of British Columbia lockups in any ministry and colourway, and download them as SVG, PDF, PNG, WebP or JPEG.
디자인JavaScript · PythonGitHub @ahzs645온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Province of British Columbia logo generator — three official lockups, any ministry, any colourway, exported as SVG, PDF, PNG, WebP or JPEG.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Province of British Columbia — logo generator
A Vite app that builds the Province's lockups — four identities' worth, spanning the crest era to
the marks in use today — for any ministry, in any colourway, and exports them as SVG, PDF, PNG,
WebP or JPEG. The rendering core underneath it is plain JavaScript with no framework dependency, so
it can be reused from another app, a build script or a server.
Already cloned without --recurse-submodules? git submodule update --init --recursive.README 전문 보기 ↗A Vite app that builds the Province's lockups — four identities' worth, spanning the crest era to the marks in use today — for any ministry, in any colourway, and exports them as SVG, PDF, PNG, WebP or JPEG. The rendering core underneath it is plain JavaScript with no framework dependency, so it can be reused from another app, a build script or a server.
git clone --recurse-submodules <this repo>
npm install
npm run dev
Already cloned without --recurse-submodules? git submodule update --init --recursive.
Without a licensed Helvetica (macOS ships one; elsewhere set FONT_SOURCE), the font step builds
from TeX Gyre Heros instead (src/fonts/stand-in): a free clone with Helvetica's widths, so layout,
outlined exports and PDFs all work, with slightly different letterforms. Builds with CI or
FONT_REQUIRED set still require Helvetica. npm run shots:salaries screenshots the salary
pages at phone and desktop widths and counts their words (needs Playwright with Chromium).
The salary search (?view=salaries) combines verified official remuneration schedules with
explicitly labelled, retained compiled disclosures. Reporting periods, source links, disclosure
scope and remaining gaps are attached to the records. The original three compiled editions are
not a complete annual history or a workforce census.
The salary audit and source recovery report explains the corrected Hydro-group and public-service years, duplicated records, earlier history, remaining source work, and the limits of name matching. The employer coverage inventory lists every employer; the source inventory distinguishes accepted reports from located sources awaiting extraction or review. The current build has 926,855 records, including 683,243 with official-source provenance. The 23 October follow-up adds Fraser Health history, eight BCIT schedules, four BC Transit schedules and salary-interface corrections.
Rebuild all salary views offline with npm run build:salaries, then reconcile their rows and
refresh the inventory with npm run check:salaries. The accepted normalized schedules, source
hashes and immutable compiled baseline are committed under research/salaries/; the original
external CSV directory is no longer required for the default build. Run npm run preview:salaries
for a salary-only development preview without the separate licensed artwork/font build. Use
npm run preview:salaries -- --build to verify its production bundle.
The repeatable external coverage comparison
imports saved or authorized Sunshine Lists snapshots and reconciles them with every published
employer file: run npm run audit:sunshine. It produces an employer inventory and source-processing
queue, keeping official records, compiled edition labels, reporting periods and disclosure scopes
distinct. The committed reference contains three employer summaries and explicitly does not
establish complete Sunshine Lists directory or annual coverage. The GitHub Compare salary
coverage with a saved reference workflow reruns it on demand and checks report freshness on PRs.
The accompanying North Island College history
adds five original employee schedules with source controls and a documented replacement review.
Internal Logos is a separate view in the title menu (?view=internal). It
opens on a Forests family card. Selecting it shows the Forest Service's
evergreen emblem — the white map of the province with a dark evergreen on a
rounded green badge, its mark before about 1973 (a working date, not yet
confirmed by a source) — and Forest Oval's three main
ovals: Forests, the long ministry name, and Forest Service, with historical
comments and sources beneath each logo. The emblem is a plain vector drawing
rather than a Forest Oval recipe; it opens its colourways (its reconstructed
green, and the two greens sampled from the posters it is printed on) and links
to those posters at their emblem (&internal-logo=forest-service-emblem).
A Forest Service, yellow-sky oval (&internal-logo=forest-service-yellow-sky), redrawn from two
photographs, opens in the two colourways they show: green around a yellow sky, and cream. A further oval, Forest Service, green and gold (&internal-logo=forest-service-green-gold), is
likewise a supplied drawing: FOREST SERVICE and BRITISH COLUMBIA in gold on a dark green oval around
a lone evergreen, mountains and a lake. Its adoption date is unverified; it opens in full colour and
two generated colourways. The oldest design, an engraved Forest Service, Lands Department seal
(&internal-logo=forest-service-lands-department), opens the family: its wording places it in the
Department of Lands years (1912–1945), and the view says why that is not yet a date. It is shown from a
lighter copy of its 5.6 MB master. Drawn designs are fetched when first shown, and recoloured by mapping their own colours to new ones
(src/internal/forestLogos.js), and their source packages are in artwork/internal/. Each oval opens its colour and service
variants: full colour, black and white, generated green and reversed colourways,
and the related Wildfire presets. Forest Service also includes black
and gold, navy and gold, and the Airtanker package with the shared tree crest.
Display recolours are labelled
separately from reference variants. The family has a direct link at
?view=internal&internal=forests; add &internal-logo=forest-service to open a
design's variants. Known sightings and related uses are kept
separate from unverified adoption dates. The artwork and
lettering engine are bundled locally from a pinned Forest Oval revision; see
vendor/forestoval/README.md. The badges retain
their reference/reconstruction labels. This view displays the specimens without
the lettering editor or its options.
An Identity switch at the top of the controls chooses between them. They have almost nothing in common, so most of the panel changes with it.
| Crest | Flag | Arms | Current | |
|---|---|---|---|---|
| What it is | The crest lockups, from the supplied artwork | BC beside the waving provincial flag | The coat of arms with the BRITISH COLUMBIA wordmark | The Province's published ministry marks |
| Wording | Any ministry, any second line, any wrapping | Any, plus an optional province line and a third line | Any, plus a trailing line | Any, typeset in the marks' own alphabet |
| Lockups | Four | Three symbols × two placements | Three arrangements × two placements | One per ministry |
| Colour | Anything, mark and type independently | Three flag palettes, plus ink | Anything | Four official colourways |
| Language | — | — | — | English and French |
| How it is made | Drawn from parts on every render | Drawn from parts | Drawn from parts | Published mark, typeset wording |
Every era keeps its own background and ink, because their palettes have nothing to do with each other. Switching identity leaves each side as you had it. Sharing them was a bug twice over: the crest era's forest green showed through the flag's gaps, and the arms' white type once landed on a white ground.
A Gallery button opens the marks the generator does not make, grouped by whose they are. The
first collection is the Province's one-off marks — BC Parks and its like — which follow no pattern
the generator can offer and so have nothing to be loaded into. Each still opens for recolouring, and
each draws itself from the same renderer as everything else, so a card cannot drift from what it
gives you. On a dark page the cards show every mark in its reversal: a mark supplied with a reversed version takes it, and the Crown corporations' other marks (ICBC, BCLC, BC Ferries, WorkSafeBC, BC Transit) have their black and navy inks drawn white, their own colours kept, rather than sitting on a white plate; opened, each is still drawn exactly as supplied. The second is BC Hydro, in all three of its identities (below); src/gallery/collections.js is where another body's
marks would go, and an entry's kind decides what opening it shows.
Every mark sits on a timeline. BC Hydro's page runs through its three identities oldest first,
and so does every other body's: BC Parks from its flag-era badge to today's logo, BC Timber Sales
from its first banner in 2003, and — under each one-off, when it is opened — WorkBC, WelcomeBC,
BC Stats, BC Wildfire Service and the rest, each with the eras its body has had. A rail across the
top steps through them. An era whose mark the gallery does not hold keeps its place as an empty
slot, with where its artwork has been seen; an era in which the body had no mark of its own says
so; and an era the generator draws (the flag logo, today's BC mark) opens there. Every era cites
its sources, and most dates are first seen in a Wayback Machine capture rather than adopted, and
say so. The eras are in src/gallery/timelines.js; how they were found, and the artwork still to
obtain, is in research/identity/.
ICBC and BCLC have collections of their own, from two logo-history research packages
(27 September 2026). ICBC's runs from a 1974 registry emblem through the half-disc lockups of 1989
to the road badge — serif, heavier sans, then rounded since about 2008, in blue and, on icbc.com
today, orange. BCLC's runs from the sun-and-waves lockup to the lowercase bclc of August 2008, and
its later purple, coral and yellow palette. BC Ferries, from a third package, runs from its
first name, the British Columbia Toll Authority Ferry System (three wordmarks, 1960 to 1964, rebuilt in
substitute lettering, in artwork/bc-ferries/toll-authority/), through
the dogwood flag of the 1960s and the geometric dogwood beside "BC FERRIES" (about 1978) to the wave of
2 April 2003, which came in with the company that replaced the Crown corporation. WorkSafeBC, from
a fourth, has the 1983 province-and-worker mark and today's black-and-orange wordmark, both rebuilt,
with its documented 1968 design kept as an empty era until a picture of it turns up. BC Transit,
from a fifth, has its blue-and-green loop (by 2009), with its earlier flag lockups kept as an empty
era; neither livery change (2007, 2024) is counted as a logo. With it, every body the research
companion listed as missing has a collection, and the "not yet in the gallery" shelf is hidden
until another is found. Their marks are
drawn exactly as supplied and are not recoloured: each package file already says whether it is
supplied paths, a declared recolour, or a reconstruction, and the gallery repeats that rather than
blurring it. The SVGs are in artwork/icbc/, artwork/bclc/,
artwork/bc-ferries/, artwork/worksafebc/ and
artwork/bc-transit/; npm run build:crown-marks packages them into
src/assets/crownMarks.js.
Most of the gallery is the Best Place on Earth years: WelcomeBC, WorkBC, BC Stats,
Environmental Reporting BC, the BC Public Service's "Where ideas work", Canada's Pacific Gateway,
and the stacked BC mark with its tagline. Each is the BC mark with a shaded sun, a gold divider, and
a name in large Garamond. scripts/build-one-offs.mjs lifts them from the published files in
artwork/one-offs/ and labels every shape with its part (sun, rays, mountains,
wordmark, tagline, name, the gold accent), so any part can be recoloured.
StrongerBC (2021) is lifted the same way but belongs to a later generation: a flat sun, gold rays over a light disc, with no shading to sample; a grey divider; and a heavy sans in place of the Garamond. The build tells the two kinds of sun apart by what the file contains. It finds the divider by its shape rather than its colour, so a grey one counts.
BC Wildfire Service has the same flat sun, but the gold divider and the Garamond are back. It comes in two arrangements, both published reversed and both lifted as drawn: the name on two lines ("BC Wildfire" over "Service"), from a page where it sits over a photograph, and on one line, from the cover of the Province's 2025 prescribed-fire report. "On white" gives the BC-blue version of either. The photograph is in the file as bitmaps; the build ignores any bitmap not clipped to a shape, so it drops out.
Environmental Lab BC is the same generation again — flat sun, gold divider, Garamond — in Environmental Reporting BC's two-line arrangement. The build reads rectangles and polygons for it, which Illustrator writes for straight-sided shapes like a divider.
PreparedBC is the one card that is not lifted. Its own lockup — used since 2015, much like this one but with "BC" in gold, and printed on its guides in one ink of each guide's colour — has not been obtained, so it is remade as a ministry mark is today: the published BC mark with "PreparedBC" set in the ministry alphabet. The card is drawn by the current era's renderer and opens in the generator with the wording typed, where every colourway and export applies to it.
BC Timber Sales has a collection of its own, because it has several marks: "BCTS" over "BC
Timber Sales", first on its own with the name in a slab serif (on its site from 2005 to 2017), then
beside the BC mark (flat sun, grey divider) with the name in a sans. Its initials were published in two greens: forest
(#016a37) on white, and teal (#009979) on the reversed mark, whose type is white — so on a white
page its picture looks like the symbol and "BCTS" alone. Every one of its marks can start from
either green. The build lifts them the same way, with two additions: a second colour beside the
mark is a descriptor line rather than more of the name, and a manifest entry marked alone is a
name with no BC mark, so there is no sun or divider to find.
B
was lifted from. WorkBC's rk pair was opened by hand: its k sits 5/1000 em right on both
sides.W sits 14/1000 em lower than the W drawn
in both WelcomeBC and WorkBC, exactly where the licensed font puts it. It was recovered from the
one corrupt file that has a W, and its height looks to have come from the font. The other
capitals the Province drew (B, N, O) also sit 11–14/1000 em from the font's, so the
artwork's Garamond is a slightly different cut. The committed W is left as it is until that is
looked into properly.The mark itself is never recreated. Both of the Province's guideline documents say in bold that
the marks must be used exactly as provided, so scripts/extract_current_marks.py lifts the drawn
vectors out of the published PDF and packages them unchanged.
The wording is a different matter, and it is now set rather than stored. The published artwork draws each ministry name as outlines, which meant a ministry that had been renamed — or one that never had a mark published — had nothing to use. So the serif was identified, and the alphabet recovered from the artwork itself:
W appears in only one file, and that file is corrupt. It was recovered by rasterising
candidate outlines and matching on overlap — an index-based resampling scored 0.44, rasterising
scored 0.054.What is committed is the alphabet the published marks are themselves drawn with, plus advance widths and kerning pairs. The rest of the alphabet is built from a licensed font and gitignored — see Requirements.
Forty-six marks have no capital N or O. No current ministry name starts a word with either, so
until the list offered historical ministries nobody noticed. Then "Forests, Lands, Natural Resource
Operations and Rural Development" was drawn as "atural Resource perations". The fix is the
Province's own drawing again, not a font: older marks were drawn in the same alphabet, and
scripts/lift-current-letters.mjs takes the letters the alphabet lacks out of any mark listed in
artwork/current/lifted/.
src/current/confirmedBreaks.js lists every one, with where it
was seen: all 46 current marks, FLNRORD, and older marks kept in
artwork/current/confirmed/. The rules only set names no mark has
shown, so improving them for one mark can never move another that is already known. The tests
still check the rules against every confirmed name. The two they miss (French Agriculture and
Education) are pinned as exceptions, so a new one fails a test instead of slipping through.U, V and the full stop, which 6 historical names use. (B came later, from
the WelcomeBC wordmark: see the gallery above.) A published mark containing them, added to the
lifted folder's index.json with the tracking it was set at, closes that gap.' is set as ’, which is what the marks use, so "Women's Equality" needs no
letter the marks never drew.The current era's ministry list is the published marks first, then every other name the other three identities offer, including every ministry since 1976. Those have no official wording, so they are set by the rules.
The four colourways are the Province's own, from its colour-accessibility guidance: Colour,
Reverse, Solid black, Solid white. Reverse is the interesting one — the mountains
lighten to BC Blue at 60% while the wordmark turns white, and both are the same blue in the source
artwork. That is why the extraction labels every shape with a data-role rather than recolouring by
fill. The solid colourways drop the sun's rays entirely so the background shows through them;
painting them white would ring the mark with a halo on anything but a white page.
In the current era the background swatches are the BC identity colours, and choosing one moves the colourway to the one the guidance pairs with it: BC Blue and black get Reverse, the golds and the 60% tints get Solid black. Choose a colourway by hand and it stops following, as the wordmark and the alignment do.
Each mark is also a plain file — current-marks/for-en.svg and so on, listed in
current-marks/index.json — so current-era
artwork can be fetched directly without running the page.
Two things worth knowing about the source PDF: it draws the marks in CMYK-native #053673 and
#fdb913, while the Province's colour-accessibility guidance specifies #234075 and #e3a82b for
screen. The extracted files carry the screen values and record the print ones. And three rows of the
PDF are inconsistent — one has its divider drawn twice, and two use a different vector export of the
same logo — all handled by the extraction rather than papered over.
These are the Crest identity's, the first of the four. The first three are reconstructed from
the supplied Illustrator exports in artwork/,
and each keeps that file's own type size, leading and tracking — they were set individually and do
not agree with each other, so the differences are preserved rather than averaged away.
| Layout | Set from | Notes | |
|---|---|---|---|
| Stacked | Mark above a left-aligned text column | artwork/lockup-stacked.svg | 122.2 units, 1.2 em leading |
| Centred | Mark centred above centred text | artwork/lockup-centred.svg | 121 units, 1.04 em leading, tracked −0.02 em |
| Horizontal | Mark left, text right, vertically centred | artwork/lockup-horizontal.svg | 121.64 units, 1.2 em leading |
| Side by side | Mark, wordmark and ministry as three columns | no vector original | 121.64 units, 1.2 em leading |
Side by side is the one without a source file. It was reconstructed from a photograph of
signage, so it borrows its type size and leading from the horizontal lockup — its closest relative,
and the only other one that sets the mark beside the type. Its two original numbers are the gap
from the mark (shared with the horizontal lockup) and the gutter between the columns, set to half
the mark's width. Those are the only invented constants in src/logo/layouts.js; everything else
there was measured. npm run compare covers the three that have originals.
The lockups disagree about the province wordmark: the centred one is drawn without it, so that lockup is just the ministry and its second line under the mark. Picking a lockup therefore adopts what its artwork does — until you set the wordmark yourself, after which it is your decision and switching lockup leaves it alone. A restored share link counts as having set it.
All three take a ministry from a list or typed in free-hand, an optional second line, separate colours for the mark and the type, a background colour or transparency, and a clear-space margin. Explicit line breaks are honoured.
BC beside the waving provincial flag, from artwork/flag/spirit-of-bc-flag.svg —
twelve shapes, kept as drawn. Three symbols (the letters beside the flag, the flag above them, the
flag alone) each take the wording below or beside them.
There are three palettes, and the supplied file is not the official one. The standards page
specifies Pantone Blue 072C, Red 032C and Yellow 109C — #10069f, #ef3340, #ffd100. The SVG
supplied for this project carries #013366, #ad0000, #fcba19, a later recolouring. Both are
offered rather than one being corrected into the other, alongside a third that sets the whole
symbol in a single ink.
That third one exists because the flag's white is the page showing through it, not a white shape. Full colour on a green ground therefore shows green through every gap in the flag, which is what the printed documents avoid by setting the whole lockup in one ink. The palette picker recommends it whenever the background is dark enough to matter.
The proportions come from seventeen printed references, because the standards page gives the symbol and its colours but never shows a ministry name against it. All seventeen reproduce. The documents disagree with each other, and where they do the reading is kept rather than averaged.
The measure the wording wraps to was wrong for a while, and wrong in a way worth recording: it had been arrived at by dividing a flag's width by its height ratio, which is not a quantity. It broke "Province of British Columbia" in two — a line nearly every document keeps whole, which is what made it visible. There is now a test that pins exactly that.
The BC Parks badge is built from this flag and its frame, but it belongs to the gallery rather than to the generator: both of its words are the wordmark, set alike, rather than a ministry name under a symbol. The frame is the real artwork and not a shape fitted to it — it was a superellipse until the drawing turned up, and the drawing is not symmetrical, running 30.3 units of wall on the left against 30.5 on the right and 29.6 at the top against 30.7 at the bottom. It was drawn by hand, and no fitted curve was going to find that.
The full achievement of arms with the BRITISH COLUMBIA wordmark, and a ministry set against it.
Both pieces are artwork — the arms as drawn, the wordmark as outlines rather than as text — so the
ministry is the only thing typeset. scripts/build_crest.py does the extraction in Python rather
than in this project's own path reader, because the source uses relative arcs and the reader does
not implement them.
Everything else here was measured off twelve printed documents, and the measuring taught more than the numbers did.
Every proportion below was taken by finding the arms and the wordmark in a rasterised reference and reading their heights. The check that makes those readings trustworthy is to compute each drawing's own aspect first: across all twelve the arms come out at 0.818–0.833 against this project's 0.831, and the wordmark at 2.483–2.511 against its 2.523. That is what rules out having measured something rescaled, cropped or simply misidentified — and it caught two documents that had been read as side by side when they in fact stack.
Three of them draw the arms and the wordmark at much the same height (0.878, 0.899, 0.891); three draw the arms about twice as large (0.493, 0.493, 0.433). Both are printed, so both exist: Stacked and Stacked, large arms. A single averaged value would have matched neither.
The same is true of the ministry's size, which runs from 0.212 to 0.294 of the wordmark, and of where the ministry's lines break, and of whether a trailing line is set smaller than the ministry above it. Each became a control rather than a number.
Reading type size off a rasterised reference means reading the height of a band of ink, which includes any descender in the line. In Helvetica the ascenders reach 0.718 em against the cap line's 0.717, so a line with ascenders and no descenders bands at exactly its cap height, and one with descenders bands at cap plus 0.208. Converting each reading that way turned a spread that looked continuous into three clean settings.
Two constants were wrong not in value but in what they were a share of.
The gap from the mark to a ministry set beneath it was measured against the arms, where the twelve documents spread 0.125 to 0.397 and no constant fits. Against the wordmark the stacked ones land on 0.453, 0.427 and 0.448. The wordmark is the one drawing whose size holds across the arrangements, so a share of it means the same thing in all three; a share of the arms does not. The ministry's size moved to the same unit for the same reason.
The measure the ministry wraps to was in arms heights, which was fine until the ministry's size became a choice — then the largest setting overran a backstop that could not grow with it. It is now in cap heights of the ministry's own type, pinned just above the widest line these documents print whole ("Ministry of Employment and Investment", 25.1 caps in its document and 26.2 as this project sets it).
The documents were set line by line and disagree about where to break, so there is no rule to infer. The measure is a backstop for text nobody has broken yet; a line broken by hand is set as typed. This is the rule the current era already followed.
selection-1 (2) reads 0.433 for wordmark-to-arms where the large-arms form uses 0.49, the median
of its three readings — it is the smallest, lowest-resolution image of the set. selection-1 (5)
cannot be compared at all: its arms are an embedded raster in the source file. And selection-1 (7)'s vertical rule is a page margin, not part of the lockup.
The gallery's second collection is BC Hydro, in its three identities, oldest first. Each opens in the generator's own layout: the preview stage with its backdrop control, then a column of panels ending in the same Download panel (SVG, PDF, PNG, WebP, JPEG).
| 1961–1990 | 1990–2016 | 2016–present | |
|---|---|---|---|
| The mark | Jim Rimmer's ringed H beside "B.C.Hydro" | "BC hydro" in a heavy slab, the symbol squared off after it | The symbol as a circle before "BC Hydro", with "Power smart" |
| Where it comes from | Rebuilt from five pages of its identity manual | Lifted from the supplied Illustrator file (artwork/hydro/bc-hydro-1990.ai) | Lifted from BC Hydro's February 2020 brand guidelines (artwork/hydro/brand-guidelines-2020-logo.pdf, its two logo pages) |
| What can change | Everything, with the manual's rules checked | Any part's colour | Only which of the guidelines' variations, the background and clear space |
scripts/extract_hydro_marks.py (npm run extract:hydro-marks) lifts the 1990 and current marks
into src/assets/hydroMarks.js, every shape labelled with its part. It checks, rather than
assumes, that the guidelines' black, reverse and untagged logos are the colour logo's own drawing,
and it tells the "BC Hydro" letters from the tagline by where each letter's top sits, since the
y descends past the symbol.
The current logo is offered only as the guidelines give it, for the same reason the Province's
current marks are served unaltered: the guidelines forbid reconfiguring, recolouring, distorting
or resetting it. That leaves six variations — Colour, Black, Reverse, Without tagline (signage and
permanent installations only), Symbol, and Symbol with border — each described in the guidelines'
own words, with a warning when the background is not the kind a variation is for. Clear space
defaults to the guidelines' own unit, one symbol's width on every side. The colours are the
guidelines' digital values (Grass #50b848, Sea #10a3c8, Granite #3e3935), not the slightly
different print conversions in the PDF's artwork.
The 1961 signature is the larger piece of work, because nothing of it survives as artwork:
| Signatures | Corporate, Gas Operations (the flame), Rail (a division after the wordmark), the full authority name on two lines |
| Applications | The signature alone; identification signs with a facility name; five single-colour forms on general backgrounds; positive and reverse vehicle pairs — 19 presets in all |
| Treatments | Corporate colour, black, white, or one other ink |
| Editable | Wording, facility names, every proportion, background, declared value, screen palette |
| Exports | The generator's formats — SVG (outlined or live text), PDF, PNG, WebP, JPEG — plus emblem only, a specimen sheet per group or of all 19, the rules as JSON, and the settings as a file the original studio's v1 and v2 files also load into |
The manual's rules are checked as you go, and each note names the page it comes from: a sign's borders are half a cap height (a full one above the Gas flame) and its facility name starts one x-height below the baseline; black is allowed on a background of at most 20% value and white on at least 80%, with nothing prescribed between; vehicles switch at 30/31% instead, and the manual says the two thresholds are not interchangeable; the alternative ink needs 70% value on white. A value is declared, never read off a hex colour — the manual's percentages describe ink on a surface, which a screen colour cannot establish. Where the manual gives no number (how much to enlarge a reversed signature), the view says so rather than inventing one.
The lettering is set in TeX Gyre Termes. The original typeface was never recovered; the
reconstruction was fitted against Nimbus Roman, and Termes is its free derivative, with identical
widths. Because Termes is under the LaTeX Project Public License, its metrics, kerning and outlines
are committed (src/hydro/serif.js, from npm run build:hydro-serif), unlike Helvetica and Adobe
Garamond — so the layout runs in Node, and the lettering draws identically on every machine with no
font installed. Exports outline it by default; live text asks for Termes, then Nimbus Roman, then
Times.
"B.C.Hydro" is not typeset. Its nine letters were fitted one at a time over the printed
signature, each with a position and scale of its own, because the original was lettered tighter
than any typeface's spacing allows (src/hydro/hydroMark.js). Any other wording is typeset at the
wordmark's size, and flagged as not historical.
The print recipes — CMYK for coated and uncoated stock, and the non-process numbers — ride along in each SVG's metadata. They do not change the screen colours, which are sampled from the scan and are approximations. None of this is current BC Hydro brand guidance.
The collected files under public/identity-collected/ are kept exactly as found, and they are what
the gallery offers for download. For the collected SVGs, the gallery shows display copies from
npm run build:collected-display (Python with numpy, scipy and Pillow, and the pre-installed
Playwright Chromium). These copies are written to public/identity-display/ and listed in
src/gallery/collectedDisplay.js. Each copy is:
Only ink that meets the page is changed. The decision is made for each place the file sets a colour,
so white lettering inside a badge keeps its colour. Per-logo exceptions are in
scripts/collected-display-overrides.json. Raster files (PNG, JPEG, GIF and EPS previews) still sit
on a plate of their own.
Where the government history records one body carrying on as another under a new name, the gallery shows a single collection with an era for each name. These are:
BC Ferries' and BC Transit's earlier bodies sit in eras of their own histories instead: the Toll
Highways and Bridges Authority's ferry system and the BC Ferry Authority, and the Urban Transit
Authority. Old ?logos=collected-… links still open the merged collection, and the collecting list
opens it at the body's era.
Only one-to-one lines are merged. A timeline of names claims a single lineage, so a body is folded into another only when the history records it becoming that body and nothing else shares the link:
So these keep a collection each, with their links left to the government diagram:
The list is CONTINUATIONS in src/gallery/collectedCollections.js, and
collectedCollections.test.js checks each fold against src/government/historyData.js.
Signs in the title menu (?view=signs) works as Posters does, on the same stage: signs grouped by
series, each opening with hidden hotspots, a panel per part, a tour and export. The first is the
British Columbia Forest Service's triangular LOOKOUT sign: click the red wordmark, BRITISH
COLUMBIA up its slopes, FOREST SERVICE along the base, or its two green frames. The wordmark's panel
says what fire lookouts were, from the Province's 2012 release on restoring them; the service's
links on to its marks in Internal Logos and to its posters and badges.
Posters and Signs are both shelves (src/posters/ShelfView.jsx): the same index, address handling,
loading and viewer, given a catalogue. A sign is added as a poster is: its drawing and parts under
src/signs/, an entry in src/signs/catalogue.js, and a loader in SignsView.jsx.
src/signs/signs.test.js checks the parts and links; the package is in
artwork/signs/.
Patches in the title menu (?view=patches) is the patch library of
Patcher, a git submodule at vendor/patcher. It holds 132
patches and emblems from the BC Forestry Patch Atlas, grouped by organization under sectors. The atlas
lists a design once per photograph it appears in; Patcher merges those into one patch (the Parks scenic
arch, seen in five photographs, is one card), and the viewer links every photograph. Some designs use a better drawing supplied to Patcher in
place of the atlas's (the Parks Branch elk roundel, the Recreation and Conservation arch, the scenic
arch's landscape, the BC Parks flag patches, which take this site's own flag badge, and the B.C. Hydro
Security shield, which takes this site's BC Hydro symbol). The British Columbia / SPCA roundel
(S56-O38) is redrawn from a supplied photograph with concentric circles, a heavier cross and revised
lettering; its source and construction are in vendor/patcher/library/supplied/bc-spca-roundel/. The Lands
Department pine-bough seal is a printed seal, not a patch, so it is left out there and kept in
Internal Logos. The atlas's Forest Service and Wildfire Service ovals are replaced by this site's own
Forest Ovals (Internal Logos → Forests): five cards (the tree oval, the Forests and long ministry-name
wildlife ovals, the yellow-sky and the green-and-gold ovals), each with a variant switch for its
colourways and its Wildfire Management, Wildfire Service, Fire Control, Airtanker and Ministry of Forests
editions. Patcher's supplied/pofbc-forest-ovals/capture.mjs renders them from this site's dev server
with the lettering outlined; an old link to an atlas id they replaced (&patch=R22-O01) opens its
variant. Among
them are the BC Forest Service, BC Parks, the Conservation Officer Service and
its Fish & Game predecessors, BC Sheriff Service, BC Corrections, Highways and Motor Vehicles, BC
Hydro's patrol patches and the universities. The atlas's logos, signs, decals and printed emblems
(the Province's ministry lockups, BC Timber Sales, the BC Hydro, BC Transit and ICBC logos, …) are
left out by Patcher's library/orgs.json. The library's 14 metal and leather badges have their own
view, Badges (?view=badges), next to Patches in the title menu, which works the same way.
(HIDDEN_VIEWS in src/site/ViewSwitcher.jsx holds any view that should open from a link without
being listed.) Filter by organization (&org=bc-parks) or search. A patch
(&patch=S25-O01) opens its vector drawing beside the same drawing sewn by Patcher's digitizer, at
3″ to 5″, with a merrow, satin or no edge, in matte or glossy thread. It downloads as an embroidered
PNG, a Tajima .dst or Melco .exp machine file, or the SVG, and opens it with
every digitizing setting exposed.
A patch's History comes from this site: src/patches/patchHistory.js matches the wording on
it (Lands Department, Forest Service, its parks, Department or Ministry of Forests, Airtanker, Wildfire)
to the dates the BC Forest Service timeline
gives for them, which bound the wording rather than date the patch, and links a Forest Oval card to
its Internal Logos entry. The Parks Branch and BC Parks flag semicircles are constructed in Patcher
(a true semicircle, its field the exact inset, concentric lettering). Nothing else about the patches
is kept here. The drawings, the organization each belongs to, and the
digitizer are all Patcher's (see its library/README.md). To
regroup a patch, edit Patcher's library/orgs.json and re-import there, then move the submodule
forward (below). PofBC only needs the view: src/patches/PatchesView.jsx (the index) and
PatchViewer.jsx (one patch). Patcher stores repeated crests and outlines once (29 MB of drawings in
8 MB), so the viewer gets each drawing from loadPatchSvg, which joins a patch with its shared parts
and checks the result against the atlas's SHA-256. vite.config.js aliases patcher and patcher/library to the
submodule's TypeScript source, which Vite compiles together with Patcher's digitizing worker.
src/patches/patches.test.js checks that the submodule is checked out, that its library hangs
together, and that every patch joins back into the atlas's drawing (or the supplied one) byte for byte.
To take a newer Patcher:
git -C vendor/patcher fetch && git -C vendor/patcher checkout origin/main
git add vendor/patcher && git commit -m "Patcher: …"
Licence Plates in the title menu (?view=plates) shows British Columbia's licence plates from
PlateForge, a git submodule at vendor/plateforge: 447
designs in 16 families (passenger, commercial, farm, trailer, motorcycle, trade, industrial,
carrier, specialty, consular, amateur radio, official, events, municipal, bicycle and samples), each
family laid out era by era from 1904 to today. Periods PlateForge documents but has not drawn are
kept in their place. Every plate is drawn live as SVG by PlateForge's renderer, with no images, and
the thumbnails are drawn only as they near the screen. A family or a plate is linked by its
address: ?view=plates&family=commercial, ?view=plates&plate=1953.
By year turns the index into a timeline, after the government view's year bar: one strip per
family on a shared axis from 1901 to today, each design a bar across the years it was issued or
valid. The year is scrubbed, played, stepped from one change to the next (a design beginning or
ending), or reset to today. The plates in use that year are listed under it, grouped by family.
Choosing a family, from the menu or its strip's label, spreads its designs out so each has its own
bar. The year is in the address too: ?view=plates&year=1953&family=trailer. An open plate shows
its family the same way under the drawing, the plate marked, with any other design a click away.
The timelines are drawn in the site's own greys and inks, with the masthead's sun as the cursor,
so they follow the light and dark themes like the rest of the page. The plates themselves are
artwork and keep their own colours. On a phone the introduction is hidden so the controls come
first.
A plate opens with the same serial its card shows, and its fields can be edited: serial, renewal tab, decal, finish, lettering and whatever else the format offers. New serial draws another valid serial, keeping the appearance choices. The viewer shows the plate's era, PlateForge's description and caveats, and its sources (BCpl8s chapters, mostly). It downloads the plate as SVG or PNG, with its fonts embedded, and links to the same design in the full PlateForge editor. Research lettering switches between the letters traced from source photographs and PlateForge's earlier dies, as PlateForge's own inspector does. These are research reconstructions, not issued registrations. PlateForge marks samples, prototypes, souvenirs and uncertain designs, and the cards carry those labels.
The view (src/plates/) is only the site's chrome. Everything else comes from PlateForge's embed
entry points, documented in its docs/embed.md:
plateforge/bc registers the B.C. region alone, and plateforge provides the renderer, the seeded
samples, export, and the family → era grouping PlateForge's own gallery uses. Both are aliased
in vite.config.js to the submodule's TypeScript source, which Vite compiles as it does Patcher's.
The plates' fonts (Barlow Condensed, Noto Sans and Serif, Pinyon Script, Noto Sans Canadian
Aboriginal) are @fontsource dependencies here, pinned to the versions PlateForge's font manifest
records, since its export checks each face against that manifest. PlateForge keeps its Chinese,
Japanese and Korean subsets in a separate list the embed never imports, so the build carries about
2 MB of plate fonts rather than about 94 MB. src/plates/plates.test.js checks that the submodule is
checked out, that the aliases reach it, and that every font it imports is installed here at the
pinned version.
To take a newer PlateForge:
git -C vendor/plateforge fetch && git -C vendor/plateforge checkout origin/main
git add vendor/plateforge && git commit -m "PlateForge: …"
If PlateForge changes a font package version, change it in package.json too. The test above says
which one.
Visual Guides in the title menu (?view=guides) holds identity manuals rebuilt page by page as
drawings, from the ManualKit reconstruction project: the Province's Visual Identity Program
(the General, Reproduction, Sign and Vehicle manuals of 1977, and the September 1982 policy memo)
and BC Hydro's Graphic Standards Manual of June 1983, 156 pages in all. Each family opens to its
books, each book to a grid of its pages, and each page full size with zoom, previous and next (the
arrow keys too), its reconstruction notes, and its SVG to download. A page is linked by its address:
?view=guides&guide=sign&page=S05.
The pages and the viewer live in brandkit, a git submodule
at vendor/brandkit, so they can be reused for other identities and brand kits: the pages are its
BC manual pack (vendor/brandkit/manuals/bc/), and the view is its manual library with this site's
links added (src/guides/guides.js). brandkit's Vite plugin serves the pages at visual-guides/
in development and copies them there in the build, the address they always had.
Only the rebuilt pages are there. The reference scans and PDFs are not: the pages are live text in
open-licence stand-ins (TeX Gyre faces for Helvetica and Times) and drawn geometry. Four pages of the
1982 memo carried cropped pieces of the scan, two photographs and two handwritten signatures; each
is replaced by a labelled placeholder. brandkit's scripts/import_visual_guides.py copies the pages
in from ManualKit and scripts/render-guide-thumbnails.mjs renders the grid images; its tests check
that every page is there and that none embeds an image, and src/guides/guides.test.js here checks
that the submodule is checked out and every family's links go somewhere. The pages embed subsets of
TeX Gyre Heros, Termes and Cursor and of Noto Sans; their licences are served beside the pages, in
visual-guides/font-licences/.
Stationery in the title menu (?view=stationery) fills in the Visual Identity Program's
General Use stationery of 1977: the calling card (3½ × 2 in), the letterhead (8½ × 11 in,
Format A) and the No. 10 envelope. Each is rebuilt from the millimetre grid and point sizes on the
Reproduction Manual's specification sheet (R08, with R03
explaining the letterhead and card): the symbol, crest and ring, at 19, 16 and 12.5 mm; the type
hung from its specified line; the rule where the band ends. Choose a ministry from the list (every
ministry since 1976) or type one; fill in a name, title, component, address and telephone once,
and every piece uses them. Each downloads as SVG (text live), PNG or PDF (text outlined), or all
three zipped.
The pieces are data (src/stationery/bcStationery.js), drawn by brandkit's template engine in the
site's Helvetica (src/stationery/helveticaFonts.js, over the same metrics and outlines as the
lockups); the editor is brandkit's template studio. Two choices are the site's, and labelled as
such: Helvetica Medium is set in the bold the site carries, and the italic is the regular slanted.
The symbol prints in Pantone 462 brown, shown as Pantone's screen conversion (#5C462B), or in black.
Posters in the title menu (?view=posters) holds printed pieces rebuilt as drawings, grouped by
series. Each opens as a full-screen stage with nothing on it marked as clickable: move the pointer
across it and the part underneath comes forward while everything else settles back. Click, and the
view glides onto that part while a panel tells its history. Arrow keys step through the parts, digits
jump, P plays a tour, E exports (SVG, PDF, PNG, WebP, JPEG) and Esc steps back out. The place is
kept in the address — ?view=posters&poster=dont-drop-it&part=credit — so any part can be linked to.
| Series | Posters |
|---|---|
| Ministry of Environment | Coastal Forest (1979–86), with its live crest-lockup studio |
| British Columbia Forest Service | REWARD — A Living Forest, Enjoy & Protect our Forests |
| B. C. Forest Service fire-prevention badges | DON’T DROP IT!, Don’t gamble with FIRE (set in the first one’s green) |
| Ministry of Forests, Forest Practices Branch | Wildlife Trees (about 2001, from the artist’s mark), told as a story too |
| British Columbia Ferries car decals | GO B.C. FERRIES (1960–64, from its Toll Authority wording), Queen of Sidney |
The panels link on: the emblem on either Forest Service poster opens the evergreen emblem in Internal Logos (which links back), a service credit opens the department the Forest Service sat in on the government diagram, a decal's authority opens the Toll Authority or the Ferry Authority there and its flag BC Ferries' marks in Logos, and each poster links to the others in its series. Wildlife Trees' tree oval opens the Forest Service tree oval in Internal Logos (which lists the poster under On the posters), and its arms signature opens the Ministry of Forests in 2001 on the government diagram, with its lockup. Every claim that is not established — a date, a typeface, an ink — is said to be so.
Story mode. A poster whose parts each carry a story (a list of paragraphs) gets a Story button
(and S): the panel becomes one scrolling column of chapters, one per part, and the drawing follows the
reading, gliding onto each part and lighting it as its chapter reaches the reading line. Stepping any other
way (the dock, the arrow keys, a click on the drawing, the tour) scrolls the column to match. It is kept in
the address as &story=1. Wildlife Trees is the first, read as it is drawn: from the broken top of the tree,
past the six animals, to the roots, then down the copy to the two marks.
Wildlife Trees is the largest drawing on the site, so it is handled differently: a lighter copy of its
45 MB master (14.8 MB, 1,960 paths, about 4.5 MB compressed; see
artwork/posters/wildlife-trees/), fetched as a file rather than
built into a script, never fetched ahead of being opened (prefetch: false in its catalogue card), and a
small JPEG for its card. It opens at once on a 198 KB four-tone preview and sharpens when the drawing
arrives: a module can give the viewer a light stand-in as its drawing and an upgrade that resolves to
the real one, which replaces it without moving the view. Add &frames=1 to the address to see how many
frames each zoom draws and how long they take, to check a drawing on a real device.
Coastal Forest was its own app, coastal-forest-poster, and imported this repository's renderer through an alias; it now lives here, importing the same modules directly.
Adding a poster is three steps: a folder under src/posters/ with its drawing and its parts,
an entry in src/posters/catalogue.js, and a loader in PostersView.jsx. A part is a box in the
drawing's own units, a layer selector to spotlight, and a panel. Panels can be data —
src/posters/forest-service/posters.js writes every part as paragraphs, facts, palettes, notes and
links (and, optionally, a story for story mode) — or components, as the coastal poster's are, through a useExtras hook that can also take over
the frame and the export targets. Where parts overlap (a badge's lettering and the cigarette laid
across it), hit: 'shape' makes the drawn shapes of the layer the hotspot instead of its box. A new
series is one more entry in SERIES. src/posters/catalogue.test.js checks that every part sits on
its drawing, names layers the drawing has, and that every link lands somewhere that exists. The
supplied reconstruction packages are in artwork/posters/.
Open Health Maps in the view menu, or link to ?view=health-map. Six chapters connect the
twenty earlier regions, the 1997 regional boards, community councils and service societies, the
December 2001 consolidation, and modern boundary comparisons. The scrolling sidecar and chapter
navigation come from the same pinned geo-toolkit source used by
PGMaps.
The original Auditor General maps retain their numbered labels. The searchable index contains 52 source labels and 51 confirmed institutional links, with the Nisga’a source area kept separate because its institutional identity is unresolved. A fourth original map, published by Statistics Canada in April 2001, depicts twenty statistical regions; it does not certify the 1997 legal board boundaries. Each linked health organization also offers a route back to its map.
The comparison chapter offers 52 working administrative estimates, with separate source-drawn approximations for every label. Twenty statistical illustrations remain a separate modern-LHA aggregation. Current references include 89 Local Health Areas, 16 Health Service Delivery Areas, five geographic Health Authorities, 28 regional districts, 160 municipalities and 59 geographic school districts, loaded on demand from local snapshots. Select an area, inspect its defining watershed/survey/municipal references, switch layers, fit the estimate, or put the original page beside it. Selection and chapter links can be copied from the address bar.
The three administrative main-map drawings are registered as vectors. Source-drawing screening now covers all 52 labels, independently of their modern comparison edges. Original B.C. Reg. 293/2001 supplies 44 later written territories; M191/1997 supplies a related Nisga’a council definition without settling the map-label identity. All geometry remains provisional; legal reconstruction, historical amendments, marine detail and inset registration remain open. See the complete area-by-area estimate review. GeoJSON, CSV, controls, screening scores, sources and remaining records are downloadable in the app.
Use Explore all 52 comparisons side by side to open an offline viewer with historical drawing,
current reference and overlay panels, six boundary types and direct links to definitions. The
six-example overview is public/health-geography/comparison-examples.png; regenerate the viewer,
SVG and PNG after rebuilding estimates with npm run build:health-comparisons.
An evidence review below the story covers all 52 labels, with explicit assumptions, eight tasks
using existing sources and seven records/provenance targets. It includes archive/direct-request
routes, possible FOI routes, proposed custodians, date scopes and unsent request drafts. See
records-to-obtain.md and the
registration method.
Use npm run preview:health-map to review the real feature at port 4174 without building the
unrelated licensed artwork fonts; npm run preview:health-map -- --build creates a standalone
production preview. The preview covers the health feature; organization-history links require
the complete application. The full app still needs its normal licensed font assets.
GeoLibre: the Health Maps evidence panels now open a portable GeoLibre review and download
the sixteen-layer project, original image/control-point CSV pairs and registered Cloud-Optimized
GeoTIFFs. It includes all working estimates and the additional comparison layers, initially hidden.
Build estimates with npm run build:health-estimates, then npm run build:health-geolibre, after installing the Python requirements in
geolibre-workflow.md. Edited GeoLibre controls
can be imported and evaluated as separate proposals; the baseline is preserved until reviewed.
The evidence preserves consequential differences: the old South Cariboo council follows the
100 Mile House lineage; North Shore is smaller than today's North Shore/Coast Garibaldi service
region; Northern Interior's candidate excludes Quesnel; and North West explicitly excludes Nisga’a.
See research/health-geography/README.md for dated sources,
asset provenance and the comparison method. Rebuild the catalogue with npm run build:health-map.
The boundary research script is documented in
boundary-comparison-README.md.
Node 20.19+ or 22.12+, a copy of Helvetica, and five git submodules. A copy of Adobe Garamond Pro is optional and widens the current era's alphabet.
vendor/geo-toolkit supplies the historical health
story's sidecar, chapter navigation and responsive workspace context. It is pinned to PGMaps's
e186e12005afb97c0b4470899bd2713c98336f36 revision. Vite imports the required source entry points
directly; the toolkit's optional mapping dependencies and separate build toolchain are not installed.
vendor/plateforge is the licence-plate renderer and
B.C. plate data behind Licence Plates (above). Like Patcher, it needs no build step; it is
marked shallow in .gitmodules, since its history carries large review images the site never
uses.
vendor/patcher is the patch library and embroidery
digitizer behind Patches (above). It needs no build step: Vite compiles its source directly.
vendor/brandkit is the manual library behind Visual
Guides, with the BC manuals' pages, and the template engine and studio behind Stationery. It
is a project of its own, with its own site: brand kits (logos, business cards, letterhead, social
graphics, a brand guide, web files) generated in the browser from one brand.json. Vite aliases
its source (brandkit, brandkit/studio, brandkit/manuals) as it does Patcher's, with React
deduplicated so its components share this app's; modules Node's test runner loads import it by
relative path. To take a newer brandkit:
git -C vendor/brandkit fetch && git -C vendor/brandkit checkout origin/main
git add vendor/brandkit && git commit -m "brandkit: …"
vendor/json-url compresses a lockup configuration into a
share link. It gitignores its own dist/, and every entry in its package exports points there,
so it has to be built before Vite can resolve the import. npm run vendor:build does that, and
prepare, dev and build all run it for you. It is a no-op once built, so the dev loop pays
nothing for it.
The artwork is set in real Helvetica — verified, not assumed: the advance widths in the source
files match Helvetica's to five decimal places, and no other face on the machine comes close. macOS
ships it at /System/Library/Fonts/Helvetica.ttc, which is where the build looks by default.
FONT_SOURCE=/path/to/Helvetica.ttc npm run build:fonts # elsewhere, or another licensed copy
Helvetica is licensed, so the subset faces the build produces are not committed —
src/fonts/generated/ and the src/fonts.css that points at it are both gitignored and rebuilt on
each machine. npm run dev and npm run build do that for you.
src/logo/fontMetrics.js is committed. It holds advance widths and side bearings, not outlines,
and it is what lets the layout engine measure text in Node — including in CI, on a machine with no
Helvetica at all.
The current era's wording is set in the serif its marks are drawn with, which is Adobe Garamond Pro. The letters the published artwork itself contains were recovered from that artwork and are committed, so every official ministry name works out of the box, as do the capitals lifted from older marks. The rest of the alphabet — the letters that appear in none of them — has to come from the font:
GARAMOND_SOURCE=/path/to/adobe-garamond-pro npm run build:current-extras
GARAMOND_SOURCE has no default, deliberately. Picking a licensed font up off the machine
automatically would mean an ordinary npm run build quietly bundled it, and a deploy published it.
Without the variable the build simply produces a smaller alphabet, and the app names any letters it
cannot set rather than dropping them silently.
artwork/ the supplied artwork — the source of truth for every era
crest/, current/, flag/ the arms' wordmark, the ministry-marks PDF (and older marks, in
current/lifted/), the flag SVG
one-offs/ the gallery's marks, as published, and what each is
hydro/ BC Hydro's 1990 artwork and the logo pages of its current guidelines
scripts/
build-mark.mjs extracts the mark, proves all three copies are identical
build-fonts.mjs subsets Helvetica, emits the metrics table and the glyph outlines
build_crest.py extracts the arms and their wordmark (relative arcs, hence Python)
extract_current_marks.py lifts the published ministry marks out of the PDF, unchanged
recover_current_names.py reads their wording back, from the outlines and the PDF's text layer
build-current-glyphs.mjs the alphabet and metrics the current era typesets from
lift-current-letters.mjs the capitals that alphabet lacks, from older published marks
build-one-offs.mjs the gallery's one-off marks, lifted from their artwork
build-hydro-serif.mjs BC Hydro's 1961 serif (TeX Gyre Termes) as metrics, kerning and outlines
extract_hydro_marks.py BC Hydro's 1990 and current marks, lifted from their artwork
letterFit.mjs finds the letters in drawn type, and the line they were set on
build-vendor-json-url.mjs builds the share-link submodule
sfnt.mjs, svgPath.mjs, the font and path surgery those need
svgAbsolute.mjs
compare-artwork.mjs re-renders each lockup over its original and diffs them
vendor/json-url/ submodule — compresses a configuration into a share link
vendor/brandkit/ submodule — the manual library and BC manual pages, and the template
engine and studio the stationery is drawn with
vendor/patcher/ submodule — the patch library and embroidery digitizer
vendor/plateforge/ submodule — licence plates: the B.C. region data and its SVG renderer
src/
assets/ generated artwork: the mark, the flag, the arms, the Parks frame
logo/ the framework-free core: layouts, measurement, colour, rendering
flag/ the flag identity, its palettes, and the BC Parks badge
crest/ the coat-of-arms identity
current/ the published marks, and the alphabet their wording is set in
gallery/ marks the generator does not make, in collections by whose they are
hydro/ BC Hydro's signatures, the manual's rules, and its view
export/ SVG/PDF/PNG/WebP/JPEG, single files or a zipped bundle
ministries/ the ministry list and its search
guides/ the Visual Guides: brandkit's manual library, with this site's links
stationery/ the 1977 General Use stationery, as brandkit templates
site/ the React generator UI
The package has no framework dependency below src/logo/BcLockup.jsx. renderLockupSvg() returns
a complete SVG document as a string and runs anywhere:
import { renderLockupSvg } from './src/logo/renderLogoSvg.js'
renderLockupSvg({
layout: 'horizontal',
ministry: 'Ministry of Water, Land and Resource Stewardship',
color: 'white', // sets both halves at once…
markColor: 'gold', // …unless one of them says otherwise
background: 'green',
padding: clearSpacePadding('snug')
})
resolveLockup() returns the resolved geometry — box, mark position, per-line baselines — without
drawing anything, for callers placing the lockup inside a larger drawing. In React:
import { BcLockup } from './src/logo/BcLockup.jsx'
<BcLockup layout="stacked" ministry="Ministry of Forests" color="white" background="green" />
The component renders the markup that the exporter produces, rather than rebuilding it as React elements, so the preview cannot drift away from the download.
The three source files are three exports of one Illustrator artboard, and each carries a full copy of the provincial mark — about 21 KB of path data, three times over, at three different positions on the board.
npm run build:mark normalises all three to a common origin, compares them coordinate by
coordinate, and writes the drawing out once:
mark verified identical across 3 lockups (largest coordinate delta 0.010)
497.02 × 497.19, 26 shapes, 21.4 KB
→ src/assets/markup.js (42.8 KB of duplicated path data dropped)
The comparison is numeric with a 0.011-unit tolerance, because Illustrator wrote two decimal places
against three different artboard offsets and the same point can land either side of a rounding
boundary. The shapes carry no fill of their own — colour inherits from the wrapping <g> — so one
copy serves every colourway with no markup rewriting at render time.
The check matters more than the saving: if a future artwork drop changes one lockup's mark and not the others, the build fails loudly instead of silently blessing whichever file was read first.
npm run compare re-renders each lockup through the generator, crops the original to the same
frame — aligned on the mark, the one element guaranteed to be shared — and writes a difference
sheet to tmp/compare/comparison.png. It needs python3 -m pip install cairosvg pillow.
Measured against the source artwork, per text line:
| Lockup | Line widths | Position |
|---|---|---|
| Stacked | exact | 0.78 units |
| Horizontal | exact | 0.00 horizontal, 7.83 vertical |
| Centred | exact | 19.1 and 28.0 units |
Every line's width matches the original exactly. The position differences are deliberate, and all three come from the same decision: the reconstruction is built on a rule, and the originals were placed by hand.
P of Province specifically. 0.78 units apart, and the rule does not depend on which
letter happens to come first.These numbers are pinned by the tests in src/logo/renderLogoSvg.test.js, so they cannot drift
without a test failing.
They have no Illustrator source to diff against, so they are checked against printed references instead — seventeen documents for the flag identity and twelve for the arms, rasterised and measured rather than eyeballed. All of them reproduce.
The method that matters is measuring each drawing's own aspect before trusting any reading
taken from it. A height read off a reference is only meaningful once you know you have found the
right drawing at its true scale, and that check caught both a misidentified arrangement and a
proportion that turned out to have two printed values rather than one. Every constant in
src/flag/flagLayout.js and src/crest/crestLayout.js carries the readings it came from in a
comment, including the ones that disagree.
Where the documents genuinely disagree the readings are kept as choices rather than averaged into a value that matches none of them. Averaging was the failure mode throughout this project: a mean across off-standard published marks, a single stacked proportion standing in for two, one ministry size standing in for three.
| Format | Notes |
|---|---|
| SVG | Both faces inlined as base64 @font-face, so the file is self-contained |
| Real vector, page sized to the lockup, type still live and selectable | |
| PNG / WebP | Transparency preserved; 512–4096 px wide |
| JPEG | No alpha channel, so it is composited onto white |
Vector exports keep their type live by default, with both faces embedded — the file stays editable, selectable and searchable. Convert text to outlines turns each letter into a path instead, which is what a printer usually means by "supply it with the text outlined": nothing in the file refers to a font any more, so nothing can substitute one.
Outlining is not an approximation. The pen arithmetic in src/logo/textOutline.js mirrors
measureLine() exactly, and the tests measure the emitted path data back and compare all four ink
edges against the layout model — they agree to within 0.01 of a unit, without involving a
rasteriser at all.
It usually makes the file smaller, because the embedded font goes away with it:
| Live text | Outlined | |
|---|---|---|
| SVG | 172 KB | 36 KB |
| 122 KB | 140 KB |
The glyph table is about 200 KB and loads on demand, so it costs nothing until someone asks for it.
The accessible <title> is kept either way — outlining removes the text from the document, and
that title is then all a screen reader has.
The viewBox hugs the ink — actual glyph extents, not the font's full ascender and descender — so a
lockup with no descenders carries no empty band beneath it. Clear space then adds a margin on
top of that, measured as a fraction of the mark's width so the proportion holds at any size. Where
the lockup has a background colour, the colour fills the margin too, so clear space also decides how
much of a coloured panel the export is. None is available for a logo being dropped into someone
else's layout, but it is not the default — type set hard against the edge of a coloured panel reads
as a mistake.
Formats the browser cannot encode are detected and disabled rather than offered and then quietly substituted.
The mark and the type take their colours independently; color is a shorthand that sets both, and
the UI keeps them linked until you say otherwise.
A transparent export has no background of its own, so the generator reports contrast twice — against white and against black — and names whichever of the mark or the type is the weaker of the two. A white lockup is 1:1 on white and 21:1 on black, and both numbers are worth knowing before you hand the file over.
The preview surface follows from the same reasoning. On Auto it turns dark when the artwork would otherwise be invisible against a light page, which is the one case where a preview actively misleads. It is a preview control only and is never part of the export; the checkerboard appears only when the export really is transparent, so the pattern always means the same thing.
Bundle in the download panel renders the cross-product of the lockups, formats and pixel widths you tick, and zips it:
bc-ministry-of-forests/
stacked/ …-stacked-ffffff.svg .pdf -1024.png -2048.png
centred/ …
horizontal/ …
columns/ …
README.txt what is in the box, and which file to hand a printer
Everything goes through the same renderLogoBlob() as a single download, so a bundled asset is
byte-for-byte the one you would have got on your own. The default selection is 16 files; ticking
everything is 56, and the button says so before you commit to the work. Already-compressed formats
are stored rather than deflated, which costs nothing and saves the time.
Copy link puts the whole configuration in the URL — there is nothing to upload and nothing
stored anywhere. @firstform/json-url does the compression,
with two of its transforms doing the work on length: defaults are stripped, so a link carries only
what was changed, and the survivors are renamed to single letters.
| Configuration | Token |
|---|---|
| Untouched | 10 characters |
| One change | 36 characters |
| A typical lockup | ~145 characters |
| Everything changed | ~195 characters |
The engine is pinned to json-url's lz codec, and a test asserts that across the whole size range.
That pin started as a workaround: json-url's raw codec (plain base64) is the natural pick for the
smallest payloads, but its base64 helper reached for Node's Buffer global, so a raw token
compressed happily in a browser and then threw on the way back. The asymmetry made it a problem for
whoever opened a link rather than whoever made one, and it only appeared on payloads small enough
for the engine to choose raw — which is the common case of a nearly-default lockup.
That is now fixed upstream in json-url (base64url is implemented locally against the buffer
package, as the rest of that library already does). The pin stays anyway: one codec that works at
every size is simpler than two, and the few characters raw would save on a short link are not worth
the branch.
A decoded link is treated as hostile, because it is: it arrives from whoever wrote the URL, not
from whoever opens it. sanitizeShare() coerces every field back into something the app could have
produced — enumerated values must be in their enum, booleans must be booleans, text is capped and
stripped of control characters, and a colour must match a pattern that cannot contain a quote or an
angle bracket. The renderer escapes what it interpolates as well; the two are independent.
The engine is loaded on demand, so a visit that neither arrives with a link nor makes one never downloads it.
Two things here are aimed at software rather than people.
An agent that has read the manifest can describe exactly the lockup it wants — and then needs a way
to hand it over. capabilities.json describes the generator's browser exports; it is not itself
an export, so without this the only route was writing the settings out as instructions for a person
to re-enter by hand.
So the configuration is a documented object, in the same vocabulary as the manifest and the tools:
{ "lockup": "columns", "ministry": "Ministry of\nEnvironment", "markAlignment": "top",
"markColor": "#eee3c0", "background": "transparent", "clearSpace": "none" }
Pass it URL-encoded as ?c=… and the generator opens with those settings already applied, ready to
export — or paste it into the Configuration box on the page. Absent fields keep their current
value, so a partial object changes only what it names. Copy readable link goes the other way.
/capabilities.json states the whole option
space in one fetch: every lockup with the artwork it was derived from, every format and whether it
holds transparency, the palette, the clear-space presets as both a rule and a number, the ministry
list with the date it was last checked, and how share links are formed. It is generated by
scripts/build-capabilities.mjs from the same constants the application imports, so it cannot
drift from what it describes — adding a lockup updates it for free, and a test asserts the two
agree.
It is written in the vocabulary the URL and the tools below accept, so a value read out of it can be passed straight back in.
Where the browser implements navigator.modelContext,
the page registers six typed tools, so an agent calls them instead of hunting for the right button:
| Tool | |
|---|---|
get_lockup_state | The current lockup, wording, colours, the size it would export at, and its contrast |
set_lockup | Lockup, ministry, second line, wordmark, alignment, clear space — any subset |
set_colours | Mark, type and background, independently |
export_lockup | Downloads in any supported format, optionally with the type outlined |
get_share_link | A URL reproducing the current lockup exactly |
find_ministry | Searches the listed ministries, ignoring case and punctuation |
Their JSON Schemas enumerate their options from LAYOUT_ORDER, EXPORT_FORMAT_ORDER and the rest,
so a tool can never offer something that does not exist.
WebMCP is a W3C draft and currently a Chrome preview, so this is written as pure progressive enhancement: where the API is absent nothing runs, and the page behaves exactly as it always did. Nothing else in the app depends on it.
What was deliberately not done. An llms.txt was considered and skipped — no major provider
documents reading one at inference time, and an analysis of 300,000 domains found no measurable
effect, so it would have been decoration. The accessibility tree is what browser agents actually
read today, and that is served by the ordinary ARIA and labelling the UI already uses.
A Government button opens the Province's structure as a radial graph, modelled on graph.civlab.org's diagrams of the US government: the people at the centre, the three branches as sectors of a disc, each tier of authority a ring further out, shape for the kind of body and colour for its branch. Choosing a body turns the disc until it sits at six o'clock, draws what it is connected to, and opens a panel with who leads it. The surfaces follow the model's warm stone; the branch colours are taken from the BC identity palette the generator already draws with, and the people are the sun.
Beneath it, a timeline runs from Confederation in 1871 to today. Moving it carries every body from where it stood to where it stands in the new year, so a reorganisation can be watched rather than inferred. The strip shows the premiers by party, each election, how many ministries changed each year, and the four identities this generator draws. That last strip is the point of putting the two together: a ministry chosen on the timeline is shown in the lockup of its own year (the flag for 1986, the arms for 2003, the sun and mountains since 2005) and opens in the generator in that identity.
src/ministries/history.js
is a faithful record of the BC Archives diagram and stays so. src/government/episodes.js closes
the eleven episodes it leaves open although they were renamed, adds what happened after its last
revision (Jobs and Economic Growth, July 2025, and the November 2024 splits and merges it records
only as endings and beginnings), and binds each rename to the pair of runs it joins. Renames
in the source are keyed by name, and a name can run three times: bound by name, the 2022 Ministry
of Forests would appear to have become Forests and Lands, which the 1976 one did in 1986.src/government/currentData.js,
checked 2026-09-25).scripts/build-government-history.mjs reads the research
files and writes src/government/historyData.js, matching each portfolio to the episode it
headed and keeping every record's source (npm run build:government-history). The research
itself is committed in research/, which explains how to add to it, how
to record an editorial decision between competing sources (research/decisions.json), and what
is still wanted (research/WANTED.md). Portfolios that headed no ministry of their own — President of the
Council, Deputy Premier, the "Minister Responsible for…" roles — are left unmatched and listed.The view takes the whole page, as its model does. The site's views are now a menu off the title ("Province of British Columbia / Generator ▾"), which the government view carries in its breadcrumb. The legend is the model's: every kind of body and every kind of line can be hidden, including the ministers' head circles. A Graph | List switch shows the same year as a list — each ministry with its minister and the bodies answering to it — for reading on a phone or with a screen reader.
The diagram's outline is the government's own shape. Each branch is one territory from the centre to the rim, separated from the next by a seam of constant width; each ministry's family of Crown corporations and agencies packs beyond it, up to three deep, and a family that needs more room than the band gives pushes a tooth out of the rim to hold it — so the cog changes with the year. Beyond their parents sit sub-agencies as dots, as the model draws its own: 239 of them today, from ministries' divisions (BC Wildfire Service, BC Parks, Service BC) and the administrative tribunals to the Crowns' subsidiaries (Powerex, BC Cancer), researched into the same build as the rest of the history.
Most were collected from 2026 sources and have no start date, so before today they are drawn only
when "Undated bodies" is on. A reviewed tranche (research/history/sub-agencies-researched.json,
2026-09-26) dates 26 of them and adds three that are gone, as claims rather than a finished history:
each start says what it dates (the Civil Resolution Tribunal's 2016 commencement, not its 2012
assent), an end is exclusive (GPEB stands until the day IGCO replaced it), and a name or parent is a
period only where a source gives one — a single sighting places it in that year alone. Where the
review dated a parent, a body is not placed under it outside that period (BC Renal joins PHSA in
2002, not at its 1997 founding); where nothing names a parent, it is drawn apart in the no-ministry
lane; and a start the review could not settle (WorkBC, Powertech) says so — BC Timber Sales' was settled
by a recorded decision. The brief listing what is still missing for every sub-agency
(research/sub-agencies/BRIEF.md) is regenerated from the data by npm run build:research-brief.
The health authorities have their own ancestry. Following the institutional-history research of 2026-10-21, the five geographic authorities no longer share one generic "1997 regional boards" predecessor: each came from the boards and councils Schedule A of B.C. Reg. 293/2001 names (3, 17, 13, 5 and 6 of them), and those boards from the councils the December 1996 orders folded into them — Prince George's council into Northern Interior, Northern Interior into Northern Health. The seven community health services societies passed their services on rather than amalgamating, so the Cariboo society's went to both Interior and Northern. A body whose start no source gives is drawn from the first day a source shows it, and says so; one with neither stays in its successor's "Came from" list without being drawn. PHSA is a society of its own (12 December 2001), not a sixth successor of the boards. A primary-evidence follow-up then dated every board and council from its original designation order (Northern Interior on 17 November 1994), drew each under the name it had that year (the Upper Fraser Valley Health Board of 1994 is the Fraser Valley Health Region of 2001), and stated which ministry each answered to, so 1997 shows the 52 bodies of that system and the societies stand until the registry dissolved them in February 2002.
Every body's line to the people. Choosing a body draws its whole line of accountability, not only its nearest connections, as graph.civlab.org does: a health authority to its ministry, the ministry's minister to the Premier, the Premier to the Assembly whose confidence they hold, the Assembly to those who elect it. Every route is kept — beside the Assembly's confidence, the Lieutenant Governor's appointment of the Premier is drawn too, and the panel says the Crown is not elected. The people's sun lights up when the line reaches it; a line that would cross the centre bows round it; each line names itself when pointed at, the people's with the number of members they elect. The panel lists each step and marks any the sources do not state for that year. Partnerships, funding and the rest are not part of it, and FNHA, the Crown and the courts have no route. The people are described as more than the electors, and a year before 1949 says whom the franchise left out.
An atlas, not just an org chart. Following the BC government atlas research package of
2026-09-25 (its model notes and acceptance cases are what the tests in
src/government/atlas.test.js check):
src/government/eventsData.js, built by
npm run build:government-events from the package's seeds and the follow-up research): a
function's origin, a unit's establishment, legal and operating names, logo changes, appointments,
transfers — each at the precision its source gives. "1957" stays 1957, never 1 January.
WorkSafeBC is the Workers' Compensation Board's operating name, not a second body.npm run build:government-atlas.The year and the chosen body are in the address bar (?view=government&year=1986&node=…), so a
view can be shared. The view loads only when opened, as the gallery does.
Ministries are renamed at every cabinet shuffle. The list lives in
src/ministries/ministries.js with a MINISTRY_LIST_REVIEWED
date that the UI displays, and the generator always accepts a typed-in name — a stale list should
never be the reason someone cannot make the logo they need.
.github/workflows/pages.yml builds and publishes to GitHub Pages on
every push to main, and can be run by hand from the Actions tab. Enable it once under
Settings → Pages → Build and deployment → Source: GitHub Actions.
Two things make this workflow unusual:
macos-latest, not Ubuntu. The build subsets the real Helvetica the artwork is set
in, and the only copy it can legally reach is the one macOS itself ships — the font is not
committed here. A Linux runner has nothing to subset. A step checks for the font up front and
fails with an explanation rather than part-way through the build. macOS minutes are free on public
repositories; on a private one they bill at ten times the Linux rate, so if that matters, the
alternative is to commit a metric-compatible libre face (Arimo or Liberation Sans have identical
advance widths, so none of the layout constants would change) and move the job to Ubuntu.vendor/json-url builds its own dist/, so submodules: recursive
is required or npm ci cannot resolve the dependency.The base path comes from the repository's own name via BASE_PATH, so renaming the repository
cannot leave every asset URL pointing at a path that no longer exists. Locally, npm run deploy
still works for a one-off publish from your own machine.
The marks are provincial symbols reproduced from the supplied artwork; their use is governed by the Government of British Columbia. The Province's guideline documents say in bold that the current ministry marks must not be altered and must be used exactly as provided, which is why that era serves them unchanged.
Helvetica and Adobe Garamond Pro are licensed typefaces. The build subsets each from a copy already
on the machine and commits neither — only advance widths and kerning, which are not letterforms.
Distributing a built site distributes the embedded subsets, which is your call to make under
whatever licence covers your copies. GARAMOND_SOURCE has no default path so that this cannot
happen by accident.
The Vancouver/Richmond comparison now applies the reviewed provisional 5 km northward local adjustment. Current reference geography, the original trace and the adjusted trace have separate layer controls; the original published inset remains visible in the evidence panel. Download all nine reference/trace features as GeoJSON, or open the focused four-layer GeoLibre project. The original global registration is retained.
src/government/timelineData.js.