Private
Public Access
1
0

chg: dev: remove the wrongly implemented font installation in docker - & replace it with static font on BattleCardGenerator (it solves the shareable image problem on bare-metal too) #8

This commit is contained in:
2026-04-21 14:18:59 +02:00
parent 8935216525
commit 085e010907
7 changed files with 66 additions and 21 deletions

View File

@@ -22,12 +22,6 @@ RUN install-php-extensions \
apcu \
sodium
RUN apt-get update && apt-get install -y --no-install-recommends \
fonts-dejavu-core \
fontconfig \
&& fc-cache -f -v \
&& rm -rf /var/lib/apt/lists/*
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
RUN printf '[opcache]\nopcache.enable=1\nopcache.memory_consumption=256\nopcache.max_accelerated_files=20000\nopcache.validate_timestamps=0\n' \
> "$PHP_INI_DIR/conf.d/opcache.ini"

View File

@@ -287,11 +287,12 @@ git push origin v2026.01
---
## Game Documentation
## Documentation
For detailed information about game mechanics, bonus systems, and scoring rules, see the [docs](./docs/) directory:
For detailed information about game mechanics, bonus systems, fonts, and other technical details, see the [docs](./docs/) directory:
- **[Bonus Points System](./docs/game-mechanics/BONUS_POINTS_SYSTEM.md)** — Complete reference for all bonus point types, calculation rules, and implementation details
- **[Fonts](./docs/FONTS.md)** — TrueType fonts used for server-side image generation
---

Binary file not shown.

View File

@@ -12,7 +12,9 @@ import { array } from 'prop-types';
import { formatDuration } from '@global-utils/format';
import Dialog from '@mui/material/Dialog';
import { createTheme, styled, ThemeProvider } from '@mui/material/styles';
import { Avatar, BonusPoints, StatRow } from '@global-components';
import { Avatar } from './battle-dialog/Avatar';
import { BonusPoints } from './battle-dialog/BonusPoints';
import { StatRow } from './battle-dialog/StatRow';
const darkTheme = createTheme({ palette: { mode: 'dark' } });
@@ -69,11 +71,11 @@ export const BattleDialog = ({ games }) => {
const endReason = resign
? `${resign.charAt(0).toUpperCase() + resign.slice(1)} resigned`
: 26 <= maxPoints ? 'Points' : 'Abandoned';
const canShare = !canContinue;
const bothRegistered = game.bothRegistered;
const canContinue = bothRegistered && !resign && 26 > maxPoints;
const playUrl = `${window.location.origin}/play/${game.uuid}`;
const shareUrl = `${window.location.origin}/battle/${game.uuid}`;
const canContinue = bothRegistered && !resign && 26 > maxPoints;
const canShare = !canContinue;
const playUrl = `${window.location.origin}/play/${game.uuid}`;
const duration = formatDuration(game.created, game.date);
const pointDiff = Math.abs((game.redPoints ?? 0) - (game.bluePoints ?? 0));

View File

@@ -28,6 +28,7 @@ services:
App\Service\BattleCardGenerator:
arguments:
$cacheDir: '%kernel.project_dir%/var/og-cache'
$fontPath: '%kernel.project_dir%/assets/fonts/Carlito-Bold.ttf'
$minioMediaStorage: '@mineseeker.media.storage'
Aws\S3\S3Client:

47
docs/FONTS.md Normal file
View File

@@ -0,0 +1,47 @@
# Font Files
This directory contains TrueType Font (TTF) files used for server-side image generation with PHP GD.
## Carlito-Bold.ttf
- **Font:** Carlito Bold
- **Source:** Google Fonts (Carlito Project)
- **License:** SIL Open Font License 1.1
- **URL:** https://github.com/googlefonts/carlito
- **Usage:** Used by `BattleCardGenerator` service for generating battle card OG images
- **Note:** Carlito is a metric-compatible font family to Calibri
## Why TTF instead of @fontsource?
The `@fontsource` npm packages provide WOFF/WOFF2 files for web usage, but PHP's GD library (`imagettftext()`) requires TrueType Font (TTF) files for server-side text rendering.
## Alternatives
If you want to use a different font:
1. **Install system fonts:**
```bash
# Find available TTF fonts
find /usr/share/fonts -name "*.ttf" -type f
# Copy desired font
cp /usr/share/fonts/path/to/Font-Bold.ttf assets/fonts/
```
2. **Download from Google Fonts:**
```bash
# Visit https://fonts.google.com
# Download the font family
# Extract the TTF file from the zip
```
3. **Update service configuration:**
Edit `config/services.yaml` and update the `$fontPath` parameter.
## Cache Clearing
After changing fonts, clear the OG image cache:
```bash
rm -rf var/og-cache/*
```

View File

@@ -34,11 +34,11 @@ final class BattleCardGenerator
{
private const int WIDTH = 1200;
private const int HEIGHT = 630;
private const string FONT = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf';
private const int AVATAR_SIZE = 120;
public function __construct(
private readonly string $cacheDir,
private readonly string $fontPath,
private readonly FilesystemOperator $minioMediaStorage,
private readonly LoggerInterface $logger,
) {
@@ -159,7 +159,7 @@ final class BattleCardGenerator
$redBonusPoints = $game->redBonusPoints ?? 0;
$blueBonusPoints = $game->blueBonusPoints ?? 0;
$bonusText = number_format((float)$redBonusPoints, 1, '.', '') . ' * : * ' . number_format((float)$blueBonusPoints, 1, '.', '');
$this->centeredText($im, $bonusText, 24, self::WIDTH / 2, 425, $gold);
$this->centeredText($im, $bonusText, 24, self::WIDTH / 2, 445, $gold);
if ($winner === 'red') {
$resultText = $redName . ' wins';
@@ -176,11 +176,11 @@ final class BattleCardGenerator
}
if ($resultText !== '') {
$this->centeredText($im, $resultText, 30, self::WIDTH / 2, 475, $resultColor);
$this->centeredText($im, $resultText, 30, self::WIDTH / 2, 495, $resultColor);
}
if ($resign) {
$this->centeredText($im, ucfirst($resign) . ' resigned', 18, self::WIDTH / 2, 508, $muted);
$this->centeredText($im, ucfirst($resign) . ' resigned', 18, self::WIDTH / 2, 528, $muted);
}
$this->centeredText($im, 'mineseeker.hu', 16, self::WIDTH / 2, self::HEIGHT - 20, $muted);
@@ -273,23 +273,23 @@ final class BattleCardGenerator
/** Draw initials */
$initials = mb_strtoupper(mb_substr($name, 0, 2));
$fontSize = 48;
$bbox = imagettfbbox($fontSize, 0, self::FONT, $initials);
$bbox = imagettfbbox($fontSize, 0, $this->fontPath, $initials);
$textW = $bbox[2] - $bbox[0];
$textH = $bbox[1] - $bbox[7];
$textX = $cx - $textW / 2;
$textY = $cy + $textH / 2;
$white = imagecolorallocate($im, 255, 255, 255);
imagettftext($im, $fontSize, 0, (int)$textX, (int)$textY, $white, self::FONT, $initials);
imagettftext($im, $fontSize, 0, (int)$textX, (int)$textY, $white, $this->fontPath, $initials);
}
}
/** Render text centered on $cx. */
private function centeredText(GdImage $im, string $text, int $size, int $cx, int $y, int $color): void
{
$bbox = imagettfbbox($size, 0, self::FONT, $text);
$bbox = imagettfbbox($size, 0, $this->fontPath, $text);
$w = $bbox[2] - $bbox[0];
imagettftext($im, $size, 0, (int)($cx - $w / 2), $y, $color, self::FONT, $text);
imagettftext($im, $size, 0, (int)($cx - $w / 2), $y, $color, $this->fontPath, $text);
}
/** Render text centered on $cx, shrinking font size to fit $maxWidth. */
@@ -302,7 +302,7 @@ final class BattleCardGenerator
int $color,
int $maxWidth
): void {
$bbox = imagettfbbox($size, 0, self::FONT, $text);
$bbox = imagettfbbox($size, 0, $this->fontPath, $text);
$w = $bbox[2] - $bbox[0];
if ($w > $maxWidth) {
$size = (int)($size * $maxWidth / $w);