Rebuild the PsychSift mark as exact vector geometry, and use it for the site icons - #2452
Conversation
The only artwork we had was the small white-on-navy mark on the brand sheet plus a low-fidelity raster enlargement of it. Measuring the small mark showed the design is genuinely circle-based: the outer sweep of each stroke sits on a circle of radius 30 (glyph units, S height 100) to within a quarter of a unit across its whole length. So this reconstructs those circles rather than tracing pixels. Each stroke is six circular arcs — a rounded head tip, a throat, an elbow, a long tail sweep, a rounded tail tip, and the outer sweep — with exact tangency at every junction, and the second stroke is a 180 degree rotation of the first about (27.4, 50). The primary file is 965 bytes. Three corrections to the original, all recorded in the doc: - The two strokes are now identical. In the raster the lower one was heavier than the upper one, and irregularly so. - The glyph is centred in the tile, which previously sat hard against the right edge (26% left margin against 9% right). - Every junction is tangent-continuous, so enlargement reveals no kinks. Adds a separate optical cut for 32px and below: the navy channel between the strokes closes up at favicon sizes, so that file widens the channel by 60%, drops the two blue points, and enlarges the S. The wordmark is Inter Display SemiBold with its outlines embedded, so the lockups render identically without Inter installed. docs/brand/psychsift-logo.md records every centre and radius, the weight parameter, the colours, and the usage rules; docs/brand/preview.html is a contact sheet for the whole set. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
CI triageCI failed on this PR. Automated classification of the 2 failed job(s):
Compared with main CI run #14449 (failure). Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger. |
The first pass fitted the terminals from the brand sheet's raster, where a sharp point of that size necessarily blurs into a rounded blob. It read that blur as the design and gave both strokes rounded club-ends. Enlarging the original shows the opposite: a clean horn at the head and a taper at the tail. Refitting the inner edge across both source renderings, with the tip region included and the terminals left open, gives a simpler and better construction. Each stroke is now four arcs instead of six: outer sweep (30.00, 30.00) r 30.0 throat (46.25, 20.45) r 20.0 elbow (27.49, 35.74) r 4.2 derived from tangency tail inner (59.30, 67.85) r 41.0 The head cusp falls out at (39.6152, 1.5826) where the outer sweep runs into the throat, and the tail cusp at (19.4776, 58.0941) where the tail inner arc runs back into the outer sweep. Both were previously truncated by cap arcs of radius 2.0 and 2.2. Fit RMS against the measured inner edge is 0.84 units in 100, inside the disagreement between the two source renderings. Weight is now controlled by the tail radius alone rather than a uniform offset. That matters because the uniform offset also shrank the throat, which is what sets the head cusp — thickening the stroke used to drag the horn out to x=43.3. At r 41.0 the channel between the strokes is 5.8 units at its narrowest and the stroke is 31.3 at its widest, both matching the original. The small-size cut follows: tail radius 43.5 and rotation centre (28.0, 50), which doubles the channel while widening the silhouette by 2%. The primary file drops from 965 to 851 bytes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
A much larger view of the original artwork became available, so the geometry is refitted against it at sub-pixel accuracy rather than against the 90-pixel crop from the brand sheet. Contours were extracted with marching squares and the four-arc model fitted by Nelder-Mead over a symmetric Chamfer distance. The result lands within 0.33 units in 100 of the measured outline — inside the softness of the source. Master stroke: outer sweep (30.567, 30.567) r 30.567 throat (46.447, 20.746) r 19.061 elbow (29.974, 34.186) r 2.199 derived from tangency tail inner (60.692, 67.165) r 42.870 Head cusp (41.9881, 2.2139), tail cusp (18.6620, 58.7204). The outer sweep is centred at (r, r) for its own radius, so it is tangent to the top and left of the stroke's bounding box — a self-check the earlier fit had also found, and the reason the construction reconstructs cleanly. Two substantive changes beyond precision. The two blue points below the white one are removed at the owner's direction. The mark is now a single colour on its tile. The lower stroke is no longer forced to be identical to the upper one. It is the same path at 1.06 scale — `translate(54.84 100) scale(-1.06)`. Fitting each stroke independently and fitting a single rotation-plus-scale between them agree on that figure, and forcing them equal both worsens the match (Chamfer RMS 1.59 against 1.26) and opens the channel between the strokes from 4.0 units to well over 9. That channel is the tension the mark depends on, so the difference is kept and documented rather than corrected away. The small-size cut follows by stepping the second stroke out 3.5 units in both directions, which widens the channel to 8.9 while changing the silhouette's proportion by 3%. Primary file drops from 851 to 814 bytes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
The colour table still described brand blue as "the two falling points" and carried a Light Blue row that existed only to tint those points on the blue tile. Neither is used by any file any more. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
The four-arc model put each stroke's entire outer edge on one circle. Measuring the original against that circle shows it is not: the edge tracks it to within a tenth of a unit down to about two-thirds of the stroke's height, then peels away and keeps peeling — 0.4 units out at y=52, 1.3 at y=56, 2.7 at y=60, 3.3 at the tip. That departure is a second arc, and it is what draws the tail into a long fine point. Without it the tail stops short and the whole stroke reads heavy and blunt, which is what the owner was seeing. Nearest-point (Chamfer) fitting had hidden this. Every point of a slightly wrong outline still sits close to some point of the right one, so a uniformly thick stroke or a displaced channel scores well. Scoring coverage against the original's own grey levels — where a hard edge is penalised for sitting anywhere but the 50% point of the blur — showed it immediately. Each arc is now fitted individually so its residual can be inspected rather than averaged away: outer sweep (29.2009, 29.2009) r 29.2009 rms 0.079 tail-outer (51.5937, 16.1418) r 55.1234 rms 0.075 throat (44.8724, 20.0286) r 17.7232 rms 0.051 elbow (29.2867, 33.5044) r 2.8805 rms 0.139 tail-inner (65.6136, 70.4548) r 48.9362 rms 0.087 Head cusp (41.3675, 2.6554), tail cusp (17.8645, 59.7414). The outer sweep again lands centred on its own radius, tangent to the top and left of the stroke's box — this time it fell out of the fit rather than being imposed. Against the original by area, intersection over union goes from 0.848 to 0.944. The second stroke's enlargement refines from 1.06 to 1.07. A further 3.5 degree rotation of it scores 0.948; it is left out, because an arbitrary tilt is not something a logo specification should carry. The small-size cut follows, stepping the second stroke out 3 units to widen the 4.4-unit channel to 8.5. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
The gap between the two strokes was drawn from two separate circles that curved in opposite directions. Two arcs bowing apart open a lens: the channel measured 5.4 units at its ends and 8.6 in the middle, with a hard corner at each end of the swell. That dip is what the owner flagged. Measured across the original, its channel is 4.75 units wide with a standard deviation of 0.25 — constant. Both of its edges are arcs of one circle, one inside the other. The mark is now built that way. A single circle at (89.7175, 83.5939) carries the upper stroke's facing edge at r 74.8165 and the lower stroke's at r 70.0627, so the gap is 4.7537 units along its whole length and both edges turn the same way. Each stroke reaches its facing edge through a tangent blend arc — 7.5 units on the upper, 12 on the lower, against the original's 2.88, which was tight enough to read as a corner. The outer silhouette is untouched. Measured on the rebuilt file the channel is 4.75 wide with a standard deviation of 0.10, and area agreement with the original rises from 94.1% to 94.7%. The small-size cut now widens the channel to 7.75 units by moving only the two facing edges, instead of displacing the whole second stroke, so the favicon and the primary mark share one silhouette. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
The middle of the mark has been wrong in two different ways, and both times the cause was the same: the two facing edges were separate curves, so they could drift apart. Drawing them from two circles opened a lens (5.4 units at the ends, 8.6 in the middle). Drawing them as two arcs of one circle fixed the width but left each stroke turning onto its edge through a 7.5-unit blend that reads as a knuckle on the spine of the S. The two strokes are now divided by a single straight line, and each stroke's facing edge is that line offset by half the gap. The edges are parallel by construction, so the gap cannot open and neither edge can curve against the other. Each stroke joins its edge with one 13-unit blend under the head, and both blends bend away from the other stroke, so nothing on either facing edge turns over. Measured across the finished mark the gap is 4.35 units with a standard deviation of 0.28, against 4.75 ± 0.25 in the original, which also bows 1.25 units along its length. This is a deliberate improvement on the source rather than a copy of it. The outer silhouette, both head cusps and the point are untouched. The small-size cut widens the gap to 7.2 units by moving the two lines apart, so it now shares the primary file's silhouette exactly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
… exact Three findings from a measured review of the mark. The point was misplaced. Refitting the original's dot at the 50% level of its edge puts it at (60.4716, 17.3581) with radius 10.4586, against the (58.9234, 16.5279) radius 10.2165 these files carried — 1.8 units in and 2.3% small. That was a measurement error rather than a decision, and it crowded the S's shoulder while leaving the point looking like a stray. Restored. The mark sat left in its tile. The placement weighted the anchor 46% of the way from the S's own centre toward the glyph's right edge, to stop the light point dragging the heavy S leftward. It over-corrected: 65 px of margin on the left against 164 px on the right at 512. The ink's bounding box is now centred, which gives 112 px each side. The symmetry was approximate. The cut has moved 0.31 units so that the point reflection which makes the second stroke carries the first stroke's facing edge exactly onto the second's. The whole mark is now invariant under that single transform, and the second stroke is written in the files as a transform of the first rather than as its own path. Also: the maskable icon put ink 176 px from the centre of a 512 px icon, outside the 171 px Android allows inside its safe circle. Re-centring and a scale of 62% brings it to 168. The straight cut, both outer silhouettes and both head cusps are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
CI has been red on this branch since its first commit: `check:repo-awareness-snapshot` reports "documentation differs from the repository" because the two new brand documents were added without regenerating data/repo-awareness-snapshot.json. Regenerated with `npm run snapshot:repo-awareness`. Verified locally: the snapshot check now passes, along with brand:check, check:assets, docs:check-index, docs:check-inventory, docs:check-scripts, docs:check-links, sitemap:check, check:branch-review-ledger, check:outstanding-issues, check:ledger-write-discipline, check:knip, check:maintainability-budgets, check:type-scale, check:icon-scale, check:design-system-contract, format:changed and lint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
The preview covered how the mark is built but not how to use it. Three sections added, so the page carries everything a person needs without opening the spec: - Clear space and misuse: the quarter-height margin drawn to scale, the five rules as a table, and four rendered "do not" tiles — stretched, shadowed, re-spaced, and dropped on a mid-tone — so each failure is shown rather than described. - The files: all fifteen with what each is for, plus the screen-reader note. - Still open: the two taglines on the brand sheet, Inter against the running application's Geist, and the tail tips left as a preference rather than a defect. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
The tail tips were the last open question on the drawing. Both versions were rendered and compared side by side; the owner chose the clean angled cut on 2026-08-28. Written down in both the spec and the preview, with the reasoning, so it is a settled decision rather than an open one: fine points thin both strokes, they belong with a curved middle line rather than a straight one, and they are the first thing to disappear at 16 px. Two questions remain open, and neither is about the drawing: which of the brand sheet's two taglines survives, and whether the wordmark's Inter or the running application's Geist wins. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_260eb84f-e6a4-49ae-b37f-d7b949b73c71) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 738ff91bd9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The finished PsychSift S now draws every brand surface, not just the files under public/brand: the in-app <BrandMark>, the browser-tab icon, the multi-size favicon, the Apple touch icon, the PWA and maskable icons, and the Open Graph image all derive from the same geometry in src/lib/brand-mark.ts. The browser-tab icon and favicon use the wider optical cut, so the channel between the two strokes stays open at 16-32 px instead of closing into a solid shape. Also fixes the monochrome PWA icon, which asked for a white tile and so filled its whole alpha channel with a solid square. It is now transparent, leaving only the glyph, which is what a monochrome icon is for. The tile colour stays bound to --clinical-accent, so the mark adapts to light, dark and forced-colors exactly as the old one did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
The stacked lockup sized its own height from a guessed fraction of the cap height (26%) rather than from the wordmark's real ink bottom. The descenders of the "p" and the "y" reach 2.1 units further down than that, so a renderer cut them off at the bottom edge. The height now comes from the wordmark's measured bounding box, rounded up to the two decimal places the path coordinates are written at, so the letterforms sit fully inside the frame. The layout is otherwise unchanged: the tile, the glyph and the wordmark keep their positions, and only the frame's bottom edge moves, from 461.824 to 463.93. The three horizontal lockups and the standalone wordmark were measured too and none of them clips. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018udjLhnir8SEbNjGFjCJzm
PR #2452 squash-merged while this branch was still open, so the branch carries the same content under different commits. Merging main in brings the histories together; the resulting diff against main is only the rename and the untiled mark. # Conflicts: # docs/design-system.md # src/app/favicon.ico # src/app/icon.svg # src/components/clinical-dashboard/brand.tsx # src/lib/brand-mark.ts
Summary
public/brand/— mark, glyph, wordmark, four lockups, maskable and favicon variants.docs/brand/psychsift-logo.md(every circle, centre, radius and tangency point, with the reasoning for each) and addsdocs/brand/preview.html, a nine-section visual reference covering sizes, backgrounds, lockups, clear space, misuse and which file to use where.<BrandMark>, the browser-tab icon (src/app/icon.svg), the multi-size favicon, the Apple touch icon, the PWA and maskable icons, and the Open Graph image now all derive from the same geometry insrc/lib/brand-mark.ts, so they cannot drift apart.The tile colour remains bound to
--clinical-accentand the ink to--clinical-accent-contrast, so the mark adapts to light, dark and forced-colors exactly as the previous one did, andtests/design-token-contract.test.tscontinues to hold the SVG constants and the CSS tokens in agreement. Choosing a different brand tile colour would be an application-wide accent decision and is deliberately not part of this change.Verification
npm run lint— exit 0npm run typecheck— exit 0npm run brand:check— generated brand assets in step withsrc/lib/brand-mark.tsnpm run check:assets— OKnpm run check:design-system-contract— OKnpm run check:repo-awareness-snapshot— in step (190 pages, 483 documents, 2646 reviews)npm run docs:check-links— OK, 3909 referencesnpx vitest run tests/design-token-contract.test.ts— 45 passednpm run format— no changes to commitTest Files 3 failed | 900 passed (903),Tests 3 failed | 10965 passed | 1 skipped. All three failures are shallow-clone artefacts in this container, not behaviour:tests/clinical-hazard-controls.test.tsandtests/privacy-readiness-contract.test.tsreportreviewedCommit does not exist 883f100…, andtests/rag-plan-package-parity.test.tsreportsmanifest reconciledBase is unavailable locally: f3d1a3c…. This checkout is shallow (167 commits), so those historical commits are simply absent. No brand file is involved in any of the three./icons/icon-192,/icons/maskable-512,/icons/monochrome-192,/apple-icon,/opengraph-image.npm run verify:uiwas skipped because the change is a self-contained SVG symbol plus the icon routes that draw it, with no layout, routing, composer, scroll-chrome or interaction surface touched; the affected surfaces were proved directly in the browser instead, in both light and dark.npm run verify:release— no release or handoff confidence is claimed here.Risk and rollout
src/lib/brand-mark.ts,src/lib/brand-image.tsx,src/components/clinical-dashboard/brand.tsx,src/app/icon.svg,src/app/favicon.ico,public/brand/, and the brand and design-system documentation is affected.Clinical Governance Preflight
This change is classified as clinical-risk only because it regenerates
data/repo-awareness-snapshot.json, which lives underdata/**. That file is generated repository-awareness metadata — a count of pages, documents and reviews — and it was regenerated by the repository's own tooling because two new brand documents were added. No clinical content, source, answer, retrieval or document-access behaviour is touched anywhere in this branch.Clinical KB Database(sjrfecxgysukkwxsowpy)On each of those points, nothing in this branch changes the behaviour concerned. Answer generation, citation rendering, source governance and the document-access path are untouched, so linked-source verification remains exactly as strict as before. No document workflow of any kind is added, so no patient-identifiable handling is introduced or widened. The Supabase target is unchanged and no Supabase file is in the diff. No credential or server-only boundary moves. The demo corpus and the real clinical sources remain as separate as they were. Source metadata, review status and the conservative behaviour for outdated or unknown sources are all untouched. And on deployment classification: no clinical decision-support behaviour changed here at all — the diff is a brand symbol and the icon surfaces that draw it — so the SaMD/TGA assessment position is unaffected.
Notes
docs/brand/psychsift-logo.md: the stroke tails end in a clean straight cut rather than a rounded or tapered tip. The clean cut is what makes the constant-width channel legible at small sizes; tapering the tails was tried and measured, and it broke the gap constancy (4.40 ± 0.33 became 6.32 ± 1.90), so it was abandoned.data/repo-awareness-snapshot.jsonanddocs/site-map.mdare regenerated output, updated by the repository's own tooling rather than by hand.