SVG-портреты рыб в дневнике и карточке улова + убраны эмодзи рыб (Этап 42): 32 flat-SVG портрета в assets/fish/fish-<id>.svg (viewBox 0 0 160 100, flat-заливки, цвета var(--f1..f4,hsl-fallback) с инлайн-fallback в каждом элементе, переменные НЕ объявляются на <svg>/<g> — иначе перекраска сквозь <use> не сработает). Встраивание — node tools/embed-fish.mjs (идемпотентно, блок между маркерами FISH-SVG:BEGIN/END сразу после <body>, 32 <symbol id="fish-<id>" viewBox="0 0 160 100">, валидация + самопроверка + check.mjs внутри; повторный запуск — md5-стабильно). Приёмка — tools/fish-preview.html (file://: сетка 32 + демо перекраски вариантов). Дневник (пойманные) и карточка улова — <use href="#fish-<id>"> вместо дублирующихся эмодзи (🐟 был у 11 видов); showCard ставит href у #cardFishUse; перекраска вариантов — CSS-переменные --f1/--f3 в #card.<variant>-card .bigemoji (copper/gold/quartz/emerald/diamond; silver/rainbow — существующие filter, boss — filter). Эмодзи рыб УБРАНЫ полностью: поле emoji удалено из всех 32 записей SPECIES (пин lc1 fieldsOk обновлён в том же коммите), тосты обрыва/срыва без эмодзи, иконка квеста catch_species — mini-SVG .qfish (<use>, скоуп .jrow .je из-за специфичности правила портрета), рыбка-маркер дистанции на канвасе — drawFishMark (path), иконки ачивок/воблера — глифы уже бывшие в субсете (🏅/💪/🗺️/⚓/🌊/🎣). Emoji-шрифт перегенерирован (tools/emoji-font.py): субсет 64→52 глифа, woff2 89→65 КБ. Тесты: пины lc1 (32 symbol + spriteIdsOk по всем id) и M6-карточка (href #fish-carass у всех 8 вариантов); 193/193 PASS, exit 0; check.mjs OK; emoji-font --check OK (52); grep 12 рыбных эмодзи — 0 вхождений. Игровая логика/баланс/пины роллов не тронуты (визуальный этап). Доки: AGENTS.md (строка «Портреты рыб (SVG-спрайт)» в «Где крутить»), DEVLOG (Этап 42, обе части).

This commit is contained in:
2026-09-20 18:23:54 +03:00
parent c250068e8a
commit cb502e4a17
38 changed files with 2026 additions and 69 deletions
+1
View File
@@ -53,6 +53,7 @@
- Хаб «Меню» (Э29): оверлей `#gamemenu` — кнопки «Продолжить» (`#btnGmResume`: uiOpen=false + `YG.gameplayStart()`), Магазин/Достижения/Дневник (`fromMenuShop(tab)` → `openShop('tackle'|'ach'|'journal')`), «Инструкции» (`#btnGmHowto` → `#menu`; «Играть» вернёт в игру), звук `#btnMute` и сброс `#btnReset` (→ `#resetDlg`) — ПЕРЕНЕСЕНЫ из HUD (id сохранены; в `.hudbtns` остались только 🛒 и ⏸). «В меню» НЕ меняет `state` — сессия (заброс/вываживание) заморожена под оверлеем и продолжается с того же места; `state='MENU'` теперь только при загрузке/после сброса (там показывается `#menu` с инструкциями — «старт новой игры» прежний). Флаг `shopFromMenu`: лавка, открытая из «Меню», при × возвращает в `#gamemenu` (uiOpen остаётся true, БЕЗ `YG.gameplayStart()`); лавка из HUD/`#coins` — как раньше, в игру. Z-порядок: `#gamemenu` в DOM позже `#shop`/`#resetDlg` (тот же z-index) — при открытии лавки/сброса из «Меню» гменю прячется, иначе перекрыл бы их.
- Монеты → лавка (Э29): клик по `#coins` (pointer-events:auto + cursor в CSS) → `openShop('tackle')` — «Лавка рыбака» на вкладке «Лавка» (`#tabTackle`, эмодзи 🛒, `T.tab_tackle` 'Лавка'/'Shop'; RU-секции «🎣 Удилища»/«🪱 Приманки» внутри не тронуты). `openShop(tab?)` — аргумент форсит вкладку (`syncTabs()` синк активных классов, вынесен из `setTab`); HUD 🛒 зовёт `openShop()` без аргумента — помнит последнюю вкладку.
- Встроенный emoji-шрифт (Э28): все emoji UI и canvas рисует вшитый шрифт — субсет Noto Color Emoji (COLRv1, OFL) как base64 `@font-face font-family:'EmojiEmbedded'` в index.html между маркерами `<!-- EMOJI-FONT:BEGIN/END -->` (внешний .woff2 невозможен: публикуется только один index.html). В font-stack `html,body` и во всех `ctx.font` (константа `UI_FONT`, секция «ОТРИСОВКА») стоит ПЕРВЫМ — единый Google-стиль emoji на всех платформах; headless-скриншоты не зависят от системных шрифтов. Первый кадр ждёт `document.fonts.load('16px "EmojiEmbedded"')` с timeout-фолбэком 1.5 с. Генератор `tools/emoji-font.py` (venv: `python3 -m venv tools/.venv && tools/.venv/bin/pip install fonttools brotli`; исходник `tools/fonts-src/NotoColorEmoji-Regular.ttf` из google/fonts, всё в gitignore): `python3 tools/emoji-font.py` — перегенерация по текущим emoji index.html (ОБЯЗАТЕЛЬНО при добавлении новых emoji), `--check` — падает, если субсет не покрывает index.html (✓ № ● ○ ↩ — в NCE их нет, это ок, рисуются системными шрифтами). Тест §Y7 (tests/test.js) гоняет `document.fonts.check('16px "EmojiEmbedded"','🪙')`; семейство переименовывать нельзя (тест + @font-face + UI_FONT).
- **Портреты рыб (SVG-спрайт)**: исходники `assets/fish/fish-<id>.svg` (32 файла, viewBox 0 0 160 100, цвета `var(--f1..f4, hsl-fallback)`; переменные НЕ объявлять на `<svg>`/`<g>`); встраивание — `node tools/embed-fish.mjs` (идемпотентно, блок между маркерами `FISH-SVG:BEGIN/END` в index.html, сразу после `<body>`; самопроверка + `check.mjs` внутри); приёмка — `tools/fish-preview.html` (file://); дневник/карточка показывают через `<use href="#fish-<id>">` (дневник `.jrow .je svg`, карточка `#cardEmoji svg`, `showCard` ставит href у `#cardFishUse`); перекраска вариантов — CSS-переменные `--f1`/`--f3` в `#card.<variant>-card .bigemoji` (наследуются сквозь `<use>`; silver/rainbow — существующие filter); правка портрета = правка `assets/fish/*.svg` + повторный запуск embed-скрипта. Эмодзи рыб УБРАНЫ (этап 42): поле emoji удалено из SPECIES, тосты без эмодзи, иконка квеста catch_species — mini-SVG `<svg class="qfish"><use href="#fish-<id>">`; субсет emoji-шрифта перегенерирован (рыбных глифов нет).
## Запуск и публикация
+26
View File
@@ -0,0 +1,26 @@
<!-- Удильщик (angler): круглое «пузырь»-тело ~1.5:1, большой тёмный рот с белыми зубами, маленький хвост, «удочка» над головой со светящимся шариком -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: маленький «веер» слева -->
<path fill="var(--f3,hsl(280,50%,32%))" d="M42 50 C32 38 16 36 10 46 C18 49 20 53 16 60 C12 68 20 74 30 68 C37 63 41 57 42 50 Z"/>
<!-- спинной плавник: небольшой горб на спине -->
<path fill="var(--f3,hsl(280,50%,32%))" d="M60 24 C66 12 82 11 92 20 C80 18 68 20 62 25 Z"/>
<!-- тело: круглый «пузырь» ~1.5:1, голова справа перетекает в тело без шеи -->
<path fill="var(--f1,hsl(280,45%,48%))" d="M38 52 C38 32 60 20 88 21 C114 22 133 36 134 56 C134 74 114 88 86 88 C58 88 38 74 38 52 Z"/>
<!-- брюхо: светлая нижняя полоса -->
<path fill="var(--f2,hsl(280,30%,70%))" d="M134 56 C134 74 114 88 86 88 C58 88 38 74 38 52 C44 62 56 70 70 73 C96 78 120 72 134 56 Z"/>
<!-- узор: тёмные пятна на теле -->
<circle fill="var(--f4,hsl(280,45%,26%))" cx="66" cy="46" r="4.5"/>
<circle fill="var(--f4,hsl(280,45%,26%))" cx="82" cy="34" r="3.5"/>
<circle fill="var(--f4,hsl(280,45%,26%))" cx="58" cy="62" r="3"/>
<!-- рот: широкая тёмная щель от носа до под глазом -->
<path fill="var(--f4,hsl(280,45%,26%))" d="M133 54 C121 60 106 61 95 58 C107 70 127 67 133 54 Z"/>
<!-- зубы: белые треугольнички в щели -->
<path fill="#fff" d="M119 57 L126 58 L122.5 63 Z M109 59 L116 59.5 L112.5 64.5 Z M99 59.5 L106 60 L102.5 65 Z M92 58.8 L98 59.3 L95 63.8 Z"/>
<!-- «удочка»: тонкая дуга от лба вверх-вперёд -->
<path fill="none" stroke="var(--f4,hsl(280,45%,26%))" stroke-width="3" stroke-linecap="round" d="M117 25 C116 12 128 5 145 8"/>
<!-- светящийся шарик на конце удочки -->
<circle fill="#ffe9a8" cx="145" cy="8" r="4"/>
<!-- глаз: белый круг + зрачок -->
<circle fill="#fff" cx="108" cy="41" r="6.5"/>
<circle fill="#142638" cx="109.5" cy="41" r="3.2"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

+26
View File
@@ -0,0 +1,26 @@
<!-- Плотва (bleak): невысокое удлинённое тело ~3:1, серебристое, мелкий вилочный хвост, тонкая тёмная полоса вдоль спины -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: мелкий вилочный -->
<path fill="var(--f3,hsl(200,50%,32%))" d="M35 42 L14 32 L24.5 47 L14 62 L35 52 Z"/>
<!-- тело: невысокое удлинённое, заострённая морда -->
<path fill="var(--f2,hsl(200,30%,70%))" d="M144 47 C132 36 110 30 84 30 C56 30 40 35 34 41 L34 53 C40 59 56 63 84 63 C110 63 132 58 144 47 Z"/>
<!-- брюхо: светлее -->
<path fill="var(--f2b,hsl(200,25%,82%))" d="M144 47 C132 58 110 63 84 63 C56 63 40 59 34 53 C40 55 56 58.5 84 58.5 C110 58.5 132 54.5 144 47 Z"/>
<!-- тонкая тёмная полоса вдоль верхнего края спины -->
<path fill="var(--f1,hsl(200,45%,48%))" d="M144 47 C132 36 110 30 84 30 C56 30 40 35 34 41 C40 39 56 34.5 84 34.5 C110 34.5 132 39.5 144 47 Z"/>
<!-- спинной плавник: низкий -->
<path fill="var(--f3,hsl(200,50%,32%))" d="M68 31 Q83 10 102 31.5 Z"/>
<!-- грудной плавник -->
<path fill="var(--f3,hsl(200,50%,32%))" d="M112 51 C107 56 107 61.5 112 64.5 C115.5 60 116.5 55.5 114 51.5 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(200,50%,32%))" d="M82 63 L77 71 L89 64 Z"/>
<!-- анальный плавник -->
<path fill="var(--f3,hsl(200,50%,32%))" d="M62 62.5 L56 70.5 L68 63.5 Z"/>
<!-- узор: тёмные точки вдоль бока -->
<ellipse fill="var(--f4,hsl(200,45%,26%))" cx="56" cy="48" rx="3.5" ry="2.2"/>
<ellipse fill="var(--f4,hsl(200,45%,26%))" cx="76" cy="46.5" rx="3.5" ry="2.2"/>
<ellipse fill="var(--f4,hsl(200,45%,26%))" cx="96" cy="45.5" rx="3.5" ry="2.2"/>
<!-- глаз -->
<circle fill="#fff" cx="127" cy="42" r="4.5"/>
<circle fill="#142638" cx="128" cy="42" r="2.2"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+14
View File
@@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path d="M38 50 L16 36 L26 50 L16 64 Z" fill="var(--f3,hsl(210,50%,32%))"/>
<path d="M36 50 Q40 18 86 16 Q130 18 146 50 Q130 82 86 84 Q40 82 36 50 Z" fill="var(--f1,hsl(210,45%,48%))"/>
<path d="M36 50 Q40 82 86 84 Q130 82 146 50 Q128 66 86 66 Q50 64 36 50 Z" fill="var(--f2,hsl(210,30%,70%))"/>
<path d="M44 30 Q76 2 128 16 Q136 26 134 36 Q84 12 44 30 Z" fill="var(--f3,hsl(210,50%,32%))"/>
<path d="M98 56 Q120 60 116 76 Q102 72 94 62 Z" fill="var(--f3,hsl(210,50%,32%))"/>
<path d="M80 82 Q92 92 108 86 Q96 82 86 80 Z" fill="var(--f3,hsl(210,50%,32%))"/>
<path d="M46 42 Q92 34 140 46 Q92 48 46 42 Z" fill="var(--f4,hsl(210,45%,26%))"/>
<path d="M64 28 Q70 24 76 28 Q70 34 64 28 Z" fill="var(--f4,hsl(210,45%,26%))"/>
<path d="M84 24 Q90 20 96 24 Q90 30 84 24 Z" fill="var(--f4,hsl(210,45%,26%))"/>
<path d="M104 30 Q110 26 116 30 Q110 36 104 30 Z" fill="var(--f4,hsl(210,45%,26%))"/>
<circle cx="126" cy="42" r="7" fill="#fff"/>
<circle cx="127.5" cy="42" r="3.2" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+10
View File
@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path d="M40 50 L14 30 L24 50 L14 70 Z" fill="var(--f3,hsl(45,50%,32%))"/>
<path d="M36 50 Q60 22 100 24 Q132 27 144 50 Q132 73 100 76 Q60 78 36 50 Z" fill="var(--f1,hsl(45,45%,48%))"/>
<path d="M144 50 Q132 73 100 76 Q60 78 36 50 Q64 66 104 66 Q130 64 144 50 Z" fill="var(--f2,hsl(45,30%,70%))"/>
<path d="M76 28 Q90 6 114 21 Q96 24 80 29 Z" fill="var(--f3,hsl(45,50%,32%))"/>
<path d="M102 54 Q124 58 120 74 Q106 70 98 60 Z" fill="var(--f3,hsl(45,50%,32%))"/>
<path d="M84 72 Q96 84 108 78 Q98 74 88 70 Z" fill="var(--f3,hsl(45,50%,32%))"/>
<circle cx="124" cy="42" r="7" fill="#fff"/>
<circle cx="125.5" cy="42" r="3.2" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 751 B

+17
View File
@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path d="M 36 50 L 10 24 Q 30 50 10 76 Z" fill="var(--f3,hsl(30,50%,32%))"/>
<path d="M 44 24 C 56 7 84 3 106 10 C 90 12 70 17 58 25 Z" fill="var(--f3,hsl(30,50%,32%))"/>
<path d="M 54 78 C 56 90 64 97 75 97 C 69 89 65 83 61 78 Z" fill="var(--f3,hsl(30,50%,32%))"/>
<path d="M 28 50 C 30 28 58 14 90 14 C 118 14 136 28 142 46 C 143 49 143 51 142 54 C 136 72 118 86 90 86 C 58 86 30 72 28 50 Z" fill="var(--f1,hsl(30,45%,48%))"/>
<path d="M 142 54 C 136 72 118 86 90 86 C 58 86 30 72 28 50 L 34 54 C 44 68 62 76 90 76 C 116 76 134 68 142 54 Z" fill="var(--f2,hsl(30,30%,70%))"/>
<path d="M 100 46 C 112 48 120 56 121 67 C 112 63 103 57 98 51 Z" fill="var(--f3,hsl(30,50%,32%))"/>
<circle cx="64" cy="38" r="4" fill="var(--f4,hsl(30,45%,26%))"/>
<circle cx="84" cy="50" r="3.5" fill="var(--f4,hsl(30,45%,26%))"/>
<circle cx="100" cy="34" r="3" fill="var(--f4,hsl(30,45%,26%))"/>
<circle cx="76" cy="62" r="3" fill="var(--f4,hsl(30,45%,26%))"/>
<circle cx="92" cy="26" r="2.5" fill="var(--f4,hsl(30,45%,26%))"/>
<circle cx="124" cy="40" r="7" fill="#fff"/>
<circle cx="126" cy="40" r="3.5" fill="#142638"/>
<path d="M 140 48 C 146 50 149 53 150 57" fill="none" stroke="var(--f4,hsl(30,45%,26%))" stroke-width="2" stroke-linecap="round"/>
<path d="M 138 54 C 144 57 146 61 147 65" fill="none" stroke="var(--f4,hsl(30,45%,26%))" stroke-width="2" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+17
View File
@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path d="M28 50 L12 36 L20 50 L12 64 Z" fill="var(--f3,hsl(260,50%,32%))"/>
<path d="M26 50 Q36 30 70 27 L124 27 Q140 30 142 45 Q139 58 128 62 Q108 76 80 77 Q46 75 26 50 Z" fill="var(--f1,hsl(260,45%,48%))"/>
<path d="M30 55 Q48 74 80 75 Q108 74 126 61 Q114 76 80 77 Q47 75 30 55 Z" fill="var(--f2,hsl(260,30%,70%))"/>
<path d="M74 27 Q94 10 112 26 Q92 22 74 27 Z" fill="var(--f3,hsl(260,50%,32%))"/>
<path d="M100 58 Q118 62 114 78 Q102 71 96 61 Z" fill="var(--f3,hsl(260,50%,32%))"/>
<path d="M58 40 Q65 36 72 40 Q65 46 58 40 Z" fill="var(--f4,hsl(260,45%,26%))"/>
<path d="M80 46 Q87 42 94 46 Q87 52 80 46 Z" fill="var(--f4,hsl(260,45%,26%))"/>
<path d="M48 52 Q55 48 62 52 Q55 58 48 52 Z" fill="var(--f4,hsl(260,45%,26%))"/>
<path d="M116 54 Q132 52 142 45 Q137 58 126 61 Q118 58 116 54 Z" fill="var(--f4,hsl(260,45%,26%))"/>
<path d="M141 44 Q152 36 156 26" fill="none" stroke="var(--f4,hsl(260,45%,26%))" stroke-width="2" stroke-linecap="round"/>
<path d="M142 50 Q154 52 158 62" fill="none" stroke="var(--f4,hsl(260,45%,26%))" stroke-width="2" stroke-linecap="round"/>
<path d="M127 55 Q116 51 106 48" fill="none" stroke="var(--f4,hsl(260,45%,26%))" stroke-width="2" stroke-linecap="round"/>
<path d="M124 60 Q112 66 102 66" fill="none" stroke="var(--f4,hsl(260,45%,26%))" stroke-width="2" stroke-linecap="round"/>
<circle cx="116" cy="36" r="5" fill="#fff"/>
<circle cx="117.5" cy="36" r="2.4" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+16
View File
@@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path fill="var(--f3,hsl(25,50%,32%))" d="M36 44 C24 36 15 28 10 22 C14 38 19 46 26 52 C19 58 14 68 12 82 C20 74 28 66 38 60 Z"/>
<path fill="var(--f3,hsl(25,50%,32%))" d="M106 40 C102 18 92 6 80 6 C60 6 42 22 30 46 C55 38 85 36 106 40 Z"/>
<path fill="var(--f1,hsl(25,45%,48%))" d="M146 53 C142 42 133 35 117 32 C92 27 56 29 34 44 L30 52 C42 66 66 74 92 73 C117 72 140 64 146 53 Z"/>
<path fill="var(--f2,hsl(25,30%,70%))" d="M146 53 C140 64 117 72 92 73 C66 74 42 66 30 52 C50 60 75 63 98 62 C120 60 138 57 146 53 Z"/>
<path fill="var(--f4,hsl(25,45%,26%))" d="M97 34 C99 44 99 54 97 60 L104 60 C106 54 106 44 104 34 Z"/>
<path fill="var(--f4,hsl(25,45%,26%))" d="M81 33 C83 43 83 53 81 62 L88 62 C90 53 90 43 88 33 Z"/>
<path fill="var(--f4,hsl(25,45%,26%))" d="M65 33 C67 43 67 53 65 62 L72 62 C74 53 74 43 72 33 Z"/>
<path fill="var(--f4,hsl(25,45%,26%))" d="M49 36 C51 44 51 52 49 59 L55 59 C57 52 57 44 55 36 Z"/>
<path fill="var(--f3,hsl(25,50%,32%))" d="M114 54 C106 58 102 64 103 70 C110 68 116 62 118 56 Z"/>
<path fill="var(--f3,hsl(25,50%,32%))" d="M74 68 C70 74 68 80 70 84 C76 80 79 75 80 70 Z"/>
<path fill="var(--f3,hsl(25,50%,32%))" d="M56 66 C52 72 51 78 53 82 C58 78 61 73 62 68 Z"/>
<path fill="var(--f4,hsl(25,45%,26%))" d="M146 56 C141 58 136 58 132 56 C136 60 142 60 146 58 Z"/>
<circle cx="128" cy="47" r="6" fill="#fff"/>
<circle cx="129.5" cy="47" r="3" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+24
View File
@@ -0,0 +1,24 @@
<!-- Сиг (cisco): бирюзово-серебристая удлинённая рыба (~3:1, тело выше, чем у сельди), высокий спинной плавник, вилочный хвост, тонкая тёмная спинная кромка, тёмная боковая линия вдоль середины тела от жабер к хвосту -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: вилочный -->
<path fill="var(--f3,hsl(172,48%,32%))" d="M40 45 L12 30 L24 49 L12 68 L40 53 Z"/>
<!-- тело: удлинённое бирюзово-серебристое, чуть выше, чем у сельди, заострённая морда -->
<path fill="var(--f2,hsl(172,28%,68%))" d="M146 49 C134 39 112 31 86 31 C58 31 42 37 34 43 L34 55 C42 62 58 67 86 67 C112 67 134 61 146 49 Z"/>
<!-- брюхо: светлее -->
<path fill="var(--f2b,hsl(172,22%,82%))" d="M146 49 C134 61 112 67 86 67 C58 67 42 62 34 55 C42 58 58 63 86 63 C112 63 134 58 146 49 Z"/>
<!-- тёмная спинная кромка: тонкая полоса -->
<path fill="var(--f1,hsl(172,42%,46%))" d="M146 49 C134 39 112 31 86 31 C58 31 42 37 34 43 C42 40.5 58 35.5 86 35.5 C112 35.5 134 41 146 49 Z"/>
<!-- спинной плавник: высокий (характерно для сиговых) -->
<path fill="var(--f3,hsl(172,48%,32%))" d="M64 33.5 Q80 -10 98 32.5 Z"/>
<!-- грудной плавник -->
<path fill="var(--f3,hsl(172,48%,32%))" d="M112 54 C107 59 107 64.5 112 67.5 C115.5 63 116.5 58.5 114 54.5 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(172,48%,32%))" d="M84 67 L79 75 L91 68.5 Z"/>
<!-- анальный плавник -->
<path fill="var(--f3,hsl(172,48%,32%))" d="M62 65.5 L56 73.5 L68 66.5 Z"/>
<!-- узор: тёмная боковая линия — ровная полоска вдоль середины тела от жабер к хвосту -->
<path fill="var(--f4,hsl(172,42%,26%))" d="M118 47.9 L38 48.4 L38 50.6 L118 50.1 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="128" cy="43.5" r="4.5"/>
<circle fill="#142638" cx="129" cy="43.5" r="2.2"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+28
View File
@@ -0,0 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<ellipse cx="25" cy="52" rx="10.5" ry="5.5" fill="var(--f3,hsl(0,50%,32%))"/>
<ellipse cx="24" cy="52" rx="12" ry="5" fill="var(--f3,hsl(0,50%,32%))" transform="rotate(-27 36 52)"/>
<ellipse cx="24" cy="52" rx="12" ry="5" fill="var(--f3,hsl(0,50%,32%))" transform="rotate(27 36 52)"/>
<ellipse cx="25" cy="52" rx="11" ry="4.5" fill="var(--f3,hsl(0,50%,32%))" transform="rotate(-55 36 52)"/>
<ellipse cx="25" cy="52" rx="11" ry="4.5" fill="var(--f3,hsl(0,50%,32%))" transform="rotate(55 36 52)"/>
<ellipse cx="44" cy="52" rx="11" ry="13.5" fill="var(--f1,hsl(0,45%,48%))"/>
<ellipse cx="58" cy="52" rx="10" ry="12" fill="var(--f1,hsl(0,45%,48%))"/>
<ellipse cx="71" cy="52" rx="10" ry="11" fill="var(--f1,hsl(0,45%,48%))"/>
<ellipse cx="50" cy="52" rx="1.8" ry="9" fill="var(--f4,hsl(0,45%,26%))"/>
<ellipse cx="64" cy="52" rx="1.8" ry="8" fill="var(--f4,hsl(0,45%,26%))"/>
<ellipse cx="48" cy="59" rx="9" ry="3.5" fill="var(--f2,hsl(0,30%,70%))"/>
<path d="M74 37 Q86 28 100 30 Q112 32 113 42 Q114 50 109 57 Q103 65 93 68 Q80 71 73 63 Q67 51 74 37 Z" fill="var(--f1,hsl(0,45%,48%))"/>
<ellipse cx="85" cy="60" rx="11" ry="3.5" fill="var(--f2,hsl(0,30%,70%))"/>
<path d="M105 44 L114 43 L115 49 L106 49 Z" fill="var(--f3,hsl(0,50%,32%))"/>
<path d="M112 39 Q121 33 126 38 Q129 42 126 44 L120 45 Q125 47 123 51 Q120 55 113 52 Q109 47 112 39 Z" fill="var(--f3,hsl(0,50%,32%))"/>
<path d="M98 58 Q110 56 116 62 L114 70 Q104 68 96 64 Z" fill="var(--f3,hsl(0,50%,32%))"/>
<path d="M114 56 Q125 47 134 51 Q141 55 139 61 L128 62 Q137 65 136 71 Q134 78 124 75 Q113 71 111 63 Q111 58 114 56 Z" fill="var(--f3,hsl(0,50%,32%))"/>
<path d="M85 65 Q83 75 79 82" fill="none" stroke="var(--f4,hsl(0,45%,26%))" stroke-width="2" stroke-linecap="round"/>
<path d="M73 63 Q71 74 67 82" fill="none" stroke="var(--f4,hsl(0,45%,26%))" stroke-width="2" stroke-linecap="round"/>
<path d="M61 62 Q60 71 57 78" fill="none" stroke="var(--f4,hsl(0,45%,26%))" stroke-width="2" stroke-linecap="round"/>
<path d="M106 34 Q128 25 146 20" fill="none" stroke="var(--f4,hsl(0,45%,26%))" stroke-width="2" stroke-linecap="round"/>
<path d="M107 39 Q130 35 148 42" fill="none" stroke="var(--f4,hsl(0,45%,26%))" stroke-width="2" stroke-linecap="round"/>
<path d="M98 31 L101 23 L104 25 L101 33 Z" fill="var(--f4,hsl(0,45%,26%))"/>
<path d="M107 32 L112 25 L115 27 L110 34 Z" fill="var(--f4,hsl(0,45%,26%))"/>
<circle cx="102.5" cy="22" r="2.8" fill="#142638"/>
<circle cx="113.5" cy="24" r="2.8" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

+19
View File
@@ -0,0 +1,19 @@
<!-- Вьюн (eelpout): тонкая S-образная лента-угорь, маленькая голова с открытым ртом, хвостового плавника нет -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- тело: изогнутая волной тонкая лента, сужается к хвосту -->
<path fill="var(--f1,hsl(35,45%,48%))" d="M22 57.5 C32 62 38 61 45 59.5 C55 54 63 43 75 41 C85 39.5 92 42 100 45 C112 47.5 124 40 135 34 C138.5 33 142 34.5 143.5 38 C144.5 40.5 144 43.5 142 45.5 C141 46.3 140 46.5 139 46.5 C130 47.5 122 49.5 112 53.5 C104 56.8 88 57 75 53 C64 52.5 54 60 45 66.5 C36 71.5 28 65 22 60.5 C21.3 59.6 21.3 58.4 22 57.5 Z"/>
<!-- брюхо: нижняя полоса ленты светлее -->
<path fill="var(--f2,hsl(35,30%,70%))" d="M22 59.4 C33 62 40 64.5 45 65 C55 60.5 65 51 75 48.8 C85 50.5 95 52 100 52.8 C112 52.5 124 45.5 135 41.8 C140 42.5 142.5 44.5 142 45.5 C141 46.3 140 46.5 139 46.5 C130 47.5 122 49.5 112 53.5 C104 56.8 88 57 75 53 C64 52.5 54 60 45 66.5 C36 71.5 28 65 22 60.5 C21.6 60 21.6 59.8 22 59.4 Z"/>
<!-- спинной плавник: низкий, вдоль хребта до самой головы -->
<path fill="var(--f3,hsl(35,50%,32%))" d="M45 59.5 C56 52 64 38 75 36.5 C86 35 93 38.5 100 40.5 C112 43 125 34 136 29.8 C139 29 141.5 30.5 141 32.5 C139 33.5 137 34 135 34 C124 40 112 47.5 100 45 C92 42 85 39.5 75 41 C63 43 55 54 45 59.5 Z"/>
<!-- узор: тёмные пятна вдоль ленты -->
<ellipse fill="var(--f4,hsl(35,45%,26%))" cx="48" cy="61.5" rx="2.6" ry="2.2"/>
<ellipse fill="var(--f4,hsl(35,45%,26%))" cx="75" cy="47.5" rx="3.2" ry="2.8"/>
<ellipse fill="var(--f4,hsl(35,45%,26%))" cx="98" cy="50.5" rx="3.2" ry="2.8"/>
<ellipse fill="var(--f4,hsl(35,45%,26%))" cx="118" cy="46" rx="2.9" ry="2.5"/>
<!-- открытый рот на конце головы -->
<path fill="var(--f4,hsl(35,45%,26%))" d="M137.5 39.5 C140.5 38.6 143 39.6 143.4 41.3 C143 43.4 140.6 44.4 138 43.6 C139.2 42 139.2 40.8 137.5 39.5 Z"/>
<!-- глаз: крошечный -->
<circle fill="#fff" cx="130" cy="38.5" r="2.2"/>
<circle fill="#142638" cx="130.8" cy="38.5" r="1.1"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+30
View File
@@ -0,0 +1,30 @@
<!-- Камбала (flounder): плоская широкая рыбина ~2.5:1, ОБА глаза на верхней стороне, мраморные пятна-камуфляж, низкий спинной плавник, маленький закруглённый хвост, заострённая морда -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: маленький, закруглённый -->
<path fill="var(--f3,hsl(40,50%,32%))" d="M30 52 C20 41 10 42 8 52 C10 62 20 63 30 52 Z"/>
<!-- спинной плавник: низкая полоса вдоль верхнего края -->
<path fill="var(--f3,hsl(40,50%,32%))" d="M32 39 C52 24 96 22 118 38.4 C92 33 60 32.5 32 39 Z"/>
<!-- тело: плоская широкая «пластина» ~2.5:1, заострённая морда справа -->
<path fill="var(--f1,hsl(40,45%,48%))" d="M140 52 C138 44 124 35 100 32 C72 29 42 31 28 40 C21 45 21 59 28 64 C42 73 72 76 100 73 C124 70 138 60 140 52 Z"/>
<!-- брюхо: светлая полоса вдоль нижнего края -->
<path fill="var(--f2,hsl(40,30%,70%))" d="M132 57 C126 66 110 71 92 72.5 C70 74.5 46 71.5 33 61 C40 66.5 58 63.5 80 63 C102 62.5 122 63 132 57 Z"/>
<!-- узор: мраморные пятна-камуфляж -->
<ellipse fill="var(--f4,hsl(40,45%,26%))" cx="46" cy="47" rx="7" ry="4.5" transform="rotate(-14 46 47)"/>
<ellipse fill="var(--f4,hsl(40,45%,26%))" cx="62" cy="58" rx="6" ry="4" transform="rotate(10 62 58)"/>
<ellipse fill="var(--f4,hsl(40,45%,26%))" cx="80" cy="45" rx="8" ry="5" transform="rotate(-8 80 45)"/>
<ellipse fill="var(--f4,hsl(40,45%,26%))" cx="95" cy="57" rx="5.5" ry="3.5" transform="rotate(12 95 57)"/>
<ellipse fill="var(--f4,hsl(40,45%,26%))" cx="58" cy="38" rx="4.5" ry="3" transform="rotate(8 58 38)"/>
<ellipse fill="var(--f4,hsl(40,45%,26%))" cx="74" cy="66" rx="5" ry="3" transform="rotate(-12 74 66)"/>
<ellipse fill="var(--f4,hsl(40,45%,26%))" cx="90" cy="38" rx="4.5" ry="3" transform="rotate(-6 90 38)"/>
<circle fill="var(--f4,hsl(40,45%,26%))" cx="36" cy="57" r="3"/>
<circle fill="var(--f4,hsl(40,45%,26%))" cx="102" cy="52" r="3.5"/>
<!-- рот: тёмная щель у заострённой морды -->
<path fill="var(--f4,hsl(40,45%,26%))" d="M139 52 C133 48.5 126 49 122 52 C127 55 134 55 139 52 Z"/>
<!-- грудной плавник -->
<ellipse fill="var(--f3,hsl(40,50%,32%))" cx="103" cy="62" rx="10" ry="5.5" transform="rotate(-15 103 62)"/>
<!-- глаза: ОБА на верхней стороне, рядом друг с другом (камбала лежит на боку) -->
<circle fill="#fff" cx="110" cy="43.5" r="5.8"/>
<circle fill="#142638" cx="112" cy="43.5" r="2.7"/>
<circle fill="#fff" cx="122" cy="45" r="5"/>
<circle fill="#142638" cx="124" cy="45" r="2.2"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

+19
View File
@@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path d="M74 40 Q60 34 52 22 Q42 12 22 10 Q34 20 30 30 Q26 38 38 42 Q50 46 58 46 Q66 48 74 48 Z" fill="var(--f3,hsl(38,78%,42%))"/>
<path d="M74 60 Q60 66 52 78 Q42 88 22 90 Q34 80 30 70 Q26 62 38 58 Q50 54 58 54 Q66 52 74 52 Z" fill="var(--f3,hsl(38,78%,42%))"/>
<path d="M71 50 Q71 18 103 18 Q135 18 135 50 Q135 82 103 82 Q71 82 71 50 Z" fill="var(--f1,hsl(42,72%,55%))"/>
<path d="M73 55 Q103 63 133 55 Q130 80 103 81.5 Q76 80 73 55 Z" fill="var(--f2,hsl(45,65%,76%))"/>
<path d="M86 24 Q100 4 120 20 Q106 22 92 28 Z" fill="var(--f3,hsl(38,78%,42%))"/>
<path d="M106 58 Q124 64 120 78 Q108 72 102 62 Z" fill="var(--f3,hsl(38,78%,42%))"/>
<path d="M90 80 Q100 94 112 86 Q102 82 94 78 Z" fill="var(--f3,hsl(38,78%,42%))"/>
<circle cx="90" cy="40" r="4" fill="var(--f4,hsl(30,62%,36%))"/>
<circle cx="112" cy="34" r="3" fill="var(--f4,hsl(30,62%,36%))"/>
<circle cx="98" cy="66" r="3.5" fill="var(--f4,hsl(30,62%,36%))"/>
<ellipse cx="131" cy="56" rx="2.8" ry="2.2" fill="var(--f4,hsl(30,62%,36%))"/>
<path d="M78 36 Q84 22 103 21 Q122 22 128 36 Q120 27 103 26 Q86 27 78 36 Z" fill="#fff6d8"/>
<circle cx="90" cy="32" r="2.5" fill="#fff6d8"/>
<circle cx="112" cy="28" r="2" fill="#fff6d8"/>
<circle cx="100" cy="48" r="1.5" fill="#fff6d8"/>
<circle cx="118" cy="42" r="7" fill="#fff"/>
<circle cx="119.5" cy="42" r="3.4" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+31
View File
@@ -0,0 +1,31 @@
<!-- Горбуна (grouper): высокая «пузатая» рыбина ~2:1, КРУПНАЯ голова ~1/3 длины с большим ртом, большие округлые плавники, тёмные пятна по телу и плавникам, светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: большой округлый «веер» -->
<path fill="var(--f3,hsl(15,50%,32%))" d="M40 40 C24 28 10 32 8 50 C10 68 24 72 40 60 C42 54 42 46 40 40 Z"/>
<!-- спинной плавник: крупный, округлый, вдоль всей спины -->
<path fill="var(--f3,hsl(15,50%,32%))" d="M44 40 C50 14 106 8 134 30 C118 26 88 24 58 30 C52 33 47 36 44 40 Z"/>
<!-- грудной плавник: большой округлый, у головы -->
<path fill="var(--f3,hsl(15,50%,32%))" d="M96 54 C98 70 118 80 132 72 C128 61 116 54 106 52 C102 51 98 52 96 54 Z"/>
<!-- анальный плавник: округлый, снизу -->
<path fill="var(--f3,hsl(15,50%,32%))" d="M60 72 C63 84 78 88 90 82 C83 78 74 74 66 72 C63 71 61 71 60 72 Z"/>
<!-- тело: высокое ~2:1, крупная голова справа с большим ртом -->
<path fill="var(--f1,hsl(15,45%,48%))" d="M38 40 C58 24 95 20 122 27 C138 31 147 40 149 49 L150 50 C149 59 143 66 134 70 C112 79 78 80 55 74 C46 71 40 66 38 58 Z"/>
<!-- брюхо: светлая нижняя полоса -->
<path fill="var(--f2,hsl(15,30%,70%))" d="M150 50 C148 59 142 66 134 70 C112 79 78 80 55 74 C46 71 40 66 38 58 C42 60 50 61 60 62 C85 64 112 65 132 62 C140 58 146 53 150 50 Z"/>
<!-- узор: тёмные пятна разного размера по телу и плавникам -->
<circle fill="var(--f4,hsl(15,45%,26%))" cx="58" cy="42" r="5"/>
<circle fill="var(--f4,hsl(15,45%,26%))" cx="76" cy="56" r="6.5"/>
<circle fill="var(--f4,hsl(15,45%,26%))" cx="94" cy="38" r="4.5"/>
<circle fill="var(--f4,hsl(15,45%,26%))" cx="108" cy="54" r="5.5"/>
<circle fill="var(--f4,hsl(15,45%,26%))" cx="86" cy="67" r="4"/>
<circle fill="var(--f4,hsl(15,45%,26%))" cx="99" cy="48" r="3"/>
<circle fill="var(--f4,hsl(15,45%,26%))" cx="66" cy="63" r="3.5"/>
<circle fill="var(--f4,hsl(15,45%,26%))" cx="114" cy="36" r="3.5"/>
<circle fill="var(--f4,hsl(15,45%,26%))" cx="24" cy="50" r="3"/>
<circle fill="var(--f4,hsl(15,45%,26%))" cx="90" cy="15" r="3"/>
<!-- рот: крупный тёмный у массивной морды -->
<path fill="var(--f4,hsl(15,45%,26%))" d="M150 50 C145 45 137 45 132 49 C136 53 145 53 150 50 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="130" cy="43" r="5.5"/>
<circle fill="#142638" cx="131.5" cy="43" r="2.6"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

+31
View File
@@ -0,0 +1,31 @@
<!-- Сельдь (herring): холодная голубовато-серебристая, самая тонкая удлинённая рыба из тройки (≈4:1), мелкий вилочный хвост, низкий спинной плавник смещён к хвосту, тёмная спинная кромка, 6 коротких тёмных вертикалей вдоль верхнего края спины, маленький глаз -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: мелкий вилочный -->
<path fill="var(--f3,hsl(205,50%,32%))" d="M37 50 L18 40 L26.5 50 L18 60 L37 50 Z"/>
<!-- тело: самое тонкое из тройки, удлинённое, заострённая морда -->
<path fill="var(--f2,hsl(205,30%,70%))" d="M146 50 C136 40 114 36 88 36 C62 36 44 40 37 46 L37 54 C44 60 62 64 88 64 C114 64 136 60 146 50 Z"/>
<!-- брюхо: ещё светлее -->
<path fill="var(--f2b,hsl(205,25%,82%))" d="M146 50 C136 60 114 64 88 64 C62 64 44 60 37 54 C44 57 62 59.5 88 59.5 C114 59.5 136 57 146 50 Z"/>
<!-- спинная кромка: тонкая тёмная полоса вдоль верхнего края -->
<path fill="var(--f1,hsl(205,45%,48%))" d="M146 50 C136 40 114 36 88 36 C62 36 44 40 37 46 C44 43 62 40.5 88 40.5 C114 40.5 136 43 146 50 Z"/>
<!-- спинной плавник: низкий, смещён к хвосту -->
<path fill="var(--f3,hsl(205,50%,32%))" d="M64 37.5 Q76 22 88 37 Z"/>
<!-- грудной плавник -->
<path fill="var(--f3,hsl(205,50%,32%))" d="M116 54.5 C112 58 111.5 62.5 115 65.5 C118 61.5 118.5 57.5 117.5 55 Z"/>
<!-- брюшной плавник: далеко сдвинут к хвосту (черта сельди) -->
<path fill="var(--f3,hsl(205,50%,32%))" d="M88 63.5 L84 70.5 L95 63.8 Z"/>
<!-- анальный плавник: ближе к хвосту -->
<path fill="var(--f3,hsl(205,50%,32%))" d="M61 63 L56 69.5 L67 63.4 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(205,45%,26%))" d="M138 50.3 C140.5 50.6 142.5 51.5 143.5 52.8 C141.8 54.2 139.4 53.9 138 52.6 Z"/>
<!-- узор: 6 коротких тёмных вертикалей вдоль верхнего края спины (~30% высоты тела, не доходят до брюха) -->
<path fill="var(--f4,hsl(205,45%,26%))" d="M117.1 39.5 L118.9 39.5 L118.9 47.5 L117.1 47.5 Z"/>
<path fill="var(--f4,hsl(205,45%,26%))" d="M105.1 38 L106.9 38 L106.9 46 L105.1 46 Z"/>
<path fill="var(--f4,hsl(205,45%,26%))" d="M93.1 37.2 L94.9 37.2 L94.9 45.2 L93.1 45.2 Z"/>
<path fill="var(--f4,hsl(205,45%,26%))" d="M81.1 37.3 L82.9 37.3 L82.9 45.3 L81.1 45.3 Z"/>
<path fill="var(--f4,hsl(205,45%,26%))" d="M69.1 37.9 L70.9 37.9 L70.9 45.9 L69.1 45.9 Z"/>
<path fill="var(--f4,hsl(205,45%,26%))" d="M57.1 39.5 L58.9 39.5 L58.9 47.5 L57.1 47.5 Z"/>
<!-- глаз: маленький -->
<circle fill="#fff" cx="130" cy="45" r="3.6"/>
<circle fill="#142638" cx="130.8" cy="45" r="1.9"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

+27
View File
@@ -0,0 +1,27 @@
<!-- Скумбрия (mackerel): удлинённое тело ~3:1, вилочный хвост, спинной плавник; 4 волнистые тёмные полосы вдоль спинки, тёмная полосатая спина / светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: вилочный -->
<path fill="var(--f3,hsl(190,50%,32%))" d="M32 45 L12 34 L23 50 L12 66 L32 55 Z"/>
<!-- спинной плавник: низкий, заострённый -->
<path fill="var(--f3,hsl(190,50%,32%))" d="M58 36 Q73 17 88 35 Z"/>
<!-- анальный плавник: смещён к хвосту (черта скумбрии) -->
<path fill="var(--f3,hsl(190,50%,32%))" d="M31 57.5 L26 65.5 L40 62.3 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(190,50%,32%))" d="M90 63.3 L87 71 L99 65.6 Z"/>
<!-- тело: удлинённое, тёмная полосатая спина -->
<path fill="var(--f1,hsl(190,45%,48%))" d="M144 50 C132 40 106 33 78 33 C54 33 38 37 30 43 L30 57 C38 63 54 67 78 67 C106 67 132 60 144 50 Z"/>
<!-- брюхо: светлое, контраст со спиной -->
<path fill="var(--f2,hsl(190,30%,70%))" d="M144 50 C132 60 106 67 78 67 C54 67 38 63 30 57 C38 60.5 54 60.5 78 60.5 C106 60.5 132 55.5 144 50 Z"/>
<!-- узор: волнистые тёмные полосы вдоль спинки (до ~40% высоты тела) -->
<path fill="var(--f4,hsl(190,45%,26%))" d="M54 35.8 C57.5 40.8 51.5 44.8 56 49.8 L60 48.6 C55.8 44.4 60.8 40.2 58.2 35.8 Z"/>
<path fill="var(--f4,hsl(190,45%,26%))" d="M70 34 C73.5 39 67.5 43 72 48 L76 46.8 C71.8 42.6 76.8 38.4 74.2 34 Z"/>
<path fill="var(--f4,hsl(190,45%,26%))" d="M86 33.9 C89.5 38.9 83.5 42.9 88 47.9 L92 46.7 C87.8 42.5 92.8 38.3 90.2 33.9 Z"/>
<path fill="var(--f4,hsl(190,45%,26%))" d="M102 35.8 C105.5 40.8 99.5 44.8 104 49.8 L108 48.6 C103.8 44.4 108.8 40.2 106.2 35.8 Z"/>
<!-- грудной плавник -->
<path fill="var(--f3,hsl(190,50%,32%))" d="M113 51 C109 55 108.5 60 112 63 C115 59 115.5 54 114.5 51.5 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(190,45%,26%))" d="M136.5 50.4 C139.5 50.7 141.5 51.7 143 53.1 C141 54.4 138.5 54 137 52.8 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="125" cy="45" r="4"/>
<circle fill="#142638" cx="125.8" cy="45" r="2.1"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

+24
View File
@@ -0,0 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- заднее крыло (влево-назад) -->
<polygon points="62,43.8 94,43 14,10" fill="var(--f1,hsl(220,45%,48%))"/>
<!-- переднее крыло (вправо-вперёд) -->
<polygon points="66,58.5 96,55.8 146,90" fill="var(--f1,hsl(220,45%,48%))"/>
<!-- хвост-хлыст -->
<polygon points="55,47.8 12,55 55,52.2" fill="var(--f3,hsl(220,50%,32%))"/>
<!-- рожки (cephalic fins) -->
<polygon points="100,46 128,32 105,51" fill="var(--f3,hsl(220,50%,32%))"/>
<polygon points="100,54 128,68 105,49" fill="var(--f3,hsl(220,50%,32%))"/>
<!-- брюхо (нижняя половина тела) -->
<path d="M 52 50 Q 79 74 106 50 Z" fill="var(--f2,hsl(220,30%,70%))"/>
<!-- тело (верхняя половина) -->
<path d="M 52 50 Q 79 26 106 50 Z" fill="var(--f1,hsl(220,45%,48%))"/>
<!-- узор: пятна на спине -->
<circle cx="66" cy="44" r="1.7" fill="var(--f4,hsl(220,45%,26%))"/>
<circle cx="75" cy="42" r="2.6" fill="var(--f4,hsl(220,45%,26%))"/>
<circle cx="85" cy="42" r="2.2" fill="var(--f4,hsl(220,45%,26%))"/>
<!-- глаза -->
<circle cx="90" cy="44.8" r="2.3" fill="#fff"/>
<circle cx="91" cy="44.8" r="1.15" fill="#142638"/>
<circle cx="90" cy="55.2" r="2.3" fill="#fff"/>
<circle cx="91" cy="55.2" r="1.15" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+23
View File
@@ -0,0 +1,23 @@
<!-- Мурена (moray): толстый S-образный угорь, крупная голова с большой открытой пастью, без хвостового плавника, тёмные пятна вдоль тела -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- тело: толстая S-образная лента, сужается к хвосту, хвостового плавника нет -->
<path fill="var(--f1,hsl(50,45%,48%))" d="M24 37.5 C30 33 34 28 40 27 C48 26 50 33 56 34 C64 36 70 42 78 43 C86 44 92 35 98 34 C104 33 110 29 118 29 C130 29 138 33 141 40 C143 44 143 50 140 55 C137 60 132 63 126 63 C118 63 108 62 98 62 C90 62 84 69 78 69 C70 69 62 59 56 58 C50 57 46 48 40 45 C34 42 28 43 24 42.5 C20 41 20 39 24 37.5 Z"/>
<!-- брюхо: нижняя полоса тела и нижняя челюсть светлее -->
<path fill="var(--f2,hsl(50,30%,70%))" d="M118 55 C108 54 102 54 98 54 C88 54 82 58 78 59 C70 61 62 52 56 49 C50 46 46 40 40 37 C34 34.5 28 36 24.5 38.5 L24 42.5 C28 43 34 42 40 45 C46 48 50 57 56 58 C62 59 70 69 78 69 C84 69 90 62 98 62 C108 62 118 63 126 63 C132 63 137 60 140 55 Z"/>
<!-- узор: тёмные пятна вдоль тела -->
<ellipse fill="var(--f4,hsl(50,45%,26%))" cx="104" cy="45" rx="4.5" ry="5.5" transform="rotate(-15 104 45)"/>
<ellipse fill="var(--f4,hsl(50,45%,26%))" cx="89" cy="49.5" rx="5" ry="6" transform="rotate(18 89 49.5)"/>
<ellipse fill="var(--f4,hsl(50,45%,26%))" cx="76" cy="55" rx="4.5" ry="5.5" transform="rotate(-22 76 55)"/>
<ellipse fill="var(--f4,hsl(50,45%,26%))" cx="63" cy="49.5" rx="4.5" ry="5" transform="rotate(12 63 49.5)"/>
<ellipse fill="var(--f4,hsl(50,45%,26%))" cx="51" cy="42" rx="4" ry="4.5" transform="rotate(-18 51 42)"/>
<ellipse fill="var(--f4,hsl(50,45%,26%))" cx="39" cy="35" rx="3.5" ry="4" transform="rotate(14 39 35)"/>
<!-- большая открытая пасть: тёмная щель-улыбка на передней части головы -->
<path fill="var(--f4,hsl(50,45%,26%))" d="M120 45.5 C128 44 137 45 142 49 C142 54 137 60 129 62 C122 59 118 51 120 45.5 Z"/>
<!-- намёк на зубы: мелкие белые клыки вдоль верхней губы -->
<path fill="#fff" d="M126.5 46.8 L129.5 47.2 L128 50.6 Z M133 47.5 L136 48 L134.5 51.6 Z M138.3 48.6 L140.3 49.3 L139.4 52.3 Z"/>
<!-- глаз: крошечный, злой -->
<circle fill="#fff" cx="126" cy="38" r="3"/>
<circle fill="#142638" cx="127" cy="38" r="1.7"/>
<!-- злая бровь над глазом -->
<path fill="var(--f4,hsl(50,45%,26%))" d="M120 32 L131 34.5 L121 37 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

+28
View File
@@ -0,0 +1,28 @@
<!-- Навага (navaga): стально-серая (холоднее и темнее соседей) тонкая удлинённая рыба ~3.5:1, тёплая оливковая полоска вдоль верхнего края спины, мелкий вилочный хвост, маленький спинной плавник смещён к хвосту, самый крупный глаз тройки -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: мелкий вилочный -->
<path fill="var(--f3,hsl(222,40%,32%))" d="M40 46 L16 34 L26 50 L16 66 L40 54 Z"/>
<!-- тело: тонкое удлинённое, заострённая морда -->
<path fill="var(--f2,hsl(222,22%,66%))" d="M144 50 C134 39 112 35 86 35 C60 35 44 41 38 47 L38 53 C44 59 60 65 86 65 C112 65 134 61 144 50 Z"/>
<!-- брюхо: ещё светлее -->
<path fill="var(--f2b,hsl(222,18%,80%))" d="M144 50 C134 61 112 65 86 65 C60 65 44 59 38 53 C44 55.5 60 59 86 59 C112 59 134 55.5 144 50 Z"/>
<!-- спинка: тёмная стальная полоса вдоль верхнего края -->
<path fill="var(--f1,hsl(222,35%,44%))" d="M144 50 C134 39 112 35 86 35 C60 35 44 41 38 47 C44 44.5 60 40.5 86 40.5 C112 40.5 134 44.5 144 50 Z"/>
<!-- оливковая полоска: тёплая, тонкая, от головы к хвосту по верхнему краю (черта наваги) -->
<path fill="var(--f4,hsl(75,40%,42%))" d="M136 47.4 C120 44.4 100 41.6 84 41.6 C62 41.6 46 44.6 40 47.6 L40 49.8 C46 47 62 44 84 44 C100 44 120 46.8 136 49.8 Z"/>
<!-- спинной плавник: маленький, смещён к хвосту -->
<path fill="var(--f3,hsl(222,40%,32%))" d="M60 38.5 Q71 18 82 37 Z"/>
<!-- грудной плавник -->
<path fill="var(--f3,hsl(222,40%,32%))" d="M104 61.5 L98 70 L110 62.5 Z"/>
<!-- брюшной плавник: ближе к хвосту -->
<path fill="var(--f3,hsl(222,40%,32%))" d="M62 60.5 L56 68.5 L68 61.5 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(222,45%,26%))" d="M134 50.2 C136.8 50.4 139.2 51.1 140.2 52.4 C138.4 54 135.8 53.7 134.2 52.4 Z"/>
<!-- узор: мелкие тёмные точки вдоль бока -->
<ellipse fill="var(--f4,hsl(222,45%,26%))" cx="70" cy="47.5" rx="2.6" ry="1.6"/>
<ellipse fill="var(--f4,hsl(222,45%,26%))" cx="88" cy="47.2" rx="2.6" ry="1.6"/>
<ellipse fill="var(--f4,hsl(222,45%,26%))" cx="106" cy="47.2" rx="2.6" ry="1.6"/>
<!-- глаз: самый крупный из тройки -->
<circle fill="#fff" cx="126" cy="45.5" r="5.4"/>
<circle fill="#142638" cx="127" cy="45.5" r="2.9"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

+18
View File
@@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path d="M 47.8 40.4 L 45.8 43.1 L 43.7 45.8 L 41.7 48.5 L 39.7 51.1 L 37.7 53.6 L 35.7 56.2 L 33.8 58.6 L 32.0 61.1 L 30.2 63.4 L 28.4 65.8 L 26.8 68.1 L 25.2 70.3 L 23.8 72.5 L 22.4 74.7 L 21.2 76.8 L 19.7 80.1 L 21.5 85.3 L 19.5 86.8 L 18.0 86.0 L 18.1 84.9 L 18.7 84.7 L 18.8 84.9 L 18.3 85.4 L 21.1 86.5 L 21.7 84.0 L 19.1 81.5 L 15.1 83.1 L 14.9 88.1 L 20.2 90.7 L 25.6 86.3 L 24.3 79.9 L 25.2 79.4 L 26.6 77.6 L 28.2 75.8 L 29.8 73.9 L 31.6 72.0 L 33.5 70.0 L 35.5 68.0 L 37.5 65.9 L 39.7 63.8 L 41.9 61.6 L 44.2 59.4 L 46.5 57.2 L 48.9 54.8 L 51.3 52.5 L 53.7 50.1 L 56.2 47.6 Z" fill="var(--f1,hsl(350,45%,48%))"/>
<path d="M 55.1 43.5 L 53.5 47.3 L 51.9 50.9 L 50.4 54.4 L 48.8 57.8 L 47.2 61.1 L 45.7 64.3 L 44.2 67.3 L 42.8 70.3 L 41.3 73.2 L 40.0 76.0 L 38.7 78.7 L 37.4 81.4 L 36.2 83.9 L 35.1 86.4 L 34.1 88.9 L 33.2 91.2 L 36.8 92.8 L 37.9 90.6 L 39.1 88.4 L 40.4 86.1 L 41.8 83.8 L 43.3 81.4 L 45.0 78.9 L 46.7 76.3 L 48.5 73.7 L 50.4 70.9 L 52.3 68.1 L 54.3 65.1 L 56.4 62.1 L 58.5 58.9 L 60.6 55.5 L 62.7 52.1 L 64.9 48.5 Z" fill="var(--f3,hsl(350,50%,32%))"/>
<path d="M 63.8 46.3 L 62.7 50.3 L 61.6 54.1 L 60.5 57.6 L 59.4 61.0 L 58.3 64.1 L 57.2 67.1 L 56.1 69.9 L 55.1 72.6 L 54.0 75.1 L 53.0 77.4 L 52.0 79.7 L 51.1 81.8 L 50.2 83.7 L 49.4 85.6 L 48.7 87.3 L 47.8 90.4 L 50.0 95.3 L 48.1 97.0 L 46.5 96.3 L 46.5 95.2 L 47.1 95.0 L 47.2 95.2 L 46.8 95.7 L 49.7 96.5 L 50.1 94.0 L 47.2 91.7 L 43.4 93.7 L 43.7 98.7 L 49.2 100.8 L 54.1 95.9 L 52.2 89.6 L 52.9 89.6 L 53.9 88.0 L 55.0 86.4 L 56.2 84.6 L 57.5 82.6 L 58.8 80.5 L 60.2 78.3 L 61.7 75.9 L 63.2 73.3 L 64.7 70.6 L 66.3 67.6 L 67.9 64.5 L 69.5 61.1 L 71.1 57.5 L 72.7 53.7 L 74.2 49.7 Z" fill="var(--f1,hsl(350,45%,48%))"/>
<path d="M 71.6 47.1 L 71.1 51.5 L 70.7 55.7 L 70.2 59.6 L 69.8 63.4 L 69.3 67.0 L 68.9 70.4 L 68.4 73.6 L 68.0 76.7 L 67.6 79.6 L 67.2 82.4 L 66.8 85.0 L 66.4 87.5 L 66.0 90.0 L 65.7 92.3 L 65.4 94.5 L 65.0 96.6 L 69.0 97.4 L 69.4 95.3 L 70.0 93.2 L 70.6 90.9 L 71.3 88.6 L 72.0 86.2 L 72.8 83.6 L 73.6 80.9 L 74.5 78.1 L 75.4 75.1 L 76.3 71.9 L 77.3 68.6 L 78.3 65.1 L 79.3 61.4 L 80.3 57.4 L 81.4 53.3 L 82.4 48.9 Z" fill="var(--f2,hsl(350,30%,70%))"/>
<path d="M 79.5 48.7 L 80.4 53.1 L 81.3 57.2 L 82.1 61.2 L 82.9 64.9 L 83.8 68.4 L 84.6 71.8 L 85.3 74.9 L 86.1 77.9 L 86.8 80.8 L 87.5 83.5 L 88.2 86.1 L 88.9 88.5 L 89.5 90.9 L 90.1 93.1 L 90.6 95.3 L 91.0 97.4 L 95.0 96.6 L 94.7 94.5 L 94.4 92.3 L 94.1 90.0 L 93.8 87.6 L 93.5 85.1 L 93.2 82.5 L 92.9 79.7 L 92.7 76.8 L 92.4 73.7 L 92.1 70.5 L 91.8 67.2 L 91.5 63.6 L 91.3 59.8 L 91.0 55.9 L 90.7 51.7 L 90.5 47.3 Z" fill="var(--f2,hsl(350,30%,70%))"/>
<path d="M 87.6 49.3 L 88.9 53.2 L 90.2 57.1 L 91.5 60.7 L 92.7 64.1 L 94.0 67.3 L 95.3 70.4 L 96.5 73.3 L 97.7 76.1 L 98.9 78.8 L 100.1 81.4 L 101.2 84.0 L 102.3 86.5 L 103.3 89.0 L 104.3 91.5 L 105.2 94.0 L 106.1 96.6 L 109.9 95.4 L 109.2 92.8 L 108.5 90.1 L 107.8 87.5 L 107.0 84.9 L 106.3 82.2 L 105.5 79.5 L 104.8 76.7 L 104.0 73.9 L 103.3 71.0 L 102.5 68.0 L 101.8 64.8 L 101.0 61.6 L 100.3 58.1 L 99.7 54.6 L 99.0 50.8 L 98.4 46.7 Z" fill="var(--f1,hsl(350,45%,48%))"/>
<path d="M 96.0 48.3 L 98.0 51.9 L 100.0 55.4 L 102.0 58.7 L 104.0 62.0 L 106.0 65.1 L 107.9 68.0 L 109.8 70.9 L 111.6 73.6 L 113.4 76.3 L 115.1 78.9 L 116.7 81.3 L 118.2 83.7 L 119.6 86.1 L 120.9 88.4 L 122.1 90.6 L 123.2 92.8 L 126.8 91.2 L 125.9 88.9 L 124.9 86.4 L 123.8 83.9 L 122.6 81.4 L 121.4 78.7 L 120.1 76.0 L 118.8 73.2 L 117.4 70.4 L 116.0 67.4 L 114.6 64.3 L 113.1 61.2 L 111.7 57.9 L 110.2 54.5 L 108.8 51.1 L 107.4 47.5 L 106.0 43.7 Z" fill="var(--f3,hsl(350,50%,32%))"/>
<path d="M 104.7 47.4 L 107.0 49.9 L 109.3 52.4 L 111.6 54.7 L 113.9 57.1 L 116.1 59.4 L 118.3 61.6 L 120.5 63.8 L 122.6 65.9 L 124.6 68.0 L 126.5 70.0 L 128.4 72.0 L 130.2 73.9 L 131.8 75.8 L 133.4 77.6 L 134.8 79.4 L 137.1 82.1 L 142.5 82.7 L 143.1 85.2 L 141.7 86.2 L 140.7 85.7 L 140.8 85.1 L 141.0 85.0 L 141.3 85.7 L 143.4 83.6 L 141.5 82.0 L 138.1 83.3 L 137.8 87.6 L 142.2 89.9 L 146.9 86.2 L 145.2 79.5 L 138.9 77.9 L 138.8 76.8 L 137.6 74.7 L 136.2 72.5 L 134.8 70.3 L 133.3 68.1 L 131.6 65.8 L 129.9 63.5 L 128.2 61.1 L 126.4 58.7 L 124.6 56.2 L 122.7 53.7 L 120.8 51.2 L 118.9 48.6 L 117.0 46.0 L 115.2 43.3 L 113.3 40.6 Z" fill="var(--f1,hsl(350,45%,48%))"/>
<path d="M 80 8 C 103 8 115 24 115 40 C 115 55 100 62 80 62 C 60 62 45 55 45 40 C 45 24 57 8 80 8 Z" fill="var(--f1,hsl(350,45%,48%))"/>
<ellipse cx="64" cy="22" rx="4" ry="3" fill="var(--f4,hsl(350,45%,26%))"/>
<ellipse cx="100" cy="21" rx="3.5" ry="3" fill="var(--f4,hsl(350,45%,26%))"/>
<ellipse cx="80" cy="46" rx="4" ry="3.5" fill="var(--f4,hsl(350,45%,26%))"/>
<circle cx="74" cy="34" r="9" fill="#fff"/>
<circle cx="96" cy="34" r="9" fill="#fff"/>
<circle cx="77" cy="34" r="4.5" fill="#142638"/>
<circle cx="99" cy="34" r="4.5" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path d="M36 50 L12 28 L22 50 L12 72 Z" fill="var(--f3,hsl(120,50%,32%))"/>
<path d="M50 38 L60 11 L72 18 L84 12 L96 22 L102 30 Z" fill="var(--f3,hsl(120,50%,32%))"/>
<path d="M32 50 Q58 21 100 23 Q133 26 148 50 Q133 74 100 77 Q58 79 32 50 Z" fill="var(--f1,hsl(120,45%,48%))"/>
<path d="M148 50 Q133 74 100 77 Q58 79 32 50 Q62 64 104 64 Q132 62 148 50 Z" fill="var(--f2,hsl(120,30%,70%))"/>
<path d="M47 37.9 Q52 34.3 57 33.1 L57 67.3 Q52 65.2 47 60.6 Z" fill="var(--f4,hsl(120,45%,26%))"/>
<path d="M61 30.8 Q66 28.1 71 27.8 L71 72.2 Q66 71.8 61 68.9 Z" fill="var(--f4,hsl(120,45%,26%))"/>
<path d="M75 26.8 Q80 24.9 85 25.3 L85 74.7 Q80 75.2 75 73.3 Z" fill="var(--f4,hsl(120,45%,26%))"/>
<path d="M89 25 Q94 23.8 99 25 L99 75 Q94 76.2 89 75 Z" fill="var(--f4,hsl(120,45%,26%))"/>
<path d="M103 25.4 Q108 25.1 113 27.2 L113 72.7 Q108 74.9 103 74.6 Z" fill="var(--f4,hsl(120,45%,26%))"/>
<path d="M108 52 Q130 56 126 72 Q112 68 104 58 Z" fill="var(--f3,hsl(120,50%,32%))"/>
<path d="M88 74 Q100 88 112 80 Q102 76 94 72 Z" fill="var(--f3,hsl(120,50%,32%))"/>
<circle cx="133" cy="43" r="6.5" fill="#fff"/>
<circle cx="134.5" cy="43" r="3" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+25
View File
@@ -0,0 +1,25 @@
<!-- Щука (pike): удлинённое тело ~4:1, плоская «утячья» морда, спинной плавник сзади, мелкий вилочный хвост -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: мелкая вилка -->
<path fill="var(--f3,hsl(100,50%,32%))" d="M20,46 L7,34 L14,44 L14,50 L7,60 L20,50 Z"/>
<!-- спинной плавник: смещён к хвосту, низкий, округлый -->
<path fill="var(--f3,hsl(100,50%,32%))" d="M28,41 C31,31 42,25 54,26 C57,26.5 58,29 57,33.5 Z"/>
<!-- брюшной плавник: маленький, снизу -->
<path fill="var(--f3,hsl(100,50%,32%))" d="M58,63 L53,71 L63,64 Z"/>
<!-- тело: удлинённое, плоская заострённая морда-«клюв» -->
<path fill="var(--f1,hsl(100,45%,48%))" d="M142,45 C137,41 128,37 116,34 C96,31 66,31 45,35 C33,38 25,42 20,47 L18,51 C25,56 33,60 45,63 C66,66 96,65 116,59 C128,56 138,52 141,48 Z"/>
<!-- брюхо: светлее, лунка вдоль нижней кромки -->
<path fill="var(--f2,hsl(100,30%,70%))" d="M18,51 C25,56 33,60 45,63 C66,66 96,65 116,59 C128,56 138,52 141,48 L142,45 C130,49 110,52 88,53 C66,54 40,53 22,50 Z"/>
<!-- грудной плавник -->
<path fill="var(--f3,hsl(100,50%,32%))" d="M98,50 C94,55 94,59 98,62 C102,58 103,54 101,50 Z"/>
<!-- пасть: тёмная щель -->
<path fill="var(--f4,hsl(100,45%,26%))" d="M142,45 L141,48 L122,46.5 Z"/>
<!-- узор: тёмные пятна по бокам -->
<ellipse fill="var(--f4,hsl(100,45%,26%))" cx="45" cy="47" rx="4" ry="2.5"/>
<ellipse fill="var(--f4,hsl(100,45%,26%))" cx="62" cy="45" rx="4.5" ry="2.5"/>
<ellipse fill="var(--f4,hsl(100,45%,26%))" cx="80" cy="46" rx="4.5" ry="2.5"/>
<ellipse fill="var(--f4,hsl(100,45%,26%))" cx="98" cy="48" rx="4" ry="2.5"/>
<!-- глаз -->
<circle fill="#fff" cx="124" cy="41" r="3.2"/>
<circle fill="#142638" cx="124.5" cy="41" r="1.6"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+24
View File
@@ -0,0 +1,24 @@
<!-- Густера (roundel): высокое широкое тело ~2:1, серебристое, вилочный хвост, спинной плавник, светлое брюхо, тёмная спинная кромка -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: вилочный -->
<path fill="var(--f3,hsl(215,50%,32%))" d="M40 50 L14 28 L27 50 L14 72 Z"/>
<!-- тело: высокое широкое, серебристое -->
<path fill="var(--f2,hsl(215,30%,70%))" d="M148 48 C140 34 116 25 90 24 C64 23 46 31 36 42 L36 58 C46 69 64 77 90 76 C116 75 140 62 148 48 Z"/>
<!-- брюхо: светлее -->
<path fill="var(--f2b,hsl(215,25%,82%))" d="M148 48 C140 62 116 75 90 76 C64 77 46 69 36 58 C46 64 64 68 90 66 C116 64 140 56 148 48 Z"/>
<!-- спинной плавник -->
<path fill="var(--f3,hsl(215,50%,32%))" d="M62 27 Q82 6 106 26 Q84 20 62 27 Z"/>
<!-- тёмная спинная кромка: тонкая полоса вдоль верхнего края -->
<path fill="var(--f1,hsl(215,45%,48%))" d="M148 48 C140 34 116 25 90 24 C64 23 46 31 36 42 C46 36 64 28 90 29 C116 30 140 38 148 48 Z"/>
<!-- узор: линия жаберной крышки -->
<path fill="var(--f4,hsl(215,45%,26%))" d="M116 36 C122 43 122 55 116 62 C119 55 119 43 116 36 Z"/>
<!-- грудной плавник -->
<path fill="var(--f3,hsl(215,50%,32%))" d="M110 55 C104 60 103 66 108 70 C112 64 114 59 112 55 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(215,50%,32%))" d="M80 73 L74 83 L88 75 Z"/>
<!-- анальный плавник -->
<path fill="var(--f3,hsl(215,50%,32%))" d="M58 68 L52 78 L66 70 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="127" cy="44" r="5.5"/>
<circle fill="#142638" cx="128.5" cy="44" r="2.8"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path d="M46 50 L20 20 L38 50 L20 80 Z" fill="var(--f3,hsl(5,70%,52%))"/>
<path d="M40 50 Q46 20 88 20 Q128 24 140 50 Q128 76 88 80 Q46 80 40 50 Z" fill="var(--f1,hsl(25,45%,48%))"/>
<path d="M40 50 Q46 80 88 80 Q128 76 140 50 Q116 64 84 64 Q54 62 40 50 Z" fill="var(--f2,hsl(25,30%,70%))"/>
<path d="M54 26 Q82 4 122 14 Q128 21 126 26 Q88 13 54 26 Z" fill="var(--f3,hsl(5,70%,52%))"/>
<path d="M114 54 Q138 58 130 78 Q116 70 106 60 Z" fill="var(--f3,hsl(5,70%,52%))"/>
<path d="M94 74 Q98 92 80 88 Q86 80 88 74 Z" fill="var(--f3,hsl(5,70%,52%))"/>
<path d="M68 72 Q64 90 50 86 Q56 78 58 68 Z" fill="var(--f3,hsl(5,70%,52%))"/>
<path d="M50 46 Q90 38 134 46 Q90 52 50 46 Z" fill="var(--f4,hsl(25,45%,26%))"/>
<path d="M68 30 Q74 26 80 30 Q74 36 68 30 Z" fill="var(--f4,hsl(25,45%,26%))"/>
<path d="M94 26 Q100 22 106 26 Q100 32 94 26 Z" fill="var(--f4,hsl(25,45%,26%))"/>
<path d="M116 32 Q122 28 128 32 Q122 38 116 32 Z" fill="var(--f4,hsl(25,45%,26%))"/>
<circle cx="124" cy="40" r="6.5" fill="#fff"/>
<circle cx="125.5" cy="40" r="3" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+28
View File
@@ -0,0 +1,28 @@
<!-- Большая белая акула (shark): коническая заострённая морда, обтекаемое тело «торпеда» ~3:1, высокий треугольный спинной плавник (узнаваемый знак), вилочный хвост с длиннейшей верхней лопастью, серая спина / белое брюхо, 3 жаберные щели, маленький тёмный глаз -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: вилка — верхняя (длиннейшая) лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 47 C29 40 18 30 11 22 C12 33 18 42 30 50 L37 47 Z"/>
<!-- хвост: вилка — нижняя (короткая) лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 53 C30 58 21 63 15 67 C17 59 24 53 30 50 L37 53 Z"/>
<!-- спинной плавник: высокий треугольник посередине спины -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M84 35.5 L100 14 L112 36.5 Z"/>
<!-- второй спинной плавник: маленький, к хвосту -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M50 39 L58 30.5 L64 37.5 Z"/>
<!-- анальный плавник: сзади под брюхом -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M46 59.5 L42 68.5 L55 62 Z"/>
<!-- тело: торпеда, коническая заострённая морда, сужается к хвостовому стеблю -->
<path fill="var(--f1,hsl(210,45%,48%))" d="M154 50 C143 44 122 35 95 33.5 C72 32.5 50 37 34 45.5 L34 54.5 C50 63 72 67.5 95 66.5 C122 65 143 56 154 50 Z"/>
<!-- брюхо: светлое, контраст «серая спина / белое брюхо» -->
<path fill="var(--f2,hsl(210,30%,70%))" d="M154 50 C143 56 122 65 95 66.5 C72 67.5 50 63 34 54.5 C45 56.5 65 57.5 95 57 C122 56 143 53 154 50 Z"/>
<!-- грудной плавник: широкий, заострённый назад -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M131 50.5 L113 66.5 L136 54 Z"/>
<!-- рот: тёмная пологая щель на конце морды -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M143 50.4 C146 50.7 148.5 51.2 150.5 51.8 C148.5 52.5 145.5 52 143.5 51.2 Z"/>
<!-- жаберные щели: 3 короткие вертикальные позади головы -->
<path fill="none" stroke="var(--f4,hsl(210,45%,26%))" stroke-width="2" stroke-linecap="round" d="M134 44.5 L134 52.5"/>
<path fill="none" stroke="var(--f4,hsl(210,45%,26%))" stroke-width="2" stroke-linecap="round" d="M129 44 L129 53"/>
<path fill="none" stroke="var(--f4,hsl(210,45%,26%))" stroke-width="2" stroke-linecap="round" d="M124 44.5 L124 53"/>
<!-- глаз: маленький тёмный, с крошечным бликом -->
<circle fill="#142638" cx="140" cy="47" r="2.2"/>
<circle fill="#fff" cx="139.3" cy="46.3" r="0.9"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

+21
View File
@@ -0,0 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path d="M 136 58 C 136 70, 134 80, 130 88 C 129 90, 127 90, 126 89 L 126 87 C 130 80, 132 70, 131 58 Z" fill="var(--f3,hsl(300,50%,32%))"/>
<path d="M 134 62 C 133 74, 130 86, 124 95 L 122 94 C 127 86, 130 74, 128 62 Z" fill="var(--f3,hsl(300,50%,32%))"/>
<path d="M 130 64 C 129 76, 122 88, 110 97 L 108 95 C 119 88, 125 76, 124 64 Z" fill="var(--f3,hsl(300,50%,32%))"/>
<path d="M 126 64 C 124 78, 112 88, 96 96 L 94 94 C 109 87, 120 77, 120 64 Z" fill="var(--f3,hsl(300,50%,32%))"/>
<path d="M 122 62 C 120 76, 108 86, 88 92 C 85 93, 83 92, 82 90 C 88 88, 104 80, 116 62 Z" fill="var(--f3,hsl(300,50%,32%))"/>
<path d="M 118 60 C 116 72, 102 80, 76 85 L 75 83 C 100 79, 113 71, 112 60 Z" fill="var(--f3,hsl(300,50%,32%))"/>
<path d="M 114 58 C 111 69, 96 75, 66 78 L 65 76 C 94 74, 108 67, 108 58 Z" fill="var(--f3,hsl(300,50%,32%))"/>
<path d="M 111 55 C 107 63, 92 67, 58 68 L 58 66 C 90 66, 104 62, 105 55 Z" fill="var(--f3,hsl(300,50%,32%))"/>
<path d="M 96 30 C 104 18, 116 14, 122 18 C 116 26, 108 32, 100 34 Z" fill="var(--f3,hsl(300,50%,32%))"/>
<path d="M 96 68 C 104 80, 116 84, 122 80 C 116 72, 108 66, 100 64 Z" fill="var(--f3,hsl(300,50%,32%))"/>
<path d="M 26 47 C 52 30, 86 26, 112 26 C 118 26, 120 30, 120 36 L 120 60 C 120 66, 118 70, 112 70 C 86 70, 52 64, 26 47 Z" fill="var(--f1,hsl(300,45%,48%))"/>
<path d="M 30 48 C 56 60, 88 66, 112 65 L 112 69 C 86 70, 52 64, 30 50 Z" fill="var(--f2,hsl(300,30%,70%))"/>
<ellipse cx="126" cy="44" rx="15" ry="17" fill="var(--f1,hsl(300,45%,48%))"/>
<ellipse cx="50" cy="46" rx="4.5" ry="3" fill="var(--f4,hsl(300,45%,26%))"/>
<ellipse cx="72" cy="42" rx="5" ry="3.5" fill="var(--f4,hsl(300,45%,26%))"/>
<ellipse cx="94" cy="48" rx="4.5" ry="3" fill="var(--f4,hsl(300,45%,26%))"/>
<ellipse cx="106" cy="58" rx="3.5" ry="2.5" fill="var(--f4,hsl(300,45%,26%))"/>
<circle cx="130" cy="40" r="8" fill="#fff"/>
<circle cx="132" cy="40" r="4" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+27
View File
@@ -0,0 +1,27 @@
<!-- Осётр (sturge): удлинённое тело ~3:1, остроконическое рыло, кырьиши вдоль спинки, разнорострый хвост (верхняя лопасть длиннее) -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: разнорострый, верхняя лопасть заметно длиннее нижней -->
<path fill="var(--f3,hsl(200,50%,32%))" d="M26,42 C18,34 10,29 5,25 C9,34 14,41 18,45 L18,55 C15,57 13,58.5 11,60 C14,58.5 18,56 22,54 Z"/>
<!-- спинной плавник: маленький, смещён к хвосту -->
<path fill="var(--f3,hsl(200,50%,32%))" d="M36,41 C40,30 49,27 56,31 C51,36 45,39 38,41 Z"/>
<!-- анальный плавник: маленький, сзади -->
<path fill="var(--f3,hsl(200,50%,32%))" d="M40,63 L36,70 L46,64 Z"/>
<!-- грудной плавник -->
<path fill="var(--f3,hsl(200,50%,32%))" d="M102,50 C96,57 96,65 103,71 C109,65 111,57 109,50 Z"/>
<!-- тело: удлинённое, заострённое коническое рыло -->
<path fill="var(--f1,hsl(200,45%,48%))" d="M154,47 C144,40 130,35.5 112,34 C96,33 80,33.5 64,35 C48,36.5 34,39 26,42 L24,44 L24,56 L26,58 C34,61 48,64 64,66 C80,67.5 96,68 112,66 C130,63.5 144,55 154,47 Z"/>
<!-- брюхо: светлее, лунка вдоль нижней кромки -->
<path fill="var(--f2,hsl(200,30%,70%))" d="M154,47 C144,55 130,63.5 112,66 C96,68 80,67.5 64,66 C48,64 34,61 26,58 L24,56 L24,51 C34,54.5 52,57 76,58 C100,59 132,55 154,47 Z"/>
<!-- кырьиши: ряд костных бугорков вдоль спинки -->
<path fill="var(--f4,hsl(200,45%,26%))" d="M35.5,39.7 L40,33.6 L44.5,38.2 Z"/>
<path fill="var(--f4,hsl(200,45%,26%))" d="M47.5,37.2 L52,32.4 L56.5,36.3 Z"/>
<path fill="var(--f4,hsl(200,45%,26%))" d="M59.5,35.9 L64,31.4 L68.5,35.2 Z"/>
<path fill="var(--f4,hsl(200,45%,26%))" d="M71.5,34.8 L76,30.4 L80.5,34.4 Z"/>
<path fill="var(--f4,hsl(200,45%,26%))" d="M83.5,34.3 L88,29.8 L92.5,34.2 Z"/>
<path fill="var(--f4,hsl(200,45%,26%))" d="M95.5,34.1 L100,30.2 L104.5,34.4 Z"/>
<!-- пасть: тёмная щель на острие рыла -->
<path fill="var(--f4,hsl(200,45%,26%))" d="M154,47 L152.2,50.2 L137,48.4 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="131" cy="42" r="3.4"/>
<circle fill="#142638" cx="131.6" cy="42" r="1.7"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

+26
View File
@@ -0,0 +1,26 @@
<!-- Рыба-меч (swordfish): удлинённое тело ~3:1, длинный заострённый «меч» спереди, высокий спинной плавник, хвост-полумесяц -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост-полумесяц: верхняя серповидная лопасть -->
<path fill="var(--f3,hsl(250,50%,32%))" d="M43,47.5 C37,41 29,32 17,25 C20,35 24,43 30,49.5 C34,49.8 38.5,48.8 43,47.5 Z"/>
<!-- хвост-полумесяц: нижняя серповидная лопасть -->
<path fill="var(--f3,hsl(250,50%,32%))" d="M43,52.5 C37,59 29,68 17,75 C20,65 24,57 30,50.5 C34,50.2 38.5,51.2 43,52.5 Z"/>
<!-- спинной плавник: большой, высокий -->
<path fill="var(--f3,hsl(250,50%,32%))" d="M64,39.5 C70,30 80,25.5 92,27.5 C86,32 82,35.5 80,38.5 C75,39 69,39.3 64,39.5 Z"/>
<!-- тело: удлинённое ~3:1, голова справа -->
<path fill="var(--f1,hsl(250,45%,48%))" d="M112,43 C98,37 78,36 60,40 C50,42.5 44,46 41,50 C44,54 50,57.5 60,60 C78,64 98,63 112,57 C115,53.5 115,46.5 112,43 Z"/>
<!-- брюхо: светлее, лунка вдоль нижней кромки -->
<path fill="var(--f2,hsl(250,30%,70%))" d="M43,48.5 C47,52 53,54.5 61,56 C78,59 97,58 110.5,53 L112,57 C98,63 78,64 60,60 C50,57.5 44,54 41,50 C41.6,49.6 42.3,49 43,48.5 Z"/>
<!-- анальный плавник: маленький, сзади -->
<path fill="var(--f3,hsl(250,50%,32%))" d="M58,59.3 C62,63.5 68,66 75,65.8 C70.5,62.5 66.5,60.3 63,59.2 Z"/>
<!-- брюшной плавник: маленький, у головы -->
<path fill="var(--f3,hsl(250,50%,32%))" d="M90,58.2 C93,62 97,64.3 103,64.3 C99,61 95.5,59 93,58.1 Z"/>
<!-- грудной плавник: у головы, под жаберной крышкой -->
<path fill="var(--f3,hsl(250,50%,32%))" d="M99,51.5 C103,54.5 107.5,56.5 112.5,57 C108.5,53.5 104.5,51.5 101.5,50.3 Z"/>
<!-- меч: длинный заострённый клинок спереди, ~30% ширины рыбы -->
<path fill="var(--f3,hsl(250,50%,32%))" d="M144,50 L106,44 L106,53 Z"/>
<!-- жаберная крышка: тонкий полумесяц-узор -->
<path fill="var(--f4,hsl(250,45%,26%))" d="M95,42.5 C98.5,46 98.5,54 95,57.5 C97.3,53.5 97.3,46.5 95,42.5 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="104" cy="47" r="3.8"/>
<circle fill="#142638" cx="105" cy="47" r="1.9"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<path d="M46 50 C34 37 24 31 17 26 C20 37 22 44 27 50 C22 56 20 63 17 74 C24 69 34 63 46 50 Z" fill="var(--f3,hsl(95,50%,32%))"/>
<path d="M54 31 C56 12 86 5 103 14 C106 16 107 21 105 28 C90 24 68 26 54 31 Z" fill="var(--f3,hsl(95,50%,32%))"/>
<path d="M140 50 C128 32 105 23 78 23 C58 23 44 30 38 42 C36 46 36 54 38 58 C44 70 58 77 78 77 C105 77 128 68 140 50 Z" fill="var(--f1,hsl(95,45%,48%))"/>
<path d="M38 58 C44 70 58 77 78 77 C105 77 128 68 140 50 C133 57 123 62 112 65 C94 70 68 70 52 64 C46 61 41 59 38 58 Z" fill="var(--f2,hsl(95,30%,70%))"/>
<path d="M103 55 C111 51 120 54 122 62 C115 65 106 63 102 58 Z" fill="var(--f3,hsl(95,50%,32%))"/>
<path d="M58 75 C62 88 76 93 88 89 C87 84 86 80 85 76 Z" fill="var(--f3,hsl(95,50%,32%))"/>
<circle cx="122" cy="55" r="4" fill="var(--f4,hsl(95,45%,26%))"/>
<circle cx="104" cy="55" r="5.5" fill="var(--f4,hsl(95,45%,26%))"/>
<circle cx="85" cy="56" r="6" fill="var(--f4,hsl(95,45%,26%))"/>
<circle cx="65" cy="55" r="6" fill="var(--f4,hsl(95,45%,26%))"/>
<circle cx="48" cy="52" r="5" fill="var(--f4,hsl(95,45%,26%))"/>
<circle cx="119" cy="44" r="6.5" fill="#fff"/>
<circle cx="120.5" cy="44" r="3" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+31
View File
@@ -0,0 +1,31 @@
<!-- Тунец (tuna): торпедообразное обтекаемое тело ~3:1, хвост-полумесяц (две серповидные лопасти), маленький спинной плавник + ряд жировых плавничков позади, тёмная спина / светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: полумесяц — верхняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 46 C28 38 17 31 10 27 C13 38 19 45 29 50 L37 46 Z"/>
<!-- хвост: полумесяц — нижняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 54 C28 62 17 69 10 73 C13 62 19 55 29 50 L37 54 Z"/>
<!-- спинной плавник: маленький, впереди -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M101 34.5 L93 18 L115 34.2 Z"/>
<!-- жировые плавнички позади спинного: 3 маленьких треугольника, к хвосту мельчают -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M91 34.3 L85 24 L79 34.6 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M77 34.8 L72 26.5 L66 35 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M64 35.6 L60 29 L55 35.9 Z"/>
<!-- анальный плавник: смещён к хвосту -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M43 58.5 L38 66 L51 62 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M107 62.5 L104 69 L113 64.5 Z"/>
<!-- тело: торпеда, сужается к хвостовому стеблю -->
<path fill="var(--f1,hsl(210,45%,48%))" d="M151 50 C139 40 111 33 81 33 C61 33 47 38 36 45.5 L36 54.5 C47 62 61 67 81 67 C111 67 139 60 151 50 Z"/>
<!-- брюхо: светлое, контраст тёмная спина / светлое брюхо -->
<path fill="var(--f2,hsl(210,30%,70%))" d="M151 50 C139 60 111 67 81 67 C61 67 47 62 36 54.5 C47 58.5 61 60 81 60 C111 60 139 55.5 151 50 Z"/>
<!-- узор: тонкие тёмные линии по нижней половине бока (черта тунца) -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M57 54.6 L73 54.6 L73 55.9 L57 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M79 54.6 L95 54.6 L95 55.9 L79 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M101 54.6 L117 54.6 L117 55.9 L101 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M123 54.6 L133 54.6 L133 55.9 L123 55.9 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M143.5 50.4 C146.5 50.7 148.5 51.7 150 53.1 C148 54.4 145.5 54 144 52.8 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="135" cy="45" r="4"/>
<circle fill="#142638" cx="135.8" cy="45" r="2.1"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

+15
View File
@@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<ellipse cx="28" cy="58" rx="6" ry="3.5" transform="rotate(-20 28 58)" fill="var(--f3,hsl(140,50%,32%))"/>
<ellipse cx="76" cy="62" rx="42" ry="18" fill="var(--f2,hsl(140,30%,70%))"/>
<ellipse cx="76" cy="50" rx="48" ry="24" fill="var(--f1,hsl(140,45%,48%))"/>
<ellipse cx="48" cy="50" rx="6" ry="14" fill="var(--f4,hsl(140,45%,26%))"/>
<ellipse cx="62" cy="50" rx="7" ry="18" fill="var(--f4,hsl(140,45%,26%))"/>
<ellipse cx="76" cy="50" rx="7" ry="20" fill="var(--f4,hsl(140,45%,26%))"/>
<ellipse cx="90" cy="50" rx="7" ry="18" fill="var(--f4,hsl(140,45%,26%))"/>
<ellipse cx="104" cy="50" rx="6" ry="14" fill="var(--f4,hsl(140,45%,26%))"/>
<path d="M 37 56 Q 25 64 25 80 Q 34 70 47 64 Z" fill="var(--f3,hsl(140,50%,32%))"/>
<path d="M 115 56 Q 124 64 127 80 Q 112 79 105 64 Z" fill="var(--f3,hsl(140,50%,32%))"/>
<ellipse cx="134" cy="44" rx="13" ry="10" fill="var(--f2,hsl(140,30%,70%))"/>
<circle cx="139" cy="42" r="4.2" fill="#fff"/>
<circle cx="140" cy="42" r="2.2" fill="#142638"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+23
View File
@@ -0,0 +1,23 @@
<!-- Синий кит (whale): огромное гладкое обтекаемое тело «труба» ~3:1, округлая голова спереди (справа), пологая тёмная щель-рот вдоль нижней челюсти, маленький серповидный боковой плавник низко на теле, ХВОСТ-ВЕСЛО: две горизонтальные лопасти влево-вверх и влево-вниз, 4 складки горла, крошечный глаз, сине-серая палитра -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост-весло: верхняя горизонтальная лопасть (влево-вверх) -->
<path fill="var(--f3,hsl(230,50%,32%))" d="M27 47 C18 43.5 9.5 39.5 6 34 C9.5 40.5 17 46.5 27 51.5 Z"/>
<!-- хвост-весло: нижняя горизонтальная лопасть (влево-вниз) -->
<path fill="var(--f3,hsl(230,50%,32%))" d="M27 55 C18 58.5 9.5 62.5 6 68 C9.5 61.5 17 55.5 27 50.5 Z"/>
<!-- тело: массивная гладкая «труба», округлая голова спереди, сужение к хвостовому стеблю -->
<path fill="var(--f1,hsl(230,45%,48%))" d="M150 48 C146 40 131 32.5 107 30.5 C82 28.5 56 31 40 37.5 C33 40.5 27.5 43.5 24 46.5 L24 55.5 C27.5 58.5 33 61.5 40 64.5 C56 71 82 73.5 107 71.5 C131 69.5 146 62 150 48 Z"/>
<!-- брюхо: светлое, пологая полоса снизу (толще к голове) -->
<path fill="var(--f2,hsl(230,30%,70%))" d="M150 48 C146 62 131 69.5 107 71.5 C82 73.5 56 71 40 64.5 C33 61.5 27.5 58.5 24 55.5 C31 58.8 38 61.3 47 63.3 C68 67.5 94 68 117 64.5 C134 61.5 145.5 55.5 150 48 Z"/>
<!-- боковой плавник: маленький серп низко на теле, заострён назад -->
<path fill="var(--f3,hsl(230,50%,32%))" d="M114 59 C107 65 98 71.5 86 76.5 C96 75.5 107 69 114 59 Z"/>
<!-- рот: пологая тёмная щель вдоль нижней части головы (не открытая пасть) -->
<path fill="var(--f4,hsl(230,45%,26%))" d="M149.5 49 C142.5 57.5 132.5 65 120.5 69 C133 67.5 144 59.5 149.5 49 Z"/>
<!-- складки горла: 4 пологие поперечные линии вдоль нижней челюсти -->
<path fill="none" stroke="var(--f4,hsl(230,45%,26%))" stroke-width="2" stroke-linecap="round" d="M143.5 55 Q141 58.5 143 62"/>
<path fill="none" stroke="var(--f4,hsl(230,45%,26%))" stroke-width="2" stroke-linecap="round" d="M134 61 Q131.5 64.5 133.5 68"/>
<path fill="none" stroke="var(--f4,hsl(230,45%,26%))" stroke-width="2" stroke-linecap="round" d="M124.5 64.5 Q122 67.5 124 70.2"/>
<path fill="none" stroke="var(--f4,hsl(230,45%,26%))" stroke-width="2" stroke-linecap="round" d="M115 66.5 Q112.5 69 114.5 71.3"/>
<!-- глаз: крошечный — белый круг + зрачок -->
<circle fill="#fff" cx="137" cy="45" r="2.9"/>
<circle fill="#142638" cx="137.8" cy="45" r="2.2"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

+24
View File
@@ -0,0 +1,24 @@
<!-- Судак (zander): удлинённое тело ~2.5:1, заострённая морда, два спинных плавника, вилочный хвост, тёмная полоса вдоль бока -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: вилочный -->
<path fill="var(--f3,hsl(180,50%,32%))" d="M40 47 L15 26 L27 50 L15 74 L40 53 Z"/>
<!-- спинной плавник (передний, колючий) -->
<path fill="var(--f3,hsl(180,50%,32%))" d="M56 36 Q68 8 86 30.5 Z"/>
<!-- спинной плавник (задний, мягкий) -->
<path fill="var(--f3,hsl(180,50%,32%))" d="M88 30 Q99 10 111 32.5 Z"/>
<!-- тело: удлинённое, заострённая морда -->
<path fill="var(--f1,hsl(180,45%,48%))" d="M36 48 C46 35 70 28 96 29 C118 30 136 40 146 50 C136 60 118 70 96 71 C70 72 46 65 36 52 Z"/>
<!-- брюхо: светлее -->
<path fill="var(--f2,hsl(180,30%,70%))" d="M36 52 C46 65 70 72 96 71 C118 70 136 60 146 50 C128 55.5 102 60 78 60.5 C58 61 43 57.5 36 52 Z"/>
<!-- узор: тёмная полоса вдоль бока от головы к хвосту -->
<path fill="var(--f4,hsl(180,45%,26%))" d="M118 41.5 C102 39.8 90 39.8 78 40.5 C60 41.5 47 44 39 47.5 L39 53.5 C47 56 60 53 78 51.5 C98 51.8 110 52.3 118 52 Z"/>
<!-- грудной плавник -->
<path fill="var(--f3,hsl(180,50%,32%))" d="M111 54 C106 59 106 63.5 111 66.5 C114 62 115 58 113 54 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(180,50%,32%))" d="M64 66.5 L59 75 L69 67.5 Z"/>
<!-- анальный плавник -->
<path fill="var(--f3,hsl(180,50%,32%))" d="M88 70 L82 78.5 L94 71 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="126" cy="43" r="4.5"/>
<circle fill="#142638" cx="127" cy="43" r="2.2"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+19
View File
@@ -761,3 +761,22 @@ git add -A && git commit -m "что изменилось" && git push
**Размеры (полная длина силуэта; лодка = 64 px):** 0.1 кг → 8 (19.6 px, 0.3×) · 1 кг → 22.7 (56 px, 0.9×) · 5 кг → 33.3 (82 px, 1.3×) · 10 кг → 37.5 (92 px, 1.4×) · 20 кг (босс min) → 44.7 (110 px, 1.7×) · 50 кг (босс max) → 47.8 (117 px, 1.8×) · 100 кг (кит max) → 52.2 (128 px, **2×**). Диапазон 8..52 px = ×6.5 (было ~9..22 = ×2.4). Тяжёлая рыба в конце вываживания (позиция `boatX+24`, поверх лодки) заметно её перекрывает — осознанный эффект «вывезена рядом с лодкой»; на мобильном 360 px кит ≈ 35% ширины.
**Тесты:** пины на размер силуэта в `tests/test.js` отсутствуют (проверено: `drawFishShape`/`drawHookedFish`/`fishReelPos` не ассертятся; `reel.w` в тестах — для физики). Итого **193/193 PASS, exit 0**; `check.mjs` OK; `tools/balance.mjs` — пины без изменений (Река 65.1/125.9 · Озёра 194.1/249.0 · Море 297.3/476.7 · Океан 329.1/552.7). Скриншоты перегенерированы (`gen-screenshots.js`, 30 кадров; кадр `reel` форсит `reel.w=12.5` — рыба ~92 px вместо ~30).
## Этап 42. SVG-портреты рыб в дневнике и карточке улова
**Задача:** подключить уже вшитый SVG-спрайт (32 symbol, предыдущий этап) к UI: дневник и карточка улова показывают портрет вида вместо эмодзи; варианты перекрашивают портрет.
**Решения:**
- **Портреты:** 32 flat-SVG в `assets/fish/fish-<id>.svg` (по одному на вид, viewBox 0 0 160 100, цвета `var(--f1..f4, hsl-fallback)` — переменные НЕ объявлены на `<svg>`/`<g>`, наследуются извне). Встраивание — `node tools/embed-fish.mjs` (идемпотентно: заменяет блок между маркерами `FISH-SVG:BEGIN/END` в index.html сразу после `<body>`; самопроверка + `check.mjs` внутри); приёмка — `tools/fish-preview.html` (file://).
- **Дневник и карточка через `<use>`:** пойманные виды в дневнике — `<svg viewBox="0 0 160 100"><use href="#fish-<id>">` в `.jrow .je` (не пойманные — по-прежнему ❓-эмодзи); карточка — `<use id="cardFishUse">` внутри `#cardEmoji` (span сохранён: на нём bob-анимация и variant-классы), `showCard` ставит `href='#fish-'+sp.id` (вместо `textContent=sp.emoji`). CSS: `.jrow .je svg` 44×28 (моб. 40×26), `#card .bigemoji svg` 120×75 (моб. 94×59, низкий экран 81×50.6 — соотношение 160:100).
- **Перекраска вариантов — CSS-переменные:** 5 новых правил `#card.<variant>-card .bigemoji{--f1:…;--f3:…}` (copper/gold/quartz/emerald/diamond — цвет тела/плавников; переменные наследуются сквозь `<use>` в спрайт). silver/rainbow закрываются существующими filter-правилами (grayscale/rainbowhue), boss — золотым filter — всё без изменений.
- **Не тронуто:** тосты улова/обрыва (`sp.emoji` + вес) и иконка квеста `catch_species` — эмодзи там уместны (перекрыто второй частью этапа — см. ниже); сам спрайт, `SPECIES` и логика улова.
**Тесты:** пины в `tests/test.js` (тот же коммит): **lc1** (10f) — `sprites===32` (число `<symbol>` в `#fishSprites`) + `spriteIdsOk` (для каждого вида из SPECIES есть id `fish-<id>`), текст «SVG-спрайт: 32 symbol, id на каждый вид»; **M6 карточка** — в пробе `showCard` (sp = SPECIES[0]) `href #cardFishUse` = `#fish-carass` для всех 8 вариантов. Итого **193/193 PASS, exit 0** (пины расширены на месте, новых ok() нет); `check.mjs` OK; `emoji-font.py --check` OK (64 emoji, новых глифов нет).
**Вторая часть этапа — полное удаление эмодзи рыб из игры:**
- **SPECIES/тосты:** поле `emoji` удалено из всех 32 записей `SPECIES`; два тоста (обрыв `snap`/`snap_big` и срыв `escaped`) — без `sp.emoji`, остаётся «… Имя вида W кг».
- **Иконка квеста `catch_species`:** `questIcon` теперь возвращает mini-SVG портрет `<svg class="qfish" viewBox="0 0 160 100"><use href="#fish-<id>">` (вид не найден — ❓). CSS `.jrow .je .qfish{width:24px;height:15px;display:inline-block;vertical-align:-2px}` — скоуп `.jrow .je` обязателен: иначе правило портрета `.jrow .je svg` (44×28, выше по специфичности) не даст иконке уместиться в строку квеста.
- **Остальные рыбные эмодзи (12 видов) заменены глифами, уже бывшими в субсете:** воблер `icon:'🐟'`→`'🎣'`; ачивки: first_catch `🐟`→`🏅`, weight_20 `🐋`→`💪` (лестница весов ⚖/💪/🚢 у 10/20/1000 кг), пер-босс 🦞/🦈/🐳 → 🗺️/⚓/🌊 (иконки локаций — те же, что у lake_first/sea_first/ocean_first). Рыбка-маркер на канвасе (в `drawMeters`: маркер на конце полоски дистанции + иконка-легенда под ней) теперь рисуется path-рыбкой — новый `drawFishMark(x,y,s)` (эллипс-тело + треугольный хвост + глазок) вместо `fillText('🐟')`; комментарии с 🐟 очищены (генератор шрифта сканирует весь файл, включая комментарии).
- **Шрифт перегенерирован:** `tools/emoji-font.py` — субсет **64 → 52 глифа** (ровно 12 рыбных; замены не добавили новых — все уже были в инвентаре), woff2 89 → 65 КБ.
- **Тесты:** `tests/test.js` (тот же коммит) — в пине **lc1** убран `s.emoji &&` из `fieldsOk` (+ комментарий «поле emoji убрано в этапе 42»); других пинов на `.emoji`/эмодзи в тостах/квестах не нашлось (grep). Итого **193/193 PASS, exit 0** (Y7 `document.fonts.check('16px "EmojiEmbedded"','🪙')` — монета в субсете на месте); `check.mjs` OK; `emoji-font.py --check` OK (52 emoji); финальный grep по 12 рыбным эмодзи в index.html — 0 вхождений.
+789 -60
View File
File diff suppressed because one or more lines are too long
+16 -9
View File
@@ -1624,14 +1624,16 @@ async function toGameMenu(p) {
res[id] = {
txt: document.getElementById('cardVariant').textContent,
hidden: document.getElementById('cardVariant').classList.contains('hidden'),
cls
cls,
// SVG-портрет: showCard ставит href у #cardFishUse на symbol вида (sp = SPECIES[0] = carass)
href: document.getElementById('cardFishUse').getAttribute('href')
};
};
for (const id of VARIANTS.map(v => v.id)) probe(id);
document.getElementById('card').classList.add('hidden');
return res;
});
ok('M6 карточка: все варианты — бейдж «МЕДНАЯ»/«СЕРЕБРЯНАЯ»/«КВАРЦЕВАЯ»/«ЗОЛОТАЯ»/«ИЗУМРУДНАЯ»/«АЛМАЗНАЯ»/«РАДУЖНАЯ» + класс <id>-card; normal — бейдж скрыт',
ok('M6 карточка: все варианты — бейдж «МЕДНАЯ»/«СЕРЕБРЯНАЯ»/«КВАРЦЕВАЯ»/«ЗОЛОТАЯ»/«ИЗУМРУДНАЯ»/«АЛМАЗНАЯ»/«РАДУЖНАЯ» + класс <id>-card; normal — бейдж скрыт; SVG-портрет: href #cardFishUse = #fish-carass (вид SPECIES[0])',
m6card.copper.hidden === false && m6card.copper.txt === 'МЕДНАЯ' && m6card.copper.cls === 'copper'
&& m6card.silver.hidden === false && m6card.silver.txt === 'СЕРЕБРЯНАЯ' && m6card.silver.cls === 'silver'
&& m6card.quartz.hidden === false && m6card.quartz.txt === 'КВАРЦЕВАЯ' && m6card.quartz.cls === 'quartz'
@@ -1639,8 +1641,9 @@ async function toGameMenu(p) {
&& m6card.emerald.hidden === false && m6card.emerald.txt === 'ИЗУМРУДНАЯ' && m6card.emerald.cls === 'emerald'
&& m6card.diamond.hidden === false && m6card.diamond.txt === 'АЛМАЗНАЯ' && m6card.diamond.cls === 'diamond'
&& m6card.rainbow.hidden === false && m6card.rainbow.txt === 'РАДУЖНАЯ' && m6card.rainbow.cls === 'rainbow'
&& m6card.normal.hidden === true && m6card.normal.cls === 'none',
JSON.stringify(m6card));
&& m6card.normal.hidden === true && m6card.normal.cls === 'none'
&& Object.values(m6card).every(r => r.href === '#fish-carass'),
JSON.stringify(m6card));
// (8) full_variants: все 8 видов × 8 вариантов → +5000 ровно один раз, coinPct +0.05, повторно — без выплаты
const m6fv = await page.evaluate(() => {
@@ -1970,8 +1973,8 @@ async function toGameMenu(p) {
lakeOrder: SPECIES.slice(8, 18).map(s => s.id).join(','),
seaOrder: SPECIES.slice(18, 23).map(s => s.id).join(','),
oceanOrder: SPECIES.slice(23).map(s => s.id).join(','),
// у каждого вида есть обязательные поля (nameEn — для EN-ветки trName)
fieldsOk: SPECIES.every(s => s.id && s.name && s.nameEn && s.emoji && typeof s.rarity === 'number' &&
// у каждого вида есть обязательные поля (nameEn — для EN-ветки trName; поле emoji убрано в этапе 42 — портреты из SVG-спрайта)
fieldsOk: SPECIES.every(s => s.id && s.name && s.nameEn && typeof s.rarity === 'number' &&
typeof s.weight === 'number' && typeof s.minDist === 'number' && typeof s.strength === 'number' &&
typeof s.wMin === 'number' && typeof s.wMax === 'number' && s.wMax > s.wMin &&
typeof s.price === 'number' && typeof s.hue === 'number'),
@@ -1979,10 +1982,13 @@ async function toGameMenu(p) {
costs: LOCATIONS.map(l => l.cost).join(','),
names: LOCATIONS.map(l => l.name).join(','),
water: LOCATIONS.every(l => Array.isArray(l.water) && l.water.length === 6 &&
l.water.every(h2 => typeof h2 === 'string' && /^#[0-9a-fA-F]{6}$/.test(h2)))
l.water.every(h2 => typeof h2 === 'string' && /^#[0-9a-fA-F]{6}$/.test(h2))),
// SVG-спрайт портретов (блок FISH-SVG, tools/embed-fish.mjs): по symbol на каждый вид
sprites: document.querySelectorAll('#fishSprites symbol').length,
spriteIdsOk: SPECIES.every(s => document.getElementById('fish-' + s.id) !== null)
};
});
ok('локации данные: SPECIES=32 (8 река + 10 озёра + 5 море + 9 океан, этапы 35/36) — zander «Судак» r2 8🪙, crayfish r3 40🪙, navaga r3 50🪙; озёрные новинки rudd «Краснопёрка» r1 5🪙, cisco «Сиг» r2 18🪙; морские herring «Сельдь» r0 8🪙, mackerel «Скумбрия» r1 18🪙, flounder «Камбала» r2 33🪙, tuna «Тунец» r3 46🪙, swordfish «Рыба-меч» r4 81🪙; океанские moray «Гигантская мурена» r0 5🪙, grouper «Горбуна» r0 5🪙, turtle «Морская черепаха» r1 9🪙, angler «Удильщик» r2 21🪙, octopus «Гигантский осьминог» r2 23🪙, manta «Скат-манта» r3 29🪙, shark «Большая белая акула» r3 31🪙, squid «Гигантский кальмар» r4 37🪙, whale «Синий кит» r4 67🪙 40–100 кг; этап 38: лестница веса (Озёра ×8 / Море ×6, меч ×4 / Океан ×4, кит ×2; Река не меняется); этап 39: цены Озёр/Моря/Океана урезаны (Озёра ≈×3 Реки, Море ≈×4, Океан ≈×5 — по дню; Река не меняется); первые 8 id не сдвинуты, новые — в конце; все поля заполнены; LOCATIONS 4 (Река 0 / Озёра 65536 / Море 131072 / Океан 196608), у каждой 6 hex в water',
ok('локации данные: SPECIES=32 (8 река + 10 озёра + 5 море + 9 океан, этапы 35/36) — zander «Судак» r2 8🪙, crayfish r3 40🪙, navaga r3 50🪙; озёрные новинки rudd «Краснопёрка» r1 5🪙, cisco «Сиг» r2 18🪙; морские herring «Сельдь» r0 8🪙, mackerel «Скумбрия» r1 18🪙, flounder «Камбала» r2 33🪙, tuna «Тунец» r3 46🪙, swordfish «Рыба-меч» r4 81🪙; океанские moray «Гигантская мурена» r0 5🪙, grouper «Горбуна» r0 5🪙, turtle «Морская черепаха» r1 9🪙, angler «Удильщик» r2 21🪙, octopus «Гигантский осьминог» r2 23🪙, manta «Скат-манта» r3 29🪙, shark «Большая белая акула» r3 31🪙, squid «Гигантский кальмар» r4 37🪙, whale «Синий кит» r4 67🪙 40–100 кг; этап 38: лестница веса (Озёра ×8 / Море ×6, меч ×4 / Океан ×4, кит ×2; Река не меняется); этап 39: цены Озёр/Моря/Океана урезаны (Озёра ≈×3 Реки, Море ≈×4, Океан ≈×5 — по дню; Река не меняется); первые 8 id не сдвинуты, новые — в конце; все поля заполнены; LOCATIONS 4 (Река 0 / Озёра 65536 / Море 131072 / Океан 196608), у каждой 6 hex в water; SVG-спрайт: 32 symbol, id на каждый вид',
lc1.n === 32 && lc1.z === 'Судак,2,8,8,48' && lc1.c === 'Хариус,1,6,1.6,16' && lc1.k === 'Гигантский рак,3,40,1.6,8'
&& lc1.b === 'Плотва,0,4,0.4,4.8' && lc1.r === 'Густера,0,5,0.8,7.2' && lc1.e === 'Вьюн,1,11,0.4,3.2'
&& lc1.t === 'Линь,2,16,2.4,32' && lc1.n2 === 'Навага,3,50,2.4,20'
@@ -1999,7 +2005,8 @@ async function toGameMenu(p) {
&& lc1.seaOrder === 'herring,mackerel,flounder,tuna,swordfish'
&& lc1.oceanOrder === 'moray,grouper,turtle,angler,octopus,manta,shark,squid,whale'
&& lc1.fieldsOk === true
&& lc1.locs === 4 && lc1.costs === '0,65536,131072,196608' && lc1.names === 'Река,Озёра,Море,Океан' && lc1.water === true,
&& lc1.locs === 4 && lc1.costs === '0,65536,131072,196608' && lc1.names === 'Река,Озёра,Море,Океан' && lc1.water === true
&& lc1.sprites === 32 && lc1.spriteIdsOk === true,
JSON.stringify(lc1));
// (2) таблицы: река — ровно старые 8 (порядок), озёра — только свои 10, море — только свои 5, океан — только свои 9, ночные веса — числа; пересечений нет
+137
View File
@@ -0,0 +1,137 @@
#!/usr/bin/env node
// tools/embed-fish.mjs — встраивает 32 SVG-портрета рыб (assets/fish/fish-<id>.svg)
// в index.html как СКРЫТЫЙ SVG-спрайт из <symbol> (id="fish-<id>", viewBox 0 0 160 100).
//
// Запуск: node tools/embed-fish.mjs (из каталога репо или откуда угодно — пути от репо)
// - идемпотентен: если маркеры FISH-SVG:BEGIN/END уже есть — заменяет ВСЁ между ними;
// если нет — вставляет блок сразу ПОСЛЕ открывающего тега <body> (в начале файла).
// - после записи — самопроверка: 32 вхождения id="fish-, оба маркера, затем node tools/check.mjs.
// Чистый Node, без npm-зависимостей. Детерминирован: одинаковый ввод → одинаковый index.html.
//
// ВАЖНО: это НЕ подключение UI. Дневник/карточка/JS-логику НЕ трогаем —
// <use href="#fish-<id>"> подключит следующий этап.
import { readFileSync, writeFileSync } from 'node:fs';
import { execFileSync } from 'node:child_process';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const INDEX = join(ROOT, 'index.html');
const ASSETS = join(ROOT, 'assets', 'fish');
// Порядок = порядок SPECIES в index.html (карасс → кит).
const IDS = [
'carass', 'perch', 'bream', 'carp', 'pike', 'catfish', 'sturge', 'gold',
'zander', 'chuch', 'crayfish', 'bleak', 'roundel', 'eelpout', 'tench', 'navaga',
'rudd', 'cisco', 'herring', 'mackerel', 'flounder', 'tuna', 'swordfish',
'moray', 'grouper', 'turtle', 'angler', 'octopus', 'manta', 'shark', 'squid', 'whale',
];
const BEGIN = '<!-- FISH-SVG:BEGIN (генерируется tools/embed-fish.mjs — не править руками) -->';
const END = '<!-- FISH-SVG:END -->';
const VIEWBOX = 'viewBox="0 0 160 100"';
function fail(msg) {
console.error(`embed-fish: ОШИБКА: ${msg}`);
process.exit(1);
}
// Чтение и валидация одного fish-<id>.svg → ВНУТРЕННЕЕ содержимое (между '>' корневого
// <svg ...> и '</svg>'). Корневой тег (width/height) в symbol не нужен — только viewBox.
function loadInner(id) {
const file = `fish-${id}.svg`;
let s;
try {
s = readFileSync(join(ASSETS, file), 'utf8');
} catch (e) {
fail(`${file} (вид ${id}): не удалось прочитать: ${e.message}`);
}
// BOM допустим
if (s.charCodeAt(0) === 0xFEFF) s = s.slice(1);
// Перед <svg допустимы пробельные символы и XML-комментарии (в файлах — поясняющий комментарий вида).
let i = 0;
for (;;) {
const ws = /^[ \t\r\n]+/.exec(s.slice(i));
if (ws) { i += ws[0].length; continue; }
const cm = /^<!--[\s\S]*?-->/.exec(s.slice(i));
if (cm) { i += cm[0].length; continue; }
break;
}
// Корневой тег: <svg, за ним пробел (атрибуты) или '>'
if (!/^<svg([ >])/.test(s.slice(i))) {
fail(`${file} (вид ${id}): файл не начинается с <svg (после BOM/пробелов/комментариев)`);
}
if (!s.includes(VIEWBOX)) {
fail(`${file} (вид ${id}): не найдено ${VIEWBOX}`);
}
if (!s.trimEnd().endsWith('</svg>')) {
fail(`${file} (вид ${id}): файл не заканчивается на </svg>`);
}
const openEnd = s.indexOf('>', i); // закрывающая '>' корневого <svg ...>
const closeStart = s.lastIndexOf('</svg>'); // финальное </svg>
if (openEnd === -1 || closeStart === -1 || closeStart < openEnd) {
fail(`${file} (вид ${id}): нераспознана структура (корневой <svg> / </svg>)`);
}
return s.slice(openEnd + 1, closeStart);
}
// Сборка блока спрайта (строка на symbol; внутреннее содержимое — как в исходнике).
function buildBlock() {
const lines = [BEGIN, '<svg id="fishSprites" width="0" height="0" style="position:absolute" aria-hidden="true">'];
for (const id of IDS) {
lines.push(`<symbol id="fish-${id}" ${VIEWBOX}>${loadInner(id)}</symbol>`);
}
lines.push('</svg>', END);
return lines.join('\n');
}
// --- основная логика ---
let html;
try {
html = readFileSync(INDEX, 'utf8');
} catch (e) {
fail(`не удалось прочитать ${INDEX}: ${e.message}`);
}
const block = buildBlock();
const b = html.indexOf(BEGIN);
const e = html.indexOf(END);
if (b !== -1 || e !== -1) {
// Маркеры есть (хотя бы один) — заменяем ВСЁ между ними (идемпотентность повторного запуска).
if (b === -1 || e === -1 || e < b) fail('маркеры FISH-SVG:BEGIN/END найдены, но парно/порядком — index.html повреждён');
html = html.slice(0, b) + block + html.slice(e + END.length);
console.log('embed-fish: маркеры уже есть — блок заменён (повторный запуск)');
} else {
// Маркеров нет — вставляем сразу ПОСЛЕ открывающего тега <body> (с атрибутами, первый в файле).
const m = /<body(\s[^>]*)?>/.exec(html);
if (!m) fail('в index.html не найден открывающий тег <body>');
const pos = m.index + m[0].length;
html = html.slice(0, pos) + '\n' + block + html.slice(pos);
console.log(`embed-fish: блок вставлен после <body> (строка ${html.slice(0, pos).split('\n').length})`);
}
writeFileSync(INDEX, html);
// --- самопроверка: перечитываем файл и убеждаемся, что всё на месте ---
const check = readFileSync(INDEX, 'utf8');
const nSymbols = (check.match(/id="fish-/g) || []).length;
if (nSymbols !== IDS.length) fail(`самопроверка: ожидалось ${IDS.length} вхождений id="fish-, найдено ${nSymbols}`);
if (check.split(BEGIN).length - 1 !== 1) fail('самопроверка: маркер FISH-SVG:BEGIN не найден (или дублируется)');
if (check.split(END).length - 1 !== 1) fail('самопроверка: маркер FISH-SVG:END не найден (или дублируется)');
// Синтаксис JS в index.html (node --check на вынутых блоках) — как п.1 «Проверки» из AGENTS.md.
let out;
try {
out = execFileSync(process.execPath, [join(ROOT, 'tools', 'check.mjs')], { encoding: 'utf8', cwd: ROOT });
} catch (err) {
process.stdout.write(err.stdout || '');
process.stderr.write(err.stderr || String(err));
fail('node tools/check.mjs завершился с ошибкой');
}
process.stdout.write(out);
const blockBytes = Buffer.byteLength(block, 'utf8');
const blockLines = block.split('\n').length;
console.log(`embed-fish: OK — ${IDS.length} символов, блок ${blockBytes} байт / ${blockLines} строк, маркеры на месте, check.mjs пройден`);
+347
View File
@@ -0,0 +1,347 @@
<!DOCTYPE html>
<!-- tools/fish-preview.html — страница визуальной приёмки портретов рыб (32 вида).
Открывается напрямую через file:// — только <img> и инлайн-SVG, без fetch().
Порядок карточек = порядок SPECIES в index.html. -->
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Портреты рыб — приёмка (32)</title>
<style>
/* Тёмный фон в стиле игры (та же база, что html,body в index.html: #0d3b66) */
body{margin:0;background:#0d3b66;color:#fff;
font-family:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
padding:24px 20px 40px}
h1{font-size:24px;margin:0 0 4px;color:#ffe9a8;text-shadow:0 1px 2px rgba(0,0,0,.4)}
h2{font-size:19px;margin:36px 0 6px;color:#ffe9a8;text-shadow:0 1px 2px rgba(0,0,0,.4)}
.sub{color:rgba(255,255,255,.65);font-size:13px;margin-bottom:16px;line-height:1.45}
/* Сетка карточек (оформление как HUD-элементы игры: тёмно-синий градиент, золотистая кайма) */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}
.card{background:linear-gradient(rgba(9,32,58,.72),rgba(6,25,45,.62));
border:1px solid rgba(255,233,168,.22);border-radius:14px;padding:10px;
display:flex;flex-direction:column;gap:8px;align-items:center;
box-shadow:0 3px 10px rgba(0,0,0,.3),inset 0 1px 0 rgba(255,255,255,.1)}
.card img{width:160px;height:100px;background:rgba(255,255,255,.05);border-radius:8px}
.card .name{font-size:14px;font-weight:600;text-align:center;line-height:1.3}
/* Блок «Варианты»: 8 копий инлайн-SVG тунца; перекраска — CSS-переменными --f1/--f3
(те же, что во всех fish-*.svg), свечение/градиент — filter на контейнере копии */
.vcard{background:linear-gradient(rgba(9,32,58,.72),rgba(6,25,45,.62));
border:1px solid rgba(255,233,168,.22);border-radius:14px;padding:10px;
display:flex;flex-direction:column;gap:8px;align-items:center;
box-shadow:0 3px 10px rgba(0,0,0,.3),inset 0 1px 0 rgba(255,255,255,.1)}
.vimg{width:160px;height:100px;background:rgba(255,255,255,.05);border-radius:8px}
.vimg svg{display:block;width:160px;height:100px}
.vlabel{font-size:13px;font-weight:600;color:#ffe9a8;font-family:ui-monospace,Consolas,monospace}
/* Оверрайды вариантов (демо того, как будут выглядеть варианты в карточке улова) */
.v-normal{ /* normal — без оверрайдов */ }
.v-copper{--f1:hsl(25,55%,55%);--f3:hsl(25,50%,35%);filter:drop-shadow(0 0 12px rgba(217,154,98,.9))}
.v-silver{filter:grayscale(.85) brightness(1.25) drop-shadow(0 0 12px rgba(210,228,245,.9))}
.v-quartz{--f1:hsl(270,25%,72%);--f3:hsl(270,25%,45%);filter:drop-shadow(0 0 12px rgba(205,191,224,.9))}
.v-gold{--f1:#ffd75e;--f3:hsl(45,70%,40%);filter:drop-shadow(0 0 12px rgba(255,215,94,.9))}
.v-emerald{--f1:hsl(150,55%,42%);--f3:hsl(150,50%,28%);filter:drop-shadow(0 0 12px rgba(46,189,107,.9))}
.v-diamond{--f1:hsl(200,60%,78%);--f3:hsl(200,50%,45%);filter:drop-shadow(0 0 12px rgba(109,184,242,.95))}
.v-rainbow{animation:hue-rotate 2.4s linear infinite}
@keyframes hue-rotate{from{filter:hue-rotate(0deg)}to{filter:hue-rotate(360deg)}}
</style>
</head>
<body>
<h1>Портреты рыб — приёмка (32)</h1>
<div class="sub">
Каждый портрет — <code>assets/fish/fish-&lt;id&gt;.svg</code> (viewBox 0 0 160 100),
цвета через <code>var(--f1..f4, hsl-фолбэк)</code>. Порядок — как в <code>SPECIES</code> в index.html.
</div>
<div class="grid">
<div class="card"><img src="../assets/fish/fish-carass.svg" width="160" height="100" alt="carass — Карась"><div class="name">carass — Карась</div></div>
<div class="card"><img src="../assets/fish/fish-perch.svg" width="160" height="100" alt="perch — Окунь"><div class="name">perch — Окунь</div></div>
<div class="card"><img src="../assets/fish/fish-bream.svg" width="160" height="100" alt="bream — Лещ"><div class="name">bream — Лещ</div></div>
<div class="card"><img src="../assets/fish/fish-carp.svg" width="160" height="100" alt="carp — Карп"><div class="name">carp — Карп</div></div>
<div class="card"><img src="../assets/fish/fish-pike.svg" width="160" height="100" alt="pike — Щука"><div class="name">pike — Щука</div></div>
<div class="card"><img src="../assets/fish/fish-catfish.svg" width="160" height="100" alt="catfish — Сом"><div class="name">catfish — Сом</div></div>
<div class="card"><img src="../assets/fish/fish-sturge.svg" width="160" height="100" alt="sturge — Осётр"><div class="name">sturge — Осётр</div></div>
<div class="card"><img src="../assets/fish/fish-gold.svg" width="160" height="100" alt="gold — Золотая рыбка"><div class="name">gold — Золотая рыбка</div></div>
<div class="card"><img src="../assets/fish/fish-zander.svg" width="160" height="100" alt="zander — Судак"><div class="name">zander — Судак</div></div>
<div class="card"><img src="../assets/fish/fish-chuch.svg" width="160" height="100" alt="chuch — Хариус"><div class="name">chuch — Хариус</div></div>
<div class="card"><img src="../assets/fish/fish-crayfish.svg" width="160" height="100" alt="crayfish — Гигантский рак"><div class="name">crayfish — Гигантский рак</div></div>
<div class="card"><img src="../assets/fish/fish-bleak.svg" width="160" height="100" alt="bleak — Плотва"><div class="name">bleak — Плотва</div></div>
<div class="card"><img src="../assets/fish/fish-roundel.svg" width="160" height="100" alt="roundel — Густера"><div class="name">roundel — Густера</div></div>
<div class="card"><img src="../assets/fish/fish-eelpout.svg" width="160" height="100" alt="eelpout — Вьюн"><div class="name">eelpout — Вьюн</div></div>
<div class="card"><img src="../assets/fish/fish-tench.svg" width="160" height="100" alt="tench — Линь"><div class="name">tench — Линь</div></div>
<div class="card"><img src="../assets/fish/fish-navaga.svg" width="160" height="100" alt="navaga — Навага"><div class="name">navaga — Навага</div></div>
<div class="card"><img src="../assets/fish/fish-rudd.svg" width="160" height="100" alt="rudd — Краснопёрка"><div class="name">rudd — Краснопёрка</div></div>
<div class="card"><img src="../assets/fish/fish-cisco.svg" width="160" height="100" alt="cisco — Сиг"><div class="name">cisco — Сиг</div></div>
<div class="card"><img src="../assets/fish/fish-herring.svg" width="160" height="100" alt="herring — Сельдь"><div class="name">herring — Сельдь</div></div>
<div class="card"><img src="../assets/fish/fish-mackerel.svg" width="160" height="100" alt="mackerel — Скумбрия"><div class="name">mackerel — Скумбрия</div></div>
<div class="card"><img src="../assets/fish/fish-flounder.svg" width="160" height="100" alt="flounder — Камбала"><div class="name">flounder — Камбала</div></div>
<div class="card"><img src="../assets/fish/fish-tuna.svg" width="160" height="100" alt="tuna — Тунец"><div class="name">tuna — Тунец</div></div>
<div class="card"><img src="../assets/fish/fish-swordfish.svg" width="160" height="100" alt="swordfish — Рыба-меч"><div class="name">swordfish — Рыба-меч</div></div>
<div class="card"><img src="../assets/fish/fish-moray.svg" width="160" height="100" alt="moray — Гигантская мурена"><div class="name">moray — Гигантская мурена</div></div>
<div class="card"><img src="../assets/fish/fish-grouper.svg" width="160" height="100" alt="grouper — Горбуна"><div class="name">grouper — Горбуна</div></div>
<div class="card"><img src="../assets/fish/fish-turtle.svg" width="160" height="100" alt="turtle — Морская черепаха"><div class="name">turtle — Морская черепаха</div></div>
<div class="card"><img src="../assets/fish/fish-angler.svg" width="160" height="100" alt="angler — Удильщик"><div class="name">angler — Удильщик</div></div>
<div class="card"><img src="../assets/fish/fish-octopus.svg" width="160" height="100" alt="octopus — Гигантский осьминог"><div class="name">octopus — Гигантский осьминог</div></div>
<div class="card"><img src="../assets/fish/fish-manta.svg" width="160" height="100" alt="manta — Скат-манта"><div class="name">manta — Скат-манта</div></div>
<div class="card"><img src="../assets/fish/fish-shark.svg" width="160" height="100" alt="shark — Большая белая акула"><div class="name">shark — Большая белая акула</div></div>
<div class="card"><img src="../assets/fish/fish-squid.svg" width="160" height="100" alt="squid — Гигантский кальмар"><div class="name">squid — Гигантский кальмар</div></div>
<div class="card"><img src="../assets/fish/fish-whale.svg" width="160" height="100" alt="whale — Синий кит"><div class="name">whale — Синий кит</div></div>
</div>
<h2>Варианты (демо перекраски через CSS-переменные)</h2>
<div class="sub">
Один и тот же инлайн-SVG (tuna) в 8 копиях — оверрайды <code>--f1</code>/<code>--f3</code>
и <code>filter</code> на контейнере копии. Так же будут перекрашиваться варианты
в карточке улова (normal/copper/silver/quartz/gold/emerald/diamond/rainbow).
</div>
<div class="grid">
<div class="vcard"><div class="vimg v-normal"><!-- Тунец (tuna): торпедообразное обтекаемое тело ~3:1, хвост-полумесяц (две серповидные лопасти), маленький спинной плавник + ряд жировых плавничков позади, тёмная спина / светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: полумесяц — верхняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 46 C28 38 17 31 10 27 C13 38 19 45 29 50 L37 46 Z"/>
<!-- хвост: полумесяц — нижняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 54 C28 62 17 69 10 73 C13 62 19 55 29 50 L37 54 Z"/>
<!-- спинной плавник: маленький, впереди -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M101 34.5 L93 18 L115 34.2 Z"/>
<!-- жировые плавнички позади спинного: 3 маленьких треугольника, к хвосту мельчают -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M91 34.3 L85 24 L79 34.6 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M77 34.8 L72 26.5 L66 35 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M64 35.6 L60 29 L55 35.9 Z"/>
<!-- анальный плавник: смещён к хвосту -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M43 58.5 L38 66 L51 62 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M107 62.5 L104 69 L113 64.5 Z"/>
<!-- тело: торпеда, сужается к хвостовому стеблю -->
<path fill="var(--f1,hsl(210,45%,48%))" d="M151 50 C139 40 111 33 81 33 C61 33 47 38 36 45.5 L36 54.5 C47 62 61 67 81 67 C111 67 139 60 151 50 Z"/>
<!-- брюхо: светлое, контраст тёмная спина / светлое брюхо -->
<path fill="var(--f2,hsl(210,30%,70%))" d="M151 50 C139 60 111 67 81 67 C61 67 47 62 36 54.5 C47 58.5 61 60 81 60 C111 60 139 55.5 151 50 Z"/>
<!-- узор: тонкие тёмные линии по нижней половине бока (черта тунца) -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M57 54.6 L73 54.6 L73 55.9 L57 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M79 54.6 L95 54.6 L95 55.9 L79 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M101 54.6 L117 54.6 L117 55.9 L101 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M123 54.6 L133 54.6 L133 55.9 L123 55.9 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M143.5 50.4 C146.5 50.7 148.5 51.7 150 53.1 C148 54.4 145.5 54 144 52.8 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="135" cy="45" r="4"/>
<circle fill="#142638" cx="135.8" cy="45" r="2.1"/>
</svg></div><div class="vlabel">normal</div></div>
<div class="vcard"><div class="vimg v-copper"><!-- Тунец (tuna): торпедообразное обтекаемое тело ~3:1, хвост-полумесяц (две серповидные лопасти), маленький спинной плавник + ряд жировых плавничков позади, тёмная спина / светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: полумесяц — верхняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 46 C28 38 17 31 10 27 C13 38 19 45 29 50 L37 46 Z"/>
<!-- хвост: полумесяц — нижняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 54 C28 62 17 69 10 73 C13 62 19 55 29 50 L37 54 Z"/>
<!-- спинной плавник: маленький, впереди -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M101 34.5 L93 18 L115 34.2 Z"/>
<!-- жировые плавнички позади спинного: 3 маленьких треугольника, к хвосту мельчают -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M91 34.3 L85 24 L79 34.6 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M77 34.8 L72 26.5 L66 35 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M64 35.6 L60 29 L55 35.9 Z"/>
<!-- анальный плавник: смещён к хвосту -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M43 58.5 L38 66 L51 62 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M107 62.5 L104 69 L113 64.5 Z"/>
<!-- тело: торпеда, сужается к хвостовому стеблю -->
<path fill="var(--f1,hsl(210,45%,48%))" d="M151 50 C139 40 111 33 81 33 C61 33 47 38 36 45.5 L36 54.5 C47 62 61 67 81 67 C111 67 139 60 151 50 Z"/>
<!-- брюхо: светлое, контраст тёмная спина / светлое брюхо -->
<path fill="var(--f2,hsl(210,30%,70%))" d="M151 50 C139 60 111 67 81 67 C61 67 47 62 36 54.5 C47 58.5 61 60 81 60 C111 60 139 55.5 151 50 Z"/>
<!-- узор: тонкие тёмные линии по нижней половине бока (черта тунца) -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M57 54.6 L73 54.6 L73 55.9 L57 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M79 54.6 L95 54.6 L95 55.9 L79 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M101 54.6 L117 54.6 L117 55.9 L101 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M123 54.6 L133 54.6 L133 55.9 L123 55.9 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M143.5 50.4 C146.5 50.7 148.5 51.7 150 53.1 C148 54.4 145.5 54 144 52.8 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="135" cy="45" r="4"/>
<circle fill="#142638" cx="135.8" cy="45" r="2.1"/>
</svg></div><div class="vlabel">copper</div></div>
<div class="vcard"><div class="vimg v-silver"><!-- Тунец (tuna): торпедообразное обтекаемое тело ~3:1, хвост-полумесяц (две серповидные лопасти), маленький спинной плавник + ряд жировых плавничков позади, тёмная спина / светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: полумесяц — верхняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 46 C28 38 17 31 10 27 C13 38 19 45 29 50 L37 46 Z"/>
<!-- хвост: полумесяц — нижняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 54 C28 62 17 69 10 73 C13 62 19 55 29 50 L37 54 Z"/>
<!-- спинной плавник: маленький, впереди -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M101 34.5 L93 18 L115 34.2 Z"/>
<!-- жировые плавнички позади спинного: 3 маленьких треугольника, к хвосту мельчают -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M91 34.3 L85 24 L79 34.6 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M77 34.8 L72 26.5 L66 35 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M64 35.6 L60 29 L55 35.9 Z"/>
<!-- анальный плавник: смещён к хвосту -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M43 58.5 L38 66 L51 62 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M107 62.5 L104 69 L113 64.5 Z"/>
<!-- тело: торпеда, сужается к хвостовому стеблю -->
<path fill="var(--f1,hsl(210,45%,48%))" d="M151 50 C139 40 111 33 81 33 C61 33 47 38 36 45.5 L36 54.5 C47 62 61 67 81 67 C111 67 139 60 151 50 Z"/>
<!-- брюхо: светлое, контраст тёмная спина / светлое брюхо -->
<path fill="var(--f2,hsl(210,30%,70%))" d="M151 50 C139 60 111 67 81 67 C61 67 47 62 36 54.5 C47 58.5 61 60 81 60 C111 60 139 55.5 151 50 Z"/>
<!-- узор: тонкие тёмные линии по нижней половине бока (черта тунца) -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M57 54.6 L73 54.6 L73 55.9 L57 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M79 54.6 L95 54.6 L95 55.9 L79 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M101 54.6 L117 54.6 L117 55.9 L101 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M123 54.6 L133 54.6 L133 55.9 L123 55.9 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M143.5 50.4 C146.5 50.7 148.5 51.7 150 53.1 C148 54.4 145.5 54 144 52.8 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="135" cy="45" r="4"/>
<circle fill="#142638" cx="135.8" cy="45" r="2.1"/>
</svg></div><div class="vlabel">silver</div></div>
<div class="vcard"><div class="vimg v-quartz"><!-- Тунец (tuna): торпедообразное обтекаемое тело ~3:1, хвост-полумесяц (две серповидные лопасти), маленький спинной плавник + ряд жировых плавничков позади, тёмная спина / светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: полумесяц — верхняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 46 C28 38 17 31 10 27 C13 38 19 45 29 50 L37 46 Z"/>
<!-- хвост: полумесяц — нижняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 54 C28 62 17 69 10 73 C13 62 19 55 29 50 L37 54 Z"/>
<!-- спинной плавник: маленький, впереди -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M101 34.5 L93 18 L115 34.2 Z"/>
<!-- жировые плавнички позади спинного: 3 маленьких треугольника, к хвосту мельчают -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M91 34.3 L85 24 L79 34.6 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M77 34.8 L72 26.5 L66 35 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M64 35.6 L60 29 L55 35.9 Z"/>
<!-- анальный плавник: смещён к хвосту -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M43 58.5 L38 66 L51 62 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M107 62.5 L104 69 L113 64.5 Z"/>
<!-- тело: торпеда, сужается к хвостовому стеблю -->
<path fill="var(--f1,hsl(210,45%,48%))" d="M151 50 C139 40 111 33 81 33 C61 33 47 38 36 45.5 L36 54.5 C47 62 61 67 81 67 C111 67 139 60 151 50 Z"/>
<!-- брюхо: светлое, контраст тёмная спина / светлое брюхо -->
<path fill="var(--f2,hsl(210,30%,70%))" d="M151 50 C139 60 111 67 81 67 C61 67 47 62 36 54.5 C47 58.5 61 60 81 60 C111 60 139 55.5 151 50 Z"/>
<!-- узор: тонкие тёмные линии по нижней половине бока (черта тунца) -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M57 54.6 L73 54.6 L73 55.9 L57 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M79 54.6 L95 54.6 L95 55.9 L79 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M101 54.6 L117 54.6 L117 55.9 L101 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M123 54.6 L133 54.6 L133 55.9 L123 55.9 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M143.5 50.4 C146.5 50.7 148.5 51.7 150 53.1 C148 54.4 145.5 54 144 52.8 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="135" cy="45" r="4"/>
<circle fill="#142638" cx="135.8" cy="45" r="2.1"/>
</svg></div><div class="vlabel">quartz</div></div>
<div class="vcard"><div class="vimg v-gold"><!-- Тунец (tuna): торпедообразное обтекаемое тело ~3:1, хвост-полумесяц (две серповидные лопасти), маленький спинной плавник + ряд жировых плавничков позади, тёмная спина / светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: полумесяц — верхняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 46 C28 38 17 31 10 27 C13 38 19 45 29 50 L37 46 Z"/>
<!-- хвост: полумесяц — нижняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 54 C28 62 17 69 10 73 C13 62 19 55 29 50 L37 54 Z"/>
<!-- спинной плавник: маленький, впереди -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M101 34.5 L93 18 L115 34.2 Z"/>
<!-- жировые плавнички позади спинного: 3 маленьких треугольника, к хвосту мельчают -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M91 34.3 L85 24 L79 34.6 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M77 34.8 L72 26.5 L66 35 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M64 35.6 L60 29 L55 35.9 Z"/>
<!-- анальный плавник: смещён к хвосту -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M43 58.5 L38 66 L51 62 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M107 62.5 L104 69 L113 64.5 Z"/>
<!-- тело: торпеда, сужается к хвостовому стеблю -->
<path fill="var(--f1,hsl(210,45%,48%))" d="M151 50 C139 40 111 33 81 33 C61 33 47 38 36 45.5 L36 54.5 C47 62 61 67 81 67 C111 67 139 60 151 50 Z"/>
<!-- брюхо: светлое, контраст тёмная спина / светлое брюхо -->
<path fill="var(--f2,hsl(210,30%,70%))" d="M151 50 C139 60 111 67 81 67 C61 67 47 62 36 54.5 C47 58.5 61 60 81 60 C111 60 139 55.5 151 50 Z"/>
<!-- узор: тонкие тёмные линии по нижней половине бока (черта тунца) -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M57 54.6 L73 54.6 L73 55.9 L57 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M79 54.6 L95 54.6 L95 55.9 L79 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M101 54.6 L117 54.6 L117 55.9 L101 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M123 54.6 L133 54.6 L133 55.9 L123 55.9 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M143.5 50.4 C146.5 50.7 148.5 51.7 150 53.1 C148 54.4 145.5 54 144 52.8 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="135" cy="45" r="4"/>
<circle fill="#142638" cx="135.8" cy="45" r="2.1"/>
</svg></div><div class="vlabel">gold</div></div>
<div class="vcard"><div class="vimg v-emerald"><!-- Тунец (tuna): торпедообразное обтекаемое тело ~3:1, хвост-полумесяц (две серповидные лопасти), маленький спинной плавник + ряд жировых плавничков позади, тёмная спина / светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: полумесяц — верхняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 46 C28 38 17 31 10 27 C13 38 19 45 29 50 L37 46 Z"/>
<!-- хвост: полумесяц — нижняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 54 C28 62 17 69 10 73 C13 62 19 55 29 50 L37 54 Z"/>
<!-- спинной плавник: маленький, впереди -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M101 34.5 L93 18 L115 34.2 Z"/>
<!-- жировые плавнички позади спинного: 3 маленьких треугольника, к хвосту мельчают -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M91 34.3 L85 24 L79 34.6 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M77 34.8 L72 26.5 L66 35 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M64 35.6 L60 29 L55 35.9 Z"/>
<!-- анальный плавник: смещён к хвосту -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M43 58.5 L38 66 L51 62 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M107 62.5 L104 69 L113 64.5 Z"/>
<!-- тело: торпеда, сужается к хвостовому стеблю -->
<path fill="var(--f1,hsl(210,45%,48%))" d="M151 50 C139 40 111 33 81 33 C61 33 47 38 36 45.5 L36 54.5 C47 62 61 67 81 67 C111 67 139 60 151 50 Z"/>
<!-- брюхо: светлое, контраст тёмная спина / светлое брюхо -->
<path fill="var(--f2,hsl(210,30%,70%))" d="M151 50 C139 60 111 67 81 67 C61 67 47 62 36 54.5 C47 58.5 61 60 81 60 C111 60 139 55.5 151 50 Z"/>
<!-- узор: тонкие тёмные линии по нижней половине бока (черта тунца) -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M57 54.6 L73 54.6 L73 55.9 L57 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M79 54.6 L95 54.6 L95 55.9 L79 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M101 54.6 L117 54.6 L117 55.9 L101 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M123 54.6 L133 54.6 L133 55.9 L123 55.9 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M143.5 50.4 C146.5 50.7 148.5 51.7 150 53.1 C148 54.4 145.5 54 144 52.8 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="135" cy="45" r="4"/>
<circle fill="#142638" cx="135.8" cy="45" r="2.1"/>
</svg></div><div class="vlabel">emerald</div></div>
<div class="vcard"><div class="vimg v-diamond"><!-- Тунец (tuna): торпедообразное обтекаемое тело ~3:1, хвост-полумесяц (две серповидные лопасти), маленький спинной плавник + ряд жировых плавничков позади, тёмная спина / светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: полумесяц — верхняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 46 C28 38 17 31 10 27 C13 38 19 45 29 50 L37 46 Z"/>
<!-- хвост: полумесяц — нижняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 54 C28 62 17 69 10 73 C13 62 19 55 29 50 L37 54 Z"/>
<!-- спинной плавник: маленький, впереди -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M101 34.5 L93 18 L115 34.2 Z"/>
<!-- жировые плавнички позади спинного: 3 маленьких треугольника, к хвосту мельчают -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M91 34.3 L85 24 L79 34.6 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M77 34.8 L72 26.5 L66 35 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M64 35.6 L60 29 L55 35.9 Z"/>
<!-- анальный плавник: смещён к хвосту -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M43 58.5 L38 66 L51 62 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M107 62.5 L104 69 L113 64.5 Z"/>
<!-- тело: торпеда, сужается к хвостовому стеблю -->
<path fill="var(--f1,hsl(210,45%,48%))" d="M151 50 C139 40 111 33 81 33 C61 33 47 38 36 45.5 L36 54.5 C47 62 61 67 81 67 C111 67 139 60 151 50 Z"/>
<!-- брюхо: светлое, контраст тёмная спина / светлое брюхо -->
<path fill="var(--f2,hsl(210,30%,70%))" d="M151 50 C139 60 111 67 81 67 C61 67 47 62 36 54.5 C47 58.5 61 60 81 60 C111 60 139 55.5 151 50 Z"/>
<!-- узор: тонкие тёмные линии по нижней половине бока (черта тунца) -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M57 54.6 L73 54.6 L73 55.9 L57 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M79 54.6 L95 54.6 L95 55.9 L79 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M101 54.6 L117 54.6 L117 55.9 L101 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M123 54.6 L133 54.6 L133 55.9 L123 55.9 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M143.5 50.4 C146.5 50.7 148.5 51.7 150 53.1 C148 54.4 145.5 54 144 52.8 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="135" cy="45" r="4"/>
<circle fill="#142638" cx="135.8" cy="45" r="2.1"/>
</svg></div><div class="vlabel">diamond</div></div>
<div class="vcard"><div class="vimg v-rainbow"><!-- Тунец (tuna): торпедообразное обтекаемое тело ~3:1, хвост-полумесяц (две серповидные лопасти), маленький спинной плавник + ряд жировых плавничков позади, тёмная спина / светлое брюхо -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100" width="160" height="100">
<!-- хвост: полумесяц — верхняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 46 C28 38 17 31 10 27 C13 38 19 45 29 50 L37 46 Z"/>
<!-- хвост: полумесяц — нижняя серповидная лопасть -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M37 54 C28 62 17 69 10 73 C13 62 19 55 29 50 L37 54 Z"/>
<!-- спинной плавник: маленький, впереди -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M101 34.5 L93 18 L115 34.2 Z"/>
<!-- жировые плавнички позади спинного: 3 маленьких треугольника, к хвосту мельчают -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M91 34.3 L85 24 L79 34.6 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M77 34.8 L72 26.5 L66 35 Z"/>
<path fill="var(--f3,hsl(210,50%,32%))" d="M64 35.6 L60 29 L55 35.9 Z"/>
<!-- анальный плавник: смещён к хвосту -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M43 58.5 L38 66 L51 62 Z"/>
<!-- брюшной плавник -->
<path fill="var(--f3,hsl(210,50%,32%))" d="M107 62.5 L104 69 L113 64.5 Z"/>
<!-- тело: торпеда, сужается к хвостовому стеблю -->
<path fill="var(--f1,hsl(210,45%,48%))" d="M151 50 C139 40 111 33 81 33 C61 33 47 38 36 45.5 L36 54.5 C47 62 61 67 81 67 C111 67 139 60 151 50 Z"/>
<!-- брюхо: светлое, контраст тёмная спина / светлое брюхо -->
<path fill="var(--f2,hsl(210,30%,70%))" d="M151 50 C139 60 111 67 81 67 C61 67 47 62 36 54.5 C47 58.5 61 60 81 60 C111 60 139 55.5 151 50 Z"/>
<!-- узор: тонкие тёмные линии по нижней половине бока (черта тунца) -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M57 54.6 L73 54.6 L73 55.9 L57 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M79 54.6 L95 54.6 L95 55.9 L79 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M101 54.6 L117 54.6 L117 55.9 L101 55.9 Z"/>
<path fill="var(--f4,hsl(210,45%,26%))" d="M123 54.6 L133 54.6 L133 55.9 L123 55.9 Z"/>
<!-- рот: маленький тёмный на конце морды -->
<path fill="var(--f4,hsl(210,45%,26%))" d="M143.5 50.4 C146.5 50.7 148.5 51.7 150 53.1 C148 54.4 145.5 54 144 52.8 Z"/>
<!-- глаз -->
<circle fill="#fff" cx="135" cy="45" r="4"/>
<circle fill="#142638" cx="135.8" cy="45" r="2.1"/>
</svg></div><div class="vlabel">rainbow</div></div>
</div>
</body>
</html>