376 lines
19 KiB
JavaScript
376 lines
19 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 = {
|
||
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')
|
||
};
|
||
|
||
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: 'Georgia',
|
||
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',
|
||
white: 'FFFFFF',
|
||
ink: '2A1A1D',
|
||
brown: '4A3327'
|
||
};
|
||
|
||
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
|
||
});
|
||
}
|
||
|
||
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 } }));
|
||
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'
|
||
});
|
||
}
|
||
|
||
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 = {}) {
|
||
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,
|
||
rectRadius: 0.05,
|
||
fill: { color: opts.fill ?? C.red },
|
||
line: { color: opts.fill ?? C.red }
|
||
});
|
||
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
|
||
});
|
||
}
|
||
|
||
function fullImage(slide, imagePath) {
|
||
slide.background = { color: C.bgDark };
|
||
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
|
||
{
|
||
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);
|
||
}
|
||
|
||
// 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, 'Ключевая формула: власть = контроль кормовой инфраструктуры');
|
||
footer(s, 2);
|
||
}
|
||
|
||
// 3 virus
|
||
{
|
||
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 });
|
||
footer(s, 3);
|
||
}
|
||
|
||
// 4 medieval origin
|
||
{
|
||
const s = pptx.addSlide();
|
||
fullImage(s, assets.medieval);
|
||
darkPlaque(s, 'XII–XIV века', 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);
|
||
}
|
||
|
||
// 5 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);
|
||
}
|
||
|
||
// 6 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);
|
||
}
|
||
|
||
// 7 recognize vampire
|
||
{
|
||
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);
|
||
}
|
||
|
||
// 8 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);
|
||
}
|
||
|
||
// 9 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);
|
||
}
|
||
|
||
// 10 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);
|
||
}
|
||
|
||
// 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
|
||
{
|
||
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);
|
||
}
|
||
|
||
// 14 food chain chart
|
||
{
|
||
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);
|
||
}
|
||
|
||
// 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 });
|
||
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);
|
||
});
|