add brandbook
@@ -0,0 +1,77 @@
|
||||
# Вечерний детектив — брендбук
|
||||
|
||||
Единый рабочий брендбук из трёх блоков: «Логотип», «Шрифты», «Цвета». Блок логотипа занимает две страницы, шрифты и цвета — по одной. Страницы белые; в основном документе оставлены только примеры и краткие правила. Технические сведения и источники сохранены в этом описании. В страницах оставлены логотипы, шрифты и палитра. Образцы диплома, бланков и фактур временно убраны из документа; исходные материалы сохранены в комплекте. Используется обновлённый логотип — детектив в шляпе с золотой круглой рамкой и прозрачным внешним фоном. Основная палитра: чёрный #111111, белый #FFFFFF и золотой #FCBF02. Бронза исключена, серый используется только как служебный цвет интерфейса; типографика закреплена за тремя гарнитурами с кириллицей и SIL OFL 1.1: Oswald 600 для логотипа и заголовков, Podkova 600 для других фирменных надписей, Noto Sans 400/700 для основного текста и выделений. Пробковая доска развивает оформление афиш и обложек. Сайт и приложения не изменены.
|
||||
|
||||
Все изменения вносятся в этот комплект. PDF и `brandbook.zip` перезаписываются; старые версии и отдельные концепции не сохраняются.
|
||||
|
||||
## Комплект
|
||||
|
||||
- `brandbook.pdf` — 4 страницы A4 для просмотра и передачи.
|
||||
- `index.html`, `brandbook.css` — редактируемый исходник без сборки и сетевых ресурсов.
|
||||
- `assets/logos/logo.png` — обновлённая на основе исходной эмблемы растровая версия, 1254 × 1254 px, RGBA. Внешний фон прозрачный, белые области внутри знака сохранены. Изображение обновлено с помощью imagegen.
|
||||
- `assets/fonts/Podkova.ttf` — фирменный вариативный шрифт, насыщенности 400–800; `Podkova-OFL.txt` — его лицензия SIL OFL 1.1. Исходный файл Google Fonts скопирован без изменения байтов, с простым локальным именем.
|
||||
- `assets/fonts/Oswald.ttf` — вариативный шрифт логотипа и заголовков (200–700), используем 600; `Oswald-OFL.txt` — лицензия. Источник: https://github.com/google/fonts/tree/main/ofl/oswald . Файл скопирован без изменения байтов, с простым локальным именем.
|
||||
- `assets/fonts/NotoSans-Regular.ttf` и `NotoSans-Bold.ttf` — основной текст 400 и выделения 700; `LICENSE.txt` и `NOTICES.txt` содержат лицензию OFL 1.1 и сведения авторства. Все три семейства используются в самом брендбуке и вложены в архив.
|
||||
- `assets/cork.jpg` — фотография пробковой доски Petr Kratochvil, 1920 × 1280 px, CC0. Источник: https://www.publicdomainpictures.net/en/view-image.php?image=25664&picture=cork-board . Лицензия на странице загрузки: https://www.publicdomainpictures.net/en/free-download.php?id=25664&image=cork-board . Скачано 31.10.2026; исходный JPEG сохранён без изменений. Масштабирование и свет поверх фото задаются CSS.
|
||||
- `assets/materials/` — действующие фактуры фронтенда, оригинальный диплом, PDF черновика и правил, их изображения для страницы и снимки живой дизайн-системы.
|
||||
- `export.cjs` — экспорт PDF и проверки в Chromium/Electron.
|
||||
- `logo-kit.cjs` — воспроизводимая сборка 16 PNG-композиций с названием в локальном Oswald 600 и двух файлов знака с белой рамкой; остальные шесть файлов знака сохраняются. Запускается той же командой Electron, что и экспорт PDF.
|
||||
- `assets/logos/catalog.html` — каталог всех PNG с прямыми ссылками. `mark` — знак, `horizontal` — название справа, `vertical` — снизу. `color-light` / `color-dark` — цветные для светлого / тёмного фона; `black` — одноцветный чёрный; `white` — чёрно-белый для тёмного фона, золото заменено белым без инверсии. `transparent` — с альфа-каналом, `background` — с подложкой #F4EDE0 / #111111.
|
||||
- `assets/logos/mono-source.png` — исходник монохромного знака, подготовленный imagegen. Его альфа-канал используется для чёрного исполнения; внутренние просветы прозрачны. Это рабочий источник, не дополнительная редакция логотипа.
|
||||
|
||||
Надпись собирается из локального Oswald 600 в Canvas и включается в готовый PNG. PNG имеет прозрачный внешний фон и подходит для размещения на цветной подложке. Это растровая эмблема, не вектор; для крупной печати потребуется векторная отрисовка.
|
||||
|
||||
|
||||
## Редактирование и экспорт
|
||||
|
||||
Откройте `index.html` в браузере. Тексты и примеры редактируются в HTML, стили — в CSS. Каждая `.page` — отдельная страница A4. Исходные диплом, бланки и снимки интерфейса доступны в assets/materials; на страницах они не показываются.
|
||||
|
||||
В Chromium: Печать → Сохранить в PDF; A4, масштаб 100%, поля отсутствуют, фон включён, колонтитулы браузера выключены.
|
||||
|
||||
Из папки `brandbook/`, используя установленный в соседнем проекте Electron:
|
||||
|
||||
```sh
|
||||
env -u ELECTRON_RUN_AS_NODE ../evening_detective_screen/node_modules/electron/dist/electron --ozone-platform=x11 export.cjs
|
||||
pdfinfo brandbook.pdf
|
||||
pdftotext -layout brandbook.pdf -
|
||||
```
|
||||
|
||||
При отсутствии соседнего проекта используйте ручную печать в браузере. Просмотр не требует Electron. Экспортёр проверяет загрузку шрифтов и изображений, отсутствие сетевых запросов, 4 HTML-страницы и отсутствие выхода содержимого за поля и границы примеров. После изменений нужен визуальный просмотр PDF.
|
||||
|
||||
## Проверки и ограничения
|
||||
|
||||
Проверены три блока и 4 страницы A4, локальные ресурсы и прозрачность PNG эмблемы. Новая основная палитра закреплена в брендбуке; её перенос в `src/assets/base.css` пока не выполнен; текст правил очной игры — с актуальным `GAME_RULES_OFFLINE.md`. Шрифты встроены в PDF.
|
||||
|
||||
Oswald, Podkova и Noto Sans разрешено использовать, встраивать и распространять по SIL OFL 1.1. При распространении шрифтов сохраняйте соответствующие лицензии и сведения авторства. При передаче файла шрифта сохраняйте `Podkova-OFL.txt` с copyright. Источник: https://github.com/google/fonts/tree/main/ofl/podkova ; файл: https://raw.githubusercontent.com/google/fonts/main/ofl/podkova/Podkova%5Bwght%5D.ttf . Файл `assets/fonts/LICENSE.txt` относится к Noto. Отдельные файлы a_OldTyper и его NOTICE удалены из комплекта.
|
||||
|
||||
Цветопроба не проводилась. Значения HEX/RGB — экранные; CMYK и Pantone определяются под конкретную типографию и бумагу. В чёрно-белой печати допустим перевод документа целиком в оттенки серого; самостоятельная монохромная версия эмблемы не создавалась.
|
||||
|
||||
## Источники существующего оформления
|
||||
|
||||
- `../evening_detective_frontend/docs/DESIGN_SYSTEM.md`, `src/assets/base.css` — палитра, разделение сайта и игры, типографика, правила знака.
|
||||
- `src/components/DesignBrand.vue`, `HeaderText.vue`, `MessagePaper.vue`, `BeltBlock.vue`, `MetalPlate.vue`, `GameInputForm.vue` — действующие визуальные компоненты. Файлы `paper.jpg`, `paper_white.jpg`, `belt.png`, `metal.png`, `pin.png`, `input_center.png`, `button.png` скопированы из `src/assets/images/` без изменения.
|
||||
- `assets/materials/frontend-site.png` и `frontend-game.png` — снимки локальной страницы `/design-system` с демонстрационными данными (31.10.2026). В живом превью сайта часть действий отображается зелёной; документ фиксирует это как состояние реализации, в текущем коде primary — #FFD43B, новый основной золотой брендбука — #FCBF02. Код фронтенда не исправлялся.
|
||||
- `../evening_detective_server/internal/services/game_print_service/assets/diploma.png` — действующий оригинал диплома, копия в комплекте идентична. `diploma.go` вписывает изображение целиком на A4 с центрированием.
|
||||
- `../evening_detective_server/internal/services/game_print_service/pdf.go` — параметры шапки, полей, шрифтов, черновика и правил. `service.go` — состав печатного комплекта.
|
||||
- `assets/materials/draft.pdf` и `rules.pdf` — готовые файлы из `/home/vladimir/Загрузки/game-4-print-materials(1)/Для игрока/`. Их PNG получены рендерингом первой страницы через `pdftoppm`. Текст `rules.pdf` совпадает с актуальным `../evening_detective_server/docs/GAME_RULES_OFFLINE.md`; отдельный онлайн-формат задаёт `GAME_RULES_ONLINE.md`.
|
||||
|
||||
Сайт и генераторы пока используют прежний шрифт. Сохранённые исходные PDF черновика и правил, снимки интерфейса и растровый диплом показывают текущие материалы; их текст и встроенная типографика не изменялись. В брендбуке они обозначены как образцы компоновки, а не образцы новой гарнитуры. Замена шрифта в рабочих продуктах требует отдельного внедрения и проверки переносов.
|
||||
|
||||
Брендбук описывает визуальное оформление и не заменяет канонический текст правил игры. При его изменении обновляются PDF-образец и изображение в этом же комплекте.
|
||||
|
||||
|
||||
## Композиции логотипа
|
||||
|
||||
Сборка использует знак размером 600 px без увеличения исходника, внешнее поле 150 px (¼ диаметра), расстояние до текста 60 px (10%). Название — Oswald 600 прописными: «ВЕЧЕРНИЙ» над «ДЕТЕКТИВ». Размер верхней строки — 45% нижней; видимая ширина нижней строки — 800 px (1⅓ диаметра знака), промежуток между видимыми границами строк — 48 px (8% диаметра). Размер шрифта подбирается по actualBoundingBox, без растяжения букв. Горизонтальный текст выровнен влево и центрирован по высоте знака; вертикальный — по центру. Цветные варианты сохраняют белую заливку внутри эмблемы; в чёрном одноцветном варианте просветы прозрачны, а в версии для тёмного фона сохранена внутренняя белая заливка. Чёрный — #000000, белый — #FFFFFF. Обычная печать и нанесение требуют проверки пробного отпечатка; PNG не заменяет вектор.
|
||||
|
||||
Проверка мелкого размера: диаметр отдельного знака 48 px, ширина файла композиции 240 px. Файлы с уже включённым полем не обрезать. Сайт и дипломы не изменялись.
|
||||
|
||||
Цвет названия в цветном логотипе: #FFFFFF на тёмной подложке, #111111 на светлой. Белый повторяет светлые детали эмблемы; цветной акцент композиции — золотая рамка и линия #FCBF02 в её оттенке. Бронза #BFA07D исключена из фирменной палитры. Оттенки старых фактур и диплома сохранены как часть изображений, а не как основные цвета бренда.
|
||||
|
||||
Черта в верхней строке: толщина 8 px в обоих вариантах при диаметре эмблемы 600 px, отступ от слова 36 px, выравнивание по середине видимой высоты «ВЕЧЕРНИЙ». В горизонтальном варианте прямая линия заканчивается на правом краю слова «ДЕТЕКТИВ», без изгибов и завитков; в вертикальном варианте симметрично повторяется слева. В монохроме черта совпадает с цветом текста.
|
||||
|
||||
Горизонтальная композиция читается как лупа: эмблема — стекло, надпись справа — ручка. Под золотой чертой, над словом «ДЕТЕКТИВ», расположен прямой блик ручки толщиной 8 px: короткий штрих 18 px по осевой линии, видимый разрыв 14 px и длинный штрих. Окончания округлые. На тёмной подложке он белый, на светлой — чёрный; замкнутой рамки вокруг текста нет. В вертикальной композиции блика нет.
|
||||
|
||||
Золотая черта не выступает за правый край текста; внешнее свободное поле — 150 px. Линия не пересекает буквы. Вертикальные варианты и знак отдельно сохранены без изменений.
|
||||
|
||||
`assets/logos/white-source.png` — чёрно-белая эмблема для тёмного фона: белая рамка вместо золотой, без инверсии лица и шляпы. При компоновке применяется круглая обрезка внешнего края, чтобы удалить артефакты вокруг рамки. Это двухцветное изображение с непрозрачной внутренней частью, не одноцветная маска для нанесения.
|
||||
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,87 @@
|
||||
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
|
||||
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
NotoSans-Bold.ttf
|
||||
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://scripts.sil.org/OFL
|
||||
|
||||
https://scripts.sil.org/OFL
|
||||
|
||||
----
|
||||
|
||||
NotoSans-Regular.ttf
|
||||
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: https://scripts.sil.org/OFL
|
||||
|
||||
https://scripts.sil.org/OFL
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2016 The Oswald Project Authors (https://github.com/googlefonts/OswaldFont)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2011 The Podkova Project Authors (https://github.com/cyrealtype/Podkova)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
After Width: | Height: | Size: 153 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 371 KiB |
|
After Width: | Height: | Size: 371 KiB |
|
After Width: | Height: | Size: 373 KiB |
|
After Width: | Height: | Size: 374 KiB |
|
After Width: | Height: | Size: 374 KiB |
|
After Width: | Height: | Size: 379 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 332 KiB |
|
After Width: | Height: | Size: 335 KiB |
|
After Width: | Height: | Size: 333 KiB |
|
After Width: | Height: | Size: 335 KiB |
|
After Width: | Height: | Size: 335 KiB |
|
After Width: | Height: | Size: 344 KiB |
|
After Width: | Height: | Size: 383 KiB |
|
After Width: | Height: | Size: 151 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 363 KiB |
|
After Width: | Height: | Size: 365 KiB |
|
After Width: | Height: | Size: 366 KiB |
|
After Width: | Height: | Size: 368 KiB |
|
After Width: | Height: | Size: 368 KiB |
|
After Width: | Height: | Size: 373 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 442 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 706 KiB |
|
After Width: | Height: | Size: 659 KiB |
|
After Width: | Height: | Size: 274 KiB |
|
After Width: | Height: | Size: 326 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 383 KiB |
@@ -0,0 +1,52 @@
|
||||
@font-face{font-family:Podkova;src:url('assets/fonts/Podkova.ttf');font-weight:400 800}
|
||||
@font-face{font-family:Noto;src:url('assets/fonts/NotoSans-Regular.ttf')}
|
||||
@font-face{font-family:Noto;src:url('assets/fonts/NotoSans-Bold.ttf');font-weight:700}
|
||||
@font-face{font-family:Oswald;src:url('assets/fonts/Oswald.ttf');font-weight:200 700}
|
||||
*{box-sizing:border-box}
|
||||
body{margin:0;background:#fff;color:#111;font:14px/1.6 Noto,sans-serif}
|
||||
.page{position:relative;width:210mm;height:297mm;margin:24px auto;padding:52px 62px 64px;background:#fff;break-after:page}
|
||||
.page:last-child{break-after:auto}
|
||||
h1,h2,h3,p{margin:0}
|
||||
h1,h2{font-family:Oswald,sans-serif;font-weight:600;font-size:48px;line-height:1.12;letter-spacing:0;margin-bottom:18px}
|
||||
h3{font-family:Oswald,sans-serif;font-weight:600;font-size:20px;line-height:1.35;margin-bottom:10px}
|
||||
p+p{margin-top:10px}
|
||||
.eyebrow,.folio,.caption,code{font-family:Noto,sans-serif}
|
||||
.eyebrow{display:flex;justify-content:space-between;font-size:10px;letter-spacing:1px;margin-bottom:28px;text-transform:uppercase}
|
||||
.eyebrow span:last-child{color:#111}
|
||||
.lead{font-size:16px;line-height:1.6;margin-bottom:25px}
|
||||
.folio{position:absolute;bottom:26px;left:62px;right:62px;border-top:1px solid #17161535;padding-top:10px;display:flex;justify-content:space-between;font-size:9px}
|
||||
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:24px}
|
||||
.rule{border-top:1px solid #17161535;padding-top:17px;margin-top:23px}
|
||||
.small{font-size:11px;line-height:1.6}
|
||||
.source-note{font-size:12px;line-height:1.6;margin-top:22px;color:#444}
|
||||
a{color:inherit;text-underline-offset:3px}
|
||||
.dark{background:#111;color:#eee}
|
||||
figure{margin:0}
|
||||
.logo-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px 20px}
|
||||
.logo-card img{display:block;width:100%;object-fit:contain;border:1px solid #17161520;background:#f4ede0 url('assets/materials/paper.jpg') center/cover}
|
||||
.logo-card:nth-child(even) img{background:#111}
|
||||
.logo-card.mark img{height:110px}
|
||||
.logo-card.horizontal img{height:120px}
|
||||
.logo-card.vertical img{height:190px}
|
||||
.logo-card figcaption{font-size:10px;margin-top:5px}
|
||||
table{width:100%;border-collapse:collapse;font-size:12px;margin-top:20px}
|
||||
th,td{text-align:left;vertical-align:top;padding:10px 0;border-bottom:1px solid #17161530}
|
||||
th{font-size:10px;letter-spacing:1px;text-transform:uppercase}
|
||||
.type-sample{background:#fff;border:1px solid #11111120;padding:16px 25px}
|
||||
.type-row+.type-row{border-top:1px solid #17161525;margin-top:10px;padding-top:10px}
|
||||
.type-heading{font:600 28px/1.25 Oswald,sans-serif;margin-top:4px}
|
||||
.type-body{font:14px/1.5 Noto,sans-serif;margin-top:4px}
|
||||
#fonts .lead{margin-bottom:16px}
|
||||
#fonts table{margin-top:12px}
|
||||
#fonts td,#fonts th{padding:7px 0}
|
||||
#fonts .rule{margin-top:16px;padding-top:14px}
|
||||
#fonts .source-note{margin-top:14px}
|
||||
.caption{font-size:10px;letter-spacing:1px}
|
||||
.type-display{font:600 26px/1.25 Podkova,serif;margin:4px 0 0}
|
||||
.palette{display:grid;gap:7px;align-content:start}
|
||||
.palette>div{height:96px;padding:12px 15px;display:flex;align-items:center;justify-content:space-between}
|
||||
.palette strong{font-size:12px}
|
||||
.palette code{font-size:12px}
|
||||
@page{size:A4;margin:0}
|
||||
@media print{body{background:transparent}.page{margin:0}*{-webkit-print-color-adjust:exact;print-color-adjust:exact}}
|
||||
@media screen and (max-width:820px){body{overflow-x:auto}.page{margin:0 0 16px}}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Run with Electron: electron --ozone-platform=x11 export.cjs
|
||||
const { app, BrowserWindow, session } = require('electron');
|
||||
const fs = require('node:fs/promises');
|
||||
const path = require('node:path');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
app.disableHardwareAcceleration();
|
||||
const timeout = setTimeout(() => { console.error('PDF export timed out after 60 seconds'); app.exit(1); }, 60000);
|
||||
app.whenReady().then(async () => {
|
||||
console.log('Chromium ready');
|
||||
const failures = [];
|
||||
session.defaultSession.webRequest.onBeforeRequest((details, callback) => {
|
||||
const remote = /^https?:/.test(details.url);
|
||||
if (remote) failures.push(`External request: ${details.url}`);
|
||||
callback({ cancel: remote });
|
||||
});
|
||||
session.defaultSession.webRequest.onErrorOccurred(details => failures.push(`${details.error}: ${details.url}`));
|
||||
const win = new BrowserWindow({ show: false, width: 1000, height: 1200,
|
||||
webPreferences: { nodeIntegration: false, contextIsolation: true, sandbox: true, backgroundThrottling: false } });
|
||||
await win.loadFile(path.join(__dirname, 'index.html'));
|
||||
console.log('HTML loaded');
|
||||
const result = await win.webContents.executeJavaScript(`(async () => {
|
||||
await document.fonts.ready;
|
||||
await Promise.all([...document.images].map(image => image.decode()));
|
||||
const pages = [...document.querySelectorAll('.page')];
|
||||
const overflow = pages.flatMap((page, index) => {
|
||||
const footer = page.querySelector('.folio').getBoundingClientRect();
|
||||
return [...page.children].filter(child => !child.classList.contains('folio'))
|
||||
.filter(child => child.getBoundingClientRect().bottom > footer.top - 8)
|
||||
.map(child => ({ page: index + 1, element: child.tagName, text: child.textContent.slice(0, 50) }));
|
||||
});
|
||||
return { blocks: pages.map(page => page.id), pages: pages.length, overflow, familiesLoaded: ['Podkova', 'Oswald', 'Noto'].every(family => [...document.fonts].some(face => face.family === family && face.status === 'loaded')), fonts: ['14px Noto', '700 14px Noto', '600 48px Oswald', '600 32px Podkova'].every(font => document.fonts.check(font)),
|
||||
images: [...document.images].length, unloaded: [...document.images].filter(image => !image.naturalWidth).length };
|
||||
})()`);
|
||||
assert.equal(result.pages, 4, 'Expected four pages across three brandbook blocks');
|
||||
assert.deepEqual(result.blocks, ['logo', 'logo-mono', 'fonts', 'colors']);
|
||||
assert.deepEqual(result.overflow, [], 'Content reaches the page footer');
|
||||
assert.equal(result.fonts, true, 'Local fonts must load');
|
||||
assert.equal(result.familiesLoaded, true, 'All three bundled font families must load');
|
||||
assert.equal(result.unloaded, 0, 'All images must load');
|
||||
assert.deepEqual(failures, [], 'All resources must load locally');
|
||||
console.log('Layout and local resources checked');
|
||||
const pdf = await win.webContents.printToPDF({ printBackground: true, preferCSSPageSize: true,
|
||||
pageSize: 'A4', margins: { top: 0, bottom: 0, left: 0, right: 0 }, generateTaggedPDF: true });
|
||||
await fs.writeFile(path.join(__dirname, 'brandbook.pdf'), pdf);
|
||||
console.log(JSON.stringify({ ...result, bytes: pdf.length, output: 'brandbook.pdf' }, null, 2));
|
||||
win.destroy();
|
||||
clearTimeout(timeout);
|
||||
app.quit();
|
||||
}).catch(error => { console.error(error); app.exit(1); });
|
||||
@@ -0,0 +1,54 @@
|
||||
<!doctype html>
|
||||
<html lang="ru">
|
||||
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Вечерний детектив — Брендбук</title><link rel="stylesheet" href="brandbook.css"></head>
|
||||
<body><main>
|
||||
<section class="page" id="logo" aria-labelledby="logo-title">
|
||||
<div class="eyebrow"><span>Вечерний детектив / Брендбук</span><span>01 / Логотип</span></div>
|
||||
<h1 id="logo-title">Логотип и название</h1>
|
||||
<p class="lead">Три композиции: знак, название справа и название снизу.</p>
|
||||
<div class="logo-grid"><figure class="logo-card mark"><a href="assets/logos/mark-color-light-background.png"><img src="assets/logos/mark-color-light-transparent.png" alt="Знак отдельно, светлый фон"></a><figcaption>Знак отдельно · светлый фон</figcaption></figure><figure class="logo-card mark"><a href="assets/logos/mark-color-dark-background.png"><img src="assets/logos/mark-color-dark-transparent.png" alt="Знак отдельно, тёмный фон"></a><figcaption>Знак отдельно · тёмный фон</figcaption></figure><figure class="logo-card horizontal"><a href="assets/logos/horizontal-color-light-background.png"><img src="assets/logos/horizontal-color-light-transparent.png" alt="Название справа, светлый фон"></a><figcaption>Название справа · светлый фон</figcaption></figure><figure class="logo-card horizontal"><a href="assets/logos/horizontal-color-dark-background.png"><img src="assets/logos/horizontal-color-dark-transparent.png" alt="Название справа, тёмный фон"></a><figcaption>Название справа · тёмный фон</figcaption></figure><figure class="logo-card vertical"><a href="assets/logos/vertical-color-light-background.png"><img src="assets/logos/vertical-color-light-transparent.png" alt="Название снизу, светлый фон"></a><figcaption>Название снизу · светлый фон</figcaption></figure><figure class="logo-card vertical"><a href="assets/logos/vertical-color-dark-background.png"><img src="assets/logos/vertical-color-dark-transparent.png" alt="Название снизу, тёмный фон"></a><figcaption>Название снизу · тёмный фон</figcaption></figure></div><div class="grid2 rule"><div><h3>Светлый фон</h3><p class="small">Чёрное название, золотые акценты.</p></div><div><h3>Тёмный фон</h3><p class="small">Белое название, золотые акценты.</p></div></div>
|
||||
<p class="source-note">Используйте готовые композиции из комплекта.</p>
|
||||
<footer class="folio"><span>ЛОГОТИП · ШРИФТЫ · ЦВЕТА</span><span>01 / 04</span></footer></section>
|
||||
<section class="page" id="logo-mono" aria-labelledby="logo-mono-title">
|
||||
<div class="eyebrow"><span>Вечерний детектив / Брендбук</span><span>01 / Логотип · продолжение</span></div>
|
||||
<h2 id="logo-mono-title">Монохром и размещение</h2>
|
||||
<p class="lead">На тёмном фоне заменяем золото белым, сохраняя рисунок эмблемы.</p>
|
||||
<div class="logo-grid"><figure class="logo-card mark"><a href="assets/logos/mark-black-background.png"><img src="assets/logos/mark-black-transparent.png" alt="Знак отдельно, светлый фон"></a><figcaption>Знак отдельно · светлый фон</figcaption></figure><figure class="logo-card mark"><a href="assets/logos/mark-white-background.png"><img src="assets/logos/mark-white-transparent.png" alt="Знак отдельно, тёмный фон"></a><figcaption>Знак отдельно · тёмный фон</figcaption></figure><figure class="logo-card horizontal"><a href="assets/logos/horizontal-black-background.png"><img src="assets/logos/horizontal-black-transparent.png" alt="Название справа, светлый фон"></a><figcaption>Название справа · светлый фон</figcaption></figure><figure class="logo-card horizontal"><a href="assets/logos/horizontal-white-background.png"><img src="assets/logos/horizontal-white-transparent.png" alt="Название справа, тёмный фон"></a><figcaption>Название справа · тёмный фон</figcaption></figure><figure class="logo-card vertical"><a href="assets/logos/vertical-black-background.png"><img src="assets/logos/vertical-black-transparent.png" alt="Название снизу, светлый фон"></a><figcaption>Название снизу · светлый фон</figcaption></figure><figure class="logo-card vertical"><a href="assets/logos/vertical-white-background.png"><img src="assets/logos/vertical-white-transparent.png" alt="Название снизу, тёмный фон"></a><figcaption>Название снизу · тёмный фон</figcaption></figure></div><div class="grid2 rule"><div><h3>Свободное поле</h3><p class="small">Не меньше ¼ диаметра знака. В готовых файлах поле уже включено.</p></div><div><h3>Размер и контраст</h3><p class="small">Знак — от 48 px. С названием — от 240 px по ширине. Фон спокойный, без пёстрого рисунка.</p></div></div>
|
||||
<p class="source-note">Не менять пропорции, цвета и расположение элементов. Не добавлять тени.</p>
|
||||
<p class="small"><a href="assets/logos/catalog.html">Все варианты логотипа →</a></p>
|
||||
<footer class="folio"><span>ЛОГОТИП · ШРИФТЫ · ЦВЕТА</span><span>02 / 04</span></footer></section>
|
||||
<section class="page" id="fonts" aria-labelledby="fonts-title">
|
||||
<div class="eyebrow"><span>Вечерний детектив / Брендбук</span><span>02 / Шрифты</span></div>
|
||||
<h2 id="fonts-title">Шрифты</h2>
|
||||
<p class="lead">Oswald — логотип и заголовки. Podkova — акцентные надписи. Noto Sans — основной текст.</p>
|
||||
<div class="type-sample">
|
||||
<div class="type-row"><div class="caption">OSWALD / SEMIBOLD 600</div><p class="type-heading">У каждого дела есть разгадка</p></div>
|
||||
<div class="type-row"><div class="caption">PODKOVA / SEMIBOLD 600</div><p class="type-display">Вечерний детектив</p></div>
|
||||
<div class="type-row"><div class="caption">NOTO SANS / REGULAR 400 · BOLD 700</div><p class="type-body">Изучите улики, обсудите версии и найдите ответ.<br><strong>Дело № 17 · Расследование продолжается.</strong></p></div>
|
||||
</div>
|
||||
<table><thead><tr><th>Роль / шрифт</th><th>Размер</th><th>Правило</th></tr></thead><tbody>
|
||||
<tr><td>Логотип / Oswald 600</td><td>По масштабу логотипа</td><td>Готовые композиции, без разрядки</td></tr>
|
||||
<tr><td>Заголовки / Oswald 600</td><td>32–48 px / 15 pt</td><td>Межстрочный интервал 1,15</td></tr>
|
||||
<tr><td>Текст / Noto Sans 400</td><td>18 px / 11 pt</td><td>Межстрочный интервал 1,5</td></tr>
|
||||
<tr><td>Подписи / Noto Sans 400</td><td>14 px / 9 pt</td><td>Краткие пояснения</td></tr>
|
||||
<tr><td>Выделение / Noto Sans 700</td><td>Как основной текст</td><td>Ключевые слова, без длинных капслоков</td></tr>
|
||||
</tbody></table>
|
||||
<p class="source-note">Шрифты включены в комплект. Лицензии SIL OFL 1.1: <a href="assets/fonts/Oswald-OFL.txt">Oswald</a>, <a href="assets/fonts/Podkova-OFL.txt">Podkova</a>, <a href="assets/fonts/LICENSE.txt">Noto Sans</a>. Передавайте шрифты вместе с лицензиями.</p>
|
||||
|
||||
<footer class="folio"><span>ЛОГОТИП · ШРИФТЫ · ЦВЕТА</span><span>03 / 04</span></footer>
|
||||
</section>
|
||||
<section class="page" id="colors" aria-labelledby="colors-title">
|
||||
<div class="eyebrow"><span>Вечерний детектив / Брендбук</span><span>03 / Цвета</span></div>
|
||||
<h2 id="colors-title">Цвета</h2>
|
||||
<p class="lead">Чёрный и белый — основа. Золотой — акцент.</p>
|
||||
<div class="palette">
|
||||
<div style="background:#111;color:#fff"><strong>Чёрный / основной фон</strong><code>#111111</code></div>
|
||||
<div style="background:#fff;border:1px solid #11111125"><strong>Белый / текст и светлый фон</strong><code>#FFFFFF</code></div>
|
||||
<div style="background:#fcbf02"><strong>Золотой / акцент</strong><code>#FCBF02</code></div>
|
||||
<p class="small">Золото — для рамки, полос и ключевых действий.</p>
|
||||
</div>
|
||||
<div class="grid2 rule"><div><h3>Служебные цвета</h3><p class="small">Серый — для элементов интерфейса. Цвета статусов сопровождаются текстом.</p></div><div><h3>Контраст</h3><p class="small">Белый на чёрном; чёрный на белом и золотом. Не набирать мелкий текст золотым на белом.</p></div></div>
|
||||
<p class="small">Для печати — цветопроба. <a href="README.md">Источники и лицензии →</a></p>
|
||||
<footer class="folio"><span>ЛОГОТИП · ШРИФТЫ · ЦВЕТА</span><span>04 / 04</span></footer>
|
||||
</section>
|
||||
</main></body></html>
|
||||
@@ -0,0 +1,106 @@
|
||||
// Run with Electron, like export.cjs. Canvas lays out the supplied raster marks and real font.
|
||||
const { app, BrowserWindow } = require('electron');
|
||||
const fs = require('node:fs/promises');
|
||||
const path = require('node:path');
|
||||
const assert = require('node:assert/strict');
|
||||
app.disableHardwareAcceleration();
|
||||
const timeout = setTimeout(() => app.exit(1), 60000);
|
||||
app.whenReady().then(async () => {
|
||||
const win = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true, sandbox: true } });
|
||||
await win.loadFile(path.join(__dirname, 'index.html'));
|
||||
const results = await win.webContents.executeJavaScript(`(async () => {
|
||||
await document.fonts.load('600 144px Oswald');
|
||||
if (![...document.fonts].some(face => face.family === 'Oswald' && face.status === 'loaded')) throw new Error('Bundled Oswald must load');
|
||||
const load = async src => { const image = new Image(); image.src = src; await image.decode(); return image; };
|
||||
const color = await load('assets/logos/logo.png');
|
||||
const mono = await load('assets/logos/mono-source.png');
|
||||
const white = await load('assets/logos/white-source.png');
|
||||
const files = [];
|
||||
const d = 600, pad = 150, gap = 60, lineGap = 48, wordWidth = 800;
|
||||
const measure = (ctx, text, size) => {
|
||||
ctx.font = '600 ' + size + 'px Oswald';
|
||||
const m = ctx.measureText(text);
|
||||
return { text, size, left: m.actualBoundingBoxLeft, width: m.actualBoundingBoxLeft + m.actualBoundingBoxRight,
|
||||
ascent: m.actualBoundingBoxAscent, height: m.actualBoundingBoxAscent + m.actualBoundingBoxDescent };
|
||||
};
|
||||
for (const layout of ['mark', 'horizontal', 'vertical']) {
|
||||
for (const variant of ['color-light', 'color-dark', 'black', 'white']) {
|
||||
if (layout === 'mark' && variant !== 'white') continue;
|
||||
for (const background of ['transparent', 'background']) {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
let size = 144;
|
||||
for (let i = 0; i < 3; i++) size *= wordWidth / measure(ctx, 'ДЕТЕКТИВ', size).width;
|
||||
const lower = measure(ctx, 'ДЕТЕКТИВ', size);
|
||||
const upper = measure(ctx, 'ВЕЧЕРНИЙ', size * 0.45);
|
||||
if (Math.abs(lower.width - wordWidth) > 1) throw new Error('Wordmark width must be 4/3 of emblem diameter');
|
||||
const textHeight = upper.height + lineGap + lower.height;
|
||||
const contentWidth = layout === 'horizontal' ? d + gap + Math.ceil(lower.width) : layout === 'mark' ? d : Math.ceil(lower.width);
|
||||
const contentHeight = layout === 'vertical' ? Math.ceil(d + gap + textHeight) : d;
|
||||
canvas.width = contentWidth + pad * 2;
|
||||
canvas.height = contentHeight + pad * 2;
|
||||
const dark = variant === 'color-dark' || variant === 'white';
|
||||
if (background === 'background') { ctx.fillStyle = dark ? '#111111' : '#f4ede0'; ctx.fillRect(0,0,canvas.width,canvas.height); }
|
||||
ctx.filter = variant === 'black' ? 'brightness(0)' : 'none';
|
||||
const imageX = layout === 'vertical' ? (canvas.width - d) / 2 : pad;
|
||||
ctx.save();
|
||||
if (variant === 'white') {
|
||||
ctx.beginPath();
|
||||
ctx.arc(imageX + d / 2, pad + d / 2, d * 0.48, 0, Math.PI * 2);
|
||||
ctx.clip();
|
||||
}
|
||||
ctx.drawImage(variant === 'white' ? white : variant.startsWith('color') ? color : mono, imageX, pad, d, d);
|
||||
ctx.restore();
|
||||
ctx.filter = 'none';
|
||||
if (layout !== 'mark') {
|
||||
ctx.fillStyle = variant === 'white' ? '#ffffff' : variant === 'black' ? '#000000' : dark ? '#ffffff' : '#111111';
|
||||
ctx.textBaseline = 'alphabetic';
|
||||
ctx.textAlign = 'left';
|
||||
const top = layout === 'vertical' ? pad + d + gap : pad + (d - textHeight) / 2;
|
||||
for (const [line, y] of [[upper, top], [lower, top + upper.height + lineGap]]) {
|
||||
const x = layout === 'vertical' ? (canvas.width - line.width) / 2 : pad + d + gap;
|
||||
if (x < pad - 1 || x + line.width > canvas.width - pad + 1 || y < pad || y + line.height > canvas.height - pad + 1)
|
||||
throw new Error('Text exceeds safety margins');
|
||||
ctx.font = '600 ' + line.size + 'px Oswald';
|
||||
ctx.fillText(line.text, x + line.left, y + line.ascent);
|
||||
}
|
||||
// Match the ring accent; symmetric rules keep the stacked lockup balanced.
|
||||
ctx.fillStyle = variant.startsWith('color') ? '#fcbf02' : variant === 'white' ? '#ffffff' : '#000000';
|
||||
const blockX = layout === 'vertical' ? (canvas.width - lower.width) / 2 : pad + d + gap;
|
||||
const upperX = layout === 'vertical' ? (canvas.width - upper.width) / 2 : blockX;
|
||||
const ruleY = Math.round(top + upper.height / 2 - 4);
|
||||
const ruleStart = upperX + upper.width + 36;
|
||||
const ruleEnd = blockX + lower.width;
|
||||
if (ruleEnd <= ruleStart) throw new Error('Accent line needs space after upper word');
|
||||
ctx.fillRect(ruleStart, ruleY, ruleEnd - ruleStart, 8);
|
||||
if (layout === 'vertical') ctx.fillRect(blockX, ruleY, upperX - 36 - blockX, 8);
|
||||
// The horizontal wordmark is the magnifier handle; its glint sits below the gold edge.
|
||||
if (layout === 'horizontal') {
|
||||
ctx.strokeStyle = dark ? '#ffffff' : '#000000';
|
||||
ctx.lineWidth = 8;
|
||||
ctx.lineCap = 'round';
|
||||
const start = ruleStart + 36, end = ruleEnd - 60;
|
||||
const y = ruleY + 33;
|
||||
if (y + 8 >= top + upper.height + lineGap) throw new Error('Handle glint overlaps lower word');
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(start, y);
|
||||
ctx.lineTo(start + 18, y);
|
||||
ctx.moveTo(start + 40, y);
|
||||
ctx.lineTo(end, y);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
const pixels = ctx.getImageData(0,0,canvas.width,canvas.height).data;
|
||||
if (background === 'transparent' && pixels[3] !== 0) throw new Error('Transparent padding required');
|
||||
if (background === 'background' && pixels[3] !== 255) throw new Error('Opaque background required');
|
||||
files.push({ name: layout + '-' + variant + '-' + background + '.png', width: canvas.width, height: canvas.height, data: canvas.toDataURL('image/png').split(',')[1] });
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
})()`);
|
||||
assert.equal(results.length, 18);
|
||||
for (const result of results) await fs.writeFile(path.join(__dirname, 'assets/logos', result.name), Buffer.from(result.data, 'base64'));
|
||||
console.log('Exported 16 wordmark files and two white-rim standalone marks, with transparent padding or opaque backgrounds.');
|
||||
win.destroy(); clearTimeout(timeout); app.quit();
|
||||
}).catch(error => { console.error(error); app.exit(1); });
|
||||