add brandbook

This commit is contained in:
2026-10-31 03:00:25 +07:00
parent 62bc237dc7
commit a7ae4ce03c
58 changed files with 630 additions and 0 deletions
+77
View File
@@ -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` — чёрно-белая эмблема для тёмного фона: белая рамка вместо золотой, без инверсии лица и шляпы. При компоновке применяется круглая обрезка внешнего края, чтобы удалить артефакты вокруг рамки. Это двухцветное изображение с непрозрачной внутренней частью, не одноцветная маска для нанесения.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

+87
View File
@@ -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.
+17
View File
@@ -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
Binary file not shown.
Binary file not shown.
+93
View File
@@ -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.
Binary file not shown.
+93
View File
@@ -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.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

+52
View File
@@ -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}}
Binary file not shown.
Binary file not shown.
+50
View File
@@ -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); });
+54
View File
@@ -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>
+106
View File
@@ -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); });