{"node":{"id":"ec50a07f-f1ee-4008-b3ce-b7e1a847d706","handle":"ec50","type":"note","authorName":"Vincent Yeung","intent":"learning","title":"Pattern: building a website with AI","aiSummary":null,"content":"**When:** you're having an AI design and build a website, from the first look through to handing it over.\n\n**Built from:** starting a new codebase, putting a site up on Cloudflare, align before you give it more.\n\n**The worry:** an AI can turn out a good-looking page in minutes, so it's tempting to take the first one. But the first one tends to look like every other AI-made page, it can ship broken in ways you don't see on your own screen, and nobody remembers why the look ended up the way it did.\n\n**What's really going on:** the look is a decision about who the site is for, and the AI can't make that for you. Once it's made, most of what goes wrong is quiet: a page that is blank for some visitors, images far too big, two copies of the site overwriting each other. You only find those by checking.\n\n**The look**\n- Settle who it's for before you pick a look. Say where it sits (between budget and luxury, say), how it should feel, and how it must never feel. A dark, luxurious look was dropped once because it would have scared off the mid-range buyers the site was for.\n- Ask for several looks that are really different. Give each one a different layout to follow: magazine, catalogue, full-screen photos, bright retail. Name the colours too. Left to choose, agents drift together: three of four \"different\" looks once picked green on their own.\n- Avoid the tells of an AI-made page: a number on every section (01, 02…), a small capitals label above every section, and a cream or beige background. Also gradient text, frosted glass for decoration, a coloured stripe down the side of cards, and rows of identical icon cards. Numbers belong only on a real sequence, like \"how it works\". Let warmth come from the accent colour, the photos and the type.\n- Keep small grey text dark enough to read. A grey picked for elegance came out at about 2.5 to 1 contrast. It needs at least 4.5 to 1. Never lighten it for looks.\n- Borrow from known brands' design systems by fit, not by fame. Pick the two or three whose problem is like yours and take one idea from each: a filterable photo wall from Pinterest, colours taken from real materials from Starbucks, one accent kept for a single moment the way Starbucks keeps gold for its rewards.\n- Write the look down in one DESIGN.md: the colours, type, spacing and components first, then layout, motion, voice, and what to do and not do. Every later change reads it, so the look doesn't drift.\n\n**Building it**\n- A fade-in must never be what makes content appear. If content starts hidden and waits for a scroll to show it, it stays blank in a hidden tab, in a screenshot tool and for search engines. That shipped blank three times on one site. Hide content only once the page's script has run, show what's already on screen at load, and add a fallback that shows everything after about a second and a half.\n- Respect the reduced-motion setting: stop anything that scrolls by itself and show content without the fade.\n- No sideways scrolling on a phone. Check at 375 pixels wide. Anything decorative or scaled up sits inside a box that hides overflow.\n- Shrink images before they go on the page. Generated images come out around 2,700 pixels wide and 2.5 MB each. Resizing to about 1,800 pixels took one site's images from 22 MB to 3.5 MB with no visible loss. Squeezing without resizing saved only about 7%.\n- When you swap in a real photo, give it a new file name. Images are usually cached for a year, so a returning visitor keeps the old one under the old name.\n- React 19 has no single-file build any more, so the old unpkg link fails. For React without a build step, load it from esm.sh with an import map, and write the markup with htm.\n- One form can do several jobs. A booking button, a quote button and an upload-your-plans button can all open the same form, with its type already picked by the button that opened it.\n- If more than one agent takes screenshots at once, give each its own browser. Sharing one, they take each other's pages. Each one checks the address before it takes a shot.\n\n**Showing it and choosing**\n- Show the options as a preview hub: each version at its own address, with a date, a short list of what changed, and a thumbnail. Use the same words in every look, so the choice is made by eye.\n- Narrow down deliberately. Going broad is useful only until it's time to pick one or two and go deep.\n\n**Shipping it**\n- One deploy path per site. When two machines both deployed the same site, a deploy from an out-of-date copy quietly put an older version back live. Pull the latest before any work, and deploy only by pushing, so GitHub Actions does it.\n- Cloudflare's own traps (headers that add up, caching, checking the right address) are in putting a site up on Cloudflare.\n\n**Handing it to someone who isn't technical**\n- They'll change it by talking to their own AI, so give that AI a CLAUDE.md in the repo. It says what to read first, that \"publish it\" means commit and push, never to deploy by hand, which words the business never uses, and that a fact marked as unconfirmed is never stated as fact.\n\n**Tools tried**\n- Meta's Astryx component library: themed through CSS variables, with strong form parts. It reads clean and systematic, so it needs a lot of theming to feel warm.\n\n**As a skill:** ask the AI to turn this page into a skill for any new site, with DESIGN.md as the first thing it writes.","capturedAt":"2026-10-29T08:34:07.045Z","createdAt":"2026-10-29T08:34:07.046Z","updatedAt":"2026-10-29T08:34:07.046Z","spanId":null,"contributor":null,"audiences":[{"kind":"public","createdAt":"2026-11-06T04:27:08.868Z"}],"fingerprint":"62d9975e4cd521f59b3f3e71719dbcae5835d307e28597ea0104247bb6721bb2","revisionNo":"1","structureHash":"e63b54c083aa93ec272c5d03a5b587824c3c5a78373b8839600f59268a5f2083","page":"https://lattris.com/by/b/memories/ec50a07f-f1ee-4008-b3ce-b7e1a847d706"},"links":[{"direction":"out","verb":"references","reason":"Read this when the site goes on Cloudflare Pages: tokens, headers, caching and silent deploy failures.","hash":"8d77a9e87427dada071ab68ea4f2e0b10a2623713a2ad423eaf4214ad3884156","node":{"id":"00c82fa2-90c7-4fe7-b145-9dd5238363b6","handle":"00c8","type":"note","title":"Pattern: putting a site up on Cloudflare","aiSummary":null,"erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/00c82fa2-90c7-4fe7-b145-9dd5238363b6?links=1","fingerprint":"5e5270fb44f8acc1d0cf09a9185b752672803b9c8d462e248595c34c32ca282c","revisionNo":"4","structureHash":"69d402a179a28c7f173da5f223acc012de8e96105b9da11c58afd2619c9c8ada","intent":"recipe","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/00c82fa2-90c7-4fe7-b145-9dd5238363b6"}},{"direction":"out","verb":"references","reason":"Read this when the site needs a real codebase rather than a single page: where code, tests and docs go.","hash":"c8998889efda09ba44c34bed535056f5119737bd3f5a0136b92683d397f0c976","node":{"id":"33705115-71bf-4415-9eb8-5c6afafeff7e","handle":"3370","type":"note","title":"Pattern: starting a new codebase","aiSummary":"One page of rules for starting a new codebase, in seven parts: project setup, the architecture rule (domain types in the middle, translation at the edges, outside systems behind ports), server, browser, testing (what to test and what to skip, every test seen failing once), security from the first day, and documents, comments and commits. Four parts hold for any language; three name a default stack of TypeScript, pnpm, NestJS, Postgres and Vue 3. Can be turned into a scaffolding skill.","erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/33705115-71bf-4415-9eb8-5c6afafeff7e?links=1","fingerprint":"6c821f8815ca1b9180fa26cc1f58daca8c42b10df809322079ec4f140043f6ec","revisionNo":"1","structureHash":"f98591a9239486ad4ed36d779485f69774f59f3233d3b3c7e48106749f7ceda3","intent":"recipe","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/33705115-71bf-4415-9eb8-5c6afafeff7e"}},{"direction":"in","verb":"references","reason":"Follow when a line marked [our build] needs its full context.","hash":"889cc91a8064a0b3d91a439592385df0e4e83ca90446bb5d9638ecc0557921ee","node":{"id":"25a75047-6f28-4228-8728-3b212e241ed5","handle":"25a7","type":"note","title":"Drawer 2: The look","aiSummary":null,"erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/25a75047-6f28-4228-8728-3b212e241ed5?links=1","fingerprint":"a7e6643893360cbb761c32fe35ac2ff509b39c054c2bef570dd0f45f48ae5652","revisionNo":"2","structureHash":"6c940c1ec3e9834f903982e4a24e1fec9929335b8b1c32092d274305442e70eb","intent":"learning","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/25a75047-6f28-4228-8728-3b212e241ed5"}},{"direction":"in","verb":"references","reason":"Read this when an AI is designing and building a website: picking the look, the quiet ways a page ships broken, choosing between versions, shipping and handing over.","hash":"878c7091ff02268a2bdb6bde044eda20fd417c7eba46e043e8c44a922bf747d7","node":{"id":"331896d2-2e9d-46b1-b56c-048a18ee23eb","handle":"3318","type":"note","title":"Patterns: a library","aiSummary":"Index of the author's patterns, one page each, built from the basics. Any pattern can be turned into a skill by asking the AI. So far: the handover, re-alignment, the clean summary, plan-execute-review, saving state for next time, knowledge reconciliation, starting a new codebase, and making an existing module readable. Grows as pages are added.","erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/331896d2-2e9d-46b1-b56c-048a18ee23eb?links=1","fingerprint":"7916c915219b006b717edc7b297d1a807abe38eb305c7baa17ff1e7f0add9bbb","revisionNo":"10","structureHash":"687289243eac53d59127886c143c7b0384c691d49d47431094cb081316c95e03","intent":"recipe","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/331896d2-2e9d-46b1-b56c-048a18ee23eb"}},{"direction":"in","verb":"references","reason":"Follow for the full account of what our own build taught.","hash":"d080c80bb407db1ac2ed06b608a9c14a066a8d2608176d13054ee152309427d1","node":{"id":"5f8b457d-b87a-4e61-9af2-3008deaf37a9","handle":"5f8b","type":"note","title":"Front-end design: the toolbox","aiSummary":null,"erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/5f8b457d-b87a-4e61-9af2-3008deaf37a9?links=1","fingerprint":"49e1c7f41f22c466c7ef1a993cab80b6dcbedab4552d2ac684133d60dea7e60b","revisionNo":"2","structureHash":"64df670c7bd82572e0ad9b2e06b8829d3b2e509be134591c04ea1fa281fca3ef","intent":"learning","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/5f8b457d-b87a-4e61-9af2-3008deaf37a9"}},{"direction":"in","verb":"references","reason":"Follow when a line marked [our build] needs its full context.","hash":"20d910dfd9e1b535ce3c69109ce4b5044b308148ddfa16d561ba64943784fee4","node":{"id":"7179765c-95bd-468d-abe7-9cc4daa6bed2","handle":"7179","type":"note","title":"Drawer 1: Direction","aiSummary":null,"erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/7179765c-95bd-468d-abe7-9cc4daa6bed2?links=1","fingerprint":"c0fa97db802a962d6c156578d81d5a0637516c4dfc2c10cfac9a59a1f36ee28c","revisionNo":"2","structureHash":"9f0efe1fa71cc332fb8cb1af8a8bd4f7f71e9ecc5f8131f8441ba3932845f68d","intent":"learning","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/7179765c-95bd-468d-abe7-9cc4daa6bed2"}},{"direction":"in","verb":"references","reason":"Follow when a line marked [our build] needs its full context.","hash":"25a1ba3e33f1810b08183c8c7d5708385dffa178e2ffa8261feeb51a307b46e9","node":{"id":"8702376d-5485-4f66-bb7b-127ebcc5dfb3","handle":"8702","type":"note","title":"Drawer 4: Behaviour","aiSummary":null,"erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/8702376d-5485-4f66-bb7b-127ebcc5dfb3?links=1","fingerprint":"3410ba76e704aa17b24369274db790497faa4d19c466648552725a87c6f439fc","revisionNo":"2","structureHash":"333a308f19d9c0501d6ede7ccb1ef3ec6254d3806322959c7fea97d305bbe1b0","intent":"learning","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/8702376d-5485-4f66-bb7b-127ebcc5dfb3"}},{"direction":"in","verb":"references","reason":"Follow when a line marked [our build] needs its full context.","hash":"3cfc59ad5adeded06f58c2d1bdd6d1be1db4d64934df5166eece040a824c7c3e","node":{"id":"98841826-13b8-4843-ba74-fd26981525db","handle":"9884","type":"note","title":"Drawer 5: Building it","aiSummary":null,"erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/98841826-13b8-4843-ba74-fd26981525db?links=1","fingerprint":"5ed8da87f333ea517c55f8b050ca46d893bb1b907cb1151fa7feef68cc0cccdf","revisionNo":"3","structureHash":"f4b3deab8497b5b9ae3a7026a8ae25e2d882e23aeece6ec80513f14acd2b4221","intent":"learning","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/98841826-13b8-4843-ba74-fd26981525db"}},{"direction":"in","verb":"references","reason":"Follow when a line marked [our build] needs its full context.","hash":"0a0466f504403c46db68ff040b7c06c7e1264d468d4eec63d616d609dc93d481","node":{"id":"bf82afc5-032e-4ecd-8a6a-205ab29f22d7","handle":"bf82","type":"note","title":"Drawer 6: Is it any good","aiSummary":null,"erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/bf82afc5-032e-4ecd-8a6a-205ab29f22d7?links=1","fingerprint":"1ea050b70d61986658d4c7346ee96979c14c9774d0b6aec5e490cddf0d5d8d57","revisionNo":"2","structureHash":"4d658c915f02ec511a2c0ee3b538c0b53325db079b1e2a9444d2bd2cb0737dd9","intent":"learning","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/bf82afc5-032e-4ecd-8a6a-205ab29f22d7"}},{"direction":"in","verb":"references","reason":"Follow when a line marked [our build] needs its full context.","hash":"b6474a7f63ad0f46490e5340f43344cc95c7f51b028635d3954c422bc8e70c22","node":{"id":"c89881f9-196f-47e1-98ed-d75a4571258d","handle":"c898","type":"note","title":"Drawer 7: Shipping","aiSummary":null,"erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/c89881f9-196f-47e1-98ed-d75a4571258d?links=1","fingerprint":"84a05c0f98df15e746ff5d66c0d77e2eda6e2b5fdafc026907c323e7bf6b9777","revisionNo":"1","structureHash":"cc128b64ee43e01d855adc5862ee568da80d0e14712743a7e5c1cbf4594437fc","intent":"learning","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/c89881f9-196f-47e1-98ed-d75a4571258d"}},{"direction":"in","verb":"references","reason":"Follow when a line marked [our build] needs its full context.","hash":"b4e44a8fd76a5e9a76d26e0c81176201a1c37cd9ea1db9c6af91947f118b9ecf","node":{"id":"d1fb677c-ee19-4031-bfea-72774baaa944","handle":"d1fb","type":"note","title":"Drawer 3: Motion","aiSummary":null,"erased":false,"href":"https://lattris.com/api/lattris/by/b/memories/d1fb677c-ee19-4031-bfea-72774baaa944?links=1","fingerprint":"4737fba3103bacfa85ff73ecc7bd88535ff37c2ffbb06555670987e986aa34da","revisionNo":"2","structureHash":"a254f5077efc5d74424160fdbda8d8b0321093d6433b99164b68d09bd99212d3","intent":"learning","authorName":"Vincent Yeung","page":"https://lattris.com/by/b/memories/d1fb677c-ee19-4031-bfea-72774baaa944"}}],"dictionary":{"lattris":"A personal knowledge base — how a person captures what they know as linked blocks they own and control. To understand how this knowledge base works: https://lattris.com/by/4/memories/lattris-a-memory-store-for-your-life-43ff","intents":"Every block can carry an intent — a label for how far you have taken the idea. The scale runs from noticing something to acting on it: noticed (something caught your attention), learning (you are working it out), truth (you are saying this is how things are), decision (you chose a course), action (you did it). Recipe sits outside that scale — it is not a stronger claim, it is a different kind of thing: a procedure, a how-to, a set of steps that ties other knowledge together. Intent is optional — leaving it blank just means you have not labelled it yet."},"instructions_to_ai":"This is knowledge from a personal knowledge base. Read it and consider how it's relevant to what the person you're talking to needs. Follow the linked blocks to explore further related topics if it might be useful to the user; open each at its page address. Start by letting the user know what this is about and how it may be relevant to them."}