diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..9b1c43f --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,124 @@ +# DESIGN.md + +Design memory for `garin.dev`. This file is the source of truth for the next visual pass. The current site content and assets are canon; the current visual layout is not canon. + +## Product intent + +- Product type: one-screen personal calling-card site for Sergei Garin. +- Audience: recruiters, founders, hiring managers, engineering leads, and people checking contact/CV credibility quickly. +- Primary read: name → role → short proof-of-work sentence → contact links. +- Primary action: open a profile, download CV, or email Sergei. +- Trust posture: calm, precise, senior, product-minded. No portfolio theatrics, no startup-template gloss. +- Target direction: Clean Identity Object — a compact masthead card where portrait, copy, and links feel like one composed identity artifact. + +Reference direction: `/Users/sergeygarin/.openclaw/media/tool-image-generation/website-clean-masthead-C-identity-object---5e6fe94d-e076-41be-b62b-68459e39537d.png`. +Use it for intent, hierarchy, density, and restraint only. Do not clone generated-image artifacts, exact composition, portrait treatment, typography, or link styling, and do not treat it as a pixel spec. + +## Artifact map + +- `DESIGN.md` is the only design-memory artifact for now. +- No supporting design docs are needed unless implementation reveals stable token/component/state rules that would make this file bloated. +- Downstream implementation should update this file if the approved design direction changes before code lands. + +## Canonical content and assets + +Current assets and approved identity content are the source of truth unless Sergey explicitly changes them. For this redesign, the preferred copy below is the copy contract; do not preserve legacy wording or layout just because it exists in the current implementation. + +- `src/pages/index.astro` +- `src/layouts/main.astro` +- `src/components/link.astro` +- `src/styles/global.css` +- `src/static/me.jpg` +- `src/static/me_cropped.jpg` +- `src/public/cv.pdf` +- `job@garin.dev` +- `https://github.com/MrFlashAccount` +- `https://twitter.com/mrflashaccount` +- `https://t.me/mrflashaccount` + +Preferred copy for the redesign: + +- Name: `Sergei Garin` +- Role: `Frontend engineer for sharp, reliable product interfaces.` +- Micro-bio: `I turn messy product ideas into calm, fast, production-ready UI.` +- Links: `GitHub`, `X`, `Telegram`, `CV`, `Email` + +Do not add invented proof, fake metrics, testimonials, project cards, employer logos, or extra sections to make the page feel fuller. + +## Composition law + +- The page should resolve as one screen, not a scroll portfolio. +- Build one compact masthead/card-like identity object. It may sit centered in the viewport with generous outer breathing room. +- Portrait and text must feel composed together, not like a photo column plus a content column. +- The photo may act as part of the object/background if readability is protected and the actual asset supports it; otherwise reduce photo dominance while keeping it visually integrated with the text block. +- The main reading path must be immediate: `Sergei Garin` first, role second, micro-bio third, links last. +- Keep the number of visible elements low. Every visible line should carry identity or action. +- Mobile should keep the same artifact feeling: compact, legible, calm, no stacked résumé page. + +## Visual system + +### Color + +- Use a restrained black / charcoal / soft-white / warm-ivory system. +- Prefer strong but soft contrast over harsh pure-white-on-pure-black glare. +- No bright accents, rainbow gradients, neon, glassmorphism, decorative blobs, textures, or noise. +- If an overlay is needed for photo readability, keep it functional and quiet. + +### Typography + +- Typography should create the drama, not decoration. +- Name gets the strongest display treatment: large, confident, elegant, and readable. +- If a serif/display face is used, keep it engineering-sharp rather than fashion/luxury editorial; readability and credibility beat reference-image mood. +- Role and micro-bio should be clean, direct, and lower-volume than the name. +- Links should feel editorial/systemic, not like app buttons. +- Avoid cramped text, generic SaaS hero scale, and random weight changes. + +### Shape, spacing, and density + +- Dense enough to feel like a precise identity card; airy enough to feel senior and deliberate. +- Use one dominant container/object at most. Do not break the page into multiple cards. +- Corners, borders, and shadows should be minimal and structural, not decorative. +- Alignment should feel measured. Avoid casual scatter, bento fragments, or floating badges. + +### Links and actions + +- Links are part of the identity system. +- Prefer plain text links in a composed row/list, optionally separated by subtle dividers. +- Avoid social-icon button clusters, filled pills, loud CTAs, and repeated competing actions. +- `Email` and `CV` can be present with equal restraint; neither should become a giant marketing button. + +### Motion and interaction + +- Motion is optional and should be nearly invisible. +- Use simple hover/focus feedback that preserves the strict identity-object feel. +- Respect reduced motion. +- Focus states must be visible and coherent with the restrained palette. + +## Hard nos + +Do not introduce: + +- portfolio/blog structure +- skills grid or `GREAT AT` chip wall +- project previews +- fake metrics, quotes, testimonials, logos, or badges +- bento/card clutter +- decorative gradients, blobs, textures, or noise +- generic `Senior Frontend Engineer` as the final hero copy +- social buttons as the primary link language +- the old/current split layout as design canon +- extra copy that weakens the sharp calling-card read + +## Implementation acceptance checks + +A later implementation is acceptable when: + +- The page reads as a one-screen personal calling-card site. +- Portrait + text + links feel like one composed identity artifact. +- The approved copy and canonical links/assets are present. +- The current content/assets are preserved unless deliberately replaced by Sergey. +- No app files treat the old visual layout as the source of truth. +- Links are restrained identity-system elements, not loud social buttons. +- The design has no decorative gradients/blobs/textures/noise and no portfolio-section creep. +- Desktop and mobile both preserve the compact masthead/card intent. +- Text contrast, readable order, focus visibility, keyboard access, and reduced-motion behavior are not visibly broken. diff --git a/src/layouts/main.astro b/src/layouts/main.astro index 7fa474d..1bc3ad2 100644 --- a/src/layouts/main.astro +++ b/src/layouts/main.astro @@ -5,6 +5,7 @@ import svgFavicon from "../static/favicon.svg?url"; import pngFavicon from "../static/favicon.png?url"; import svgDevFavicon from "../static/favicon-dev.svg?url"; import appleTouchIcon from "../static/apple-touch-icon.png?url"; +import syneLatinVariable from "../static/font/Syne-400-800-latin.woff2?url"; const favicon = process.env.NODE_ENV === "production" ? svgFavicon : svgDevFavicon; @@ -40,7 +41,7 @@ const baseCSSString = result.root.toString(); lang="en" itemtype="https://schema.org/Person" itemscope - class="flex h-[100dvh] min-w-[320px] flex-col" + class="flex min-h-[100dvh] min-w-[320px] flex-col bg-[#080807]" > @@ -51,22 +52,36 @@ const baseCSSString = result.root.toString(); Sergei Garin - + + - + diff --git a/src/pages/index.astro b/src/pages/index.astro index a61c49b..32a3b9f 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,241 +1,275 @@ --- import { getImage } from "astro:assets"; -import resolveConfig from "tailwindcss/resolveConfig"; -import tailwindConfig from "../../tailwind.config.js"; -import me from "../static/me_cropped.jpg"; -import meOriginal from "../static/me.jpg?url"; +import meDesktop from "../static/me.jpg"; +import meMobile from "../static/me_cropped.jpg"; import Link from "../components/link.astro"; import MainLayout from "../layouts/main.astro"; -const fullConfig = resolveConfig(tailwindConfig); - -const meMobileAvif = await getImage({ - src: me, +const portraitDesktop = await getImage({ + src: meDesktop, format: "avif", - width: 80, - height: 80, - densities: [1, 2, 3], + width: 760, + height: 1060, + densities: [1, 1.5], }); -const meDesktopAvif = await getImage({ - src: me, - format: "avif", - width: 320, - height: 320, +const portraitDesktopFallback = await getImage({ + src: meDesktop, + format: "jpg", + width: 760, + height: 1060, densities: [1, 1.5], }); -const meScaledAvif = await getImage({ - src: me, +const portraitDesktopZoom = await getImage({ + src: meDesktop, + format: "avif", + width: 1024, + height: 1428, +}); +const portraitDesktopZoomFallback = await getImage({ + src: meDesktop, + format: "jpg", + width: 1024, + height: 1428, +}); +const portraitMobile = await getImage({ + src: meMobile, + format: "avif", + width: 640, + height: 640, + densities: [1, 2], +}); +const portraitMobileFallback = await getImage({ + src: meMobile, + format: "jpg", + width: 640, + height: 640, + densities: [1, 2], +}); +const portraitMobileZoom = await getImage({ + src: meMobile, format: "avif", - width: 360, - height: 360, - densities: [1, 2, 3], + width: 1024, + height: 1024, }); -const meFallback = await getImage({ - src: me, +const portraitMobileZoomFallback = await getImage({ + src: meMobile, format: "jpg", - width: 240, - height: 240, + width: 1024, + height: 1024, }); -const skills = [ - "TypeScript", - "React", - "Next.js", - "Node.js", - "Tailwind", - "Design Systems", - "Microfrontends", - "Web Performance", - "Accessibility", - "Testing", +const links = [ + { + label: "GitHub", + href: "https://github.com/MrFlashAccount", + rel: "me", + itemProp: "sameAs", + }, + { + label: "X", + href: "https://twitter.com/mrflashaccount", + rel: "me", + itemProp: "sameAs", + }, + { + label: "Telegram", + href: "https://t.me/mrflashaccount", + rel: "me", + itemProp: "sameAs", + }, + { + label: "CV", + href: "/cv.pdf", + download: "Sergei Garin CV.pdf", + }, + { + label: "Email", + href: "mailto:job@garin.dev", + itemProp: "email", + }, ]; ---
- - - +
+ - - -
-

- Sergei - Garin -

-

Senior Frontend Engineer

+
-

- Senior Frontend Engineer specializing in architecting performant - applications that drive business results. Proven track record of - achieving dramatic performance gains (10x+) and leading development of - revenue-generating features. -

- -
-

GREAT AT

-
- { - skills.map((skill) => ( - - {skill} - - )) - } -
-
+ + + + + + + +
+

- Get in touch - - - - Sergei + Garin +

+ +

- Download CV - - - - -

+ Frontend engineer for sharp, reliable product interfaces. +

-
-
- - - - - GitHub - - - - - - - Twitter - - + I turn messy product ideas into calm, fast, + production-ready UI. +

+ +
+ { + links.map((link, index) => ( +
  • + {index > 0 && ( +
  • + )) + } + +
    - -
    diff --git a/src/static/font/Syne-400-800-latin.woff2 b/src/static/font/Syne-400-800-latin.woff2 new file mode 100644 index 0000000..e311600 Binary files /dev/null and b/src/static/font/Syne-400-800-latin.woff2 differ diff --git a/src/static/font/Syne-OFL.txt b/src/static/font/Syne-OFL.txt new file mode 100644 index 0000000..f410e51 --- /dev/null +++ b/src/static/font/Syne-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2017 The Syne Project Authors (https://gitlab.com/bonjour-monde/fonderie/syne-typeface) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/styles/global.css b/src/styles/global.css index e8eb271..0741735 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -1,53 +1,20 @@ @font-face { - font-family: "OpenRunde"; + font-family: "Syne"; font-style: normal; - font-weight: 400; - src: url("../static/font/OpenRunde-400.otf") format("otf"); -} - -@font-face { - font-family: "OpenRunde"; - font-style: normal; - font-weight: 600; - src: url("../static/font/OpenRunde-600.otf") format("otf"); -} - -@font-face { - font-family: "OpenRunde"; - font-style: normal; - font-weight: 400; - font-display: swap; - src: url("../static/font/OpenRunde-400.woff2") format("woff2"); -} - -@font-face { - font-family: "OpenRunde Fallback"; - font-style: normal; - font-weight: 400; - src: local("Arial"); - ascent-override: 96.88%; - descent-override: 24.15%; - line-gap-override: 0%; - size-adjust: 100%; -} - -@font-face { - font-family: "OpenRunde"; - font-style: normal; - font-weight: 600; + font-weight: 400 800; font-display: swap; - src: url("../static/font/OpenRunde-600.woff2") format("woff2"); + src: url("../static/font/Syne-400-800-latin.woff2") format("woff2"); } @font-face { - font-family: "OpenRunde Fallback"; + font-family: "Syne Fallback"; font-style: normal; - font-weight: 600; + font-weight: 400 800; src: local("Arial"); - ascent-override: 96.88%; - descent-override: 24.15%; + ascent-override: 92.5%; + descent-override: 27.5%; line-gap-override: 0%; - size-adjust: 100%; + size-adjust: 96.42%; } @tailwind base; @@ -64,11 +31,11 @@ font-feature-settings: normal; font-variation-settings: normal; font-family: - OpenRunde, - OpenRunde Fallback, - serif; + Syne, + Syne Fallback, + sans-serif; line-height: 1.5; - color-scheme: dark light; + color-scheme: light; } @media (prefers-reduced-motion: reduce) { @@ -81,17 +48,6 @@ } } - @media (prefers-color-scheme: dark) { - :where(body:not(:is(img, picture, video, canvas))) { - filter: invert(100%) hue-rotate(180deg) brightness(1.2); - } - - /* Invert to normal color images, pictures, videos, and canvases */ - :where(:is(img, picture, video, canvas)) { - filter: invert(90%) hue-rotate(180deg) brightness(1.2); - } - } - :where(*) { margin: 0; text-box-trim: trim-both;