Part of #6.
The page is designed for the moment someone is looking at it and for no moment after that. A tab, a bookmark, an iPhone home-screen shortcut, a Slack or iMessage unfurl and a search result are each a first impression the page never wrote any markup for, and most of the material to fix them is already sitting in the repository unreferenced. While checking which files are used, the same pass turned up sixteen files under public/ that nothing references and that the deploy serves to anyone who guesses the path.
What is there today
- The entire link and meta block is
resources/views/index.stx#L90-L107: charset, viewport, title, description, canonical, seven social tags,color-scheme, two font preconnects, the font stylesheet and the hero preload. There is norel="icon", norel="apple-touch-icon", notheme-colorand no manifest.resources/views/404.stx#L10-L18is the same block, shorter, with the same omissions. - There is no
public/favicon.ico, so the browser's implicit fallback finds nothing either. config/images.ts#L70setsfavicon: falseunderappIconswithfaviconDir: 'public'atconfig/images.ts#L71, so the framework generates no icons on this project's behalf.public/images/logos/favicon.svgandpublic/images/logos/favicon-dark.svgexist and are referenced nowhere underresources/,app/,config/orroutes/. Two things about them the audit did not catch: the files are byte-identical (1,606 bytes each), sofavicon-dark.svgis not a dark variant of anything, and both render the Stacks "S" mark in#C14A15on a#FFF7ECfield, which is neither Uplink's mark nor Uplink's palette.resources/assets/images/app-icon.pngis Uplink's own mark, an amber satellite on a dark rounded square, 1024x1024, 305,562 bytes. Nothing references it.config/images.ts#L68names anoutputDirfor generated app icons but the generator is off atconfig/images.ts#L66.- The social card at
resources/views/index.stx#L96-L102setsog:type,og:url,og:title,og:description,og:image,og:image:altandtwitter:card, then stops. Noog:site_name, noog:locale, noog:image:widthorog:image:height. - The declared
og:imageatresources/views/index.stx#L100is/images/california-night-1920.jpg, which is the hero photo. It is 1920x1277 both in its own attributes atresources/views/index.stx#L210-L211and on disk, so its aspect ratio is 1.50:1. Twitter, Slack, Discord and iMessage all crop a large summary card to 1.91:1, which takes roughly a fifth of the height off, top and bottom, with no say in where. - Neither view contains a
<script type="application/ld+json">block. resources/data/release.json#L2-L5already holdsversion,bytes,minimumMacOSandurl, andresources/views/index.stx#L47-L50already imports them to build the download caption.- The surface token the icon colours should agree with is
--paper,#fafaf9atresources/views/index.stx#L111and#0c0c0eatresources/views/index.stx#L122. - Sixteen files under
public/are referenced by nothing inresources/,app/,config/orroutes/, and total 773,554 bytes against a 1.7 MBpublic/.images/screenshots/dashboard.png(188,733) andimages/screenshots/payroll.webp(63,592) are screenshots of an unrelated product.images/screenshots/background-features.jpg(185,111),images/background-call-to-action.jpg(166,090) andimages/background-faqs.jpg(75,877) are Stacks template backgrounds.images/avatars/avatar-1.pngthroughavatar-5.png(60,091 together) are stock faces.svgs/403.svg,svgs/404.svg,svgs/500.svgandsvgs/503.svg(30,848 together) illustrate framework error pages this app never serves, becauseconfig/ui.ts#L50setsdefaultViews: falseandresources/views/404.stx#L2-L3says so in its own header comment. The two Stacks logo SVGs above are the last two.
Proposal
- Cut the icon set from
resources/assets/images/app-icon.png, which is the mark the app already ships: a 32x32 and 16x16favicon.ico, a 180x180apple-touch-icon.png, and anicon.svgif a vector version of that mark can be produced. Put them at the root ofpublic/. - Add to the head in
resources/views/index.stx, after the canonical link atresources/views/index.stx#L95:rel="icon"pointing at the ICO, a secondrel="icon" type="image/png"ortype="image/svg+xml"entry if a vector exists, andrel="apple-touch-icon"at 180x180. - Add the
theme-colorpair in the same block,#fafaf9undermedia="(prefers-color-scheme: light)"and#0c0c0eundermedia="(prefers-color-scheme: dark)", matching--paperatresources/views/index.stx#L111and#L122. - Copy the same icon and
theme-colorlines intoresources/views/404.stx#L10-L18. - Complete the social card at
resources/views/index.stx#L96-L102withog:site_nameset to Uplink,og:localeset toen_USto matchlang="en"atresources/views/index.stx#L89, andog:image:widthandog:image:height. - Resolve the aspect ratio before declaring the dimensions. Either declare 1920 and 1277 and accept the centre crop, or cut a dedicated 1200x630 card from the same ISS photo, point
og:imageat it and declare 1200 and 630. The second is the better result, because a purpose-cut card can carry the product name, which a bare photograph in an unfurl does not. - Add a
SoftwareApplicationJSON-LD block toresources/views/index.stx, readingsoftwareVersion,operatingSystemanddownloadUrlfrom thereleaseimport atresources/views/index.stx#L47, withapplicationCategoryset toDeveloperApplication,offersat price 0 in USD, andsameAspointing athttps://github.com/stacksjs/uplink, the URL the footer already links atresources/views/index.stx#L376. - Delete all sixteen unreferenced files listed above, the two Stacks logo SVGs included.
Requirements
- Do not wire up
public/images/logos/favicon.svg. The audit that produced this issue proposed it and was wrong. It is the Stacks "S", so shipping it puts the framework's logo in the tab of a product that has its own.favicon-dark.svgis the same bytes, so there is no dark variant to pair with it. Both go in the delete list. - One source for every icon. Derive the ICO, the apple-touch-icon and any SVG from
resources/assets/images/app-icon.pngso they cannot drift apart. If that file gets used, it stops being dead weight inresources/assets/. - The apple-touch-icon needs an opaque background. iOS composites it on the home screen with no transparency handling, so a transparent PNG gets a black square.
app-icon.pngalready has its dark rounded square baked in, so export it flattened at 180x180 without adding a second corner radius. - Each
theme-colorcarries its ownmediaattribute. A single unqualifiedtheme-colorpaints the same bar in both themes and looks broken in one of them. - The declared image dimensions must match the bytes actually served. If step 6 produces a new 1200x630 card,
og:image,og:image:widthandog:image:heightall change together, andog:image:altatresources/views/index.stx#L101is rewritten to describe the crop rather than the full frame. og:imagestays an absolute URL. It is built fromsiteUrlatresources/views/index.stx#L15today and must keep being, because relative URLs in Open Graph do not resolve for every consumer.- Read the JSON-LD values from the
releaseimport, never from literals.resources/views/index.stx#L50already renders the same three values into the download caption, so a literal in the structured data is a second place to forget when a release ships. - Render the JSON-LD and parse it. stx escapes interpolated output, and a
"inside ald+jsonblock produces markup that validates as HTML and fails as JSON. Check the built page, not the template. - No web manifest. This is one page with no offline story and no install prompt worth having. A manifest is a fourth file to keep in sync for nothing.
- Delete the sixteen files rather than gitignoring them. They are committed, so ignoring them leaves them in the tree and on the deploy.
Acceptance
curl -I https://uplink.stacksjs.com/favicon.icoreturns 200 with a non-zero length, and the same for/apple-touch-icon.png.- The deployed home page and 404 page both show the amber satellite mark in a browser tab, and adding the site to an iPhone home screen produces that mark and not a page thumbnail.
- The macOS menu bar tints to
#fafaf9in light mode and#0c0c0ein dark mode when the page is open in Safari, with no manual reload between theme switches. resources/views/index.stxandresources/views/404.stxcontain no reference toimages/logos/, andgit statusafter the delete shows sixteen removals totalling 773,554 bytes.https://uplink.stacksjs.com/images/screenshots/payroll.webpandhttps://uplink.stacksjs.com/images/avatars/avatar-1.pngboth return 404.- Pasting the home page URL into Slack and into an iMessage thread shows a card whose image is not cropped through the subject, with the site name present.
- The Google Rich Results test and the Schema.org validator both parse the
SoftwareApplicationblock with no errors, and the version it reports equals the version inresources/data/release.json. ./buddy lintand./buddy typecheckpass.