431 lines
23 KiB
JavaScript
431 lines
23 KiB
JavaScript
const path = require('path');
|
||
const pptxgen = require('pptxgenjs');
|
||
|
||
const base = __dirname;
|
||
const outPath = path.join(base, 'prezentaciya-vampiricheskoe-tenevoe-pravitelstvo.pptx');
|
||
const assets = {
|
||
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'),
|
||
signTeeth: path.join(base, 'assets', 'generated', 'ai-sign-01-teeth-canines.png'),
|
||
signEyeNeutral: path.join(base, 'assets', 'generated', 'ai-sign-02-eye-neutral.png'),
|
||
signEyeHunger: path.join(base, 'assets', 'generated', 'ai-sign-03-eye-hunger.png'),
|
||
signSkin: path.join(base, 'assets', 'generated', 'ai-sign-04-skin-aging.png'),
|
||
signHand: path.join(base, 'assets', 'generated', 'ai-sign-05-hand-motorics.png'),
|
||
signBehavior: path.join(base, 'assets', 'generated', 'ai-sign-06-behavioral-portrait.png')
|
||
};
|
||
|
||
const pptx = new pptxgen();
|
||
pptx.layout = 'LAYOUT_WIDE';
|
||
pptx.author = 'Hermes Agent';
|
||
pptx.company = 'Nous Research';
|
||
pptx.subject = 'Строгая псевдонаучная модель гемозависимой элиты';
|
||
pptx.title = 'Пищевая цепочка: от тебя до теневого правительства';
|
||
pptx.lang = 'ru-RU';
|
||
pptx.theme = {
|
||
headFontFace: 'Aptos Display',
|
||
bodyFontFace: 'Aptos',
|
||
lang: 'ru-RU'
|
||
};
|
||
|
||
const C = {
|
||
bg: 'F7F9FC',
|
||
white: 'FFFFFF',
|
||
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.48,
|
||
y: 7.02,
|
||
w: 0.36,
|
||
h: 0.18,
|
||
fontSize: 10,
|
||
color: dark ? 'D0DAE6' : C.muted,
|
||
align: 'right',
|
||
margin: 0
|
||
});
|
||
}
|
||
|
||
function put(slide, text, x, y, w, h, opts = {}) {
|
||
slide.addText(text, {
|
||
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 card(slide, x, y, w, h, title, body, opts = {}) {
|
||
slide.addShape(pptx.ShapeType.roundRect, {
|
||
x, y, w, h,
|
||
rectRadius: 0.05,
|
||
fill: { color: opts.fill ?? C.white },
|
||
line: { color: opts.line ?? C.line, pt: opts.pt ?? 1.1 }
|
||
});
|
||
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.white };
|
||
slide.addImage({ path: imagePath, x: 0, y: 0, w: 13.333, h: 7.5 });
|
||
}
|
||
|
||
// 1. title
|
||
{
|
||
const s = pptx.addSlide();
|
||
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
|
||
{
|
||
const s = pptx.addSlide();
|
||
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. biological agent
|
||
{
|
||
const s = pptx.addSlide();
|
||
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 spread map
|
||
{
|
||
const s = pptx.addSlide();
|
||
fullImage(s, assets.medieval);
|
||
put(s, 'Средневековье создаёт идеальную среду', 0.22, 0.28, 4.12, 0.34, { fontSize: 21, bold: true, color: C.dark, align: 'center' });
|
||
put(s, 'XII–XIV века: торговля, миграции, войны и эпидемии', 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. physiological changes
|
||
{
|
||
const s = pptx.addSlide();
|
||
textSlideBase(s, 'Как вирус меняет организм');
|
||
card(s, 0.88, 1.4, 3.88, 1.4, 'Кровяная среда', 'Норма: транспорт O₂.\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);
|
||
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);
|
||
}
|
||
|
||
// 8. failed infection
|
||
{
|
||
const s = pptx.addSlide();
|
||
fullImage(s, assets.failed);
|
||
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);
|
||
}
|
||
|
||
// 9. recognition slide built in ppt
|
||
{
|
||
const s = pptx.addSlide();
|
||
textSlideBase(s, 'Как распознать вампира');
|
||
const items = [
|
||
{ x: 0.72, y: 1.22, img: assets.signTeeth, title: 'Клыки', body: 'удлинение без деформации' },
|
||
{ x: 4.38, y: 1.22, img: assets.signEyeNeutral, title: 'Глаз: сытая фаза', body: 'зрачок почти нормален' },
|
||
{ x: 8.04, y: 1.22, img: assets.signEyeHunger, title: 'Глаз: голод', body: 'зрачок расширен и темнее' },
|
||
{ x: 0.72, y: 4.02, img: assets.signSkin, title: 'Кожа и возраст', body: 'ровная кожа, слабый возрастной шум' },
|
||
{ x: 4.38, y: 4.02, img: assets.signHand, title: 'Кисть и моторика', body: 'точность, вены, холодная пластика' },
|
||
{ x: 8.04, y: 4.02, img: assets.signBehavior, title: 'Поведение', body: 'кровь, документы, закрытые круги' }
|
||
];
|
||
|
||
items.forEach((item) => {
|
||
card(s, item.x, item.y, 3.05, 2.48, '', '', { fill: C.white, line: C.line, pt: 1.15 });
|
||
s.addImage({ path: item.img, x: item.x + 0.12, y: item.y + 0.12, w: 2.81, h: 1.72 });
|
||
put(s, item.title, item.x + 0.14, item.y + 1.88, 2.76, 0.18, {
|
||
fontSize: 11.8,
|
||
bold: true,
|
||
color: C.dark,
|
||
align: 'center',
|
||
margin: 0
|
||
});
|
||
put(s, item.body, item.x + 0.18, item.y + 2.08, 2.68, 0.22, {
|
||
fontSize: 9.6,
|
||
color: C.muted,
|
||
align: 'center',
|
||
margin: 0
|
||
});
|
||
});
|
||
|
||
pill(s, 1.58, 6.9, 10.15, 0.34, 'Смотреть нужно на комбинацию признаков.', { fill: C.dark, line: C.dark, color: C.white, fontSize: 12.4, bold: true });
|
||
footer(s, 9);
|
||
}
|
||
|
||
// 10. blood economy
|
||
{
|
||
const s = pptx.addSlide();
|
||
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, 'Массовая кровь — периферии.\nПиковая и династическая — элите.', 0.45, 6.3, 4.3, 0.8, { fontSize: 11.3, color: C.muted, align: 'center' });
|
||
put(s, 'Чем древнее адаптант,\nтем уже доступ.', 5.05, 6.3, 4.3, 0.8, { fontSize: 11.3, color: C.muted, align: 'center' });
|
||
footer(s, 10);
|
||
}
|
||
|
||
// 11. live vs artificial blood
|
||
{
|
||
const s = pptx.addSlide();
|
||
fullImage(s, assets.artificial);
|
||
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);
|
||
}
|
||
|
||
// 12. hidden donor market
|
||
{
|
||
const s = pptx.addSlide();
|
||
fullImage(s, assets.market);
|
||
put(s, 'Тайный рынок доноров', 0.28, 0.18, 12.75, 0.36, { fontSize: 22, bold: true, color: C.dark, align: 'center' });
|
||
put(s, 'Поток: источник → отбор → биобанк → доставка.\nКлючевые узкие места: объём, холод, безопасность.', 9.52, 5.85, 3.1, 1.0, {
|
||
fontSize: 10.8, color: C.ink, align: 'left', valign: 'top'
|
||
});
|
||
footer(s, 12);
|
||
}
|
||
|
||
// 13. feeding zones map
|
||
{
|
||
const s = pptx.addSlide();
|
||
fullImage(s, assets.zones);
|
||
put(s, 'Геополитика кормовых зон', 1.02, 0.18, 10.6, 0.34, { fontSize: 22, bold: true, color: C.dark, align: 'center' });
|
||
put(s, 'Не страны, а контуры снабжения:\nрезервуары, коридоры, убежища, эксперименты.', 11.18, 5.2, 1.74, 1.2, {
|
||
fontSize: 10.2, color: C.ink, align: 'center'
|
||
});
|
||
footer(s, 13);
|
||
}
|
||
|
||
// 14. consequences matrix
|
||
{
|
||
const s = pptx.addSlide();
|
||
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
|
||
{
|
||
const s = pptx.addSlide();
|
||
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);
|
||
}
|
||
|
||
async function main() {
|
||
await pptx.writeFile({ fileName: outPath });
|
||
}
|
||
|
||
main().catch((err) => {
|
||
console.error(err.stack || err.message || String(err));
|
||
process.exit(1);
|
||
}); |