pixel perfect scaling even on high density screens

This commit is contained in:
Corwin 2024-04-29 00:28:17 +01:00
parent 1991fbf056
commit 917d7b3d5a
No known key found for this signature in database
7 changed files with 60 additions and 37 deletions

View file

@ -1,6 +1,6 @@
import type { Metadata } from "next";
import "./globalStyles.css";
import StyledComponentsRegistry from "./registry";
import StyledComponentsRegistry, { BodyPixelRatio } from "./registry";
export const metadata: Metadata = {
title: "agb - a rust framework for making Game Boy Advance games",
@ -13,9 +13,9 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body>
<BodyPixelRatio>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</BodyPixelRatio>
</html>
);
}

View file

@ -16,6 +16,8 @@ import { ExternalLink } from "@/components/externalLink";
const HelpLinks = styled.div`
display: flex;
flex-wrap: wrap;
gap: 16px;
justify-content: space-around;
`;

View file

@ -1,8 +1,8 @@
"use client";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
import { ServerStyleSheet, StyleSheetManager } from "styled-components";
import styled, { ServerStyleSheet, StyleSheetManager } from "styled-components";
export default function StyledComponentsRegistry({
children,
@ -27,3 +27,18 @@ export default function StyledComponentsRegistry({
</StyleSheetManager>
);
}
const BodyWithPixelRatio = styled.body<{
$pixel?: number;
}>`
--device-pixel: calc(1px / ${(props) => props.$pixel});
`;
export function BodyPixelRatio({ children }: { children: React.ReactNode }) {
const [pixel, setPixel] = useState(1);
useEffect(() => {
setPixel(window.devicePixelRatio);
}, []);
return <BodyWithPixelRatio $pixel={pixel}>{children}</BodyWithPixelRatio>;
}

View file

@ -3,13 +3,11 @@ import { Games, ShowcaseGame } from "../games";
import { ContentBlock } from "@/components/contentBlock";
import { ExternalLink } from "@/components/externalLink";
import Link from "next/link";
import Image, { StaticImageData } from "next/image";
import {
ScreenshotsWrapper,
ScreenshotWrapper,
BackToShowcaseWrapper,
DescriptionAndScreenshots,
Description,
Screenshots,
} from "./styled";
export async function generateStaticParams() {
@ -51,18 +49,6 @@ function DeveloperNames({ names }: { names: string[] }) {
return first.join(", ") + `, and ${names[names.length - 1]}`;
}
function Screenshots({ screenshots }: { screenshots: StaticImageData[] }) {
return (
<ScreenshotsWrapper>
{screenshots.map((screenshot) => (
<ScreenshotWrapper key={screenshot.src}>
<Image src={screenshot} alt="" />
</ScreenshotWrapper>
))}
</ScreenshotsWrapper>
);
}
function Display({ game }: { game: ShowcaseGame }) {
return (
<>

View file

@ -1,19 +1,35 @@
"use client";
import { styled } from "styled-components";
import Image, { StaticImageData } from "next/image";
export const ScreenshotsWrapper = styled.div`
export function Screenshots({
screenshots,
}: {
screenshots: StaticImageData[];
}) {
return (
<ScreenshotsWrapper>
{screenshots.map((screenshot) => (
<Screenshot src={screenshot} alt="" key={screenshot.src} />
))}
</ScreenshotsWrapper>
);
}
const ScreenshotsWrapper = styled.div`
flex: 4;
text-align: center;
`;
export const ScreenshotWrapper = styled.div`
text-align: center;
img {
width: 100%;
width: round(down, 100%, 240px);
height: auto;
image-rendering: pixelated;
}
const Screenshot = styled(Image)`
width: 100%;
width: max(
round(down, 100%, calc(240 * var(--device-pixel))),
calc(240 * var(--device-pixel))
);
height: auto;
image-rendering: pixelated;
`;
export const Description = styled.div`
@ -26,6 +42,10 @@ export const Description = styled.div`
export const DescriptionAndScreenshots = styled.div`
display: flex;
gap: 16px;
@media (max-width: 1000px) {
display: block;
}
`;
export const BackToShowcaseWrapper = styled.div`

View file

@ -6,20 +6,23 @@ import Image from "next/image";
export const GameGrid = styled.div`
display: grid;
grid-template-columns: repeat(auto-fit, 600px);
grid-template-columns: repeat(auto-fit, min(100vw, 600px));
justify-content: center;
gap: 48px;
`;
export const GameImage = styled(Image)`
width: 100%;
width: round(down, 100%, 240px);
width: max(
round(down, 100%, calc(240 * var(--device-pixel))),
min(calc(240 * var(--device-pixel)), 100vw)
);
height: auto;
image-rendering: pixelated;
`;
export const GameDisplay = styled(Link)`
width: 600px;
width: 100%;
text-align: center;
color: black;
text-decoration: none;

View file

@ -14,11 +14,8 @@ const Section = styled.section<{ $color: string }>`
const CENTERED_CSS = `
margin-left: auto;
margin-right: auto;
max-width: 60%;
@media (max-width: 40rem) {
max-width: 90%;
}
width: 60%;
min-width: min(95%, 1000px);
`;
export const CenteredBlock = styled.div`