diff --git a/.gitignore b/.gitignore index 42f08a0ecb..0a4715ba2e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target/ *.spv *.exrc +website/public diff --git a/website/sass/base.scss b/website/sass/base.scss index a793b85bc4..ac4a9b65aa 100644 --- a/website/sass/base.scss +++ b/website/sass/base.scss @@ -9,6 +9,35 @@ --max-width: 1600px; --max-width-plus-padding: calc(var(--max-width) + 40px * 2); --variable-px: Min(1px, 0.15vw); + --font-size-intro-heading: 60px; + --font-size-intro-body: 22px; + --font-size-link: 24px; + --font-size-heading: 40px; + --font-size-body: 18px; + + @media screen and (max-width: 760px) { + --font-size-intro-heading: 40px; + --font-size-intro-body: 18px; + --font-size-link: 20px; + --font-size-heading: 32px; + --font-size-body: 16px; + } + + @media screen and (max-width: 500px) { + --font-size-intro-heading: 32px; + --font-size-intro-body: 16px; + --font-size-link: 16px; + --font-size-heading: 28px; + --font-size-body: 16px; + } + + @media screen and (max-width: 400px) { + --font-size-intro-heading: 24px; + --font-size-intro-body: 14px; + --font-size-link: 14px; + --font-size-heading: 24px; + --font-size-body: 16px; + } } // Global element styles @@ -22,7 +51,7 @@ body { font-family: "Inter", sans-serif; line-height: 1.5; font-weight: 500; - font-size: 18px; + font-size: var(--font-size-body); color: var(--color-navy); } @@ -43,10 +72,10 @@ h1 { font-feature-settings: "lnum"; line-height: 1.25; font-weight: 700; - font-size: 60px; + font-size: var(--font-size-intro-heading); ~ p { - font-size: 22px; + font-size: var(--font-size-intro-body); } } @@ -55,11 +84,11 @@ h2 { font-feature-settings: "lnum"; line-height: 1.25; font-weight: 700; - font-size: 40px; + font-size: var(--font-size-heading); } h3 { - font-size: 24px; + font-size: var(--font-size-link); font-weight: 800; text-transform: uppercase; @@ -81,7 +110,7 @@ h4 { font-family: "Bona Nova", serif; font-feature-settings: "lnum"; line-height: 1.25; - font-size: 32px; + font-size: var(--font-size-heading); font-weight: 400; } @@ -105,7 +134,7 @@ p + p { .link { display: inline-block; - font-size: 24px; + font-size: var(--font-size-link); font-weight: 800; text-decoration: none; color: var(--color-crimson); @@ -120,10 +149,10 @@ p + p { color: var(--color-crimson); display: inline-block; border: 2px solid currentColor; - height: 48px; - line-height: calc(48px - 2 * 2px); - font-size: 24px; - padding: 0 24px; + height: calc(var(--font-size-link) * 2); + line-height: calc(var(--font-size-link) * 2 - 2 * 2px); + font-size: var(--font-size-link); + padding: 0 var(--font-size-link); box-sizing: border-box; text-decoration: none; font-weight: 800; @@ -189,6 +218,11 @@ p + p { display: block; width: 100%; height: auto; + + @media screen and (max-width: 800px) { + width: auto; + height: 120px; + } } } @@ -248,6 +282,13 @@ p + p { min-width: 280px; } + @media screen and (max-width: 600px) { + &.diptych .section, + &.triptych .section { + min-width: 100%; + } + } + img[alt=""]{ display: block; @@ -270,7 +311,7 @@ p + p { .page { box-sizing: border-box; overflow: hidden; - min-width: 600px; + min-width: 320px; header { padding: 0 40px; @@ -299,7 +340,10 @@ p + p { display: flex; justify-content: space-between; padding: 30px 0; - gap: 80px; + + @media screen and (max-width: 760px) { + padding: 20px 0; + } .left, .right { @@ -316,19 +360,18 @@ p + p { text-decoration: none; --height: 60px; --button-padding: 24px; - --font-size: 36px; - font-size: var(--font-size); + --nav-font-size: 32px; + font-size: var(--nav-font-size); &.button { height: var(--height); padding-left: var(--button-padding); padding-right: var(--button-padding); line-height: calc(var(--height) - 2 * 2px); - font-size: var(--font-size); + font-size: var(--nav-font-size); &::after { - content: "»"; - margin-left: 8px + content: " »"; } } @@ -339,34 +382,74 @@ p + p { height: var(--height); } } - } - @media screen and (max-width: 960px) { - gap: 60px; - - .left, - .right { + @media screen and (max-width: 960px) { gap: 30px; a { --height: 50px; --button-padding: 16px; - --font-size: 26px; + --nav-font-size: 26px; } } - } - - @media screen and (max-width: 760px) { - gap: 40px; - - .left, - .right { + + @media screen and (max-width: 760px) { gap: 20px; a { --height: 40px; - --button-padding: 16px; - --font-size: 22px; + --button-padding: 12px; + --nav-font-size: 22px; + } + } + + @media screen and (max-width: 600px) { + gap: 16px; + + a { + --height: 30px; + --button-padding: 8px; + --nav-font-size: 18px; + } + } + + @media screen and (max-width: 500px) { + gap: 12px; + + a { + --height: 24px; + --button-padding: 8px; + --nav-font-size: 16px; + } + } + + @media screen and (max-width: 460px) { + gap: 10px; + + a { + --height: 22px; + --button-padding: 6px; + --nav-font-size: 14px; + } + } + + @media screen and (max-width: 400px) { + gap: 8px; + + a { + --height: 20px; + --button-padding: 4px; + --nav-font-size: 12px; + } + } + + @media screen and (max-width: 360px) { + gap: 6px; + + a { + --height: 20px; + --button-padding: 4px; + --nav-font-size: 10px; } } } diff --git a/website/sass/index.scss b/website/sass/index.scss index 2dc9436389..533c42efb6 100644 --- a/website/sass/index.scss +++ b/website/sass/index.scss @@ -1,25 +1,40 @@ #logo { display: flex; + + img { + width: auto; + max-width: 100%; + max-height: 240px; + } +} - svg { - display: block; - height: auto; +.pencil-texture { + position: absolute; + --remaining-width-to-full: calc(var(--max-width-plus-padding) - min(calc(100vw - 100px), var(--max-width-plus-padding))); + left: Max(calc(-1 * var(--remaining-width-to-full)), -50px); + width: 100px; + mix-blend-mode: multiply; + + @media screen and (max-width: 1000px) { + width: 40px; + top: 400px; + left: -10px; } } #quick-links { margin-bottom: calc(120 * var(--variable-px)); display: flex; - gap: 20px; + gap: calc(var(--font-size-link) * 0.8); flex-wrap: wrap; } -.pencil-texture { - position: absolute; - --remaining-width-to-full: calc(var(--max-width-plus-padding) - min(calc(100vw - 100px), var(--max-width-plus-padding))); - left: Max(calc(-1 * var(--remaining-width-to-full)), -40px); - width: 100px; - mix-blend-mode: multiply; +#hero-message { + @media screen and (max-width: 1400px) { + p { + max-width: unset !important; + } + } } .hexagons { @@ -196,6 +211,13 @@ margin-right: auto; } } + + // 1600px is var(--max-width) + @media screen and (max-width: 1600px) { + .carousel.torn { + display: none; + } + } } #upcoming-tech { @@ -209,6 +231,7 @@ #community { #newsletter form { + width: 100%; margin-top: 40px; display: flex; gap: 20px; @@ -238,6 +261,11 @@ &.name { flex: 1 0 0; min-width: 240px; + + } + + &.phone { + display: none; } &.email { @@ -245,6 +273,13 @@ min-width: 240px; } + @media screen and (max-width: 400px) { + &.name, + &.email { + min-width: 100%; + } + } + &.submit { flex: 1 0 0; } @@ -255,7 +290,7 @@ } label { - font-size: 24px; + font-size: var(--font-size-link); font-weight: 800; margin-bottom: 10px; line-height: 1; @@ -264,13 +299,13 @@ input:not([type="submit"]) { flex: 0 0 auto; width: 100%; - height: 48px; - font-size: 22px; + height: calc(var(--font-size-link) * 2); + font-size: calc(var(--font-size-link) * 0.9); color: inherit; border: 2px solid currentColor; outline: none; margin: 0; - padding: 0 24px; + padding: 0 var(--font-size-link); font-family: inherit; font-weight: inherit; box-sizing: border-box; @@ -308,6 +343,11 @@ text-decoration: none; display: flex; + img { + width: 48px; + height: 48px; + } + span { line-height: 48px; margin-left: 20px; diff --git a/website/static/images/graphics/brush.svg b/website/static/images/graphics/brush.svg index eb34378c3e..b86e74876d 100644 --- a/website/static/images/graphics/brush.svg +++ b/website/static/images/graphics/brush.svg @@ -1,4 +1,4 @@ - + diff --git a/website/static/images/graphics/discord.svg b/website/static/images/graphics/discord.svg new file mode 100644 index 0000000000..8c5a492dff --- /dev/null +++ b/website/static/images/graphics/discord.svg @@ -0,0 +1,3 @@ + + + diff --git a/website/static/images/graphics/github.svg b/website/static/images/graphics/github.svg new file mode 100644 index 0000000000..8db896567b --- /dev/null +++ b/website/static/images/graphics/github.svg @@ -0,0 +1,3 @@ + + + diff --git a/website/static/images/graphics/logotype.svg b/website/static/images/graphics/logotype.svg new file mode 100644 index 0000000000..13da53e0d5 --- /dev/null +++ b/website/static/images/graphics/logotype.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + diff --git a/website/static/images/graphics/reddit.svg b/website/static/images/graphics/reddit.svg new file mode 100644 index 0000000000..14ca813b5a --- /dev/null +++ b/website/static/images/graphics/reddit.svg @@ -0,0 +1,3 @@ + + + diff --git a/website/static/images/graphics/twitter.svg b/website/static/images/graphics/twitter.svg new file mode 100644 index 0000000000..7c1b035d7d --- /dev/null +++ b/website/static/images/graphics/twitter.svg @@ -0,0 +1,3 @@ + + + diff --git a/website/static/js/carousel.js b/website/static/js/carousel.js index 2294a8b865..db3ca0de53 100644 --- a/website/static/js/carousel.js +++ b/website/static/js/carousel.js @@ -1,14 +1,17 @@ +const FLING_VELOCITY_THRESHOLD = 10; +const FLING_VELOCITY_WINDOW_SIZE = 20; + let carouselImages; let carouselDirectionPrev; let carouselDirectionNext; let carouselDots; let carouselDescriptions; let carouselDragLastClientX; -let velocityDeltaWindow = Array.from({ length: 20 }, () => ({ time: 0, delta: 0 })); +let velocityDeltaWindow = Array.from({ length: FLING_VELOCITY_WINDOW_SIZE }, () => ({ time: 0, delta: 0 })); window.addEventListener("DOMContentLoaded", initializeCarousel); -window.addEventListener("pointerup", dragEnd); -window.addEventListener("scroll", dragEnd); +window.addEventListener("pointerup", () => dragEnd(false)); +window.addEventListener("scroll", () => dragEnd(true)); window.addEventListener("pointermove", dragMove); function initializeCarousel() { @@ -87,7 +90,7 @@ function dragBegin(event) { document.querySelector("#screenshots").classList.add("dragging"); } -function dragEnd() { +function dragEnd(dropWithoutVelocity) { if (!carouselImages) return; carouselDragLastClientX = undefined; @@ -108,7 +111,7 @@ function dragEnd() { const activeDotIndex = currentActiveDotIndex(); // If the speed is fast enough, slide to the next or previous image in that direction - if (Math.abs(recentVelocity) > 10) { + if (Math.abs(recentVelocity) > FLING_VELOCITY_THRESHOLD && !dropWithoutVelocity) { // Positive velocity should go to the previous image if (recentVelocity > 0) { // Don't apply the velocity-based fling if we're already snapping to the next image @@ -128,6 +131,7 @@ function dragEnd() { } // If we didn't slide in a direction due to clear velocity, just snap to the closest image + // This can be reached either by not entering the if statement above, or by its inner if statements not returning early and exiting back to this scope slideTo(clamp(closestImageIndex, 0, carouselDots.length - 1), true); } @@ -138,7 +142,7 @@ function dragMove(event) { const LEFT_MOUSE_BUTTON = 1; if (!(event.buttons & LEFT_MOUSE_BUTTON)) { - dragEnd(); + dragEnd(false); return; } diff --git a/website/static/js/navbar.js b/website/static/js/navbar.js index 466ad066a7..e565c3a9fc 100644 --- a/website/static/js/navbar.js +++ b/website/static/js/navbar.js @@ -15,40 +15,6 @@ let activeRippleIndex; window.addEventListener("DOMContentLoaded", initializeRipples); window.addEventListener("resize", () => animate(true)); -function setRipples(mediaQueryScaleFactor) { - const rippleSvgRect = rippleSvg.getBoundingClientRect(); - const rippleSvgLeft = rippleSvgRect.left; - const rippleSvgWidth = rippleSvgRect.width; - - let path = `M 0,${fullRippleHeight + 3} `; - - ripples.forEach((ripple) => { - if (!ripple.animationStartTime || !ripple.animationEndTime) return; - - const t = Math.min((Date.now() - ripple.animationStartTime) / (ripple.animationEndTime - ripple.animationStartTime), 1); - const height = fullRippleHeight * (ripple.goingUp ? ease(t) : 1 - ease(t)); - - const buttonRect = ripple.element.getBoundingClientRect(); - - const buttonCenter = buttonRect.width / 2; - const rippleCenter = RIPPLE_WIDTH / 2 * mediaQueryScaleFactor; - const rippleOffset = rippleCenter - buttonCenter; - - const rippleStartX = buttonRect.left - rippleSvgLeft - rippleOffset; - - const rippleRadius = RIPPLE_WIDTH / 2 * mediaQueryScaleFactor; - const handleRadius = rippleRadius * HANDLE_STRETCH; - - path += `L ${rippleStartX},${fullRippleHeight + 3} `; - path += `c ${handleRadius},0 ${rippleRadius - handleRadius},-${height} ${rippleRadius},-${height} `; - path += `s ${rippleRadius - handleRadius},${height} ${rippleRadius},${height} `; - }); - - path += `l ${rippleSvgWidth},0`; - - ripplePath.setAttribute("d", path); -} - function initializeRipples() { ripplesInitialized = true; @@ -110,6 +76,40 @@ function animate(forceRefresh) { } } +function setRipples(mediaQueryScaleFactor) { + const rippleSvgRect = rippleSvg.getBoundingClientRect(); + const rippleSvgLeft = rippleSvgRect.left; + const rippleSvgWidth = rippleSvgRect.width; + + let path = `M 0,${fullRippleHeight + 3} `; + + ripples.forEach((ripple) => { + if (!ripple.animationStartTime || !ripple.animationEndTime) return; + + const t = Math.min((Date.now() - ripple.animationStartTime) / (ripple.animationEndTime - ripple.animationStartTime), 1); + const height = fullRippleHeight * (ripple.goingUp ? ease(t) : 1 - ease(t)); + + const buttonRect = ripple.element.getBoundingClientRect(); + + const buttonCenter = buttonRect.width / 2; + const rippleCenter = RIPPLE_WIDTH / 2 * mediaQueryScaleFactor; + const rippleOffset = rippleCenter - buttonCenter; + + const rippleStartX = buttonRect.left - rippleSvgLeft - rippleOffset; + + const rippleRadius = RIPPLE_WIDTH / 2 * mediaQueryScaleFactor; + const handleRadius = rippleRadius * HANDLE_STRETCH; + + path += `L ${rippleStartX},${fullRippleHeight + 3} `; + path += `c ${handleRadius},0 ${rippleRadius - handleRadius},-${height} ${rippleRadius},-${height} `; + path += `s ${rippleRadius - handleRadius},${height} ${rippleRadius},${height} `; + }); + + path += `l ${rippleSvgWidth},0`; + + ripplePath.setAttribute("d", path); +} + function ease(x) { return 1 - (1 - x) * (1 - x); } diff --git a/website/templates/404.html b/website/templates/404.html index 5ca96b89f0..384c27ffc4 100644 --- a/website/templates/404.html +++ b/website/templates/404.html @@ -2,7 +2,7 @@ {% block title %}Page not found.{% endblock title %} {% block content %} -
+

Page not found (yet).

diff --git a/website/templates/base.html b/website/templates/base.html index e5b1c23878..fb0af2b6ec 100644 --- a/website/templates/base.html +++ b/website/templates/base.html @@ -2,7 +2,7 @@ - + Graphite | {% block title %}{% endblock title %} {% block head %}{% endblock head %} diff --git a/website/templates/index.html b/website/templates/index.html index c75efc567f..8ca2fcf81c 100644 --- a/website/templates/index.html +++ b/website/templates/index.html @@ -8,33 +8,7 @@ {% block content %}

@@ -98,7 +72,7 @@

View of the current alpha version of the Graphite editor with a blank canvas. Try this out at editor.graphite.rs - right in your browser. Send in your artwork to potentially be featured here in place of this blank canvas.

+ instantly in your browser. Send in your artwork to potentially be featured here in place of this blank canvas.

Interface mockup showcasing a photo editing project that utilizes Graphite's raster graphics pipeline, one of the upcoming roadmap milestones. Photo editing is not yet supported.

This last screenshot is currently identical to the previous one, serving as a placeholder. Work is ongoing to replace this image with a node graph mockup.

@@ -109,7 +83,7 @@
- +

Professional 2D content creation for everyone.

@@ -117,7 +91,7 @@ With great power comes great accessibility. Graphite is built on the belief that the best creative tools can be powerful and within reach of all.

- The software is designed with a friendly and intuitive interface where a delightful user experience is of first-class importance. It is available for free under an open source license and usable instantly through a web browser or an upcoming native client on Windows, Mac, and Linux.

@@ -131,7 +105,7 @@
- +

Available now for alpha testing.

@@ -197,7 +171,7 @@ color handling (ACES/OpenColorIO). Real-time collaboration. A rich ecosystem of custom nodes.

- Learn more about the planned technology in forthcoming Graphite releases. + Learn more about the planned technology in forthcoming Graphite releases:

Features
@@ -207,7 +181,7 @@
- +

Built for the future, powered by Rust.

@@ -249,15 +223,19 @@ Graphite is early in development and the most exciting, ambitious features are still to come. Enter your email below to receive only occasional announcements when major updates are ready for your enjoyment. The first newsletter will likely be sent out for the Graphite alpha milestone 2 release, featuring node-based editing, later this year.

-
+
- + +
+
+ +