{"version":"https://jsonfeed.org/version/1.1","title":"Engineer — Brand — Portefølje og noter","home_page_url":"https://brand.engineer.company/da/","feed_url":"https://brand.engineer.company/da/feed.json","description":"Engineer ApS — softwareudvikling \u0026 IT-rådgivning i København, Danmark. En portefølje af dokumenterede ingeniørresultater inden for software, data, cloud og IT.","language":"da","icon":"https://brand.engineer.company/assets/images/brand/card.webp","favicon":"https://brand.engineer.company/assets/icons/apple/apple-touch-icon.png","authors":[{"name":"Engineer ApS","url":"https://brand.engineer.company/da/"}],"items":[{"id":"https://brand.engineer.company/da/portfolio/increased-brand-popularity-by-200x-through-successful-brand-1/","url":"https://brand.engineer.company/da/portfolio/increased-brand-popularity-by-200x-through-successful-brand-1/","title":"Har øget brandets popularitet 200 gange gennem succesfuld brandudvikling på tværs af offline- og onlineplatforme.","summary":"Øgede brandets rækkevidde omkring 200× på tværs af offline- og onlineplatforme — fra ukendt nytilkommen til et genkendt navn.","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e Engineer ApS var en helt ny konsulentvirksomhed med reel teknisk dybde og næsten ingen, der havde hørt om den. Det er en bestemt slags frustrerende: kunnen er der, arbejdet ville være godt, men intet af det betyder noget, hvis de kunder og partnere, der ville have det, ikke ved, man findes. En ung virksomhed skal ses, før den kan vinde noget som helst.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e Opgaven var at opbygge et brand, folk faktisk ville genkende — på tværs af både offline- og onlinesiden — og at omsætte virksomhedens tekniske troværdighed til synlig tilstedeværelse på markedet frem for at lade den ligge som en velbevaret hemmelighed.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e Brandet blev bygget bevidst og holdt konsistent. Det startede med en klar identitet — en tone, et visuelt sprog og en portefølje, der førte an med konkrete tekniske resultater frem for det vage \u0026ldquo;vi skaber værdi\u0026rdquo;-sprog, alle andre bruger. Så kørte det på tværs af de kanaler, der betyder noget for den slags virksomhed — websitet, LinkedIn, GitHub, fysiske arrangementer — med hvert kontaktpunkt, der sagde det samme frem for hver at drive af på sin egen måde. Den røde tråd var at føre an med rigtige case‑studier og rigtige resultater, så troværdigheden var noget, man kunne se bevis for, ikke bare en påstand.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e Brandets rækkevidde voksede omkring 200 gange på tværs af offline- og onlineplatforme — en ukendt nytilkommen blev til noget, folk faktisk genkendte. Og det var ikke forfængelig rækkevidde; synligheden begyndte at producere en stabil strøm af indgående henvendelser og muligheder, der simpelthen ikke havde været der før.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["Brand \u0026 marketing","Produkt \u0026 krav","Stakeholder \u0026 rapportering","Brand, marketing \u0026 SEO","Produktstrategi \u0026 kravspecifikation"]},{"id":"https://brand.engineer.company/da/portfolio/drove-brand-engagement-and-loyalty-by-100-through-2/","url":"https://brand.engineer.company/da/portfolio/drove-brand-engagement-and-loyalty-by-100-through-2/","title":"Har øget brandengagement og -loyalitet med 100 % gennem analyse af markedstendenser og indsigt i forbrugeradfærd.","summary":"Fordoblede brandengagement og -loyalitet (+100 %) via analyse af markedstendenser og forbrugeradfærd — et publikum, der kom tilbage.","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e Efterhånden som synligheden klatrede, nåede Engineer ApS flere mennesker — men engagementet var tyndt. Folk lagde mærke til det og gik videre; den tidlige interesse blev ikke til relationer, der holdt. Rækkevidde uden engagement er bare støj, og brandet lavede støj mere end forbindelser.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e Målet var at uddybe engagementet og loyaliteten, og gøre det ved faktisk at kigge på, hvad markedet og publikummet reagerede på, frem for at stole på mavefornemmelse.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e Så brandet blev datainformeret i stedet for intuitionsstyret. Det betød at kigge på markedstendenserne og på, hvordan publikummet faktisk opførte sig på tværs af kanalerne — ikke hvad nogen antog, de ville kunne lide, men hvad de påviseligt engagerede sig i. Det afslørede de emner og formater, der trak ægte opmærksomhed, og indholdet og opsøgningen blev styret mod dem. Den vigtige del var at stramme loopet: se, hvad der landede, udgiv mere af den form næste gang, og lad hver cyklus være en smule bedre rettet end den forrige.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e Engagement og loyalitet blev fordoblet — en forbedring på 100 % — med et publikum, der kom tilbage og engagerede sig frem for at kigge én gang og gå, og markant stærkere relationer til potentielle kunder og partnere. Brandet holdt op med at udsende ud i tomrummet og begyndte at opbygge noget, der kom tilbage.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["Brand \u0026 marketing","Dataanalyse","Produkt \u0026 krav","Stakeholder \u0026 rapportering","Brand, marketing \u0026 SEO","Dataanalyse \u0026 BI‑dashboards","Produktstrategi \u0026 kravspecifikation"]},{"id":"https://brand.engineer.company/da/portfolio/drove-client-web-success-by-combining-custom-website-91/","url":"https://brand.engineer.company/da/portfolio/drove-client-web-success-by-combining-custom-website-91/","title":"Har skabt succes for kunder på nettet ved at kombinere skræddersyet webudvikling og -design med SEO, indholdsstrategi og tekstforfatning.","summary":"Skabte succes for kunder på nettet ved at kombinere skræddersyet webudvikling og -design med SEO, indholdsstrategi og tekstforfatning.","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e Kunder ville ikke egentlig have et website; de ville have det, et website er ment til at gøre for dem — at blive fundet, at trække kunder ind, faktisk at virke som en kanal. Et smukt site, ingen kan finde, er en fiasko, der ligner en succes.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e At kombinere opbygningen og vækstsiden i ét tilbud var opgaven, frem for at aflevere et site og ønske dem held og lykke.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e De to halvdele blev sat sammen — skræddersyet webudvikling og -design på den ene side, SEO, indholdsstrategi og tekstforfatning på den anden — så en kunde fik noget, der både var velbygget og faktisk synligt. De bliver som regel behandlet som separate jobs, hvilket er, hvordan man ender med et smukt site, der rangerer ingen steder, eller et veloptimeret site, der er ubehageligt at bruge. At gøre begge dele betød, at sitet var designet fra starten til at blive fundet, ikke optimeret som en eftertanke.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e Kunderne endte med stærkere synlighed og mere engagement — deres sites virkede som ægte vækstkanaler frem for online brochurer. At bygge tingen og gøre den findbar i én omgang er det, der gjorde et website fra en omkostning til noget, der faktisk tjente sig ind.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["Brand \u0026 marketing","Frontend‑udvikling","Produkt \u0026 krav","UX/UI‑design","Webudvikling","Brand, marketing \u0026 SEO","UI/UX‑design \u0026 designsystemer","Webstedsudvikling \u0026 CMS"]},{"id":"https://brand.engineer.company/da/portfolio/replaced-27-font-sizes-with-a-six-step-scale-129/","url":"https://brand.engineer.company/da/portfolio/replaced-27-font-sizes-with-a-six-step-scale-129/","title":"Har erstattet 27 gengivne skriftstørrelser, hvis nærmeste naboer lå 0,6 % fra hinanden, med en seks‑trins Major Third‑skala og har skrevet den linter, der fejler på den otteogtyvende.","summary":"Seks størrelser hvor der var syvogtyve, med et oplyst forhold, en oplyst tekstbredde og et tjek der afviser den næste uplanlagte værdi.","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e En måling af sitets gengivne tekst fandt syvogtyve forskellige skriftstørrelser i brug. Flere var adskilt af mindre end én procent — fem værdier mellem 0,8 og 0,85 af brødteksten var alle i live på samme tid, hvilket er en forskel ingen læser kan opfatte, og enhver fremtidig redaktør vil lægge til. To af overskrifterne blev slet ikke størrelsessat af stylesheetet og faldt igennem til browserens egne standarder, et forhold på 1,33 der ikke matchede noget andet på siden.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e Størrelserne skulle blive til en skala med et oplyst forhold, og noget skulle forhindre den otteogtyvende.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e Skalaen er en stor terts, forhold 1,25, seks navngivne trin fra finskrift til display, hvert et token frem for en værdi. Overskrifter er eksplicit knyttet til trin i stedet for at arve hvad browseren nu mener, hvilket er det der rettede de to, som ikke havde nogen størrelse af deres egen. Kun det nederste trin har et gulv, så finskrift forbliver læselig på en telefon uden at hele skalaen er låst fast. Logotyper er undtaget ved navn frem for ved et tilfælde. Linteren er den del der får det til at holde: den gengiver sitet og fejler på den otteogtyvende forskellige størrelse. Den har allerede vist sit værd to gange — den fangede en overskrift der ankom på 1,17 af brødteksten, hvilket ikke er et trin i noget som helst, og navngav forholdet i fejlbeskeden; og den fangede inline‑kode på 0,9, hvilket er præcis den slags værdi skalaen findes for at forhindre. Sammen med skalaen kom en tekstbredde på omkring tooghalvfjerds tegn, der erstattede en nedarvet fast bredde, som frembragte enoghalvfems tegn på en anmeldelsesside og hundrede og ti på kontaktsiden.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e Seks størrelser hvor der var syvogtyve, med et oplyst forhold, en oplyst tekstbredde og et tjek der afviser den næste uplanlagte værdi. Begrænsningen er reel og lejlighedsvis ubelejlig: et design der vil have en størrelse mellem to trin, må flytte sig til et trin eller argumentere for at ændre skalaen, og det argument er blevet ført og tabt mere end én gang.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["Automatisering \u0026 CI/CD","Designsystemer \u0026 UI","Dokumentation","Frontend‑udvikling","Test \u0026 QA","UX/UI‑design","Brand, marketing \u0026 SEO","UI/UX‑design \u0026 designsystemer"]},{"id":"https://brand.engineer.company/da/portfolio/generated-321-achievement-pages-from-a-sqlite-export-132/","url":"https://brand.engineer.company/da/portfolio/generated-321-achievement-pages-from-a-sqlite-export-132/","title":"Har genereret 495 achievement‑sider på tre sprog fra en skrivebeskyttet SQLite‑eksport, med sidens adresse forfattet som data, så en rettet sætning ikke længere flyttede siden og brød linket.","summary":"Fire hundrede og femoghalvfems sider genereres fra én kilde, at rette et udsagn koster intet, og de adresser dette site nogensinde har udgivet, svarer fortsat.","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e Virksomhedens porteføljeindhold skrives i en særskilt database — den samme der frembringer CV\u0026rsquo;et — og websitet skal udgive det som sider, på tre sprog, uden at de to kopier driver fra hinanden. Den naive tilgang, at skrive siderne i hånden og holde dem i takt, fejler ved den første rettelse.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e Websitet skulle generere sit indhold fra databasen som et byggeinput, med sideadresser der overlever, at sætningerne på dem bliver skrevet om.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e En eksportør læser databasen skrivebeskyttet og skriver én side per achievement per sprog — 495 sider — plus de taksonomi- og ydelsesdata skabelonerne har brug for. Den bruger kun standardbiblioteket, så sitets bygning ikke afhænger af generatorens miljø, og det committede output betyder, at sitet bygger selvstændigt. Den mest konsekvensrige beslutning i den handler om adresser. Sitet plejede at udlede en sides URL fra de indledende ord i dens engelske udsagn, så at rette en sætning flyttede tavst siden og ødelagde hvert link til den — et site hvis argument for sig selv er, at det retter ting, og som opkrævede sig selv et dødt link, hver gang det gjorde. Adressen skrives nu som data: én række per adresse per achievement, den første er den aktuelle, og hver senere er en pensioneret adresse, sitet udsender som en omdirigering. To andre fælder er noteret fra det samme arbejde. En periodesammenligning mod en tekstkolonne matchede tavst alle toogtredive rækker på grund af, hvordan databasen tildeler typeaffinitet på tværs af en sammenligning. Og sproglisten er nu den ene akse, som skriveløkken, datafilerne og forespørgslerne alle udledes af, så at tilføje et fjerde sprog er én opslagspost frem for en søgning.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e Fire hundrede og femoghalvfems sider genereres fra én kilde, at rette et udsagn koster intet, og de adresser dette site nogensinde har udgivet, svarer fortsat. Eksportøren ejer også præcis én præsentationsbeslutning — hvordan ydelser grupperes i tematiske afsnit — og det er bevidst: alt andet den skriver, tilhører databasen, og en gruppeoverskrift der mangler et sprog, fejler eksporten frem for at gengive engelsk oven på oversat indhold.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["Databaser","Datapipelines (ETL/ELT)","Frontend‑udvikling","Internationalisering","Python","SQL","Webudvikling","Brand, marketing \u0026 SEO","Internationalisering \u0026 lokalisering","Udvikling af datapipelines (ETL/ELT)","Webstedsudvikling \u0026 CMS"]},{"id":"https://brand.engineer.company/da/portfolio/closed-the-colour-system-at-28-colours-133/","url":"https://brand.engineer.company/da/portfolio/closed-the-colour-system-at-28-colours-133/","title":"Har lukket farvesystemet ved 28 dokumenterede farver med en linter, der fejler på en værdi, der er malet men udokumenteret, dokumenteret men umalet, fejlmålt, omstavet som en literal eller inden for en perceptuel afstand på 0,02 fra en, der allerede findes.","summary":"Paletten er et lukket, målt sæt, der ikke tavst kan vokse, og de to næsten enslydende stavemåder, der foranledigede den, er væk.","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e Farve på et site med en mørk standard, et lyst tema, et printstylesheet, en tvungne farver‑tilstand og et illustreret mærke forbliver ikke et lille sæt af sig selv. Det var allerede begyndt at drive på den måde det altid gør: to stavemåder af den samme farve liggende tæt nok på, at ingen kunne skelne dem, værdier gentastet som literaler ved siden af de tokens der definerede dem, og dokumenterede farver som intet malede.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e Paletten skulle blive et lukket sæt med en oplyst tærskel for særpræg, og noget skulle håndhæve lukningen.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e Otteogtyve farver, hver dokumenteret med det kontrastforhold den måler på den flade den optræder på, og elleve mærkeværdier erklæret én gang som tokens. Tærsklen er talmæssig frem for redaktionel: to farver tættere på hinanden end en perceptuel afstand på 0,02 i et ensartet farverum er én farve med to stavemåder. Linteren fejler på fem forskellige måder — en værdi malet men udokumenteret, dokumenteret men umalet, noteret med det forkerte forhold, inden for tærsklen af en der allerede findes, eller en mærkeværdi gentastet som en literal. Den fandt to med det samme: en temafarve der fandtes i to stavemåder 0,018 fra hinanden, og en baggrundsfarve der stod for en væg, den lå 0,021 fra. Gennemsigtighed bruger relativ farvesyntaks frem for blandingsfunktionen, netop fordi vagtposten ikke kan se gennem en blanding, og en paletvagt der kan omgås, er ikke en vagt. Reglen der følger med er kort: ret et token frem for en regel, tilføj kun en farve når ingen passer, og sænk aldrig et dokumenteret forhold for at få et design til at virke.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e Paletten er et lukket, målt sæt, der ikke tavst kan vokse, og de to næsten enslydende stavemåder, der foranledigede den, er væk. Det er en begrænsning der lejlighedsvis siger nej — et design der vil have en lidt anden blå, må tage den der findes eller føre sagen for en niogtyvende farve, og den sag skal indeholde forholdet.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["Automatisering \u0026 CI/CD","Designsystemer \u0026 UI","Dokumentation","Frontend‑udvikling","Test \u0026 QA","UX/UI‑design","Brand, marketing \u0026 SEO","UI/UX‑design \u0026 designsystemer"]},{"id":"https://brand.engineer.company/da/portfolio/replaced-963-structured-data-blocks-with-one-graph-138/","url":"https://brand.engineer.company/da/portfolio/replaced-963-structured-data-blocks-with-one-graph-138/","title":"Har erstattet 963 anonyme blokke med strukturerede data, der gentog virksomheden 1.671 gange, med én sammenkædet graf af 16 typer præget fra stabile oprindelsesidentifikatorer.","summary":"Én graf med stabil identitet erstatter 963 anonyme gentagelser, og siderne bærer mindre frem for mere.","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e Sitet udsendte strukturerede data på den måde de fleste sites gør: en blok per side, hver af dem beskrev organisationen forfra igen. På tværs af sitet blev det til 963 blokke, der gentog den samme virksomhed 1.671 gange, anonymt — ingen stabil identifikator nogen steder, så intet der forbrugte det, kunne se at organisationen på én side var organisationen på en anden.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e De strukturerede data skulle blive én graf med stabil identitet frem for en bunke blokke, der tilfældigvis indeholder de samme ord.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e Identifikatorer udstedes nu fra sitets oprindelse — én til organisationen, én til sitet, én til personen — og hver blok refererer til dem frem for at gentage deres indhold. Identifikatorerne er fælles for oprindelsen frem for per sprog, for virksomheden er den samme virksomhed på dansk. Seksten typer er i spil og dækker ydelseskataloget og dets tilbud, anmeldelserne og det arbejde de beskriver, samlingerne og deres brødkrummer. To beslutninger holdt vægten nede. Oversigtssider udgiver deres elementer kun ved URL frem for at indlejre dem, hvilket blev målt: at navngive dem på porteføljeoversigten ville have betydet 107 fulde udsagn og en stigning på 52 procent i den komprimerede side. Og det tjek der vogter det, validerer ikke blot syntaks — det efterprøver at hver blok kan parses, at hver identifikator resolverer, og at hver URL grafen navngiver, faktisk blev bygget, så en graf der peger på en side der ikke findes, fejler gaten.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e Én graf med stabil identitet erstatter 963 anonyme gentagelser, og siderne bærer mindre frem for mere. Den måling der satte arbejdet i gang, er værd at holde sig for øje: sitet havde udsendt den samme organisationsbeskrivelse 1.671 gange, uden at noget var i stand til at føje dem sammen.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["API'er \u0026 integration","Automatisering \u0026 CI/CD","Brand \u0026 marketing","Data governance","Frontend‑udvikling","Webudvikling","Brand, marketing \u0026 SEO","Data governance \u0026 datakvalitet","Webstedsudvikling \u0026 CMS"]},{"id":"https://brand.engineer.company/da/portfolio/cut-the-stylesheet-bundle-from-87kb-to-31kb-139/","url":"https://brand.engineer.company/da/portfolio/cut-the-stylesheet-bundle-from-87kb-to-31kb-139/","title":"Har skåret stylesheet‑bundtet fra 87 KB til 31 KB ved at tage en base64‑skrifttype ud af det og har droppet 756 KB fordelt på 22 filer, der blev udgivet ved hver deploy og refereret af intet.","summary":"Bundtet er 31 KB i stedet for 87, 756 KB døde aktiver holdt op med at blive udrullet, og hver beslutning har en måling knyttet til sig — herunder den der gik…","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e Sitets stylesheet‑bundt var 87 KB, hvilket for et dokumentsite uden framework er det meste af en sidevægt brugt, før noget indhold ankommer. Sitet udgav også et katalog af ikoner ved hver udrulning, genereret én gang og siden refereret af intet.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e Vægten skulle ned uden at designet ændrede sig, og den skulle ned af en grund man kunne pege på frem for ved almindelig oprydning.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e Måling først. To tredjedele af det største stylesheet var én base64‑kodet font — omkring 56 KB tekst der koder omkring 42 KB font — indlejret for en gevinst ved første optegning, som en forudindlæst ekstern fil alligevel får, og betalt på hver side, uanset om vægten var nødvendig. At tage den ud tog den fil fra 84 KB til 28 og hele bundtet fra 87 til 31. De tre fontvægte forudindlæses i stedet, og den tredje kom først på listen, da feltdata viste at den lukkede den længste kritiske kæde, frem for fordi tre lød komplet. Særskilt fandt en audit af hvad udrulningen faktisk udgav enogtyve genererede ikoner og en dubleret konfigurationsfil, 756 KB, sendt ud hver gang og refereret fra ingen steder; og sitets ikonfil selv kom ned fra 145 KB til 15. Et moderne billedformat blev vurderet til mærket, målt og afvist — det kom ud større, og udvælgelsesmekanismen vælger efter rækkefølge frem for efter størrelse, så en moderne browser ville have taget den tungere fil overalt. To tjek holder nu linjen: intet fotografi må vises bredere end halvdelen af sine kildepixels, og hver illustration skal udgives i en størrelse dens egne pixels understøtter ved både normal og høj tæthed.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e Bundtet er 31 KB i stedet for 87, 756 KB døde aktiver holdt op med at blive udrullet, og hver beslutning har en måling knyttet til sig — herunder den der gik den anden vej, hvilket er den mest nyttige af de to optegnelser.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["Automatisering \u0026 CI/CD","Designsystemer \u0026 UI","Frontend‑udvikling","Performanceoptimering","Webudvikling","Brand, marketing \u0026 SEO","Webstedsudvikling \u0026 CMS"]},{"id":"https://brand.engineer.company/da/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/","url":"https://brand.engineer.company/da/portfolio/fixed-a-sitemap-with-one-shared-timestamp-140/","title":"Har rettet et sitemap, hvor 172 af 176 URL'er delte ét ændringstidsstempel, ved at tage datoen fra git‑historikken efter at have fastslået, at eksporten omskriver hver fil ved hver kørsel.","summary":"En gensynkronisering efter en måneds indholdsredigeringer rører nu otte filer af 186 i stedet for dem alle, og sitemappet siger noget sandt.","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e Sitets sitemap fortalte søgemaskiner, at 172 af dets 176 sider sidst var ændret i det samme øjeblik. Det er ikke en subtil unøjagtighed — en ændringsdato er et løfte til en crawler om, at en sides indhold ændrede sig, og et site der giver det løfte 172 gange samtidig, fortæller enten sandheden om en fuld omskrivning eller fortæller ingen noget brugbart.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e Datoerne skulle beskrive indholdet frem for filen, uden at opfinde en præcision repositoryet ikke har.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e Årsagen var, at datoen kom fra filens ændringstidspunkt, og indholdseksporten omskriver hver fil ved hver kørsel, så en enkelt synkronisering stemplede hele korpuset. Rettelsen flytter kilden til versionshistorikken med en faldbagkæde, der først prøver et eksplicit felt, så commit‑historikken, så filen. Fælden i den rettelse er værd at notere: det bogstavelige feltnavn skal optræde på listen, ellers læser generatoren det aldrig, så en konfiguration der ser ud til at foretrække en skreven dato, men udelader navnet, ignorerer tavst hver skreven dato. To andre datobeslutninger kom ud af det samme arbejde. Databasen bærer nu hvornår hver post blev skrevet og sidst revideret, holdt bevidst adskilt fra hvornår arbejdet skete — de ligger år fra hinanden, og at slå dem sammen ville datere en side skrevet i år til et årti siden. Og rækker i den fil er valgfrie, og intet udledes, for repositoryets egen historik begynder efter indholdet gjorde: en manglende dato lader feltet stå tomt frem for at registrere en migrering, ud fra det princip at et præcist forkert tal er værre end et fraværende, eftersom det kun er det forkerte der bliver troet.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e En gensynkronisering efter en måneds indholdsredigeringer rører nu otte filer af 186 i stedet for dem alle, og sitemappet siger noget sandt. Den generelle regel kom i metadatadokumentet ved siden af, for den samme fælde gælder hvert felt der har en faldbagkæde.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["Automatisering \u0026 CI/CD","Brand \u0026 marketing","Python","Test \u0026 QA","Webudvikling","Brand, marketing \u0026 SEO","DevOps \u0026 CI/CD‑automatisering","Webstedsudvikling \u0026 CMS"]},{"id":"https://brand.engineer.company/da/portfolio/built-a-48-token-design-system-160/","url":"https://brand.engineer.company/da/portfolio/built-a-48-token-design-system-160/","title":"Har bygget et designsystem på 48 tokens oven på platformens eget glasmateriale og har skrevet den linter, der afviser et magisk tal, en hårdkodet skriftstørrelse eller en animation, der ignorerer præferencen for reduceret bevægelse.","summary":"Otteogfyrre tokens beskriver hele grænsefladen, udseendet følger systemet, og ingen af de tre former for smuldren kan committes.","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e En grænseflade bygget ved at tilføje visninger ophober værdier: en hjørneradius her, en fjortenpunktsskrift der, en animation på to tiendedele sekund et andet sted. Hver for sig er hver af dem rimelig, og tilsammen er de et design, der ikke kan ændres, for der findes ikke noget, der hedder \u0026ldquo;hjørneradiussen\u0026rdquo; at ændre — der er fyrre af dem, en smule forskellige, spredt over halvtreds filer.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e Det visuelle ordforråd skulle skæres ned til en navngiven mængde, udtrykt mod platformens eget materiale frem for genopfundet, og forsvaret af et tjek, så det forbliver nedskåret.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e Systemet er otteogfyrre tokens i seks grupper: mellemrum, typografi, farve, radius, ophøjning og bevægelse. Farve og materiale er bygget på platformens semantiske farver og dens glasmateriale frem for faste værdier, hvilket er det, der får grænsefladen til at følge systemets udseende, accentfarven og kontrastindstillingerne uden nogen kode, der holder øje med dem. Typografi kortlægges til platformens tekststile, så den skalerer med brugerens størrelsespræference i stedet for at fastnagle en punktværdi. Linteren afviser tre ting: en talliteral hvor et mellemrums- eller radiustoken hører til, en hårdkodet skriftstørrelse hvor som helst, og en animation erklæret uden at respektere præferencen for reduceret bevægelse. Den tredje er den, der ellers ville smuldre hurtigst, for en animation tilføjes i et øjeblik af finpudsning, og præferencetjekket er den del, der bliver sprunget over — så reglen gør selve animationen umulig at skrive uden det frem for at bede nogen huske det.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e Otteogfyrre tokens beskriver hele grænsefladen, udseendet følger systemet, og ingen af de tre former for smuldren kan committes. Begrænsningen er, at et tokensystem begrænser ensartethed og ikke kvalitet — alt passer nu sammen, og at passe sammen er ikke det samme som at være veludformet, hvilket er en vurdering, ingen linter i dette projekt foretager.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["Automatisering \u0026 CI/CD","Designsystemer \u0026 UI","Frontend‑udvikling","Test \u0026 QA","UX/UI‑design","Brand, marketing \u0026 SEO","UI/UX‑design \u0026 designsystemer"]},{"id":"https://brand.engineer.company/da/portfolio/built-the-visual-identity-from-two-drawings-164/","url":"https://brand.engineer.company/da/portfolio/built-the-visual-identity-from-two-drawings-164/","title":"Har bygget virksomhedens ikon- og favicon‑sæt ud fra to håndlavede tegninger, hvor hvert afledt aktiv genskabes af et script og et tjek fejler, når en afledt fil er committet før sin kilde.","summary":"To tegninger frembringer hvert udgivet ikon, genskabelse er én kommando, og et forældet aktiv fejler bygningen.","content_html":"\u003cp\u003e\u003cstrong\u003eSituation.\u003c/strong\u003e Et lille firmas visuelle identitet købes som regel, frembringes maskinelt eller sættes sammen af arkivmateriale, og resultatet er en identitet, der tilhører ingen. Det alternative problem er værre: håndlavet grafik, der kun findes som eksporterede filer, hvor kildetegningen er gået tabt, eksporterne redigeres direkte, og inden for et år er de versioner, der er i brug, uenige med hinanden, og der er ingen original tilbage til at afgøre det.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOpgave.\u003c/strong\u003e Identiteten skulle tegnes frem for skaffes, og rørledningen fra tegning til udgivet aktiv skulle være gentagelig, så hver fil på webstedet kan udledes frem for opbevares.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eHandling.\u003c/strong\u003e To håndlavede tegninger ligger til grund for det frembragte billedmateriale — firmamærket og tandhjulet, der blev til faviconet — og hvert ikon sitet udgiver frembringes ud fra dem. Mærket er en rastertegning; tandhjulet er en vektor. Ud fra disse frembringer skripter hver afledt form: favicon‑sættet i dets krævede størrelser, berøringsikonerne, billederne til social forhåndsvisning, de tilpassede rastervarianter i hver bredde og i hvert moderne format samt de temaspecifikke versioner. Frembringelsen er en opgave, enhver kan køre, så spørgsmålet \u0026ldquo;hvor kommer denne fil fra\u0026rdquo; har et svar, der er en kommando. Forældelsestjekket er det stykke, der får det til at holde: det sammenligner ændringstidspunktet for hvert afledt aktiv med dets kilde og fejler, når en afledt fil er ældre, hvilket fanger netop den fejl, denne udformning findes for at forhindre — nogen redigerer kilden, glemmer at genskabe, og det udgivne websted bliver ved med at vise grafik, der ikke længere svarer til originalen. Reglen om, at afledte filer aldrig redigeres i hånden, er angivet dér, hvor kilderne bor.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eResultat.\u003c/strong\u003e To tegninger frembringer hvert udgivet ikon, genskabelse er én kommando, og et forældet aktiv fejler bygningen. Afvejningen er en hård afhængighed af værktøjskæden: de afledte filer er committet, så webstedet bygger hvor som helst, men at ændre identiteten kræver, at frembringelsesværktøjet stadig virker, og et kildeformat, der holder op med at kunne læses, tager hele identiteten med sig.\u003c/p\u003e\n","date_published":"2026-09-13T01:45:50+02:00","date_modified":"2026-09-13T01:45:50+02:00","language":"da","tags":["Automatisering \u0026 CI/CD","Brand \u0026 marketing","Designsystemer \u0026 UI","Test \u0026 QA","UX/UI‑design","Webudvikling","Brand, marketing \u0026 SEO","UI/UX‑design \u0026 designsystemer","Webstedsudvikling \u0026 CMS"]},{"id":"https://brand.engineer.company/da/notes/solana-mobile-wallet-deeplinks/","url":"https://brand.engineer.company/da/notes/solana-mobile-wallet-deeplinks/","title":"Sådan åbner man en dApp i Solana-mobilwallets","summary":"Hvorfor browse-deeplinks til Phantom, Solflare og Backpack fejler på mobilen — og de formater, regler og rettelser, der får dem til at virke.","content_html":"\u003cp\u003eEn React-dApp bygget på \u003ccode\u003e@solana/wallet-adapter-react\u003c/code\u003e forbinder\ndesktop-wallets uden problemer, men på en telefon falder det samme flow fra\nhinanden: wallet\u0026rsquo;en skal åbne dApp\u0026rsquo;en i sin egen indbyggede browser, og de\ndeeplinks, der skulle klare det, virker bare ikke. Backpack lander på en \u0026ldquo;hent\nappen\u0026rdquo;-side; Solflare åbner appen, men aldrig sitet; alle varianter ser ud til\nat fejle. Vi skilte problemet ad, og det viste sig at være fire adskilte\nproblemer med ét fælles symptom.\u003c/p\u003e\n\u003ch2 id=\"de-fire-problemer\"\u003eDe fire problemer\u003c/h2\u003e\n\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eBackpack-linket var forkert bygget.\u003c/strong\u003e Det eneste dokumenterede format er\n\u003ccode\u003ehttps://backpack.app/ul/v1/browse/\u0026lt;url\u0026gt;?ref=\u0026lt;ref\u0026gt;\u003c/code\u003e — et universelt link med\nmål-URL\u0026rsquo;en i stien og et påkrævet \u003ccode\u003eref\u003c/code\u003e. Et gæt med eget skema som\n\u003ccode\u003ebackpack://ul/v1/browse?url=...\u003c/code\u003e matcher ingen rute i appen, så brugeren\nender på wallet\u0026rsquo;ens installationsside.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSolflare skal også bruge sit universelle link:\u003c/strong\u003e\n\u003ccode\u003ehttps://solflare.com/ul/v1/browse/\u0026lt;url\u0026gt;?ref=\u0026lt;ref\u0026gt;\u003c/code\u003e — ikke det rå\n\u003ccode\u003esolflare://\u003c/code\u003e-skema. Et råt skema kan starte appen uden at dirigere den —\nhvilket er præcis \u0026ldquo;appen åbner, men site-fanen må åbnes med hånden\u0026rdquo;.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBegge parametre skal være kodet.\u003c/strong\u003e \u003ccode\u003eurl\u003c/code\u003e er dApp\u0026rsquo;ens fulde absolutte\nadresse, og \u003ccode\u003eref\u003c/code\u003e er den kaldende origin, hver især gennem\n\u003ccode\u003eencodeURIComponent\u003c/code\u003e. Et ukodet \u003ccode\u003e?\u003c/code\u003e eller \u003ccode\u003e\u0026amp;\u003c/code\u003e i målet ødelægger\nfortolkningen, og wallet\u0026rsquo;en åbner på sin forside i stedet for browserfanen.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eUdløsningen betyder lige så meget som linket.\u003c/strong\u003e Universelle links skifter\nkun app ved en navigation, styresystemet stoler på — og de gør med vilje\ningenting, når de indsættes i adresselinjen, hvilket også er sådan, et helt\nkorrekt link \u0026ldquo;fejler\u0026rdquo; under test.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"de-dokumenterede-formater\"\u003eDe dokumenterede formater\u003c/h2\u003e\n\n\u003cul\u003e\n\u003cli\u003ePhantom: \u003ccode\u003ehttps://phantom.app/ul/browse/\u0026lt;url\u0026gt;?ref=\u0026lt;ref\u0026gt;\u003c/code\u003e — uden \u003ccode\u003e/v1\u003c/code\u003e i\nnetop dette.\u003c/li\u003e\n\u003cli\u003eSolflare: \u003ccode\u003ehttps://solflare.com/ul/v1/browse/\u0026lt;url\u0026gt;?ref=\u0026lt;ref\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eBackpack: \u003ccode\u003ehttps://backpack.app/ul/v1/browse/\u0026lt;url\u0026gt;?ref=\u0026lt;ref\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eÉt mønster dækker alle tre:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003econst WALLET_BROWSE = {\n  phantom: (url, ref) =\u0026gt;\n    `https://phantom.app/ul/browse/${url}?ref=${ref}`,\n  solflare: (url, ref) =\u0026gt;\n    `https://solflare.com/ul/v1/browse/${url}?ref=${ref}`,\n  backpack: (url, ref) =\u0026gt;\n    `https://backpack.app/ul/v1/browse/${url}?ref=${ref}`,\n};\n\nfunction walletBrowseLink(\n  walletName,\n  targetUrl = window.location.href,\n) {\n  const build = WALLET_BROWSE[walletName.toLowerCase()];\n  if (!build) return null;\n  return build(\n    encodeURIComponent(targetUrl),\n    encodeURIComponent(window.location.origin),\n  );\n}\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"udløs-linket-så-ios-og-android-accepterer-det\"\u003eUdløs linket, så iOS og Android accepterer det\u003c/h2\u003e\n\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eRender et rigtigt anker, beregnet på forhånd.\u003c/strong\u003e Et almindeligt\n\u003ccode\u003e\u0026lt;a href={walletBrowseLink('phantom')}\u0026gt;\u003c/code\u003e er den mest pålidelige udløser på\nbegge platforme.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSkal det ske programmatisk\u003c/strong\u003e, så tildel \u003ccode\u003ewindow.location.href\u003c/code\u003e synkront\ninde i tryk-handleren — ingen \u003ccode\u003eawait\u003c/code\u003e, ingen \u003ccode\u003efetch\u003c/code\u003e, ingen \u003ccode\u003esetTimeout\u003c/code\u003e\nførst. Efter asynkront arbejde er gestus-konteksten væk, og iOS falder\ntilbage til wallet\u0026rsquo;ens websted. Aldrig \u003ccode\u003ewindow.open\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTest aldrig ved at indsætte i adresselinjen.\u003c/strong\u003e Universelle links udløses\nmed vilje ikke dér; test med et link, der trykkes på, eller en QR-kode, som\nkameraet scanner.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePas på messenger-webviews.\u003c/strong\u003e Åbnet i Telegrams eller Instagrams indbyggede\nbrowser bliver universelle links ofte slugt, og wallet\u0026rsquo;ens almindelige\nwebsted indlæses i stedet. User-agent-detektion er i bedste fald et gæt, så\ngiv også brugerne en synlig nødudgang: \u0026ldquo;åbn i Safari eller Chrome, og\nforbind derefter\u0026rdquo;.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"den-større-løsning-på-android\"\u003eDen større løsning på Android\u003c/h2\u003e\n\n\u003cp\u003eHåndbyggede deeplinks er iOS-historien. På Android lader Solana Mobiles Mobile\nWallet Adapter en dApp i mobilbrowseren forbinde direkte til den installerede\nwallet-app, helt uden omvejen om den indbyggede browser. Nyere versioner af\n\u003ccode\u003e@solana/wallet-adapter-react\u003c/code\u003e registrerer mobiladapteren automatisk, så en\nopgradering af wallet-adapter-pakkerne kan løse Android alene. Målarkitekturen:\nMobile Wallet Adapter på Android, universelle browse-links på iOS, hvor Apple\nikke tillader en tilsvarende løsning.\u003c/p\u003e\n\u003ch2 id=\"efterprøv-på-en-enhed\"\u003eEfterprøv på en enhed\u003c/h2\u003e\n\n\u003col\u003e\n\u003cli\u003eRigtig enhed, wallet installeret, link åbnet fra systembrowseren — ikke fra\nen messenger.\u003c/li\u003e\n\u003cli\u003eTryk på et renderet link, eller scan en QR-kode; indsæt aldrig i\nadresselinjen.\u003c/li\u003e\n\u003cli\u003eBekræft, at wallet\u0026rsquo;en åbner, og at dApp\u0026rsquo;en indlæses i dens indbyggede\nbrowserfane — anden halvdel er den, der fejler.\u003c/li\u003e\n\u003cli\u003eGentag uden wallet\u0026rsquo;en installeret: det universelle link skal falde tilbage\ntil wallet\u0026rsquo;ens websted. Ser du dén side, mens appen er installeret, er\nlinket eller udløsningen stadig forkert.\u003c/li\u003e\n\u003cli\u003eTest derefter messenger-vejen, og tilføj \u0026ldquo;åbn i browser\u0026rdquo;-hjælpen, hvis den\nfejler dér.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"kilder\"\u003eKilder\u003c/h2\u003e\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://docs.phantom.com/phantom-deeplinks/deeplinks-ios-and-android\"\u003ePhantom: deeplinks på iOS og Android\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://docs.solflare.com/solflare/technical/deeplinks/other-methods/browse\"\u003eSolflare: Browse-deeplinket\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://docs.backpack.app/deeplinks/other-methods/browse\"\u003eBackpack: Browse-deeplinket\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://docs.solanamobile.com/mobile-wallet-adapter/mobile-apps\"\u003eSolana Mobile: Mobile Wallet Adapter\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","date_published":"2026-08-10T00:00:00Z","date_modified":"2026-09-13T01:45:50+02:00","language":"da"}]}