# -*- coding: utf-8 -*- from pptx import Presentation from pptx.util import Inches, Pt from pptx.dml.color import RGBColor from pptx.enum.text import PP_ALIGN, MSO_ANCHOR from pptx.enum.shapes import MSO_SHAPE, MSO_CONNECTOR OUT = 'Метод_Дегтярева_презентация.pptx' BG = '121417' CARD = '1C2024' CARD2 = '23282D' GREEN = '3FA37A' GREEN_LIGHT = '7FD1AE' ROSE = 'D94A6A' WHITE = 'F5F5F5' GRAY = '9AA0A6' DARK_GRAY = '6B7075' GOLD = 'C9A227' def rgb(hexstr): return RGBColor.from_string(hexstr) def add_bg(slide, color=BG): bg = slide.background fill = bg.fill fill.solid() fill.fore_color.rgb = rgb(color) def add_text(slide, x, y, w, h, text, font='Arial', size=12, color=WHITE, bold=False, italic=False, align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP, line_spacing=1.0, space_after=0, margins=(0, 0, 0, 0)): tb = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h)) tf = tb.text_frame tf.word_wrap = True tf.margin_left = Inches(margins[0]) tf.margin_right = Inches(margins[1]) tf.margin_top = Inches(margins[2]) tf.margin_bottom = Inches(margins[3]) tf.vertical_anchor = anchor lines = text.split('\n') for i, line in enumerate(lines): p = tf.paragraphs[0] if i == 0 else tf.add_paragraph() p.alignment = align p.line_spacing = line_spacing p.space_after = Pt(space_after) r = p.add_run() r.text = line r.font.name = font r.font.size = Pt(size) r.font.bold = bold r.font.italic = italic r.font.color.rgb = rgb(color) return tb def add_rect(slide, x, y, w, h, fill=None, line=None, line_w=1.0, shape=MSO_SHAPE.ROUNDED_RECTANGLE, radius=0.06): shp = slide.shapes.add_shape(shape, Inches(x), Inches(y), Inches(w), Inches(h)) if fill: shp.fill.solid() shp.fill.fore_color.rgb = rgb(fill) else: shp.fill.background() if line: shp.line.color.rgb = rgb(line) shp.line.width = Pt(line_w) else: shp.line.fill.background() try: shp.shadow.inherit = False except Exception: pass if shape == MSO_SHAPE.ROUNDED_RECTANGLE: try: shp.adjustments[0] = radius except Exception: pass return shp def add_line(slide, x1, y1, x2, y2, color=DARK_GRAY, width=1.0): conn = slide.shapes.add_connector(MSO_CONNECTOR.STRAIGHT, Inches(x1), Inches(y1), Inches(x2), Inches(y2)) conn.line.color.rgb = rgb(color) conn.line.width = Pt(width) return conn def add_notes(slide, text): slide.notes_slide.notes_text_frame.text = text def slide_title(prs): s = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(s) add_rect(s, 0.75, 1.15, 0.055, 4.95, fill=GREEN, shape=MSO_SHAPE.RECTANGLE) add_text(s, 1.05, 0.72, 8.2, 0.3, 'ФОРУМ МОЛОДЁЖИ ДОНБАССА • СМЕНА 1 «ПСБ ПАТРИОТ»', size=10, color=GRAY, bold=True) add_text(s, 1.0, 1.32, 8.3, 2.35, 'МЕТОД\nДЕГТЯРЕВА', font='Georgia', size=54, color=WHITE, bold=True, line_spacing=0.92) add_text(s, 1.05, 3.78, 8.2, 0.55, 'Цифра, у которой есть хозяин', font='Georgia', size=24, color=GREEN, italic=True) add_text(s, 1.05, 4.48, 8.2, 0.4, 'От забоя до миллиона роз', size=14, color=GRAY) add_text(s, 1.05, 5.05, 8.2, 0.35, 'Бойко К.С. • эксперт и наставник трека', size=11, color=GREEN_LIGHT, bold=True) add_line(s, 1.05, 6.18, 8.4, 6.18, color='2A2F34', width=1.0) add_text(s, 1.05, 6.38, 8.2, 0.35, '3 дня • 5 шагов • 1 защита', size=11, color=DARK_GRAY) # Big 5 circle add_rect(s, 9.55, 1.55, 3.1, 3.1, fill=None, line=GREEN, line_w=1.5, shape=MSO_SHAPE.OVAL) add_text(s, 9.55, 1.72, 3.1, 1.9, '5', font='Georgia', size=96, color=GREEN, bold=True, align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE) add_text(s, 9.55, 3.62, 3.1, 0.35, 'ШАГОВ', size=12, color=GRAY, bold=True, align=PP_ALIGN.CENTER) add_rect(s, 12.28, 4.28, 0.34, 0.34, fill=ROSE, shape=MSO_SHAPE.OVAL) add_notes(s, 'Хук: В 1970-х ЮНЕСКО назвала Донецк самым зелёным промышленным городом планеты. ' 'Город, который мы привыкли называть всесоюзной кочегаркой. Это сделал человек, ' 'у которого не было ни интернета, ни смартфона, ни искусственного интеллекта. ' 'Его звали Владимир Дегтярев. И у него был метод. За три дня мы применим этот метод к цифре.') return s def slide_paradox(prs): s = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(s) add_text(s, 0.75, 0.55, 11.8, 0.7, 'Парадокс, который стоит изучать', font='Georgia', size=30, color=WHITE, bold=True) add_text(s, 0.75, 1.22, 11.8, 0.4, 'Донецк: из «всесоюзной кочегарки» — в самый зелёный промышленный город планеты', size=13, color=GRAY) # Left card add_rect(s, 0.75, 2.0, 4.55, 2.15, fill=CARD) add_text(s, 1.0, 2.2, 4.05, 0.3, 'ДО 1963', size=10, color=DARK_GRAY, bold=True) add_text(s, 1.0, 2.55, 4.05, 0.95, 'ВСЕСОЮЗНАЯ\nКОЧЕГАРКА', font='Georgia', size=22, color=GRAY, bold=True, line_spacing=0.95) add_text(s, 1.0, 3.55, 4.05, 0.4, 'уголь, бараки, дефицит воды', size=11, color=DARK_GRAY) # Arrow add_rect(s, 5.55, 2.82, 0.65, 0.5, fill=GREEN, shape=MSO_SHAPE.RIGHT_ARROW) # Right card add_rect(s, 6.45, 2.0, 6.1, 2.15, fill=CARD) add_text(s, 6.7, 2.2, 5.6, 0.3, '1970-Е', size=10, color=GREEN, bold=True) add_text(s, 6.7, 2.55, 5.6, 1.0, 'САМЫЙ ЗЕЛЁНЫЙ\nПРОМЫШЛЕННЫЙ ГОРОД\nПЛАНЕТЫ', font='Georgia', size=19, color=GREEN, bold=True, line_spacing=0.95) add_text(s, 6.7, 3.62, 5.6, 0.35, 'ЮНЕСКО. Миллион роз. Ботанический сад.', size=11, color=GRAY) # Stats stats = [ ('3,1×', 'рост жилищного фонда', GREEN), ('5', 'академических институтов', GREEN), ('1 000 000', 'кустов роз', ROSE), ] x = 0.75 for num, label, color in stats: add_rect(s, x, 4.65, 3.8, 1.45, fill=CARD2) add_text(s, x + 0.25, 4.82, 3.3, 0.65, num, font='Georgia', size=32, color=color, bold=True) add_text(s, x + 0.25, 5.5, 3.3, 0.35, label, size=10.5, color=GRAY) x += 4.0 add_text(s, 0.75, 6.55, 11.8, 0.3, 'По материалам Донецкого агентства новостей, 20.02.2026', size=9, color=DARK_GRAY) add_notes(s, 'Парадокс: город угля и бараков стал самым зелёным промышленным городом планеты. ' 'Жильё выросло в 3,1 раза, появился научный центр из пяти институтов, миллион роз. ' 'Вопрос: как? Ответ — метод.') return s def slide_man(prs): s = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(s) add_text(s, 0.75, 0.55, 11.8, 0.7, 'Человек, который не был айтишником', font='Georgia', size=30, color=WHITE, bold=True) add_text(s, 0.75, 1.22, 11.8, 0.4, 'Владимир Иванович Дегтярев (1920–1993) — «хозяин Донбасса»', size=13, color=GRAY) facts = [ ('1920', 'Родился под Ставрополем в семье железнодорожного рабочего'), ('1948', 'Назначен на шахту «Центральная» в Чистяково (Торез)'), ('1953', 'Возглавил трест «Чистяковантрацит». Ему неполных 33 года'), ('1963–1976', 'Первый секретарь Донецкого обкома. 13 лет преобразований'), ] x = 0.75 for year, text in facts: add_rect(s, x, 2.0, 2.85, 2.55, fill=CARD) add_text(s, x + 0.22, 2.2, 2.4, 0.55, year, font='Georgia', size=24, color=GREEN, bold=True) add_text(s, x + 0.22, 2.85, 2.4, 1.5, text, size=10.5, color=WHITE, line_spacing=1.1) x += 3.05 # Quote add_rect(s, 0.75, 4.95, 11.8, 1.25, fill=CARD2) add_rect(s, 0.75, 4.95, 0.06, 1.25, fill=ROSE, shape=MSO_SHAPE.RECTANGLE) add_text(s, 1.05, 5.12, 11.2, 0.6, '«Опыта в работе мало, да и годы невелики: было всего неполных 33 года».', font='Georgia', size=16, color=WHITE, italic=True) add_text(s, 1.05, 5.78, 11.2, 0.3, '— В. И. Дегтярев', size=10, color=GRAY) add_text(s, 0.75, 6.5, 11.8, 0.35, 'Его называли «хозяином» не за должность, а за метод.', size=12, color=GREEN_LIGHT, bold=True) add_notes(s, 'Биография: горный инженер, начальник участка шахты, в 32 года — управляющий трестом, ' 'в 43 — первый секретарь обкома. За 13 лет: жильё, наука, культура, зелёный город. ' 'Он не был айтишником. Он был хозяином.') return s def slide_method(prs): s = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(s) add_text(s, 0.75, 0.55, 11.8, 0.7, 'Пять шагов хозяина', font='Georgia', size=30, color=WHITE, bold=True) add_text(s, 0.75, 1.22, 11.8, 0.4, 'Каждый шаг — вопрос и артефакт на канвасе', size=13, color=GRAY) steps = [ ('01', 'ЗАБОЙ', 'Что болит\nна самом деле?', 'Карта проблемы', GREEN), ('02', 'СМЕТА', 'Кому и насколько\nстанет лучше?', 'Портрет + метрики', GREEN), ('03', 'ЗАВОД', 'Что нужно, чтобы\nрешалось системно?', 'Архитектура + ресурсы', GREEN), ('04', 'РОЗА', 'Как люди это\nпочувствуют?', 'Ценность + MVP', ROSE), ('05', 'ХОЗЯИН', 'Кто останется\nпосле нас?', 'Устойчивость + план', ROSE), ] x = 0.75 for num, name, question, artifact, color in steps: add_rect(s, x, 2.0, 2.3, 3.85, fill=CARD) add_text(s, x + 0.2, 2.18, 1.9, 0.3, num, size=12, color=color, bold=True) add_text(s, x + 0.2, 2.55, 1.9, 0.45, name, font='Georgia', size=19, color=WHITE, bold=True) add_text(s, x + 0.2, 3.15, 1.9, 0.95, question, size=11, color=GRAY, line_spacing=1.1) add_line(s, x + 0.2, 4.35, x + 2.1, 4.35, color='2E3439', width=1.0) add_text(s, x + 0.2, 4.5, 1.9, 0.7, artifact, size=9.5, color=color, bold=True, line_spacing=1.05) x += 2.45 add_text(s, 0.75, 6.25, 11.8, 0.4, 'Метод работает и для проекта, и для карьеры, и для региона.', size=12, color=GREEN_LIGHT, bold=True) add_notes(s, 'Метод: Забой — спустись туда, где реально болит. Смета — посчитай в людях, а не в отчётах. ' 'Завод — построй систему, а не разовую акцию. Роза — сделай результат видимым и желанным. ' 'Хозяин — останься после запуска.') return s def slide_map(prs): s = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(s) add_text(s, 0.75, 0.55, 11.8, 0.7, 'Три дня — пять шагов', font='Georgia', size=30, color=WHITE, bold=True) add_text(s, 0.75, 1.22, 11.8, 0.4, 'Лекции дают контекст. Лаборатории дают артефакты. Защита даёт обратную связь.', size=13, color=GRAY) add_line(s, 0.9, 3.05, 12.45, 3.05, color='2E3439', width=2.0) nodes = [ ('10.11 • 19:30', 'Установка', 'Зачем и как', 1.9), ('11.11 • 10:45', 'Забой + Смета', 'Проблема и пользователь', 4.9), ('11.11 • 18:00', 'Завод + Роза', 'Решение и ценность', 7.9), ('12.11 • 10:30', 'Хозяин', 'Устойчивость и метрики', 10.9), ] for date, title, desc, cx in nodes: add_rect(s, cx - 0.11, 2.94, 0.22, 0.22, fill=GREEN, shape=MSO_SHAPE.OVAL) add_text(s, cx - 1.25, 2.35, 2.5, 0.3, date, size=10.5, color=GREEN, bold=True, align=PP_ALIGN.CENTER) add_text(s, cx - 1.4, 3.35, 2.8, 0.4, title, font='Georgia', size=15, color=WHITE, bold=True, align=PP_ALIGN.CENTER) add_text(s, cx - 1.4, 3.78, 2.8, 0.6, desc, size=10, color=GRAY, align=PP_ALIGN.CENTER, line_spacing=1.05) chips = [ 'Цифровая трансформация', 'Ограничения как топливо', 'Технология человечная', 'Регион как лаборатория', 'ИИ в действии', ] x = 0.75 for chip in chips: add_rect(s, x, 5.0, 2.25, 0.55, fill=CARD, line='2E3439', line_w=0.75) add_text(s, x + 0.1, 5.08, 2.05, 0.4, chip, size=9, color=GRAY, align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE) x += 2.4 add_text(s, 0.75, 6.15, 11.8, 0.4, '14:45 — защита проектов. 3 минуты питч + 2 минуты вопросы.', size=12, color=GREEN_LIGHT, bold=True) add_notes(s, 'Карта трека: 10 ноября — установка. 11 ноября — проблема, пользователь, решение, ценность. ' '12 ноября — устойчивость, консультации, сборка и защита. Лекции работают на метод.') return s def slide_team(prs): s = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(s) add_text(s, 0.75, 0.55, 11.8, 0.7, 'Команда = маленький обком', font='Georgia', size=30, color=WHITE, bold=True) add_text(s, 0.75, 1.22, 11.8, 0.4, '5–7 человек. Разные специальности. Один канвас.', size=13, color=GRAY) roles = [ ('ЗАБОЙЩИК', 'исследователь: поле, интервью, данные', GREEN), ('ИНЖЕНЕР', 'технарь: решение, архитектура, MVP', GREEN), ('ХОЗЯИН', 'экономист: ресурсы, метрики, устойчивость', ROSE), ('ГОЛОС', 'коммуникатор: питч, визуал, история', ROSE), ] positions = [(0.75, 2.0), (3.9, 2.0), (0.75, 3.95), (3.9, 3.95)] for (name, desc, color), (x, y) in zip(roles, positions): add_rect(s, x, y, 2.95, 1.7, fill=CARD) add_text(s, x + 0.22, y + 0.18, 2.5, 0.35, name, font='Georgia', size=15, color=color, bold=True) add_text(s, x + 0.22, y + 0.65, 2.5, 0.85, desc, size=10, color=GRAY, line_spacing=1.1) # Canvas preview add_rect(s, 7.15, 2.0, 5.45, 4.25, fill=CARD2) add_text(s, 7.4, 2.18, 4.9, 0.3, 'КАНВАС «МЕТОД ДЕГТЯРЕВА»', size=10, color=GREEN, bold=True) rows = [ ('01', 'Забой', 'проблема и доказательства'), ('02', 'Смета', 'пользователь и метрики'), ('03', 'Завод', 'решение и ресурсы'), ('04', 'Роза', 'ценность и MVP'), ('05', 'Хозяин', 'устойчивость и план'), ] y = 2.65 for num, name, desc in rows: add_text(s, 7.4, y, 0.45, 0.3, num, size=9, color=GREEN, bold=True) add_text(s, 7.85, y - 0.02, 1.3, 0.3, name, size=11, color=WHITE, bold=True) add_text(s, 9.15, y, 3.2, 0.3, desc, size=9.5, color=GRAY) add_line(s, 7.4, y + 0.42, 12.3, y + 0.42, color='2E3439', width=0.75) y += 0.68 add_text(s, 0.75, 6.5, 11.8, 0.35, 'Канвас печатается на А4. Один на команду.', size=11, color=DARK_GRAY) add_notes(s, 'Роли: Забойщик, Инженер, Хозяин, Голос. Команда смешанная. Канвас — один на команду, ' 'заполняется по шагам. Это не отчёт, а рабочий инструмент.') return s def slide_result(prs): s = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(s) add_text(s, 0.75, 0.55, 11.8, 0.7, 'Что вы унесёте', font='Georgia', size=30, color=WHITE, bold=True) add_text(s, 0.75, 1.22, 11.8, 0.4, 'Проект не заканчивается защитой.', size=13, color=GRAY) # Left column add_text(s, 0.75, 1.95, 5.5, 0.35, 'УЧАСТНИК', size=11, color=GREEN, bold=True) left = [ ('1', 'паспорт проекта'), ('3', 'минуты питча'), ('30/90', 'дней дорожная карта'), ('5', 'шагов методичка'), ] y = 2.45 for num, label in left: add_text(s, 0.75, y, 1.35, 0.55, num, font='Georgia', size=24, color=GREEN, bold=True) add_text(s, 2.15, y + 0.08, 4.0, 0.4, label, size=12, color=WHITE) add_line(s, 0.75, y + 0.72, 6.1, y + 0.72, color='2E3439', width=0.75) y += 0.9 # Right column add_text(s, 6.95, 1.95, 5.5, 0.35, 'РЕГИОН', size=11, color=ROSE, bold=True) right = [ ('5–7', 'концепций цифровых сервисов'), ('1', 'банк проблем'), ('2–3', 'проекта к пилоту или гранту'), ('∞', 'тиражируемая методика'), ] y = 2.45 for num, label in right: add_text(s, 6.95, y, 1.35, 0.55, num, font='Georgia', size=24, color=ROSE, bold=True) add_text(s, 8.35, y + 0.08, 4.2, 0.4, label, size=12, color=WHITE) add_line(s, 6.95, y + 0.72, 12.3, y + 0.72, color='2E3439', width=0.75) y += 0.9 add_text(s, 0.75, 6.35, 11.8, 0.4, 'Лучшие проекты получают дорожную карту и поддержку партнёров.', size=12, color=GREEN_LIGHT, bold=True) add_notes(s, 'Результат: у участника — паспорт, питч, дорожная карта, методичка. ' 'У региона — банк проблем, 5–7 концепций, 2–3 проекта к пилоту или гранту, ' 'тиражируемая методика.') return s def slide_cta(prs): s = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(s) add_rect(s, 0.75, 1.15, 0.055, 4.95, fill=ROSE, shape=MSO_SHAPE.RECTANGLE) add_text(s, 1.05, 1.35, 8.2, 0.4, 'ЗАВТРА В 10:45', size=16, color=GREEN, bold=True) add_text(s, 1.0, 1.9, 8.6, 1.2, 'Спуск в забой.', font='Georgia', size=48, color=WHITE, bold=True) add_text(s, 1.05, 3.35, 8.4, 1.2, 'Приходите с проблемой,\nа не с идеей.', font='Georgia', size=26, color=ROSE, italic=True, line_spacing=1.05) add_text(s, 1.05, 4.95, 8.2, 0.4, 'Зал «Жуков 2»', size=14, color=GRAY) add_line(s, 1.05, 6.15, 8.4, 6.15, color='2A2F34', width=1.0) add_text(s, 1.05, 6.35, 8.2, 0.35, 'Метод Дегтярева • Цифра, у которой есть хозяин', size=11, color=DARK_GRAY) # Decorative circle add_rect(s, 9.55, 1.55, 3.1, 3.1, fill=None, line=ROSE, line_w=1.5, shape=MSO_SHAPE.OVAL) add_text(s, 9.55, 2.55, 3.1, 1.1, '→', font='Georgia', size=64, color=ROSE, bold=True, align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE) add_notes(s, 'Вызов: завтра в 10:45 — спуск в забой. Зал «Жуков 2». ' 'Приходите с проблемой, а не с идеей. Дальше — метод Дегтярева.') return s def build(): prs = Presentation() prs.slide_width = Inches(13.333) prs.slide_height = Inches(7.5) slide_title(prs) slide_paradox(prs) slide_man(prs) slide_method(prs) slide_map(prs) slide_team(prs) slide_result(prs) slide_cta(prs) prs.save(OUT) print('saved', OUT) if __name__ == '__main__': build()