This commit is contained in:
m.elgin
2026-06-30 15:29:48 +03:00
parent 79acf6c317
commit 3b5624e2ab
40 changed files with 303 additions and 429 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="01-title-food-chain.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Титульная картинка</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">Вампирическая пищевая цепочка: элита, отбор и человечество как ресурс</text>
</svg>

Before

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="02-medieval-origin.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Происхождение вируса</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">XII-XIV века: войны, эпидемии и скрытое распространение SNV-12</text>
</svg>

Before

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="03-vampire-classes.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Классы вампиров</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">Молодой носитель, старший адаптант и гемарх в одной иерархии</text>
</svg>

Before

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="04-failed-infection.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Неудачное заражение</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">Феррогемный каскад и термогемолитический коллапс</text>
</svg>

Before

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="05-recognize-vampire.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Как распознать вампира</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">Судебно-медицинский плакат с внешними и поведенческими маркерами</text>
</svg>

Before

Width:  |  Height:  |  Size: 814 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="06-blood-economy.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Экономика качественной крови</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">Массовая, стабильная, пиковая и династическая кровь как ресурс</text>
</svg>

Before

Width:  |  Height:  |  Size: 816 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="07-artificial-blood.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Почему искусственная кровь не подходит</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">Сравнение живой сигнатуры крови и стерильного суррогата</text>
</svg>

Before

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="08-hidden-donor-market.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Тайный рынок доноров</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">Клиники, биобанки, школы, клубы и логистика к верхушке</text>
</svg>

Before

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="09-donor-house.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Донорский дом</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">Элитный пансион как скрытая инфраструктура премиальных доноров</text>
</svg>

Before

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="10-blood-etiquette.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Кровяной этикет элиты</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">Аристократический ритуал оценки донора как дегустация вина</text>
</svg>

Before

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="11-feeding-zones-map.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Геополитика кормовых зон</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">Резервуары населения, коридоры, убежища и экспериментальные территории</text>
</svg>

Before

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="12-food-chain-chart.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Пищевая цепочка</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">От человека через сортировку и рынок качества к гемархам</text>
</svg>

Before

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 MiB

View File

@@ -1,8 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080" width="1920" height="1080">
<rect width="1920" height="1080" fill="#130b0d"/>
<image href="13-medieval-europe-map.png" x="0" y="0" width="1920" height="1080" preserveAspectRatio="xMidYMid slice"/>
<rect x="0" y="0" width="1920" height="176" fill="#130b0d" opacity="0.86"/>
<rect x="0" y="176" width="1920" height="4" fill="#c7a56a" opacity="0.95"/>
<text x="76" y="78" font-family="Aptos Display, Arial, sans-serif" font-size="48" font-weight="700" fill="#fff8f2">Средневековье создаёт идеальную среду</text>
<text x="78" y="130" font-family="Aptos, Arial, sans-serif" font-size="27" fill="#f5e6d3">XII-XIV века: войны, миграции, антисанитария, эпидемии</text>
</svg>

Before

Width:  |  Height:  |  Size: 816 B

View File

@@ -1,56 +0,0 @@
# Generated vampire visuals
Подписанные версии лежат в SVG-файлах: плашка с текстом редактируется прямо в SVG. Чистые PNG лежат рядом с теми же номерами.
- 01-title-food-chain
- PNG: `01-title-food-chain.png`
- Подписанная версия: `01-title-food-chain.signed.svg`
- Подпись: Титульная картинка — Вампирическая пищевая цепочка: элита, отбор и человечество как ресурс
- 02-medieval-origin
- PNG: `02-medieval-origin.png`
- Подписанная версия: `02-medieval-origin.signed.svg`
- Подпись: Происхождение вируса — XII-XIV века: войны, эпидемии и скрытое распространение SNV-12
- 03-vampire-classes
- PNG: `03-vampire-classes.png`
- Подписанная версия: `03-vampire-classes.signed.svg`
- Подпись: Классы вампиров — Молодой носитель, старший адаптант и гемарх в одной иерархии
- 04-failed-infection
- PNG: `04-failed-infection.png`
- Подписанная версия: `04-failed-infection.signed.svg`
- Подпись: Неудачное заражение — Феррогемный каскад и термогемолитический коллапс
- 05-recognize-vampire
- PNG: `05-recognize-vampire.png`
- Подписанная версия: `05-recognize-vampire.signed.svg`
- Подпись: Как распознать вампира — Судебно-медицинский плакат с внешними и поведенческими маркерами
- 06-blood-economy
- PNG: `06-blood-economy.png`
- Подписанная версия: `06-blood-economy.signed.svg`
- Подпись: Экономика качественной крови — Массовая, стабильная, пиковая и династическая кровь как ресурс
- 07-artificial-blood
- PNG: `07-artificial-blood.png`
- Подписанная версия: `07-artificial-blood.signed.svg`
- Подпись: Почему искусственная кровь не подходит — Сравнение живой сигнатуры крови и стерильного суррогата
- 08-hidden-donor-market
- PNG: `08-hidden-donor-market.png`
- Подписанная версия: `08-hidden-donor-market.signed.svg`
- Подпись: Тайный рынок доноров — Клиники, биобанки, школы, клубы и логистика к верхушке
- 09-donor-house
- PNG: `09-donor-house.png`
- Подписанная версия: `09-donor-house.signed.svg`
- Подпись: Донорский дом — Элитный пансион как скрытая инфраструктура премиальных доноров
- 10-blood-etiquette
- PNG: `10-blood-etiquette.png`
- Подписанная версия: `10-blood-etiquette.signed.svg`
- Подпись: Кровяной этикет элиты — Аристократический ритуал оценки донора как дегустация вина
- 11-feeding-zones-map
- PNG: `11-feeding-zones-map.png`
- Подписанная версия: `11-feeding-zones-map.signed.svg`
- Подпись: Геополитика кормовых зон — Резервуары населения, коридоры, убежища и экспериментальные территории
- 12-food-chain-chart
- PNG: `12-food-chain-chart.png`
- Подписанная версия: `12-food-chain-chart.signed.svg`
- Подпись: Пищевая цепочка — От человека через сортировку и рынок качества к гемархам
- 13-medieval-europe-map
- PNG: `13-medieval-europe-map.png`
- Подписанная версия: `13-medieval-europe-map.signed.svg`
- Подпись: Средневековье создаёт идеальную среду — XII-XIV века: войны, миграции, антисанитария, эпидемии

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

@@ -4,364 +4,394 @@ const pptxgen = require('pptxgenjs');
const base = __dirname;
const outPath = path.join(base, 'prezentaciya-vampiricheskoe-tenevoe-pravitelstvo.pptx');
const assets = {
title: path.join(base, 'assets', 'generated', '01-title-food-chain.png'),
medieval: path.join(base, 'assets', 'generated', '02-medieval-origin.png'),
classes: path.join(base, 'assets', 'generated', '03-vampire-classes.png'),
failed: path.join(base, 'assets', 'generated', '04-failed-infection.png'),
recognize: path.join(base, 'assets', 'generated', '05-recognize-vampire.png'),
blood: path.join(base, 'assets', 'generated', '06-blood-economy.png'),
artificial: path.join(base, 'assets', 'generated', '07-artificial-blood.png'),
market: path.join(base, 'assets', 'generated', '08-hidden-donor-market.png'),
donorHouse: path.join(base, 'assets', 'generated', '09-donor-house.png'),
etiquette: path.join(base, 'assets', 'generated', '10-blood-etiquette.png'),
zones: path.join(base, 'assets', 'generated', '11-feeding-zones-map.png'),
chain: path.join(base, 'assets', 'generated', '12-food-chain-chart.png')
agent: path.join(base, 'assets', 'generated', 'ai-01-snv12-agent.png'),
medieval: path.join(base, 'assets', 'generated', 'ai-02-medieval-spread-map.png'),
classes: path.join(base, 'assets', 'generated', 'ai-03-vampire-classes.png'),
failed: path.join(base, 'assets', 'generated', 'ai-04-failed-infection.png'),
economy: path.join(base, 'assets', 'generated', 'ai-05-blood-economy.png'),
artificial: path.join(base, 'assets', 'generated', 'ai-06-live-vs-artificial-blood.png'),
market: path.join(base, 'assets', 'generated', 'ai-07-hidden-donor-market.png'),
zones: path.join(base, 'assets', 'generated', 'ai-08-feeding-zones-map.png')
};
const pptx = new pptxgen();
pptx.layout = 'LAYOUT_WIDE';
pptx.author = 'Hermes Agent';
pptx.company = 'Nous Research';
pptx.subject = 'Псевдонаучная теория о гемозависимой элите';
pptx.subject = 'Строгая псевдонаучная модель гемозависимой элиты';
pptx.title = 'Пищевая цепочка: от тебя до теневого правительства';
pptx.lang = 'ru-RU';
pptx.theme = {
headFontFace: 'Georgia',
headFontFace: 'Aptos Display',
bodyFontFace: 'Aptos',
lang: 'ru-RU'
};
const C = {
bgDark: '130B0D',
bgLight: 'F3EADF',
card: 'FFF7EE',
red: '7A1623',
red2: 'A42A37',
text: '24181A',
cream: 'F5E6D3',
gold: 'C7A56A',
muted: '705A5D',
bg: 'F7F9FC',
white: 'FFFFFF',
ink: '2A1A1D',
brown: '4A3327'
ink: '1F2937',
muted: '667085',
line: 'CAD5E2',
blue: '245B8F',
blueSoft: 'EAF2FB',
red: 'B42318',
redSoft: 'FDECEC',
graySoft: 'EEF2F6',
dark: '102A43'
};
function footer(slide, n, dark = false) {
slide.addText(String(n).padStart(2, '0'), {
x: 12.42, y: 7.02, w: 0.4, h: 0.18,
fontSize: 10, color: dark ? 'B89B82' : C.muted,
align: 'right', margin: 0
x: 12.48,
y: 7.02,
w: 0.36,
h: 0.18,
fontSize: 10,
color: dark ? 'D0DAE6' : C.muted,
align: 'right',
margin: 0
});
}
function baseTextSlide(slide, title, tag = 'Псевдонаучная реконструкция') {
slide.background = { color: C.bgLight };
slide.addShape(pptx.ShapeType.rect, { x: 0, y: 0, w: 13.333, h: 0.42, fill: { color: C.red }, line: { color: C.red } });
slide.addText(title, { x: 0.62, y: 0.58, w: 8.8, h: 0.38, fontFace: 'Georgia', fontSize: 26, bold: true, color: C.ink, margin: 0 });
slide.addText(tag, { x: 10.0, y: 0.62, w: 2.65, h: 0.18, fontSize: 10, color: C.red2, italic: true, align: 'right', margin: 0 });
}
function addBullets(slide, items, opts = {}) {
const text = [];
items.forEach((item) => text.push({ text: item, options: { bullet: { indent: 14 }, breakLine: true } }));
function put(slide, text, x, y, w, h, opts = {}) {
slide.addText(text, {
x: opts.x ?? 0.9,
y: opts.y ?? 1.6,
w: opts.w ?? 5.2,
h: opts.h ?? 4.4,
fontSize: opts.fontSize ?? 18,
color: opts.color ?? C.text,
paraSpaceAfterPt: opts.paraSpaceAfterPt ?? 8,
margin: 0.04,
valign: 'top'
x, y, w, h,
fontFace: opts.fontFace ?? 'Aptos',
fontSize: opts.fontSize ?? 14,
color: opts.color ?? C.ink,
bold: opts.bold ?? false,
italic: opts.italic ?? false,
align: opts.align ?? 'left',
valign: opts.valign ?? 'mid',
margin: opts.margin ?? 0.02,
breakLine: opts.breakLine ?? true
});
}
function addCard(slide, x, y, w, h, title, body, accent = C.red2) {
slide.addShape(pptx.ShapeType.roundRect, { x, y, w, h, rectRadius: 0.06, fill: { color: C.card }, line: { color: accent, pt: 1.2 } });
slide.addText(title, { x: x + 0.18, y: y + 0.16, w: w - 0.36, h: 0.24, fontSize: 17, bold: true, color: C.red, margin: 0 });
slide.addText(body, { x: x + 0.18, y: y + 0.52, w: w - 0.36, h: h - 0.7, fontSize: 14.6, color: C.text, margin: 0.02, valign: 'mid' });
}
function addCallout(slide, text, opts = {}) {
function card(slide, x, y, w, h, title, body, opts = {}) {
slide.addShape(pptx.ShapeType.roundRect, {
x: opts.x ?? 0.9,
y: opts.y ?? 5.82,
w: opts.w ?? 11.5,
h: opts.h ?? 0.58,
x, y, w, h,
rectRadius: 0.05,
fill: { color: opts.fill ?? C.red },
line: { color: opts.fill ?? C.red }
fill: { color: opts.fill ?? C.white },
line: { color: opts.line ?? C.line, pt: opts.pt ?? 1.1 }
});
slide.addText(text, {
x: (opts.x ?? 0.9) + 0.14,
y: (opts.y ?? 5.82) + 0.13,
w: (opts.w ?? 11.5) - 0.28,
h: 0.23,
align: 'center', color: C.white,
fontSize: opts.fontSize ?? 20,
bold: true, italic: opts.italic ?? true, margin: 0
if (title) {
put(slide, title, x + 0.18, y + 0.16, w - 0.36, 0.28, {
fontSize: opts.titleSize ?? 16,
bold: true,
color: opts.titleColor ?? C.ink
});
}
if (body) {
put(slide, body, x + 0.18, y + (title ? 0.52 : 0.18), w - 0.36, h - (title ? 0.68 : 0.28), {
fontSize: opts.bodySize ?? 13.5,
color: opts.bodyColor ?? C.ink,
valign: opts.bodyValign ?? 'top',
margin: 0.04
});
}
}
function pill(slide, x, y, w, h, text, opts = {}) {
slide.addShape(pptx.ShapeType.roundRect, {
x, y, w, h,
rectRadius: 0.08,
fill: { color: opts.fill ?? C.graySoft },
line: { color: opts.line ?? C.graySoft, pt: 1 }
});
put(slide, text, x + 0.08, y + 0.05, w - 0.16, h - 0.1, {
fontSize: opts.fontSize ?? 12.5,
color: opts.color ?? C.ink,
bold: opts.bold ?? false,
align: opts.align ?? 'center'
});
}
function titleSlideBase(slide, title, subtitle) {
slide.background = { color: C.bg };
put(slide, title, 0.9, 0.78, 6.1, 1.25, { fontSize: 28, bold: true, color: C.dark, margin: 0 });
put(slide, subtitle, 0.92, 2.18, 6.3, 0.55, { fontSize: 16, color: C.muted, margin: 0 });
}
function textSlideBase(slide, title, kicker = 'Псевдонаучная реконструкция') {
slide.background = { color: C.bg };
put(slide, title, 0.7, 0.52, 8.4, 0.42, { fontSize: 26, bold: true, color: C.dark, margin: 0 });
put(slide, kicker, 10.05, 0.58, 2.55, 0.2, { fontSize: 10.5, color: C.blue, italic: true, align: 'right', margin: 0 });
}
function fullImage(slide, imagePath) {
slide.background = { color: C.bgDark };
slide.background = { color: C.white };
slide.addImage({ path: imagePath, x: 0, y: 0, w: 13.333, h: 7.5 });
}
function lightPlaque(slide, text, x, y, w, h, fontSize = 12, opts = {}) {
slide.addText(text, {
x, y, w, h,
fontFace: opts.fontFace ?? 'Georgia',
fontSize,
bold: opts.bold ?? false,
italic: opts.italic ?? false,
color: opts.color ?? C.brown,
align: opts.align ?? 'center',
valign: opts.valign ?? 'mid',
margin: opts.margin ?? 0.02,
breakLine: true
});
}
function darkPlaque(slide, text, x, y, w, h, fontSize = 12, opts = {}) {
slide.addText(text, {
x, y, w, h,
fontFace: opts.fontFace ?? 'Georgia',
fontSize,
bold: opts.bold ?? false,
italic: opts.italic ?? false,
color: opts.color ?? C.cream,
align: opts.align ?? 'center',
valign: opts.valign ?? 'mid',
margin: opts.margin ?? 0.02,
breakLine: true
});
}
// 1 title
// 1. title
{
const s = pptx.addSlide();
fullImage(s, assets.title);
s.addShape(pptx.ShapeType.rect, { x: 0, y: 0, w: 13.333, h: 7.5, fill: { color: '120A0D', transparency: 34 }, line: { color: '120A0D', transparency: 100 } });
s.addShape(pptx.ShapeType.roundRect, { x: 0.72, y: 0.82, w: 6.95, h: 5.25, rectRadius: 0.06, fill: { color: '1B1114', transparency: 15 }, line: { color: C.red2, pt: 1.1, transparency: 20 } });
s.addText('Пищевая цепочка:\nот тебя до теневого правительства', { x: 1.0, y: 1.15, w: 6.3, h: 1.5, color: C.white, fontFace: 'Georgia', fontSize: 24, bold: true, margin: 0 });
s.addText('Расширенная версия: типы вампиров,\nкачественная кровь и скрытый рынок доноров', { x: 1.04, y: 2.95, w: 6.0, h: 0.75, color: C.cream, fontSize: 17.5, italic: true, margin: 0 });
s.addText('Клуб шапочек из фольги\nПсевдонаучный доклад в академическом стиле', { x: 1.04, y: 4.0, w: 4.9, h: 0.8, color: 'E0D0C4', fontSize: 16, margin: 0 });
footer(s, 1, true);
titleSlideBase(s,
'Пищевая цепочка:\nот тебя до теневого правительства',
'Псевдонаучная модель гемозависимой элиты и скрытой инфраструктуры питания'
);
card(s, 0.92, 3.0, 5.25, 2.25, 'Исходная гипотеза',
'Теневое правительство — это не только политическая сеть. В этой модели оно выступает как долгоживущая гемозависимая каста, которая превратила институты контроля в устойчивую систему отбора, хранения и распределения качественной человеческой крови.',
{ fill: C.white, line: C.line, bodySize: 15, bodyValign: 'mid' }
);
card(s, 7.1, 1.2, 5.2, 4.95, 'Минимальная схема', '', { fill: C.white, line: C.line });
pill(s, 7.6, 2.0, 1.1, 0.5, 'человек', { fill: C.blueSoft, line: C.blue, color: C.blue, bold: true });
put(s, '→', 8.85, 2.08, 0.3, 0.2, { fontSize: 24, color: C.muted, align: 'center' });
pill(s, 9.25, 2.0, 1.2, 0.5, 'отбор', { fill: C.graySoft, line: C.line, color: C.ink, bold: true });
put(s, '→', 10.55, 2.08, 0.3, 0.2, { fontSize: 24, color: C.muted, align: 'center' });
pill(s, 10.95, 2.0, 1.1, 0.5, 'кровь', { fill: C.redSoft, line: C.red, color: C.red, bold: true });
put(s, '→', 8.85, 3.48, 0.3, 0.2, { fontSize: 24, color: C.muted, align: 'center' });
pill(s, 9.25, 3.4, 2.05, 0.56, 'верхушка элиты', { fill: C.dark, line: C.dark, color: C.white, bold: true });
put(s, 'долгожительство\nселекция\nскрытая логистика', 7.58, 4.28, 4.1, 0.95, {
fontSize: 16,
color: C.muted,
align: 'center'
});
put(s, 'Жанр: строгая псевдонаучная подача для клуба шапочек из фольги', 0.95, 6.55, 6.8, 0.22, {
fontSize: 12.5,
color: C.muted,
italic: true,
margin: 0
});
footer(s, 1);
}
// 2 hypothesis
// 2. hypothesis
{
const s = pptx.addSlide();
baseTextSlide(s, 'Гипотеза исследования');
addCard(s, 0.88, 1.55, 5.35, 2.15, 'Базовая идея', 'Теневое правительство — это не просто политическая сеть, а долгоживущая гемозависимая каста, превратившая власть в механизм стабильного питания.');
addBullets(s, [
'вирусное происхождение касты;',
'долголетие как источник стратегического преимущества;',
'кровь как ресурс, валюта и предмет селекции;',
'власть как надстройка над пищевой цепочкой.'
], { x: 7.05, y: 1.72, w: 5.0, h: 3.6, fontSize: 18 });
addCallout(s, 'Ключевая формула: власть = контроль кормовой инфраструктуры');
textSlideBase(s, 'Исходная гипотеза');
card(s, 0.88, 1.45, 12.0, 1.2,
'Тезис',
'Элита не просто управляет обществом — она питается им, а долгожительство превращает биологическую зависимость в устойчивое политическое преимущество.',
{ fill: C.white, line: C.blue, titleColor: C.blue, bodySize: 17, bodyValign: 'mid' }
);
card(s, 0.88, 3.0, 2.75, 2.05, '1. Биология', 'Вампиризм интерпретируется как вирусная адаптация, а не мистическое проклятие.', { fill: C.redSoft, line: C.red });
card(s, 3.85, 3.0, 2.75, 2.05, '2. Долголетие', 'Большой горизонт планирования даёт накопление власти, знаний и скрытых сетей.', { fill: C.blueSoft, line: C.blue });
card(s, 6.82, 3.0, 2.75, 2.05, '3. Кровь как ресурс', 'Кровь одновременно еда, валюта, индикатор качества и объект селекции.', { fill: C.white, line: C.line });
card(s, 9.79, 3.0, 3.09, 2.05, '4. Институты', 'Государства, клиники и элитные клубы работают как фасад для кормовой инфраструктуры.', { fill: C.white, line: C.line });
pill(s, 1.7, 5.72, 9.9, 0.62, 'Ключевая формула: власть = контроль кормовой инфраструктуры', { fill: C.dark, line: C.dark, color: C.white, fontSize: 20, bold: true });
footer(s, 2);
}
// 3 virus
// 3. biological agent
{
const s = pptx.addSlide();
baseTextSlide(s, 'Sanguis Noctis Virus (SNV-12)');
addBullets(s, [
'латентная вирус-индуцированная вампиризация;',
'хроническая антропогематофагия;',
'гемозависимый постчеловеческий синдром;',
'обратимая фототолерантность после кормления.'
], { x: 0.88, y: 1.7, w: 5.0, h: 3.8, fontSize: 18 });
addCard(s, 6.8, 1.55, 5.3, 3.9, 'Ключевые эффекты', 'SNV-12 не делает человека мистическим существом мгновенно. Он перестраивает обменные пути, усиливает регенерацию, замедляет старение и формирует зависимость от человеческой крови как от носителя редких сигнальных молекул.');
addCallout(s, 'Вампиризм здесь — не проклятие, а вирусная адаптация', { fill: C.red2 });
fullImage(s, assets.agent);
put(s, 'Биологический агент: вирус, молекула и механизм действия', 0.62, 0.23, 11.98, 0.42, {
fontSize: 24, bold: true, color: C.dark, align: 'center'
});
put(s, '1. Вирион SNV-12', 1.28, 1.3, 2.45, 0.26, { fontSize: 14, bold: true, color: C.red, align: 'center' });
put(s, '2. Гемофильный регуляторный комплекс', 5.0, 1.3, 2.75, 0.26, { fontSize: 13.6, bold: true, color: C.red, align: 'center' });
put(s, 'комплекс HEP + MitoX + Reg\nкоординирует метаболическую перестройку', 7.7, 2.46, 1.68, 0.78, { fontSize: 11, color: C.ink, align: 'center' });
put(s, 'Связывание → эндоцитоз → выход РНК → внутриклеточный транспорт', 4.58, 5.9, 3.24, 0.34, { fontSize: 11.2, color: C.blue, align: 'center', bold: true });
put(s, '3. Клеточные мишени и системные эффекты', 9.08, 1.3, 3.9, 0.26, { fontSize: 13.2, bold: true, color: C.red, align: 'center' });
put(s, 'ROS↑,\nпотенциал↓', 8.42, 3.18, 1.35, 0.38, { fontSize: 10.5, color: C.red, align: 'center' });
put(s, 'сдвиг\nметаболизма гема', 9.88, 3.18, 1.62, 0.38, { fontSize: 10.5, color: C.red, align: 'center' });
put(s, 'ускорение\nрепарации тканей', 11.52, 3.18, 1.2, 0.38, { fontSize: 10.1, color: C.red, align: 'center' });
put(s, 'сумеречное зрение\nи фоточувствительность', 8.42, 5.15, 1.34, 0.42, { fontSize: 9.8, color: C.blue, align: 'center' });
put(s, 'лактатный сдвиг\nи экономия энергии', 11.52, 5.15, 1.16, 0.42, { fontSize: 9.8, color: C.blue, align: 'center' });
put(s, 'Зависимость от донорской крови: сигналы донора → цитокины и факторы → гем и железо → гормоны и липиды → адаптация хозяина', 8.18, 6.05, 4.1, 0.28, {
fontSize: 10.2, color: C.blue, align: 'center', bold: true
});
put(s, 'Рабочая гипотеза: вампиризм — результат вирусной перенастройки обмена, регенерации и светочувствительности.', 10.63, 6.75, 2.2, 0.48, {
fontSize: 10.2, color: C.muted, align: 'center'
});
footer(s, 3);
}
// 4 medieval origin
// 4. medieval spread map
{
const s = pptx.addSlide();
fullImage(s, assets.medieval);
darkPlaque(s, 'XIIXIV века', 5.05, 0.38, 3.2, 0.34, 18, { bold: true });
lightPlaque(s, 'войны и миграции', 1.18, 6.24, 2.25, 0.34, 12);
lightPlaque(s, 'антисанитария', 3.63, 6.24, 2.15, 0.34, 12);
lightPlaque(s, 'эпидемии и массовая смертность', 6.05, 6.24, 3.0, 0.34, 12);
lightPlaque(s, 'аристократические линии', 9.35, 6.24, 2.8, 0.34, 12);
darkPlaque(s, 'Средневековье создаёт идеальную среду для скрытого патогена', 2.55, 6.83, 8.2, 0.26, 16, { italic: true, bold: true });
footer(s, 4, true);
put(s, 'Средневековье создаёт идеальную среду', 0.22, 0.28, 4.12, 0.34, { fontSize: 21, bold: true, color: C.dark, align: 'center' });
put(s, 'XIIXIV века: торговля, миграции, войны и эпидемии', 0.22, 0.62, 4.12, 0.22, { fontSize: 11.2, color: C.muted, align: 'center' });
put(s, 'Карта показывает не романтизированное Средневековье, а эпидемиологическую логику: плотные торговые сети и конфликтные зоны создают коридоры для скрытого распространения SNV-12.', 11.28, 5.55, 1.82, 1.34, {
fontSize: 10.4, color: C.ink, align: 'center', valign: 'mid'
});
footer(s, 4);
}
// 5 classes
// 5. physiological changes
{
const s = pptx.addSlide();
textSlideBase(s, 'Как вирус меняет организм');
card(s, 0.88, 1.4, 3.88, 1.4, 'Кровяная среда', 'Норма: обычный транспорт кислорода.\nЗаражение: рост потребности в гем-сигналах.\nАдаптация: кровь становится носителем регуляторных факторов.', { fill: C.white, line: C.red });
card(s, 4.95, 1.4, 3.88, 1.4, 'Обмен веществ', 'Норма: стандартный энергетический цикл.\nЗаражение: гиперметаболический стресс.\nАдаптация: экономичный режим и сдвиг к лактатной утилизации.', { fill: C.white, line: C.blue });
card(s, 9.02, 1.4, 3.43, 1.4, 'Нервная система', 'Норма: стабильный базовый тонус.\nЗаражение: сенсорная перегрузка.\nАдаптация: фокус на сигналы риска и добычи.', { fill: C.white, line: C.line });
card(s, 0.88, 3.15, 3.88, 1.4, 'Зрение и свет', 'Норма: дневная фототрансдукция.\nЗаражение: фоточувствительность и стресс.\nАдаптация: усиление сумеречного зрения ценой непереносимости яркого света.', { fill: C.white, line: C.blue });
card(s, 4.95, 3.15, 3.88, 1.4, 'Регенерация', 'Норма: обычное заживление.\nЗаражение: воспалительный всплеск.\nАдаптация: ускоренная репарация тканей и выживание после травм.', { fill: C.white, line: C.red });
card(s, 9.02, 3.15, 3.43, 1.4, 'Старение', 'Норма: обычный клеточный цикл.\nЗаражение: сильная нагрузка на ткани.\nАдаптация: замедленное старение и накопление опыта.', { fill: C.white, line: C.line });
card(s, 0.88, 5.08, 11.98, 1.08, 'Переход к симптомам', 'Именно эта системная перестройка далее объясняет четыре наблюдаемых свойства: питание кровью, чувствительность к солнечному свету, быстрое восстановление и долговременное биологическое долголетие.', { fill: C.dark, line: C.dark, titleColor: C.white, bodyColor: 'EAF2FB', bodySize: 15, bodyValign: 'mid' });
footer(s, 5);
}
// 6. dependency on blood
{
const s = pptx.addSlide();
textSlideBase(s, 'Почему возникает зависимость от крови');
pill(s, 0.92, 2.1, 2.25, 0.9, '1. Вирус требует\nживые сигнальные молекулы', { fill: C.redSoft, line: C.red, color: C.red, bold: true, fontSize: 15 });
put(s, '→', 3.3, 2.34, 0.4, 0.2, { fontSize: 28, color: C.muted, align: 'center' });
pill(s, 3.82, 2.1, 2.25, 0.9, '2. Донорская кровь несёт\nцитокины, гормоны и стресс-маркеры', { fill: C.blueSoft, line: C.blue, color: C.blue, bold: true, fontSize: 14.2 });
put(s, '→', 6.22, 2.34, 0.4, 0.2, { fontSize: 28, color: C.muted, align: 'center' });
pill(s, 6.72, 2.1, 2.25, 0.9, '3. Искусственный суррогат\nсохраняет транспорт, но не сигналы', { fill: C.graySoft, line: C.line, color: C.ink, bold: true, fontSize: 14.2 });
put(s, '→', 9.12, 2.34, 0.4, 0.2, { fontSize: 28, color: C.muted, align: 'center' });
pill(s, 9.62, 2.1, 2.75, 0.9, '4. Голод = дефицит регуляторных\nкомпонентов, а не просто калорий', { fill: C.dark, line: C.dark, color: C.white, bold: true, fontSize: 14.2 });
card(s, 1.15, 4.0, 3.45, 1.25, 'Живая кровь', 'Биохимический пакет с вариативностью, метаболической активностью и поведенческим следом донора.', { fill: C.white, line: C.red });
card(s, 5.0, 4.0, 3.45, 1.25, 'Искусственная кровь', 'Полезна как транспортная среда, но слишком стерильна и бедна на активные сигналы.', { fill: C.white, line: C.blue });
card(s, 8.85, 4.0, 3.45, 1.25, 'Следствие', 'Отсюда возникает селекция по качеству, ритуалы допуска и рынок дефицитных доноров.', { fill: C.white, line: C.line });
footer(s, 6);
}
// 7. classes
{
const s = pptx.addSlide();
fullImage(s, assets.classes);
lightPlaque(s, 'нестабилен, часто голоден', 0.45, 5.93, 3.42, 0.4, 12);
lightPlaque(s, 'контроль только формируется', 0.45, 6.36, 3.42, 0.38, 11.5);
lightPlaque(s, 'устойчив, скрытен, дисциплинирован', 4.62, 5.93, 3.42, 0.4, 11.6);
lightPlaque(s, 'столетнее накопление опыта', 4.62, 6.36, 3.42, 0.38, 11.3);
lightPlaque(s, 'редкое питание, максимальная селекция', 8.95, 5.93, 3.45, 0.4, 11.3);
lightPlaque(s, 'биологическая верхушка касты', 8.95, 6.36, 3.45, 0.38, 11.5);
footer(s, 5, true);
put(s, 'Классы вампирической адаптации', 0.88, 0.3, 11.6, 0.36, { fontSize: 22, bold: true, color: C.dark, align: 'center' });
put(s, 'Чем выше класс, тем больше контроль голода, доступ к качественной крови и политическое влияние.', 0.3, 6.9, 12.7, 0.24, { fontSize: 11.5, color: C.muted, align: 'center' });
footer(s, 7);
}
// 6 failed infection
// 8. failed infection
{
const s = pptx.addSlide();
fullImage(s, assets.failed);
lightPlaque(s, 'объект: носитель SNV-12\nс несовместимым фенотипом', 0.52, 0.8, 3.47, 1.16, 12.5, { bold: true });
lightPlaque(s, 'сосудистый\nперегрев', 4.48, 1.74, 0.78, 0.28, 10.8);
lightPlaque(s, 'гемолиз', 4.47, 2.7, 0.78, 0.28, 10.8);
lightPlaque(s, 'системный\nколлапс', 4.47, 3.54, 0.78, 0.3, 10.5);
lightPlaque(s, 'рост температуры\nдо критического порога', 1.2, 4.0, 2.8, 0.28, 10.8);
lightPlaque(s, 'утрата стабильности\nкровяной среды', 0.9, 6.05, 3.1, 0.38, 12);
lightPlaque(s, 'Неудачное обращение объясняется\nтермогемолитическим коллапсом.', 4.35, 5.45, 3.8, 1.1, 13, { bold: true });
footer(s, 6, true);
put(s, 'Неудачное заражение: каскад несовместимости', 1.1, 0.28, 11.1, 0.36, { fontSize: 22, bold: true, color: C.dark, align: 'center' });
put(s, 'нейровегетативный\nсбой', 3.6, 1.78, 1.44, 0.44, { fontSize: 11.2, color: C.blue, align: 'center' });
put(s, 'кардиореспираторный\nстресс', 3.57, 2.92, 1.5, 0.44, { fontSize: 11.2, color: C.blue, align: 'center' });
put(s, 'абдоминальный\nсосудистый криз', 3.58, 4.12, 1.48, 0.44, { fontSize: 11.0, color: C.blue, align: 'center' });
put(s, 'периферический\nспазм', 3.58, 5.33, 1.48, 0.4, { fontSize: 11.0, color: C.blue, align: 'center' });
put(s, 'терминальное\nистощение', 3.58, 6.42, 1.48, 0.4, { fontSize: 11.0, color: C.blue, align: 'center' });
put(s, 'генетическая и иммунная\nнесовместимость', 7.62, 1.7, 4.66, 0.42, { fontSize: 12.2, color: C.red, align: 'center', bold: true });
put(s, 'сосудистый перегрев\nи гиперметаболизм', 7.62, 3.0, 4.66, 0.42, { fontSize: 12.2, color: C.red, align: 'center', bold: true });
put(s, 'массовый гемолиз\nи высвобождение гема', 7.62, 4.25, 4.66, 0.42, { fontSize: 12.2, color: C.red, align: 'center', bold: true });
put(s, 'воспалительный каскад\nи токсическая перегрузка', 7.62, 5.46, 4.66, 0.42, { fontSize: 12.2, color: C.red, align: 'center', bold: true });
put(s, 'системный коллапс\nбез устойчивой адаптации', 7.62, 6.65, 4.66, 0.42, { fontSize: 12.2, color: C.red, align: 'center', bold: true });
footer(s, 8);
}
// 7 recognize vampire
// 9. recognition slide built in ppt
{
const s = pptx.addSlide();
fullImage(s, assets.recognize);
lightPlaque(s, 'слегка увеличенные\nклыки', 0.42, 2.06, 2.38, 0.46, 12.4);
lightPlaque(s, 'медленное\nстарение', 0.42, 3.58, 2.38, 0.46, 12.4);
lightPlaque(s, 'слишком ровная\nкожа', 0.42, 5.14, 2.38, 0.46, 12.2);
lightPlaque(s, 'тёмный расширенный\nзрачок', 10.53, 2.06, 2.38, 0.46, 12.2);
lightPlaque(s, 'интерес к крови\nи травмам', 10.53, 3.58, 2.38, 0.46, 12.2);
lightPlaque(s, 'закрытые клубы\nи тайные круги', 10.53, 5.14, 2.38, 0.46, 12.0);
footer(s, 7, true);
textSlideBase(s, 'Как распознать вампира');
card(s, 4.45, 1.55, 4.45, 4.4, 'Гемозависимый фенотип', 'Наблюдаемая форма — это не «монстр из мифа», а человек с устойчивыми физиологическими и поведенческими отклонениями, которые становятся заметны в фазах голода, отбора и социальной маскировки.', { fill: C.white, line: C.blue, bodySize: 16, bodyValign: 'mid' });
card(s, 0.86, 1.55, 3.1, 1.06, 'Внешний маркер 1', 'слегка увеличенные клыки', { fill: C.redSoft, line: C.red, bodySize: 14.5 });
card(s, 0.86, 2.82, 3.1, 1.06, 'Внешний маркер 2', 'медленное старение и слишком ровная кожа', { fill: C.redSoft, line: C.red, bodySize: 14.2 });
card(s, 0.86, 4.09, 3.1, 1.06, 'Внешний маркер 3', 'расширенный тёмный зрачок в фазе голода', { fill: C.redSoft, line: C.red, bodySize: 14.2 });
card(s, 9.33, 1.55, 3.14, 1.06, 'Поведение 1', 'фиксация на крови, травмах и медицинских темах', { fill: C.blueSoft, line: C.blue, bodySize: 14.2 });
card(s, 9.33, 2.82, 3.14, 1.06, 'Поведение 2', 'тяга к закрытым элитным кругам и ритуалам допуска', { fill: C.blueSoft, line: C.blue, bodySize: 14.2 });
card(s, 9.33, 4.09, 3.14, 1.06, 'Поведение 3', 'необычная дисциплина питания и контроля среды', { fill: C.blueSoft, line: C.blue, bodySize: 14.2 });
pill(s, 1.62, 6.15, 10.0, 0.56, 'Один признак ничего не доказывает; показательна именно устойчивая комбинация физиологии, голода и социального поведения.', { fill: C.dark, line: C.dark, color: C.white, fontSize: 16, bold: true });
footer(s, 9);
}
// 8 blood economy
// 10. blood economy
{
const s = pptx.addSlide();
fullImage(s, assets.blood);
lightPlaque(s, 'базовое\nподдержание', 1.26, 1.84, 2.05, 0.36, 12.2);
lightPlaque(s, 'норма для\nпериферии', 1.26, 3.33, 2.05, 0.36, 12.2);
lightPlaque(s, 'усиление\nспособностей', 1.26, 4.82, 2.05, 0.36, 12.0);
lightPlaque(s, 'ресурс для элиты\nи ритуалов', 1.26, 6.3, 2.05, 0.36, 11.6);
lightPlaque(s, 'минимальные\nтребования', 10.16, 2.0, 1.62, 0.28, 10.4);
lightPlaque(s, 'устойчивый\nрацион', 10.16, 3.48, 1.62, 0.28, 10.4);
lightPlaque(s, 'для старших\nадаптантов', 10.16, 4.98, 1.62, 0.28, 10.2);
lightPlaque(s, 'только для\nдревних', 10.16, 6.47, 1.62, 0.28, 10.2);
lightPlaque(s, 'дефицит создаёт власть', 0.78, 6.72, 2.2, 0.24, 11.2, { bold: true });
lightPlaque(s, 'чем старше древний,\nтем выше требования', 10.38, 6.72, 2.2, 0.34, 10.5, { bold: true });
footer(s, 8, true);
fullImage(s, assets.economy);
put(s, 'Экономика качественной крови', 0.42, 0.32, 12.48, 0.34, { fontSize: 22, bold: true, color: C.dark, align: 'center' });
put(s, 'Массовая кровь поддерживает периферию; пиковая и династическая питают верхушку и ритуалы.', 0.45, 6.3, 4.3, 0.8, { fontSize: 11.3, color: C.muted, align: 'center' });
put(s, 'Чем древнее адаптант, тем выше требования к сигнальному профилю донора и тем уже доступ.', 5.05, 6.3, 4.3, 0.8, { fontSize: 11.3, color: C.muted, align: 'center' });
footer(s, 10);
}
// 9 artificial blood
// 11. live vs artificial blood
{
const s = pptx.addSlide();
fullImage(s, assets.artificial);
lightPlaque(s, 'высокая\nвариативность', 4.78, 1.58, 1.55, 0.28, 10.2);
lightPlaque(s, ыражены', 4.78, 2.54, 1.55, 0.28, 10.2);
lightPlaque(s, 'уникален', 4.78, 3.48, 1.55, 0.28, 10.2);
lightPlaque(s, 'активна', 4.78, 4.42, 1.55, 0.28, 10.2);
lightPlaque(s, 'есть', 4.78, 5.47, 1.55, 0.28, 10.2);
lightPlaque(s, 'полное', 4.78, 6.33, 1.55, 0.28, 10.2);
lightPlaque(s, 'сглажен', 10.2, 1.58, 1.55, 0.28, 10.2);
lightPlaque(s, 'почти нет', 10.2, 2.54, 1.55, 0.28, 10.2);
lightPlaque(s, 'стёрт', 10.2, 3.48, 1.55, 0.28, 10.2);
lightPlaque(s, 'низкая', 10.2, 4.42, 1.55, 0.28, 10.2);
lightPlaque(s, 'нет', 10.2, 5.47, 1.55, 0.28, 10.2);
lightPlaque(s, 'минимальное', 10.2, 6.33, 1.55, 0.28, 10.2);
footer(s, 9, true);
put(s, 'Почему искусственная кровь не подходит', 1.78, 0.2, 9.8, 0.34, { fontSize: 22, bold: true, color: C.dark, align: 'center' });
put(s, ариативность\nсигналов', 0.24, 3.15, 2.05, 0.38, { fontSize: 10.8, color: C.red, align: 'center' });
put(s, 'активная\nнейрохимия', 0.24, 4.16, 2.05, 0.38, { fontSize: 10.8, color: C.red, align: 'center' });
put(s, 'иммунный\nотклик', 0.24, 5.18, 2.05, 0.38, { fontSize: 10.8, color: C.red, align: 'center' });
put(s, 'эффект\nнасыщения', 0.24, 6.2, 2.05, 0.38, { fontSize: 10.8, color: C.red, align: 'center' });
put(s, 'сигналы\nсглажены', 11.0, 3.15, 2.05, 0.38, { fontSize: 10.8, color: C.blue, align: 'center' });
put(s, 'подпись\nстёрта', 11.0, 4.16, 2.05, 0.38, { fontSize: 10.8, color: C.blue, align: 'center' });
put(s, 'ответ\nнизкий', 11.0, 5.18, 2.05, 0.38, { fontSize: 10.8, color: C.blue, align: 'center' });
put(s, 'сытости\nнет', 11.0, 6.2, 2.05, 0.38, { fontSize: 10.8, color: C.blue, align: 'center' });
put(s, 'Живая кровь даёт вариативный биохимический пакет: гормоны, стресс-маркеры, активный метаболизм и индивидуальный нейрохимический след.', 0.2, 6.7, 5.7, 0.48, {
fontSize: 11.4, color: C.red, align: 'center', bold: true
});
put(s, 'Искусственный суррогат сохраняет транспортную функцию, но слишком стерилен и не вызывает полноценного насыщения.', 7.48, 6.7, 5.7, 0.48, {
fontSize: 11.4, color: C.blue, align: 'center', bold: true
});
footer(s, 11);
}
// 10 hidden donor market
// 12. hidden donor market
{
const s = pptx.addSlide();
fullImage(s, assets.market);
darkPlaque(s, 'Тайный рынок доноров', 5.35, 2.06, 2.1, 0.28, 16, { bold: true });
darkPlaque(s, 'Элитные\nшколы', 0.95, 1.95, 1.35, 0.26, 10.6);
darkPlaque(s, 'Закрытые\nклубы', 2.78, 1.95, 1.35, 0.26, 10.6);
darkPlaque(s, 'Донорские\nдома', 9.0, 1.95, 1.48, 0.26, 10.4);
darkPlaque(s, 'Династии', 10.85, 1.95, 1.45, 0.26, 10.6);
darkPlaque(s, 'Клиники', 0.75, 4.13, 1.9, 0.22, 10.8);
darkPlaque(s, 'Медицинский\nотбор', 2.95, 4.13, 1.9, 0.22, 10.0);
lightPlaque(s, 'лаунджи для\nудержания доноров', 5.55, 4.88, 2.42, 0.34, 10.5);
darkPlaque(s, 'Биобанки', 9.02, 4.13, 1.9, 0.22, 10.8);
darkPlaque(s, 'Архивы и\nдосье', 11.18, 4.13, 1.72, 0.22, 10.0);
darkPlaque(s, 'доноры', 0.62, 6.86, 1.05, 0.2, 9.8);
darkPlaque(s, 'анкеты', 2.62, 6.86, 1.05, 0.2, 9.8);
darkPlaque(s, 'отбор', 4.83, 6.86, 1.05, 0.2, 9.8);
darkPlaque(s, 'пробирки', 6.93, 6.86, 1.05, 0.2, 9.8);
darkPlaque(s, 'архив', 9.13, 6.86, 1.05, 0.2, 9.8);
darkPlaque(s, 'сердце рынка', 11.28, 6.86, 1.18, 0.2, 9.4);
footer(s, 10, true);
put(s, 'Тайный рынок доноров', 0.28, 0.18, 12.75, 0.36, { fontSize: 22, bold: true, color: C.dark, align: 'center' });
put(s, 'Критический поток идёт от источников и донорских домов к сортировке, биобанкам и узлам доставки. Бутылочные горлышки — пропускная способность, холодовая цепь и безопасность маршрутов. Система работает как дисциплинированная логистическая сеть, а не как хаотичный чёрный рынок.', 9.52, 5.85, 3.1, 1.0, {
fontSize: 10.8, color: C.ink, align: 'left', valign: 'top'
});
footer(s, 12);
}
// 11 donor house
{
const s = pptx.addSlide();
fullImage(s, assets.donorHouse);
darkPlaque(s, 'Донорский дом', 0.82, 0.52, 4.95, 0.4, 22, { bold: true });
darkPlaque(s, 'санаторий, пансион и селекционный узел\nпод одной крышей', 0.92, 1.0, 4.7, 0.44, 12.8, { italic: true });
darkPlaque(s, 'отбор', 7.15, 6.52, 1.1, 0.22, 10.5);
darkPlaque(s, 'обучение', 9.26, 6.52, 1.1, 0.22, 10.5);
darkPlaque(s, 'медицина', 11.32, 6.52, 1.1, 0.22, 10.5);
darkPlaque(s, 'селекция', 12.45, 6.52, 0.65, 0.22, 9.5);
footer(s, 11, true);
}
// 12 blood etiquette
{
const s = pptx.addSlide();
fullImage(s, assets.etiquette);
lightPlaque(s, 'Кровяной этикет элиты', 3.95, 0.42, 5.38, 0.42, 22, { bold: true });
darkPlaque(s, 'оценка донора', 3.05, 6.86, 2.05, 0.22, 11.2, { bold: true });
darkPlaque(s, 'ритуал насыщения', 5.36, 6.86, 2.3, 0.22, 11.2, { bold: true });
darkPlaque(s, 'учёт качества', 7.96, 6.86, 2.1, 0.22, 11.2, { bold: true });
darkPlaque(s, 'документы допуска', 10.45, 6.86, 2.15, 0.22, 10.6, { bold: true });
footer(s, 12, true);
}
// 13 feeding zones
// 13. feeding zones map
{
const s = pptx.addSlide();
fullImage(s, assets.zones);
lightPlaque(s, 'Геополитика кормовых зон', 3.62, 0.34, 5.9, 0.34, 20, { bold: true });
lightPlaque(s, 'резервуары\nнаселения', 0.68, 3.62, 1.8, 0.26, 10.4);
lightPlaque(s, 'морские\nкоридоры', 0.68, 4.07, 1.8, 0.26, 10.4);
lightPlaque(s, 'авиационные\nузлы', 0.68, 4.53, 1.8, 0.26, 10.2);
lightPlaque(s, 'убежища\nэлиты', 0.68, 4.99, 1.8, 0.26, 10.4);
lightPlaque(s, 'эксперименты\nи селекция', 0.68, 5.45, 1.8, 0.26, 10.0);
lightPlaque(s, 'карта показывает не государства,\nа контуры биологического снабжения', 4.72, 6.88, 3.95, 0.36, 11.6, { bold: true });
footer(s, 13, true);
put(s, 'Геополитика кормовых зон', 1.02, 0.18, 10.6, 0.34, { fontSize: 22, bold: true, color: C.dark, align: 'center' });
put(s, 'Карта показывает не государства, а контуры биологического снабжения: резервуары населения, коридоры доставки, безопасные зоны элиты и территории управляемых экспериментов.', 11.18, 5.2, 1.74, 1.2, {
fontSize: 10.2, color: C.ink, align: 'center'
});
footer(s, 13);
}
// 14 food chain chart
// 14. consequences matrix
{
const s = pptx.addSlide();
fullImage(s, assets.chain);
lightPlaque(s, 'Пищевая цепочка: от тебя до теневого правительства', 1.82, 0.28, 9.72, 0.34, 17.5, { bold: true });
darkPlaque(s, 'человек', 0.32, 1.8, 1.48, 0.2, 10.2);
darkPlaque(s, 'наблюдение', 2.45, 1.8, 1.48, 0.2, 10.2);
darkPlaque(s, 'сортировка', 4.64, 1.8, 1.48, 0.2, 10.2);
darkPlaque(s, 'логистика', 6.82, 1.8, 1.48, 0.2, 10.2);
darkPlaque(s, 'встреча\nэлиты', 9.02, 1.8, 1.48, 0.2, 9.8);
darkPlaque(s, 'досье', 11.18, 1.8, 1.48, 0.2, 10.2);
darkPlaque(s, 'гемарх', 12.08, 1.8, 0.95, 0.2, 10.0);
lightPlaque(s, 'массовая\nдонорская база', 0.33, 4.92, 1.7, 0.42, 10.3);
lightPlaque(s, 'отбор по\nбиометрии', 4.0, 6.16, 1.85, 0.3, 10.2);
lightPlaque(s, 'качество важнее\nколичества', 7.67, 6.16, 1.95, 0.3, 10.0);
lightPlaque(s, 'верхушка\nспроса', 11.32, 4.92, 1.6, 0.42, 10.4);
footer(s, 14, true);
textSlideBase(s, 'Следствия: почему вампиры именно такие');
card(s, 0.92, 1.5, 5.8, 0.62, 'Биомеханизм', '', { fill: C.dark, line: C.dark, titleColor: C.white });
card(s, 6.82, 1.5, 5.58, 0.62, 'Наблюдаемое следствие', '', { fill: C.red, line: C.red, titleColor: C.white });
const left = [
'дефицит сигнальных молекул',
'изменённые фоторецепторные пути',
'усиленная регенеративная сигнализация',
'перестройка клеточного цикла',
'хронический голодный стресс',
'высокая цена качественной крови'
];
const right = [
'питание кровью и отказ от стерильных суррогатов',
'чувствительность к яркому солнечному свету',
'быстрое восстановление после травм',
'замедленное старение и накопление опыта',
'ритуалы отбора, дисциплина и иерархия доступа',
'скрытая политика, элитные сети и рынок доноров'
];
for (let i = 0; i < left.length; i += 1) {
const y = 2.35 + i * 0.7;
card(s, 0.92, y, 5.8, 0.56, '', left[i], { fill: C.white, line: C.line, bodySize: 13.3, bodyValign: 'mid' });
card(s, 6.82, y, 5.58, 0.56, '', right[i], { fill: C.white, line: C.line, bodySize: 13.3, bodyValign: 'mid' });
}
footer(s, 14);
}
// 15 conclusion
// 15. conclusion
{
const s = pptx.addSlide();
s.background = { color: C.bgDark };
s.addShape(pptx.ShapeType.rect, { x: 0, y: 0, w: 13.333, h: 7.5, fill: { color: C.bgDark }, line: { color: C.bgDark } });
s.addText('Вывод', { x: 0.92, y: 0.92, w: 3.0, h: 0.5, color: C.white, fontFace: 'Georgia', fontSize: 28, bold: true, margin: 0 });
s.addText('Если теория верна, вершина мировой политики — это не кабинет и не трон, а хорошо организованная столовая премиум-класса, где человечество давно числится в меню.', { x: 0.95, y: 2.0, w: 8.15, h: 1.9, fontSize: 24, color: C.cream, margin: 0.02, valign: 'mid' });
s.addShape(pptx.ShapeType.roundRect, { x: 9.15, y: 1.6, w: 2.85, h: 3.4, rectRadius: 0.08, fill: { color: '2A1419' }, line: { color: C.gold, pt: 1.3 } });
s.addText('Ключевые\nформулы', { x: 9.72, y: 2.0, w: 1.75, h: 0.6, align: 'center', fontSize: 20, bold: true, color: C.white, margin: 0 });
s.addText('• власть = кормовая логистика\n• кровь = валюта\n• элита скрывает не власть, а рацион', { x: 9.45, y: 2.9, w: 2.25, h: 1.25, fontSize: 15.5, color: C.cream, margin: 0.02 });
s.addText('Жанр: академически поданная псевдонаука для клуба шапочек из фольги', { x: 1.0, y: 6.45, w: 7.4, h: 0.22, fontSize: 13, color: 'D2B8A5', italic: true, margin: 0 });
s.background = { color: C.dark };
put(s, 'Вывод', 0.95, 0.92, 2.5, 0.42, { fontSize: 28, bold: true, color: C.white, margin: 0 });
put(s,
'Если теория верна, то вершина мировой политики — это не кабинет и не трон, а хорошо организованная биологическая инфраструктура, где власть определяется устойчивым доступом к качественной крови.',
0.95, 2.0, 7.35, 1.55,
{ fontSize: 23, color: 'EAF2FB', margin: 0.02, valign: 'mid' }
);
card(s, 9.0, 1.7, 3.15, 3.4, 'Ключевые формулы', '• вампиризм = биологическая зависимость + социальная инфраструктура\n\n• власть = устойчивый доступ к качественной крови\n\n• миф о монстре скрывает проблему системы снабжения', {
fill: '16324F',
line: '7FA6C9',
titleColor: C.white,
bodyColor: 'EAF2FB',
bodySize: 15,
bodyValign: 'mid'
});
put(s, 'Жанр: строго стилизованная псевдонаука для клуба шапочек из фольги', 0.98, 6.48, 6.9, 0.2, { fontSize: 12.5, color: 'B8C7D9', italic: true, margin: 0 });
footer(s, 15, true);
}
@@ -372,4 +402,4 @@ async function main() {
main().catch((err) => {
console.error(err.stack || err.message || String(err));
process.exit(1);
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 804 KiB

After

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -24,11 +24,12 @@ async function main() {
const report = fs.readFileSync(reportPath, 'utf8');
const handout = fs.readFileSync(handoutPath, 'utf8');
const generator = fs.readFileSync(generatorPath, 'utf8');
assert(report.includes('Sanguis Noctis Virus'), 'В докладе отсутствует ключевой термин');
assert(report.includes('Экономика качественной крови'), 'В докладе нет раздела о качественной крови');
assert(report.includes('Почему искусственная кровь им не подходит'), 'В докладе нет раздела про искусственную кровь');
assert(handout.includes('Тайный рынок доноров'), 'В раздатке нет блока про тайный рынок доноров');
assert(generator.includes("12-food-chain-chart.png") && generator.includes("assets', 'generated'"), 'Генератор не использует пакет generated PNG');
assert(generator.includes('ai-01-snv12-agent.png') && generator.includes('ai-08-feeding-zones-map.png'), 'Генератор не использует новый набор scientific PNG');
const pptxBuf = fs.readFileSync(pptxPath);
const zip = await JSZip.loadAsync(pptxBuf);
@@ -38,10 +39,13 @@ async function main() {
assert(slideFiles.length === 15, `Ожидалось 15 слайдов, получено ${slideFiles.length}`);
const firstSlide = await zip.files[slideFiles[0]].async('string');
const chainSlide = await zip.files[slideFiles[13]].async('string');
const agentSlide = await zip.files[slideFiles[2]].async('string');
const marketSlide = await zip.files[slideFiles[11]].async('string');
const lastSlide = await zip.files[slideFiles[slideFiles.length - 1]].async('string');
assert(firstSlide.includes('Пищевая цепочка:'), 'На первом слайде нет заголовка');
assert(chainSlide.includes('Пищевая цепочка: от тебя до теневого правительства'), 'На слайде пищевой цепочки нет подписанного изображения');
assert(agentSlide.includes('SNV-12'), 'На биологическом слайде нет SNV-12');
assert(marketSlide.includes('Тайный рынок доноров'), 'На слайде рынка доноров нет заголовка');
assert(lastSlide.includes('Вывод'), 'На последнем слайде нет слайда с выводом');
try {
@@ -67,4 +71,4 @@ async function main() {
main().catch((err) => {
console.error(err.stack || err.message || String(err));
process.exit(1);
});
});