commit 2c79f59064fcdf598fff06495ddb1aa860b942dc Author: Kavalar Date: Mon Nov 9 00:08:45 2026 +0300 Трек «Метод Дегтярева»: концепция, презентация и рабочие листы diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3cdc374 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Временные файлы +~$* +*.tmp +_*.png +_*.pdf +_*.docx +_*.pptx +_names.txt +__pycache__/ +*.pyc + +# ОС +Thumbs.db +.DS_Store +desktop.ini diff --git a/1 смена Проект программы ФМД_07.11.docx b/1 смена Проект программы ФМД_07.11.docx new file mode 100644 index 0000000..646a131 Binary files /dev/null and b/1 смена Проект программы ФМД_07.11.docx differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..37ecd4d --- /dev/null +++ b/README.md @@ -0,0 +1,135 @@ +# Трек «Метод Дегтярева» + +Материалы трека Форума молодёжи Донбасса «ФМД: у нас так принято». +Смена 1 «ПСБ Патриот», 10–13 ноября 2026. + +**Эксперт и наставник трека:** Бойко К.С. + +--- + +## О треке + +Трек о том, как превращать реальные проблемы региона в цифровые социальные проекты. В основе — метод Владимира Дегтярева, «хозяина Донбасса», который в 1963–1976 годах превратил шахтёрский край в самый зелёный промышленный город планеты. + +**Слоган:** «От забоя до миллиона роз». + +**Главная мысль:** цифровизация начинается не с сервера, а с человека. Технология становится ценной только тогда, когда у неё есть хозяин — тот, кто понимает, кому и зачем она служит. + +### Пять шагов + +| Шаг | Вопрос | Артефакт | +|---|---|---| +| **Забой** | Что болит на самом деле? | Карта проблемы, интервью, данные | +| **Смета** | Кому и насколько станет лучше? | Портрет пользователя, 3 метрики | +| **Завод** | Что нужно, чтобы решалось системно? | Архитектура, ресурсы, партнёры | +| **Роза** | Как люди это почувствуют? | Ценность, сценарий, MVP | +| **Хозяин** | Кто останется после нас? | Устойчивость, дорожная карта 30/90 | + +### Прикладной результат + +**Участник:** паспорт проекта на 1 странице, питч на 3 минуты, дорожная карта 30/90, методичка «5 шагов». + +**Регион:** банк проблем, 5–7 концепций цифровых социальных сервисов, 2–3 проекта к пилоту или гранту, тиражируемая методика. + +--- + +## Материалы + +| Файл | Назначение | +|---|---| +| `Метод_Дегтярева_концепция_трека.docx` | Полная концепция: задумка, цели, задачи, результат, метод, встройка в программу, роли, критерии, сценарии на 7 и 5 минут, Q&A | +| `Метод_Дегтярева_презентация.pptx` | 8 слайдов под установочную сессию 10.11, 19:30. В заметках — текст выступления | +| `Метод_Дегтярева_карта_проблемы.docx` | Рабочий лист «Забой»: кто, где, что мешает, что теряет, доказательства, 5 почему | +| `Метод_Дегтярева_гайд_интервью.docx` | 8 карточек с вопросами и правилами интервью | +| `Метод_Дегтярева_смета.docx` | Рабочий лист «Смета»: пользователь, было → стало, три метрики, масштаб, цена эффекта | +| `Метод_Дегтярева_роза.docx` | Рабочий лист «Роза»: ценность, сценарий, эмоции, MVP, отличие, питч | +| `Метод_Дегтярева_хозяин.docx` | Рабочий лист «Хозяин»: команда, модель устойчивости, партнёры, дорожная карта 30/90, риски | +| `Метод_Дегтярева_канвас.docx` | Универсальный канвас на 8 блоков для команд | +| `Метод_Дегтярева_концепция_трека.md` | Исходный текст концепции в Markdown | +| `1 смена Проект программы ФМД_07.11.docx` | Исходная программа форума | + +PDF-версии всех материалов лежат рядом с исходниками и предназначены для печати и быстрой отправки. + +--- + +## Как использовать + +### Печать + +- Формат A4, масштаб 100%, без «по размеру страницы». +- «Карта проблемы», «Смета», «Роза», «Хозяин» — по одной на команду. +- «Гайд интервью» — по одной карточке на пару интервьюеров. В файле 8 карточек. +- «Канвас» — по одному на команду как сводный рабочий лист. +- Презентация — 8 слайдов, рассчитана на 7 минут. В заметках — текст выступления. + +### Установочная сессия + +10 ноября, 19:30–20:00. Презентация трека: зачем, как, что получится. Регламент — 5–7 минут. В концепции есть полный сценарий на 7 минут и сжатая версия на 5 минут. + +### Лаборатории + +| Дата | Время | Шаг | Материал | +|---|---|---|---| +| 11.11 | 10:45–12:00 | Забой + Смета | «Карта проблемы», «Гайд интервью» | +| 11.11 | 18:00–19:00 | Завод + Роза | «Роза», канвас | +| 12.11 | 10:30–11:30 | Хозяин | «Хозяин» | +| 12.11 | 11:30–12:30 | Консультации | Индивидуально | +| 12.11 | 13:00–14:30 | Сборка | Паспорт проекта, питч | +| 12.11 | 14:45–16:30 | Защита | 3 минуты питч + 2 минуты вопросы | + +--- + +## Структура репозитория + +``` +. +├── README.md +├── Метод_Дегтярева_концепция_трека.md +├── Метод_Дегтярева_концепция_трека.docx / .pdf +├── Метод_Дегтярева_презентация.pptx / .pdf +├── Метод_Дегтярева_карта_проблемы.docx / .pdf +├── Метод_Дегтярева_гайд_интервью.docx / .pdf +├── Метод_Дегтярева_смета.docx / .pdf +├── Метод_Дегтярева_роза.docx / .pdf +├── Метод_Дегтярева_хозяин.docx / .pdf +├── Метод_Дегтярева_канвас.docx / .pdf +├── build_*.py +└── 1 смена Проект программы ФМД_07.11.docx +``` + +--- + +## Сборка материалов + +Требования: Python 3.12, пакеты `python-docx` и `python-pptx`. Для PDF — LibreOffice. + +```bash +py -3 -m pip install python-docx python-pptx + +py -3 build_docx.py +py -3 build_pptx.py +py -3 build_canvas.py +py -3 build_problem_card.py +py -3 build_interview_cards.py +py -3 build_estimate_card.py +py -3 build_rose_card.py +py -3 build_owner_card.py +``` + +Конвертация в PDF: + +```bash +soffice --headless --convert-to pdf --outdir . <файл>.docx +``` + +--- + +## Автор + +Бойко К.С., эксперт и наставник трека «Метод Дегтярева». + +--- + +## Примечание + +В репозитории хранятся только материалы трека. Пароли, токены и другие секреты в него не добавляются. diff --git a/build_canvas.py b/build_canvas.py new file mode 100644 index 0000000..e4cfcaa --- /dev/null +++ b/build_canvas.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +from docx import Document +from docx.shared import Pt, Cm, RGBColor +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.enum.section import WD_ORIENT +from docx.enum.table import WD_TABLE_ALIGNMENT +from docx.oxml.ns import qn +from docx.oxml import OxmlElement + +OUT = 'Метод_Дегтярева_канвас.docx' + +GREEN = RGBColor(0x2E, 0x7D, 0x5B) +ROSE = RGBColor(0xB0, 0x3A, 0x55) +DARK = RGBColor(0x1A, 0x1A, 0x1A) +GRAY = RGBColor(0x5F, 0x66, 0x6B) +LIGHT = RGBColor(0x8A, 0x90, 0x95) + + +def set_run(run, name='Arial', size=9, bold=False, italic=False, color=DARK): + run.font.name = name + run.font.size = Pt(size) + run.font.bold = bold + run.font.italic = italic + run.font.color.rgb = color + rPr = run._element.get_or_add_rPr() + rFonts = rPr.find(qn('w:rFonts')) + if rFonts is None: + rFonts = OxmlElement('w:rFonts') + rPr.append(rFonts) + for attr in ('w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs'): + rFonts.set(qn(attr), name) + + +def shade(cell, hex_color): + tcPr = cell._tc.get_or_add_tcPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear') + shd.set(qn('w:color'), 'auto') + shd.set(qn('w:fill'), hex_color) + tcPr.append(shd) + + +def cell_margins(table, top=60, bottom=60, left=140, right=140): + tblPr = table._tbl.tblPr + mar = OxmlElement('w:tblCellMar') + for tag, val in (('top', top), ('left', left), ('bottom', bottom), ('right', right)): + el = OxmlElement('w:' + tag) + el.set(qn('w:w'), str(val)) + el.set(qn('w:type'), 'dxa') + mar.append(el) + tblPr.append(mar) + + +def table_borders(table, color='C9D6CF', size=6): + tblPr = table._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), str(size)) + el.set(qn('w:space'), '0') + el.set(qn('w:color'), color) + borders.append(el) + tblPr.append(borders) + + +def dotted_line(paragraph, color='C9D6CF'): + pPr = paragraph._p.get_or_add_pPr() + pBdr = OxmlElement('w:pBdr') + bottom = OxmlElement('w:bottom') + bottom.set(qn('w:val'), 'dotted') + bottom.set(qn('w:sz'), '4') + bottom.set(qn('w:space'), '1') + bottom.set(qn('w:color'), color) + pBdr.append(bottom) + pPr.append(pBdr) + + +def add_line_table(cell, lines=3, width_cm=12.4): + tbl = cell.add_table(rows=lines, cols=1) + tbl.autofit = False + tblPr = tbl._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'none') + borders.append(el) + tblPr.append(borders) + for row in tbl.rows: + row.height = Cm(0.55) + c = row.cells[0] + c.width = Cm(width_cm) + tcPr = c._tc.get_or_add_tcPr() + tcBorders = OxmlElement('w:tcBorders') + bottom = OxmlElement('w:bottom') + bottom.set(qn('w:val'), 'dotted') + bottom.set(qn('w:sz'), '4') + bottom.set(qn('w:space'), '0') + bottom.set(qn('w:color'), 'AFC4B9') + tcBorders.append(bottom) + tcPr.append(tcBorders) + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.line_spacing = 1.0 + + +def add_block(cell, num, title, prompt, color, fill, lines=3): + cell.text = '' + shade(cell, fill) + + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(2) + r = p.add_run(num + ' ') + set_run(r, size=8, bold=True, color=color) + r = p.add_run(title) + set_run(r, name='Georgia', size=12, bold=True, color=color) + + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(6) + p.paragraph_format.line_spacing = 1.0 + r = p.add_run(prompt) + set_run(r, size=8, color=GRAY) + + add_line_table(cell, lines=lines) + + +def build(): + doc = Document() + + section = doc.sections[0] + section.orientation = WD_ORIENT.LANDSCAPE + section.page_width = Cm(29.7) + section.page_height = Cm(21.0) + section.top_margin = Cm(1.1) + section.bottom_margin = Cm(1.0) + section.left_margin = Cm(1.2) + section.right_margin = Cm(1.2) + + normal = doc.styles['Normal'] + normal.font.name = 'Arial' + normal.font.size = Pt(9) + normal.font.color.rgb = DARK + + # Header + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('КАНВАС «МЕТОД ДЕГТЯРЕВА»') + set_run(r, name='Georgia', size=18, bold=True, color=GREEN) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(2) + p.paragraph_format.space_after = Pt(4) + r = p.add_run('Команда: ______________________________ Проблема: ______________________________________ Трек: «Метод Дегтярева»') + set_run(r, size=8.5, color=GRAY) + + # Table + table = doc.add_table(rows=4, cols=2) + table.alignment = WD_TABLE_ALIGNMENT.CENTER + table.autofit = False + table_borders(table) + cell_margins(table) + + for row in table.rows: + row.height = Cm(3.45) + for cell in row.cells: + cell.width = Cm(13.5) + + blocks = [ + ('01', 'ЗАБОЙ', 'Что болит на самом деле? У кого? Доказательства: факты, интервью, данные.', GREEN, 'F3F9F6'), + ('02', 'СМЕТА', 'Кому и насколько станет лучше? Сколько людей? Как измерим? 3 метрики.', GREEN, 'F3F9F6'), + ('03', 'ЗАВОД', 'Что нужно, чтобы решалось системно? Люди, данные, партнёры, деньги.', GREEN, 'F3F9F6'), + ('04', 'РОЗА', 'Как люди это почувствуют? Сценарий использования. Что скажут?', ROSE, 'FDF4F6'), + ('05', 'ХОЗЯИН', 'Кто останется после форума? Модель, команда, первый шаг.', ROSE, 'FDF4F6'), + ('06', 'РИСКИ', 'Что может пойти не так? Как снижаем?', ROSE, 'FDF4F6'), + ('07', 'МЕТРИКИ', '3 цифры, по которым поймём, что получилось.', GREEN, 'F3F9F6'), + ('08', 'ПИТЧ', 'Одна фраза, с которой начнём защиту.', GREEN, 'F3F9F6'), + ] + + for idx, (num, title, prompt, color, fill) in enumerate(blocks): + row = idx // 2 + col = idx % 2 + add_block(table.cell(row, col), num, title, prompt, color, fill, lines=3) + + # Footer + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(4) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('Заполняйте по шагам. Не переходите к следующему блоку, пока не закрыт предыдущий. • Метод Дегтярева • Форум молодёжи Донбасса, 2026') + set_run(r, size=7.5, color=LIGHT) + + doc.save(OUT) + print('saved', OUT) + + +if __name__ == '__main__': + build() diff --git a/build_docx.py b/build_docx.py new file mode 100644 index 0000000..acc07a3 --- /dev/null +++ b/build_docx.py @@ -0,0 +1,351 @@ +# -*- coding: utf-8 -*- +import re +from docx import Document +from docx.shared import Pt, Cm, RGBColor +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.enum.section import WD_ORIENT +from docx.oxml.ns import qn +from docx.oxml import OxmlElement + +SRC = 'Метод_Дегтярева_концепция_трека.md' +OUT = 'Метод_Дегтярева_концепция_трека.docx' + +GREEN = RGBColor(0x2E, 0x7D, 0x5B) +DARK = RGBColor(0x1A, 0x1A, 0x1A) +GRAY = RGBColor(0x5F, 0x66, 0x6B) +LIGHT_GRAY = RGBColor(0x8A, 0x90, 0x95) +ROSE = RGBColor(0xB0, 0x3A, 0x55) + + +def set_run(run, name='Arial', size=10.5, bold=False, italic=False, color=DARK): + run.font.name = name + run.font.size = Pt(size) + run.font.bold = bold + run.font.italic = italic + run.font.color.rgb = color + rPr = run._element.get_or_add_rPr() + rFonts = rPr.find(qn('w:rFonts')) + if rFonts is None: + rFonts = OxmlElement('w:rFonts') + rPr.append(rFonts) + rFonts.set(qn('w:ascii'), name) + rFonts.set(qn('w:hAnsi'), name) + rFonts.set(qn('w:eastAsia'), name) + rFonts.set(qn('w:cs'), name) + + +def shade(cell, hex_color): + tcPr = cell._tc.get_or_add_tcPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear') + shd.set(qn('w:color'), 'auto') + shd.set(qn('w:fill'), hex_color) + tcPr.append(shd) + + +def cell_margins(table, top=45, bottom=45, left=80, right=80): + tblPr = table._tbl.tblPr + mar = OxmlElement('w:tblCellMar') + for tag, val in (('top', top), ('left', left), ('bottom', bottom), ('right', right)): + el = OxmlElement('w:' + tag) + el.set(qn('w:w'), str(val)) + el.set(qn('w:type'), 'dxa') + mar.append(el) + tblPr.append(mar) + + +def table_borders(table, color='D9E2DD', size=4): + tblPr = table._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), str(size)) + el.set(qn('w:space'), '0') + el.set(qn('w:color'), color) + borders.append(el) + tblPr.append(borders) + + +def para_bottom_border(paragraph, color='2E7D5B', size=8): + pPr = paragraph._p.get_or_add_pPr() + pBdr = OxmlElement('w:pBdr') + bottom = OxmlElement('w:bottom') + bottom.set(qn('w:val'), 'single') + bottom.set(qn('w:sz'), str(size)) + bottom.set(qn('w:space'), '4') + bottom.set(qn('w:color'), color) + pBdr.append(bottom) + pPr.append(pBdr) + + +def para_left_border(paragraph, color='B03A55', size=18): + pPr = paragraph._p.get_or_add_pPr() + pBdr = OxmlElement('w:pBdr') + left = OxmlElement('w:left') + left.set(qn('w:val'), 'single') + left.set(qn('w:sz'), str(size)) + left.set(qn('w:space'), '8') + left.set(qn('w:color'), color) + pBdr.append(left) + pPr.append(pBdr) + + +def add_page_number(paragraph): + run = paragraph.add_run() + fld1 = OxmlElement('w:fldChar') + fld1.set(qn('w:fldCharType'), 'begin') + instr = OxmlElement('w:instrText') + instr.set(qn('xml:space'), 'preserve') + instr.text = 'PAGE' + fld2 = OxmlElement('w:fldChar') + fld2.set(qn('w:fldCharType'), 'end') + run._r.append(fld1) + run._r.append(instr) + run._r.append(fld2) + set_run(run, size=8, color=LIGHT_GRAY) + + +def parse_inline(text): + parts = re.split(r'(\*\*.*?\*\*|_.*?_)', text) + out = [] + for p in parts: + if not p: + continue + if p.startswith('**') and p.endswith('**') and len(p) > 4: + out.append((p[2:-2], True, False)) + elif p.startswith('_') and p.endswith('_') and len(p) > 2: + out.append((p[1:-1], False, True)) + else: + out.append((p, False, False)) + return out + + +def add_rich_paragraph(doc, text, style=None, size=10.5, color=DARK, bold=False, + italic=False, align=None, space_before=0, space_after=4, + left_indent=None, first_line_indent=None, line_spacing=1.15): + p = doc.add_paragraph(style=style) if style else doc.add_paragraph() + pf = p.paragraph_format + pf.space_before = Pt(space_before) + pf.space_after = Pt(space_after) + pf.line_spacing = line_spacing + if align is not None: + p.alignment = align + if left_indent is not None: + pf.left_indent = Cm(left_indent) + if first_line_indent is not None: + pf.first_line_indent = Cm(first_line_indent) + for chunk, b, i in parse_inline(text): + r = p.add_run(chunk) + set_run(r, size=size, bold=(bold or b), italic=(italic or i), color=color) + return p + + +def add_heading(doc, text, level): + p = doc.add_paragraph() + pf = p.paragraph_format + pf.keep_with_next = True + if level == 1: + pf.space_before = Pt(14) + pf.space_after = Pt(5) + r = p.add_run(text) + set_run(r, name='Georgia', size=15, bold=True, color=GREEN) + para_bottom_border(p, color='CFE3D9', size=6) + else: + pf.space_before = Pt(10) + pf.space_after = Pt(3) + r = p.add_run(text) + set_run(r, name='Arial', size=11.5, bold=True, color=DARK) + return p + + +def add_table(doc, rows, keep_together=True): + ncols = len(rows[0]) + table = doc.add_table(rows=len(rows), cols=ncols) + table.alignment = 1 + table.autofit = True + table_borders(table) + cell_margins(table) + for ri, row in enumerate(rows): + tr = table.rows[ri]._tr + trPr = tr.get_or_add_trPr() + cantSplit = OxmlElement('w:cantSplit') + trPr.append(cantSplit) + if ri == 0: + tblHeader = OxmlElement('w:tblHeader') + trPr.append(tblHeader) + for ci, cell_text in enumerate(row): + cell = table.cell(ri, ci) + cell.text = '' + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.line_spacing = 1.0 + if keep_together and ri < len(rows) - 1: + p.paragraph_format.keep_with_next = True + for chunk, b, i in parse_inline(cell_text): + r = p.add_run(chunk) + if ri == 0: + set_run(r, size=8.8, bold=True, color=GREEN) + else: + set_run(r, size=8.8, bold=b, italic=i, color=DARK) + if ri == 0: + shade(cell, 'EAF4EF') + elif ri % 2 == 0: + shade(cell, 'F7FAF8') + doc.add_paragraph().paragraph_format.space_after = Pt(2) + return table + + +def build(): + doc = Document() + + # Page setup + section = doc.sections[0] + section.page_width = Cm(21.0) + section.page_height = Cm(29.7) + section.top_margin = Cm(2.0) + section.bottom_margin = Cm(2.0) + section.left_margin = Cm(2.2) + section.right_margin = Cm(2.2) + + # Base styles + normal = doc.styles['Normal'] + normal.font.name = 'Arial' + normal.font.size = Pt(10.5) + normal.font.color.rgb = DARK + normal.paragraph_format.line_spacing = 1.15 + normal.paragraph_format.space_after = Pt(4) + + # Footer + footer_p = section.footer.paragraphs[0] + footer_p.alignment = WD_ALIGN_PARAGRAPH.RIGHT + r = footer_p.add_run('Метод Дегтярева • Форум молодёжи Донбасса • ') + set_run(r, size=8, color=LIGHT_GRAY) + add_page_number(footer_p) + + # Cover block + p = doc.add_paragraph() + p.paragraph_format.space_after = Pt(2) + r = p.add_run('ФОРУМ МОЛОДЁЖИ ДОНБАССА «ФМД: У НАС ТАК ПРИНЯТО»') + set_run(r, size=8.5, bold=True, color=GRAY) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(10) + p.paragraph_format.space_after = Pt(2) + r = p.add_run('ТРЕК «МЕТОД ДЕГТЯРЕВА»') + set_run(r, name='Georgia', size=26, bold=True, color=DARK) + + p = doc.add_paragraph() + p.paragraph_format.space_after = Pt(8) + r = p.add_run('Цифра, у которой есть хозяин') + set_run(r, name='Georgia', size=15, italic=True, color=GREEN) + + p = doc.add_paragraph() + p.paragraph_format.space_after = Pt(1) + r = p.add_run('Смена 1 «ПСБ Патриот» • 10–13 ноября 2026') + set_run(r, size=9.5, color=GRAY) + + p = doc.add_paragraph() + p.paragraph_format.space_after = Pt(10) + r = p.add_run('Эксперт и наставник трека: Бойко К.С.') + set_run(r, size=9.5, color=GRAY) + para_bottom_border(p, color='2E7D5B', size=10) + + # Parse markdown from the first content heading + with open(SRC, 'r', encoding='utf-8') as f: + lines = f.read().splitlines() + + start = 0 + for i, line in enumerate(lines): + if line.strip().startswith('## Короткая версия'): + start = i + break + + i = start + while i < len(lines): + line = lines[i] + stripped = line.strip() + + if not stripped: + i += 1 + continue + + if stripped == '---': + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(2) + p.paragraph_format.space_after = Pt(2) + para_bottom_border(p, color='E3E8E5', size=4) + i += 1 + continue + + if stripped.startswith('### '): + add_heading(doc, stripped[4:].strip(), 2) + i += 1 + continue + + if stripped.startswith('## '): + add_heading(doc, stripped[3:].strip(), 1) + i += 1 + continue + + if stripped.startswith('# '): + add_heading(doc, stripped[2:].strip(), 1) + i += 1 + continue + + # Table + if stripped.startswith('|') and stripped.endswith('|'): + rows = [] + while i < len(lines): + s = lines[i].strip() + if not (s.startswith('|') and s.endswith('|')): + break + cells = [c.strip() for c in s.strip('|').split('|')] + if all(re.fullmatch(r':?-{2,}:?', c) for c in cells): + i += 1 + continue + rows.append(cells) + i += 1 + if rows: + add_table(doc, rows, keep_together=(len(rows) <= 7)) + continue + + # Blockquote + if stripped.startswith('> '): + text = stripped[2:].strip() + p = add_rich_paragraph(doc, text, size=10.5, italic=True, color=GRAY, + left_indent=0.8, space_before=2, space_after=6) + para_left_border(p, color='B03A55', size=14) + i += 1 + continue + + # Bullet + if stripped.startswith('- '): + text = stripped[2:].strip() + p = add_rich_paragraph(doc, '• ' + text, size=10.5, + left_indent=0.55, first_line_indent=-0.55, + space_after=2) + i += 1 + continue + + # Numbered list + m = re.match(r'^(\d+)\.\s+(.*)$', stripped) + if m: + num, text = m.group(1), m.group(2) + p = add_rich_paragraph(doc, f'{num}. ' + text, size=10.5, + left_indent=0.6, first_line_indent=-0.6, + space_after=2) + i += 1 + continue + + # Regular paragraph + add_rich_paragraph(doc, stripped, size=10.5, space_after=4) + i += 1 + + doc.save(OUT) + print('saved', OUT) + + +if __name__ == '__main__': + build() diff --git a/build_estimate_card.py b/build_estimate_card.py new file mode 100644 index 0000000..23d626b --- /dev/null +++ b/build_estimate_card.py @@ -0,0 +1,363 @@ +# -*- coding: utf-8 -*- +from docx import Document +from docx.shared import Pt, Cm, RGBColor +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.enum.table import WD_TABLE_ALIGNMENT +from docx.oxml.ns import qn +from docx.oxml import OxmlElement + +OUT = 'Метод_Дегтярева_смета.docx' + +GREEN = RGBColor(0x2E, 0x7D, 0x5B) +ROSE = RGBColor(0xB0, 0x3A, 0x55) +DARK = RGBColor(0x1A, 0x1A, 0x1A) +GRAY = RGBColor(0x5F, 0x66, 0x6B) +LIGHT = RGBColor(0x8A, 0x90, 0x95) + + +def set_run(run, name='Arial', size=9, bold=False, italic=False, color=DARK): + run.font.name = name + run.font.size = Pt(size) + run.font.bold = bold + run.font.italic = italic + run.font.color.rgb = color + rPr = run._element.get_or_add_rPr() + rFonts = rPr.find(qn('w:rFonts')) + if rFonts is None: + rFonts = OxmlElement('w:rFonts') + rPr.append(rFonts) + for attr in ('w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs'): + rFonts.set(qn(attr), name) + + +def shade(cell, hex_color): + tcPr = cell._tc.get_or_add_tcPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear') + shd.set(qn('w:color'), 'auto') + shd.set(qn('w:fill'), hex_color) + tcPr.append(shd) + + +def cell_margins(table, top=60, bottom=60, left=100, right=100): + tblPr = table._tbl.tblPr + mar = OxmlElement('w:tblCellMar') + for tag, val in (('top', top), ('left', left), ('bottom', bottom), ('right', right)): + el = OxmlElement('w:' + tag) + el.set(qn('w:w'), str(val)) + el.set(qn('w:type'), 'dxa') + mar.append(el) + tblPr.append(mar) + + +def table_borders(table, color='C9D6CF', size=6): + tblPr = table._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), str(size)) + el.set(qn('w:space'), '0') + el.set(qn('w:color'), color) + borders.append(el) + tblPr.append(borders) + + +def add_line_table(cell, lines=2, width_cm=8.0, height_cm=0.5): + tbl = cell.add_table(rows=lines, cols=1) + tbl.autofit = False + tblPr = tbl._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'none') + borders.append(el) + tblPr.append(borders) + for row in tbl.rows: + row.height = Cm(height_cm) + c = row.cells[0] + c.width = Cm(width_cm) + tcPr = c._tc.get_or_add_tcPr() + tcBorders = OxmlElement('w:tcBorders') + bottom = OxmlElement('w:bottom') + bottom.set(qn('w:val'), 'dotted') + bottom.set(qn('w:sz'), '4') + bottom.set(qn('w:space'), '0') + bottom.set(qn('w:color'), 'AFC4B9') + tcBorders.append(bottom) + tcPr.append(tcBorders) + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.line_spacing = 1.0 + + +def add_block(cell, num, title, prompt, color=GREEN, fill='F3F9F6', lines=2, width_cm=8.0): + cell.text = '' + shade(cell, fill) + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run(num + ' ') + set_run(r, size=7.5, bold=True, color=color) + r = p.add_run(title) + set_run(r, size=9.5, bold=True, color=color) + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + p.paragraph_format.line_spacing = 1.0 + r = p.add_run(prompt) + set_run(r, size=7.5, color=GRAY) + add_line_table(cell, lines=lines, width_cm=width_cm, height_cm=0.5) + + +def nested_grid(cell, rows, cols, widths, header_fill='EAF4EF'): + tbl = cell.add_table(rows=rows, cols=cols) + tbl.autofit = False + tblPr = tbl._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), '4') + el.set(qn('w:space'), '0') + el.set(qn('w:color'), 'D9E2DD') + borders.append(el) + tblPr.append(borders) + for row in tbl.rows: + for i, c in enumerate(row.cells): + c.width = Cm(widths[i]) + return tbl + + +def build(): + doc = Document() + section = doc.sections[0] + section.page_width = Cm(21.0) + section.page_height = Cm(29.7) + section.top_margin = Cm(1.3) + section.bottom_margin = Cm(1.1) + section.left_margin = Cm(1.4) + section.right_margin = Cm(1.4) + + normal = doc.styles['Normal'] + normal.font.name = 'Arial' + normal.font.size = Pt(9) + normal.font.color.rgb = DARK + + # Header + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('СМЕТА') + set_run(r, name='Georgia', size=20, bold=True, color=GREEN) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(1) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('Шаг 2. «Смета» • Метод Дегтярева') + set_run(r, size=9, bold=True, color=GRAY) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('Смета — не бухгалтерия. Считаем эффект в людях и ресурсах.') + set_run(r, size=8, italic=True, color=ROSE) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(5) + r = p.add_run('Команда: ______________________________ Проблема: ______________________________________') + set_run(r, size=8.5, color=GRAY) + + # Main table + table = doc.add_table(rows=7, cols=2) + table.alignment = WD_TABLE_ALIGNMENT.CENTER + table.autofit = False + table_borders(table) + cell_margins(table) + + heights = [3.2, 3.2, 4.8, 2.6, 2.6, 2.4, 2.8] + for i, row in enumerate(table.rows): + row.height = Cm(heights[i]) + for cell in row.cells: + cell.width = Cm(9.0) + + # 01 User (merged) + c = table.cell(0, 0).merge(table.cell(0, 1)) + add_block(c, '01', 'ПОЛЬЗОВАТЕЛЬ', + 'Кто конкретно? Где и в каком контексте? Что для него важно? Что он делает сейчас?', + lines=3, width_cm=17.2) + + # 02 Before / 03 After + add_block(table.cell(1, 0), '02', 'БЫЛО', + 'Что человек делает сейчас? Сколько тратит времени, денег, сил?', + color=GRAY, fill='F7F8F8', lines=2, width_cm=8.2) + add_block(table.cell(1, 1), '03', 'СТАЛО', + 'Что изменится? Быстрее, дешевле, проще, доступнее?', + color=GREEN, fill='F3F9F6', lines=2, width_cm=8.2) + + # 04 Metrics (merged) + c = table.cell(2, 0).merge(table.cell(2, 1)) + c.text = '' + shade(c, 'F3F9F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('04 ') + set_run(r, size=7.5, bold=True, color=GREEN) + r = p.add_run('ТРИ МЕТРИКИ ЭФФЕКТА') + set_run(r, size=9.5, bold=True, color=GREEN) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + r = p.add_run('Охват • Скорость / доступность • Качество / удовлетворённость') + set_run(r, size=7.5, color=GRAY) + + metrics = nested_grid(c, 4, 3, [4.6, 6.4, 6.2]) + metrics.rows[0].height = Cm(0.5) + for ri in range(1, 4): + metrics.rows[ri].height = Cm(0.95) + headers = ['МЕТРИКА', 'КАК СЧИТАЕМ', 'СЕЙЧАС → ЦЕЛЬ'] + for i, h in enumerate(headers): + cell = metrics.cell(0, i) + cell.text = '' + shade(cell, 'EAF4EF') + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(h) + set_run(r, size=7, bold=True, color=GREEN) + labels = ['1. Охват', '2. Скорость', '3. Качество'] + for ri in range(1, 4): + cell = metrics.cell(ri, 0) + cell.text = '' + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(labels[ri - 1]) + set_run(r, size=7.5, bold=True, color=DARK) + for ci in (1, 2): + cell = metrics.cell(ri, ci) + cell.text = '' + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(' ') + set_run(r, size=7, color=RGBColor(0xFF, 0xFF, 0xFF)) + + # 05 Scale (merged) + c = table.cell(3, 0).merge(table.cell(3, 1)) + c.text = '' + shade(c, 'FDF4F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('05 ') + set_run(r, size=7.5, bold=True, color=ROSE) + r = p.add_run('МАСШТАБ') + set_run(r, size=9.5, bold=True, color=ROSE) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + r = p.add_run('Сколько людей сталкивается, до кого дотянемся, кого охватим за первый год?') + set_run(r, size=7.5, color=GRAY) + + scale = nested_grid(c, 2, 3, [5.7, 5.7, 5.7]) + scale.rows[0].height = Cm(0.45) + scale.rows[1].height = Cm(0.85) + scale_headers = ['TAM — все, кто сталкивается', 'SAM — до кого дотянемся', 'SOM — охватим за год'] + for i, h in enumerate(scale_headers): + cell = scale.cell(0, i) + cell.text = '' + shade(cell, 'FDF4F6') + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(h) + set_run(r, size=7, bold=True, color=ROSE) + for i in range(3): + cell = scale.cell(1, i) + cell.text = '' + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(' ') + set_run(r, size=7, color=RGBColor(0xFF, 0xFF, 0xFF)) + + # 06 Price (merged) + c = table.cell(4, 0).merge(table.cell(4, 1)) + c.text = '' + shade(c, 'F3F9F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('06 ') + set_run(r, size=7.5, bold=True, color=GREEN) + r = p.add_run('ЦЕНА ЭФФЕКТА') + set_run(r, size=9.5, bold=True, color=GREEN) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + r = p.add_run('Что нужно, чтобы эффект случился? Не отчёт, а ресурсы.') + set_run(r, size=7.5, color=GRAY) + + price = nested_grid(c, 2, 5, [3.4, 3.4, 3.4, 3.4, 3.4]) + price.rows[0].height = Cm(0.45) + price.rows[1].height = Cm(0.85) + price_headers = ['ЛЮДИ', 'ВРЕМЯ', 'ДЕНЬГИ', 'ДАННЫЕ', 'ПАРТНЁРЫ'] + for i, h in enumerate(price_headers): + cell = price.cell(0, i) + cell.text = '' + shade(cell, 'EAF4EF') + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(h) + set_run(r, size=7, bold=True, color=GREEN) + for i in range(5): + cell = price.cell(1, i) + cell.text = '' + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(' ') + set_run(r, size=7, color=RGBColor(0xFF, 0xFF, 0xFF)) + + # 07 Check (merged) + c = table.cell(5, 0).merge(table.cell(5, 1)) + add_block(c, '07', 'ПРОВЕРКА', + 'Самый дешёвый способ проверить эффект до разработки: интервью, лендинг, ручной прототип, пилот на 10 пользователях.', + color=ROSE, fill='FDF4F6', lines=2, width_cm=17.2) + + # 08 Formulation (merged) + c = table.cell(6, 0).merge(table.cell(6, 1)) + c.text = '' + shade(c, 'F3F9F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('08 ') + set_run(r, size=7.5, bold=True, color=GREEN) + r = p.add_run('ФОРМУЛИРОВКА ЭФФЕКТА') + set_run(r, size=9.5, bold=True, color=GREEN) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(2) + r = p.add_run('«___________ получит ___________, потому что ___________. Мы измерим это по ___________.»') + set_run(r, size=8, italic=True, color=GRAY) + add_line_table(c, lines=2, width_cm=17.2, height_cm=0.5) + + # Footer + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(5) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('Считайте в людях, а не в лайках. • Метод Дегтярева • Форум молодёжи Донбасса, 2026') + set_run(r, size=7.5, color=LIGHT) + + doc.save(OUT) + print('saved', OUT) + + +if __name__ == '__main__': + build() diff --git a/build_interview_cards.py b/build_interview_cards.py new file mode 100644 index 0000000..ec3153d --- /dev/null +++ b/build_interview_cards.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- +from docx import Document +from docx.shared import Pt, Cm, RGBColor +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.enum.table import WD_TABLE_ALIGNMENT +from docx.oxml.ns import qn +from docx.oxml import OxmlElement + +OUT = 'Метод_Дегтярева_гайд_интервью.docx' + +GREEN = RGBColor(0x2E, 0x7D, 0x5B) +ROSE = RGBColor(0xB0, 0x3A, 0x55) +DARK = RGBColor(0x1A, 0x1A, 0x1A) +GRAY = RGBColor(0x5F, 0x66, 0x6B) +LIGHT = RGBColor(0x8A, 0x90, 0x95) + + +def set_run(run, name='Arial', size=9, bold=False, italic=False, color=DARK): + run.font.name = name + run.font.size = Pt(size) + run.font.bold = bold + run.font.italic = italic + run.font.color.rgb = color + rPr = run._element.get_or_add_rPr() + rFonts = rPr.find(qn('w:rFonts')) + if rFonts is None: + rFonts = OxmlElement('w:rFonts') + rPr.append(rFonts) + for attr in ('w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs'): + rFonts.set(qn(attr), name) + + +def cell_margins(table, top=80, bottom=80, left=180, right=180): + tblPr = table._tbl.tblPr + mar = OxmlElement('w:tblCellMar') + for tag, val in (('top', top), ('left', left), ('bottom', bottom), ('right', right)): + el = OxmlElement('w:' + tag) + el.set(qn('w:w'), str(val)) + el.set(qn('w:type'), 'dxa') + mar.append(el) + tblPr.append(mar) + + +def add_line_table(cell, lines=4, width_cm=17.5, height_cm=0.6): + tbl = cell.add_table(rows=lines, cols=1) + tbl.autofit = False + tblPr = tbl._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'none') + borders.append(el) + tblPr.append(borders) + for row in tbl.rows: + row.height = Cm(height_cm) + c = row.cells[0] + c.width = Cm(width_cm) + tcPr = c._tc.get_or_add_tcPr() + tcBorders = OxmlElement('w:tcBorders') + bottom = OxmlElement('w:bottom') + bottom.set(qn('w:val'), 'dotted') + bottom.set(qn('w:sz'), '4') + bottom.set(qn('w:space'), '0') + bottom.set(qn('w:color'), 'AFC4B9') + tcBorders.append(bottom) + tcPr.append(tcBorders) + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.line_spacing = 1.0 + + +def card_border(cell): + tcPr = cell._tc.get_or_add_tcPr() + tcBorders = OxmlElement('w:tcBorders') + for edge in ('top', 'left', 'bottom', 'right'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), '14' if edge == 'top' else '4') + el.set(qn('w:space'), '0') + el.set(qn('w:color'), '2E7D5B' if edge == 'top' else 'C9D6CF') + tcBorders.append(el) + tcPr.append(tcBorders) + + +def add_card(cell): + cell.text = '' + card_border(cell) + + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('ГАЙД ИНТЕРВЬЮ') + set_run(r, name='Georgia', size=15, bold=True, color=GREEN) + + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(1) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('Шаг 1. «Забой» • Метод Дегтярева') + set_run(r, size=8, bold=True, color=GRAY) + + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(4) + r = p.add_run('Команда: ______________________________') + set_run(r, size=8, color=GRAY) + + questions = [ + 'Расскажите, как вы в последний раз решали эту задачу?', + 'Что в этом процессе было самым неприятным? Почему?', + 'Что вы сделали, чтобы это обойти?', + 'Сколько времени, денег или сил это у вас забрало?', + 'Кто ещё с этим сталкивается?', + 'Что происходит, если проблему не решить?', + 'Если бы это исчезло, что бы изменилось?', + ] + for i, q in enumerate(questions, 1): + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + p.paragraph_format.left_indent = Cm(0.5) + p.paragraph_format.first_line_indent = Cm(-0.5) + p.paragraph_format.line_spacing = 1.0 + r = p.add_run(f'{i}. ') + set_run(r, size=9, bold=True, color=GREEN) + r = p.add_run(q) + set_run(r, size=9, color=DARK) + + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(4) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('ПРАВИЛА') + set_run(r, size=8, bold=True, color=ROSE) + + rules = [ + 'Спрашивайте о прошлом, а не о будущем.', + 'Не презентуйте свою идею — слушайте.', + 'Записывайте точные цитаты.', + 'Ищите повторяемость, а не яркие истории.', + 'Минимум 5 интервью, лучше 10.', + ] + for rule in rules: + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.left_indent = Cm(0.45) + p.paragraph_format.first_line_indent = Cm(-0.45) + p.paragraph_format.line_spacing = 1.0 + r = p.add_run('• ') + set_run(r, size=8, color=ROSE) + r = p.add_run(rule) + set_run(r, size=8, color=GRAY) + + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(4) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('ЗАМЕТКИ') + set_run(r, size=8, bold=True, color=GREEN) + add_line_table(cell, lines=4, width_cm=17.5, height_cm=0.6) + + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(2) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('5 интервью — минимум. Спрашивайте о прошлом, не о будущем.') + set_run(r, size=7, italic=True, color=LIGHT) + + +def build(): + doc = Document() + section = doc.sections[0] + section.page_width = Cm(21.0) + section.page_height = Cm(29.7) + section.top_margin = Cm(1.0) + section.bottom_margin = Cm(1.0) + section.left_margin = Cm(1.0) + section.right_margin = Cm(1.0) + + normal = doc.styles['Normal'] + normal.font.name = 'Arial' + normal.font.size = Pt(9) + normal.font.color.rgb = DARK + + for page in range(4): + table = doc.add_table(rows=2, cols=1) + table.alignment = WD_TABLE_ALIGNMENT.CENTER + table.autofit = False + cell_margins(table) + for row in table.rows: + row.height = Cm(13.2) + row.cells[0].width = Cm(19.0) + add_card(row.cells[0]) + if page < 3: + doc.add_page_break() + + doc.save(OUT) + print('saved', OUT) + + +if __name__ == '__main__': + build() diff --git a/build_owner_card.py b/build_owner_card.py new file mode 100644 index 0000000..7a236f1 --- /dev/null +++ b/build_owner_card.py @@ -0,0 +1,375 @@ +# -*- coding: utf-8 -*- +from docx import Document +from docx.shared import Pt, Cm, RGBColor +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.enum.table import WD_TABLE_ALIGNMENT +from docx.oxml.ns import qn +from docx.oxml import OxmlElement + +OUT = 'Метод_Дегтярева_хозяин.docx' + +GREEN = RGBColor(0x2E, 0x7D, 0x5B) +ROSE = RGBColor(0xB0, 0x3A, 0x55) +DARK = RGBColor(0x1A, 0x1A, 0x1A) +GRAY = RGBColor(0x5F, 0x66, 0x6B) +LIGHT = RGBColor(0x8A, 0x90, 0x95) + + +def set_run(run, name='Arial', size=9, bold=False, italic=False, color=DARK): + run.font.name = name + run.font.size = Pt(size) + run.font.bold = bold + run.font.italic = italic + run.font.color.rgb = color + rPr = run._element.get_or_add_rPr() + rFonts = rPr.find(qn('w:rFonts')) + if rFonts is None: + rFonts = OxmlElement('w:rFonts') + rPr.append(rFonts) + for attr in ('w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs'): + rFonts.set(qn(attr), name) + + +def shade(cell, hex_color): + tcPr = cell._tc.get_or_add_tcPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear') + shd.set(qn('w:color'), 'auto') + shd.set(qn('w:fill'), hex_color) + tcPr.append(shd) + + +def cell_margins(table, top=60, bottom=60, left=100, right=100): + tblPr = table._tbl.tblPr + mar = OxmlElement('w:tblCellMar') + for tag, val in (('top', top), ('left', left), ('bottom', bottom), ('right', right)): + el = OxmlElement('w:' + tag) + el.set(qn('w:w'), str(val)) + el.set(qn('w:type'), 'dxa') + mar.append(el) + tblPr.append(mar) + + +def table_borders(table, color='C9D6CF', size=6): + tblPr = table._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), str(size)) + el.set(qn('w:space'), '0') + el.set(qn('w:color'), color) + borders.append(el) + tblPr.append(borders) + + +def add_line_table(cell, lines=2, width_cm=8.0, height_cm=0.5): + tbl = cell.add_table(rows=lines, cols=1) + tbl.autofit = False + tblPr = tbl._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'none') + borders.append(el) + tblPr.append(borders) + for row in tbl.rows: + row.height = Cm(height_cm) + c = row.cells[0] + c.width = Cm(width_cm) + tcPr = c._tc.get_or_add_tcPr() + tcBorders = OxmlElement('w:tcBorders') + bottom = OxmlElement('w:bottom') + bottom.set(qn('w:val'), 'dotted') + bottom.set(qn('w:sz'), '4') + bottom.set(qn('w:space'), '0') + bottom.set(qn('w:color'), 'AFC4B9') + tcBorders.append(bottom) + tcPr.append(tcBorders) + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.line_spacing = 1.0 + + +def add_block(cell, num, title, prompt, color=GREEN, fill='F3F9F6', lines=2, width_cm=8.0): + cell.text = '' + shade(cell, fill) + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run(num + ' ') + set_run(r, size=7.5, bold=True, color=color) + r = p.add_run(title) + set_run(r, size=9.5, bold=True, color=color) + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + p.paragraph_format.line_spacing = 1.0 + r = p.add_run(prompt) + set_run(r, size=7.5, color=GRAY) + add_line_table(cell, lines=lines, width_cm=width_cm, height_cm=0.5) + + +def nested_grid(cell, rows, cols, widths, header_fill='EAF4EF'): + tbl = cell.add_table(rows=rows, cols=cols) + tbl.autofit = False + tblPr = tbl._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), '4') + el.set(qn('w:space'), '0') + el.set(qn('w:color'), 'D9E2DD') + borders.append(el) + tblPr.append(borders) + for row in tbl.rows: + for i, c in enumerate(row.cells): + c.width = Cm(widths[i]) + return tbl + + +def build(): + doc = Document() + section = doc.sections[0] + section.page_width = Cm(21.0) + section.page_height = Cm(29.7) + section.top_margin = Cm(1.3) + section.bottom_margin = Cm(1.1) + section.left_margin = Cm(1.4) + section.right_margin = Cm(1.4) + + normal = doc.styles['Normal'] + normal.font.name = 'Arial' + normal.font.size = Pt(9) + normal.font.color.rgb = DARK + + # Header + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('ХОЗЯИН') + set_run(r, name='Georgia', size=20, bold=True, color=GREEN) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(1) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('Шаг 5. «Хозяин» • Метод Дегтярева') + set_run(r, size=9, bold=True, color=GRAY) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('Проект не заканчивается защитой. Кто останется после форума?') + set_run(r, size=8, italic=True, color=ROSE) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(5) + r = p.add_run('Команда: ______________________________ Проект: ______________________________________') + set_run(r, size=8.5, color=GRAY) + + # Main table + table = doc.add_table(rows=6, cols=2) + table.alignment = WD_TABLE_ALIGNMENT.CENTER + table.autofit = False + table_borders(table) + cell_margins(table) + + heights = [3.2, 2.6, 3.0, 3.6, 3.2, 2.6] + for i, row in enumerate(table.rows): + row.height = Cm(heights[i]) + for cell in row.cells: + cell.width = Cm(9.0) + + # 01 Team (merged) + c = table.cell(0, 0).merge(table.cell(0, 1)) + c.text = '' + shade(c, 'F3F9F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('01 ') + set_run(r, size=7.5, bold=True, color=GREEN) + r = p.add_run('КОМАНДА ПОСЛЕ ФОРУМА') + set_run(r, size=9.5, bold=True, color=GREEN) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + r = p.add_run('Кто остаётся? За что отвечает? Почему не уйдёт?') + set_run(r, size=7.5, color=GRAY) + + team = nested_grid(c, 2, 4, [4.3, 4.3, 4.3, 4.3]) + team.rows[0].height = Cm(0.45) + team.rows[1].height = Cm(1.55) + team_headers = ['ПРОДУКТ', 'ТЕХНОЛОГИЯ', 'ПАРТНЁРЫ', 'ДЕНЬГИ'] + for i, h in enumerate(team_headers): + cell = team.cell(0, i) + cell.text = '' + shade(cell, 'EAF4EF') + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(h) + set_run(r, size=7, bold=True, color=GREEN) + cell2 = team.cell(1, i) + cell2.text = '' + p = cell2.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('Кто?') + set_run(r, size=6.5, color=GRAY) + + # 02 Sustainability model (merged) + c = table.cell(1, 0).merge(table.cell(1, 1)) + c.text = '' + shade(c, 'FDF4F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('02 ') + set_run(r, size=7.5, bold=True, color=ROSE) + r = p.add_run('МОДЕЛЬ УСТОЙЧИВОСТИ') + set_run(r, size=9.5, bold=True, color=ROSE) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(2) + r = p.add_run('Как проект живёт без форума? Выберите 1–2 модели.') + set_run(r, size=7.5, color=GRAY) + + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(2) + r = p.add_run('□ Грант □ Партнёр □ Бюджет региона □ Подписка □ Вуз □ Волонтёры □ Другое: ____________') + set_run(r, size=8, color=DARK) + + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('Почему это сработает: ____________________________________________________________') + set_run(r, size=7.5, color=GRAY) + + # 03 Partners (two columns) + add_block(table.cell(2, 0), '03', 'ПАРТНЁРЫ: КТО НУЖЕН', + 'Вуз, IT-компания, НКО, министерство, бизнес, школа.', + lines=3, width_cm=8.2) + add_block(table.cell(2, 1), '04', 'ЧТО МЫ ДАЁМ', + 'Данные, пилот, охват, репутация, кадры. Партнёр должен получить выгоду.', + color=ROSE, fill='FDF4F6', lines=3, width_cm=8.2) + + # 05 Roadmap (merged) + c = table.cell(3, 0).merge(table.cell(3, 1)) + c.text = '' + shade(c, 'F3F9F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('05 ') + set_run(r, size=7.5, bold=True, color=GREEN) + r = p.add_run('ДОРОЖНАЯ КАРТА 30/90') + set_run(r, size=9.5, bold=True, color=GREEN) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + r = p.add_run('Что делаем в первые 30 и 90 дней после форума?') + set_run(r, size=7.5, color=GRAY) + + road = nested_grid(c, 2, 2, [8.6, 8.6]) + road.rows[0].height = Cm(0.45) + road.rows[1].height = Cm(1.75) + road_headers = ['30 ДНЕЙ: пилот, 10 пользователей, первая метрика', '90 ДНЕЙ: масштаб, партнёр, заявка на грант'] + for i, h in enumerate(road_headers): + cell = road.cell(0, i) + cell.text = '' + shade(cell, 'EAF4EF') + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(h) + set_run(r, size=7, bold=True, color=GREEN) + cell2 = road.cell(1, i) + cell2.text = '' + p = cell2.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(' ') + set_run(r, size=7, color=RGBColor(0xFF, 0xFF, 0xFF)) + + # 06 Risks (merged) + c = table.cell(4, 0).merge(table.cell(4, 1)) + c.text = '' + shade(c, 'FDF4F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('06 ') + set_run(r, size=7.5, bold=True, color=ROSE) + r = p.add_run('РИСКИ') + set_run(r, size=9.5, bold=True, color=ROSE) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + r = p.add_run('Что может убить проект? Как снижаем? Кто отвечает?') + set_run(r, size=7.5, color=GRAY) + + risks = nested_grid(c, 3, 3, [6.0, 6.6, 4.6]) + risks.rows[0].height = Cm(0.45) + risks.rows[1].height = Cm(0.75) + risks.rows[2].height = Cm(0.75) + risk_headers = ['РИСК', 'КАК СНИЖАЕМ', 'КТО ОТВЕЧАЕТ'] + for i, h in enumerate(risk_headers): + cell = risks.cell(0, i) + cell.text = '' + shade(cell, 'FDF4F6') + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(h) + set_run(r, size=7, bold=True, color=ROSE) + for ri in (1, 2): + for ci in range(3): + cell = risks.cell(ri, ci) + cell.text = '' + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(' ') + set_run(r, size=7, color=RGBColor(0xFF, 0xFF, 0xFF)) + + # 07 Survival metric + first step (merged) + c = table.cell(5, 0).merge(table.cell(5, 1)) + c.text = '' + shade(c, 'F3F9F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('07 ') + set_run(r, size=7.5, bold=True, color=GREEN) + r = p.add_run('МЕТРИКА ВЫЖИВАНИЯ И ПЕРВЫЙ ШАГ') + set_run(r, size=9.5, bold=True, color=GREEN) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(2) + r = p.add_run('«Если через 90 дней ___________ не достигнет ___________, мы меняем модель».') + set_run(r, size=8, italic=True, color=GRAY) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(2) + r = p.add_run('Первый шаг на следующей неделе: ______________________. Ответственный: ____________. Дата: ________.') + set_run(r, size=7.5, color=GRAY) + add_line_table(c, lines=1, width_cm=17.2, height_cm=0.5) + + # Footer + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(5) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('Останьтесь хозяином после запуска. • Метод Дегтярева • Форум молодёжи Донбасса, 2026') + set_run(r, size=7.5, color=LIGHT) + + doc.save(OUT) + print('saved', OUT) + + +if __name__ == '__main__': + build() diff --git a/build_pptx.py b/build_pptx.py new file mode 100644 index 0000000..da33a3b --- /dev/null +++ b/build_pptx.py @@ -0,0 +1,484 @@ +# -*- 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() diff --git a/build_problem_card.py b/build_problem_card.py new file mode 100644 index 0000000..f2d2477 --- /dev/null +++ b/build_problem_card.py @@ -0,0 +1,254 @@ +# -*- coding: utf-8 -*- +from docx import Document +from docx.shared import Pt, Cm, RGBColor +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.enum.table import WD_TABLE_ALIGNMENT +from docx.oxml.ns import qn +from docx.oxml import OxmlElement + +OUT = 'Метод_Дегтярева_карта_проблемы.docx' + +GREEN = RGBColor(0x2E, 0x7D, 0x5B) +ROSE = RGBColor(0xB0, 0x3A, 0x55) +DARK = RGBColor(0x1A, 0x1A, 0x1A) +GRAY = RGBColor(0x5F, 0x66, 0x6B) +LIGHT = RGBColor(0x8A, 0x90, 0x95) + + +def set_run(run, name='Arial', size=9, bold=False, italic=False, color=DARK): + run.font.name = name + run.font.size = Pt(size) + run.font.bold = bold + run.font.italic = italic + run.font.color.rgb = color + rPr = run._element.get_or_add_rPr() + rFonts = rPr.find(qn('w:rFonts')) + if rFonts is None: + rFonts = OxmlElement('w:rFonts') + rPr.append(rFonts) + for attr in ('w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs'): + rFonts.set(qn(attr), name) + + +def shade(cell, hex_color): + tcPr = cell._tc.get_or_add_tcPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear') + shd.set(qn('w:color'), 'auto') + shd.set(qn('w:fill'), hex_color) + tcPr.append(shd) + + +def cell_margins(table, top=70, bottom=70, left=110, right=110): + tblPr = table._tbl.tblPr + mar = OxmlElement('w:tblCellMar') + for tag, val in (('top', top), ('left', left), ('bottom', bottom), ('right', right)): + el = OxmlElement('w:' + tag) + el.set(qn('w:w'), str(val)) + el.set(qn('w:type'), 'dxa') + mar.append(el) + tblPr.append(mar) + + +def table_borders(table, color='C9D6CF', size=6): + tblPr = table._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), str(size)) + el.set(qn('w:space'), '0') + el.set(qn('w:color'), color) + borders.append(el) + tblPr.append(borders) + + +def add_line_table(cell, lines=2, width_cm=8.0, height_cm=0.5): + tbl = cell.add_table(rows=lines, cols=1) + tbl.autofit = False + tblPr = tbl._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'none') + borders.append(el) + tblPr.append(borders) + for row in tbl.rows: + row.height = Cm(height_cm) + c = row.cells[0] + c.width = Cm(width_cm) + tcPr = c._tc.get_or_add_tcPr() + tcBorders = OxmlElement('w:tcBorders') + bottom = OxmlElement('w:bottom') + bottom.set(qn('w:val'), 'dotted') + bottom.set(qn('w:sz'), '4') + bottom.set(qn('w:space'), '0') + bottom.set(qn('w:color'), 'AFC4B9') + tcBorders.append(bottom) + tcPr.append(tcBorders) + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.line_spacing = 1.0 + + +def add_block(cell, num, title, prompt, color=GREEN, fill='F3F9F6', lines=2, width_cm=8.0): + cell.text = '' + shade(cell, fill) + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run(num + ' ') + set_run(r, size=7.5, bold=True, color=color) + r = p.add_run(title) + set_run(r, size=9.5, bold=True, color=color) + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + p.paragraph_format.line_spacing = 1.0 + r = p.add_run(prompt) + set_run(r, size=7.5, color=GRAY) + add_line_table(cell, lines=lines, width_cm=width_cm, height_cm=0.5) + + +def build(): + doc = Document() + section = doc.sections[0] + section.page_width = Cm(21.0) + section.page_height = Cm(29.7) + section.top_margin = Cm(1.3) + section.bottom_margin = Cm(1.1) + section.left_margin = Cm(1.4) + section.right_margin = Cm(1.4) + + normal = doc.styles['Normal'] + normal.font.name = 'Arial' + normal.font.size = Pt(9) + normal.font.color.rgb = DARK + + # Header + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('КАРТА ПРОБЛЕМЫ') + set_run(r, name='Georgia', size=20, bold=True, color=GREEN) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(1) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('Шаг 1. «Забой» • Метод Дегтярева') + set_run(r, size=9, bold=True, color=GRAY) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(5) + r = p.add_run('Команда: ______________________________ Проблемное поле: ______________________________________') + set_run(r, size=8.5, color=GRAY) + + # Main table + table = doc.add_table(rows=7, cols=2) + table.alignment = WD_TABLE_ALIGNMENT.CENTER + table.autofit = False + table_borders(table) + cell_margins(table) + + heights = [3.0, 3.0, 3.0, 1.8, 3.8, 3.2, 2.8] + for i, row in enumerate(table.rows): + row.height = Cm(heights[i]) + for cell in row.cells: + cell.width = Cm(9.0) + + # Rows 0-2: two columns + blocks = [ + ('01', 'КТО?', 'Конкретная группа. Не «люди», а кто именно.', 0, 0), + ('02', 'КОГДА И ГДЕ?', 'Контекст: в какой момент и в каком месте возникает проблема.', 0, 1), + ('03', 'ЧТО ПЫТАЕТСЯ СДЕЛАТЬ?', 'Действие человека: какую задачу он решает.', 1, 0), + ('04', 'ЧТО МЕШАЕТ?', 'Барьер: что конкретно не даёт это сделать.', 1, 1), + ('05', 'ЧТО ТЕРЯЕТ?', 'Последствие: время, деньги, здоровье, нервы.', 2, 0), + ('06', 'КАК РЕШАЕТ СЕЙЧАС?', 'Обходной путь — главный признак реальной боли.', 2, 1), + ] + for num, title, prompt, row, col in blocks: + add_block(table.cell(row, col), num, title, prompt, lines=2, width_cm=8.2) + + # Row 3: scale (merged) + c = table.cell(3, 0).merge(table.cell(3, 1)) + add_block(c, '07', 'МАСШТАБ', 'Сколько таких людей? Как часто возникает проблема?', lines=1, width_cm=17.2) + + # Row 4: evidence (merged) + c = table.cell(4, 0).merge(table.cell(4, 1)) + add_block(c, '08', 'ДОКАЗАТЕЛЬСТВА', '5 цитат • 2–3 цифры • 1 наблюдение. Записывайте точные слова людей.', lines=4, width_cm=17.2) + + # Row 5: 5 why (merged) + c = table.cell(5, 0).merge(table.cell(5, 1)) + c.text = '' + shade(c, 'FDF4F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('09 ') + set_run(r, size=7.5, bold=True, color=ROSE) + r = p.add_run('5 ПОЧЕМУ') + set_run(r, size=9.5, bold=True, color=ROSE) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + r = p.add_run('Цепочка до причины, а не симптома.') + set_run(r, size=7.5, color=GRAY) + + why = c.add_table(rows=1, cols=5) + why.autofit = False + tblPr = why._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), '4') + el.set(qn('w:space'), '0') + el.set(qn('w:color'), 'D9E2DD') + borders.append(el) + tblPr.append(borders) + for i, cell in enumerate(why.rows[0].cells): + cell.width = Cm(3.4) + cell.text = '' + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(str(i + 1)) + set_run(r, size=8, bold=True, color=ROSE) + p2 = cell.add_paragraph() + p2.paragraph_format.space_before = Pt(0) + p2.paragraph_format.space_after = Pt(0) + r = p2.add_run('Почему?') + set_run(r, size=7, color=GRAY) + + # Row 6: formulation (merged) + c = table.cell(6, 0).merge(table.cell(6, 1)) + c.text = '' + shade(c, 'F3F9F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('10 ') + set_run(r, size=7.5, bold=True, color=GREEN) + r = p.add_run('ФОРМУЛИРОВКА ПРОБЛЕМЫ') + set_run(r, size=9.5, bold=True, color=GREEN) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(2) + r = p.add_run('«___________ не может ___________, потому что ___________. Это стоит им ___________.»') + set_run(r, size=8, italic=True, color=GRAY) + add_line_table(c, lines=1, width_cm=17.2, height_cm=0.5) + + # Footer + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(5) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('Не называйте решение. Сначала проблема. • Метод Дегтярева • Форум молодёжи Донбасса, 2026') + set_run(r, size=7.5, color=LIGHT) + + doc.save(OUT) + print('saved', OUT) + + +if __name__ == '__main__': + build() diff --git a/build_rose_card.py b/build_rose_card.py new file mode 100644 index 0000000..cdec790 --- /dev/null +++ b/build_rose_card.py @@ -0,0 +1,345 @@ +# -*- coding: utf-8 -*- +from docx import Document +from docx.shared import Pt, Cm, RGBColor +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.enum.table import WD_TABLE_ALIGNMENT +from docx.oxml.ns import qn +from docx.oxml import OxmlElement + +OUT = 'Метод_Дегтярева_роза.docx' + +GREEN = RGBColor(0x2E, 0x7D, 0x5B) +ROSE = RGBColor(0xB0, 0x3A, 0x55) +DARK = RGBColor(0x1A, 0x1A, 0x1A) +GRAY = RGBColor(0x5F, 0x66, 0x6B) +LIGHT = RGBColor(0x8A, 0x90, 0x95) + + +def set_run(run, name='Arial', size=9, bold=False, italic=False, color=DARK): + run.font.name = name + run.font.size = Pt(size) + run.font.bold = bold + run.font.italic = italic + run.font.color.rgb = color + rPr = run._element.get_or_add_rPr() + rFonts = rPr.find(qn('w:rFonts')) + if rFonts is None: + rFonts = OxmlElement('w:rFonts') + rPr.append(rFonts) + for attr in ('w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs'): + rFonts.set(qn(attr), name) + + +def shade(cell, hex_color): + tcPr = cell._tc.get_or_add_tcPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear') + shd.set(qn('w:color'), 'auto') + shd.set(qn('w:fill'), hex_color) + tcPr.append(shd) + + +def cell_margins(table, top=60, bottom=60, left=100, right=100): + tblPr = table._tbl.tblPr + mar = OxmlElement('w:tblCellMar') + for tag, val in (('top', top), ('left', left), ('bottom', bottom), ('right', right)): + el = OxmlElement('w:' + tag) + el.set(qn('w:w'), str(val)) + el.set(qn('w:type'), 'dxa') + mar.append(el) + tblPr.append(mar) + + +def table_borders(table, color='C9D6CF', size=6): + tblPr = table._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), str(size)) + el.set(qn('w:space'), '0') + el.set(qn('w:color'), color) + borders.append(el) + tblPr.append(borders) + + +def add_line_table(cell, lines=2, width_cm=8.0, height_cm=0.5): + tbl = cell.add_table(rows=lines, cols=1) + tbl.autofit = False + tblPr = tbl._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'none') + borders.append(el) + tblPr.append(borders) + for row in tbl.rows: + row.height = Cm(height_cm) + c = row.cells[0] + c.width = Cm(width_cm) + tcPr = c._tc.get_or_add_tcPr() + tcBorders = OxmlElement('w:tcBorders') + bottom = OxmlElement('w:bottom') + bottom.set(qn('w:val'), 'dotted') + bottom.set(qn('w:sz'), '4') + bottom.set(qn('w:space'), '0') + bottom.set(qn('w:color'), 'AFC4B9') + tcBorders.append(bottom) + tcPr.append(tcBorders) + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + p.paragraph_format.line_spacing = 1.0 + + +def add_block(cell, num, title, prompt, color=GREEN, fill='F3F9F6', lines=2, width_cm=8.0): + cell.text = '' + shade(cell, fill) + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run(num + ' ') + set_run(r, size=7.5, bold=True, color=color) + r = p.add_run(title) + set_run(r, size=9.5, bold=True, color=color) + p = cell.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + p.paragraph_format.line_spacing = 1.0 + r = p.add_run(prompt) + set_run(r, size=7.5, color=GRAY) + add_line_table(cell, lines=lines, width_cm=width_cm, height_cm=0.5) + + +def nested_grid(cell, rows, cols, widths, header_fill='EAF4EF'): + tbl = cell.add_table(rows=rows, cols=cols) + tbl.autofit = False + tblPr = tbl._tbl.tblPr + borders = OxmlElement('w:tblBorders') + for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): + el = OxmlElement('w:' + edge) + el.set(qn('w:val'), 'single') + el.set(qn('w:sz'), '4') + el.set(qn('w:space'), '0') + el.set(qn('w:color'), 'D9E2DD') + borders.append(el) + tblPr.append(borders) + for row in tbl.rows: + for i, c in enumerate(row.cells): + c.width = Cm(widths[i]) + return tbl + + +def build(): + doc = Document() + section = doc.sections[0] + section.page_width = Cm(21.0) + section.page_height = Cm(29.7) + section.top_margin = Cm(1.3) + section.bottom_margin = Cm(1.1) + section.left_margin = Cm(1.4) + section.right_margin = Cm(1.4) + + normal = doc.styles['Normal'] + normal.font.name = 'Arial' + normal.font.size = Pt(9) + normal.font.color.rgb = DARK + + # Header + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('РОЗА') + set_run(r, name='Georgia', size=20, bold=True, color=ROSE) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(1) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('Шаг 4. «Роза» • Метод Дегтярева') + set_run(r, size=9, bold=True, color=GRAY) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('Сделайте результат видимым и желанным. Не функция, а то, что человек почувствует.') + set_run(r, size=8, italic=True, color=ROSE) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(5) + r = p.add_run('Команда: ______________________________ Продукт: ______________________________________') + set_run(r, size=8.5, color=GRAY) + + # Main table + table = doc.add_table(rows=6, cols=2) + table.alignment = WD_TABLE_ALIGNMENT.CENTER + table.autofit = False + table_borders(table) + cell_margins(table) + + heights = [3.0, 3.6, 2.6, 3.2, 3.0, 2.6] + for i, row in enumerate(table.rows): + row.height = Cm(heights[i]) + for cell in row.cells: + cell.width = Cm(9.0) + + # 01 Value (merged) + c = table.cell(0, 0).merge(table.cell(0, 1)) + add_block(c, '01', 'ЦЕННОСТЬ В ОДНОМ ПРЕДЛОЖЕНИИ', + '«[Продукт] помогает [группа] [решить проблему] за счёт [механизм]. В отличие от [альтернатива], мы [отличие]».', + lines=3, width_cm=17.2) + + # 02 Scenario (merged) + c = table.cell(1, 0).merge(table.cell(1, 1)) + c.text = '' + shade(c, 'F3F9F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('02 ') + set_run(r, size=7.5, bold=True, color=GREEN) + r = p.add_run('СЦЕНАРИЙ ИСПОЛЬЗОВАНИЯ') + set_run(r, size=9.5, bold=True, color=GREEN) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + r = p.add_run('Путь человека от боли до результата. Пять шагов.') + set_run(r, size=7.5, color=GRAY) + + scenario = nested_grid(c, 2, 5, [3.4, 3.4, 3.4, 3.4, 3.4]) + scenario.rows[0].height = Cm(0.45) + scenario.rows[1].height = Cm(1.55) + headers = ['1. ТРИГГЕР', '2. ВХОД', '3. ДЕЙСТВИЕ', '4. РЕЗУЛЬТАТ', '5. ВОЗВРАТ'] + prompts = ['Что происходит в момент боли?', 'Как человек попадает в продукт?', 'Что он делает?', 'Что получает?', 'Почему возвращается?'] + for i, h in enumerate(headers): + cell = scenario.cell(0, i) + cell.text = '' + shade(cell, 'EAF4EF') + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(h) + set_run(r, size=6.8, bold=True, color=GREEN) + cell2 = scenario.cell(1, i) + cell2.text = '' + p = cell2.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(prompts[i]) + set_run(r, size=6.5, color=GRAY) + + # 03 Before / 04 After + add_block(table.cell(2, 0), '03', 'ДО', + 'Что человек чувствует сейчас: тревога, злость, усталость, стыд?', + color=GRAY, fill='F7F8F8', lines=2, width_cm=8.2) + add_block(table.cell(2, 1), '04', 'ПОСЛЕ', + 'Что он почувствует с продуктом: спокойствие, контроль, гордость?', + color=ROSE, fill='FDF4F6', lines=2, width_cm=8.2) + + # 05 MVP (merged) + c = table.cell(3, 0).merge(table.cell(3, 1)) + c.text = '' + shade(c, 'F3F9F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('05 ') + set_run(r, size=7.5, bold=True, color=GREEN) + r = p.add_run('MVP — МИНИМАЛЬНАЯ ВЕРСИЯ, КОТОРАЯ ПРОВЕРЯЕТ ЦЕННОСТЬ') + set_run(r, size=9.5, bold=True, color=GREEN) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + r = p.add_run('Что обязательно входит, что делаем вручную, что не входит в первую версию.') + set_run(r, size=7.5, color=GRAY) + + mvp = nested_grid(c, 2, 3, [5.7, 5.7, 5.7]) + mvp.rows[0].height = Cm(0.45) + mvp.rows[1].height = Cm(1.35) + mvp_headers = ['ВХОДИТ В MVP', 'ДЕЛАЕМ ВРУЧНУЮ', 'НЕ ВХОДИТ'] + for i, h in enumerate(mvp_headers): + cell = mvp.cell(0, i) + cell.text = '' + shade(cell, 'EAF4EF') + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(h) + set_run(r, size=7, bold=True, color=GREEN) + cell2 = mvp.cell(1, i) + cell2.text = '' + p = cell2.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(' ') + set_run(r, size=7, color=RGBColor(0xFF, 0xFF, 0xFF)) + + # 06 Difference (merged) + c = table.cell(4, 0).merge(table.cell(4, 1)) + c.text = '' + shade(c, 'FDF4F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('06 ') + set_run(r, size=7.5, bold=True, color=ROSE) + r = p.add_run('ОТЛИЧИЕ ОТ АЛЬТЕРНАТИВ') + set_run(r, size=9.5, bold=True, color=ROSE) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(3) + r = p.add_run('Чем вы лучше по трём параметрам: скорость, цена, доверие?') + set_run(r, size=7.5, color=GRAY) + + diff = nested_grid(c, 2, 3, [5.7, 5.7, 5.7]) + diff.rows[0].height = Cm(0.45) + diff.rows[1].height = Cm(1.25) + diff_headers = ['МЫ', 'АЛЬТЕРНАТИВА 1', 'АЛЬТЕРНАТИВА 2'] + for i, h in enumerate(diff_headers): + cell = diff.cell(0, i) + cell.text = '' + shade(cell, 'FDF4F6') + p = cell.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(h) + set_run(r, size=7, bold=True, color=ROSE) + cell2 = diff.cell(1, i) + cell2.text = '' + p = cell2.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(0) + r = p.add_run(' ') + set_run(r, size=7, color=RGBColor(0xFF, 0xFF, 0xFF)) + + # 07 Pitch (merged) + c = table.cell(5, 0).merge(table.cell(5, 1)) + c.text = '' + shade(c, 'F3F9F6') + p = c.paragraphs[0] + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(1) + r = p.add_run('07 ') + set_run(r, size=7.5, bold=True, color=GREEN) + r = p.add_run('ПИТЧ-ФОРМУЛА') + set_run(r, size=9.5, bold=True, color=GREEN) + p = c.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(2) + r = p.add_run('Проблема → Решение → Ценность → Доказательство → Призыв.') + set_run(r, size=8, italic=True, color=GRAY) + add_line_table(c, lines=2, width_cm=17.2, height_cm=0.5) + + # Footer + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(5) + p.paragraph_format.space_after = Pt(0) + r = p.add_run('Сделайте результат видимым. • Метод Дегтярева • Форум молодёжи Донбасса, 2026') + set_run(r, size=7.5, color=LIGHT) + + doc.save(OUT) + print('saved', OUT) + + +if __name__ == '__main__': + build() diff --git a/Метод_Дегтярева_гайд_интервью.docx b/Метод_Дегтярева_гайд_интервью.docx new file mode 100644 index 0000000..80a2916 Binary files /dev/null and b/Метод_Дегтярева_гайд_интервью.docx differ diff --git a/Метод_Дегтярева_гайд_интервью.pdf b/Метод_Дегтярева_гайд_интервью.pdf new file mode 100644 index 0000000..d40a19a Binary files /dev/null and b/Метод_Дегтярева_гайд_интервью.pdf differ diff --git a/Метод_Дегтярева_канвас.docx b/Метод_Дегтярева_канвас.docx new file mode 100644 index 0000000..741688c Binary files /dev/null and b/Метод_Дегтярева_канвас.docx differ diff --git a/Метод_Дегтярева_канвас.pdf b/Метод_Дегтярева_канвас.pdf new file mode 100644 index 0000000..f87aee5 Binary files /dev/null and b/Метод_Дегтярева_канвас.pdf differ diff --git a/Метод_Дегтярева_карта_проблемы.docx b/Метод_Дегтярева_карта_проблемы.docx new file mode 100644 index 0000000..4def07f Binary files /dev/null and b/Метод_Дегтярева_карта_проблемы.docx differ diff --git a/Метод_Дегтярева_карта_проблемы.pdf b/Метод_Дегтярева_карта_проблемы.pdf new file mode 100644 index 0000000..41464a2 Binary files /dev/null and b/Метод_Дегтярева_карта_проблемы.pdf differ diff --git a/Метод_Дегтярева_концепция_трека.docx b/Метод_Дегтярева_концепция_трека.docx new file mode 100644 index 0000000..80bd9ad Binary files /dev/null and b/Метод_Дегтярева_концепция_трека.docx differ diff --git a/Метод_Дегтярева_концепция_трека.md b/Метод_Дегтярева_концепция_трека.md new file mode 100644 index 0000000..073fde5 --- /dev/null +++ b/Метод_Дегтярева_концепция_трека.md @@ -0,0 +1,277 @@ +# ТРЕК «МЕТОД ДЕГТЯРЕВА» +## Цифра, у которой есть хозяин + +**Форум молодёжи Донбасса «ФМД: у нас так принято»** +Смена 1 «ПСБ Патриот» • 10–13 ноября 2026 +Эксперт и наставник трека: **Бойко К.С.** + +--- + +## Короткая версия для заявки + +Трек «Метод Дегтярева» — о том, как превращать реальные проблемы региона в цифровые социальные проекты. В основе — метод Владимира Дегтярева, «хозяина Донбасса», который в 1963–1976 годах превратил шахтёрский край в самый зелёный промышленный город планеты. Пять шагов: **Забой** (найди реальную проблему), **Смета** (посчитай в людях и ресурсах), **Завод** (построй системное решение), **Роза** (сделай результат видимым), **Хозяин** (останься после запуска). За три дня смешанные команды студентов технических, социальных и экономических специальностей проходят путь от проблемы до паспорта проекта и питча на 3 минуты. Прикладной результат: 5–7 концепций цифровых социальных сервисов, банк проблем региона, 2–3 проекта, готовых к пилоту или гранту, и тиражируемая методичка. + +--- + +## 1. Задумка трека + +В 1970-х годах ЮНЕСКО признала Донецк самым зелёным промышленным городом планеты. Город, который десятилетиями называли «всесоюзной кочегаркой», получил миллион роз, Ботанический сад, новые микрорайоны, научный центр, университеты, цирк «Космос» и Дворец молодёжи «Юность». + +За этим стоит **Владимир Иванович Дегтярев** — горный инженер, прошедший путь от начальника участка шахты до первого секретаря Донецкого обкома (1963–1976). Его называли «хозяином Донбасса» не за должность, а за способ думать и отвечать за результат. + +У Дегтярева не было ни интернета, ни смартфона, ни искусственного интеллекта. Но у него был метод: + +1. сначала спуститься туда, где реально болит; +2. потом посчитать в людях и ресурсах; +3. построить систему, а не разовую акцию; +4. сделать результат видимым и желанным; +5. остаться за него ответственным. + +**Задумка трека** — перенести этот метод в цифровую эпоху. Мы не учим «делать сайты» и не соревнуемся в технологиях. Мы учим превращать реальную проблему региона в концепцию цифрового социального продукта или сервиса — и доводить её до состояния, в котором её можно защитить, показать партнёру и подать на грант. + +**Слоган:** «От забоя до миллиона роз». + +**Главная мысль:** цифровизация начинается не с сервера, а с человека. Технология становится ценной только тогда, когда у неё есть хозяин — тот, кто понимает, кому и зачем она служит. + +--- + +## 2. Цель трека + +Сформировать у участников практическую компетенцию превращать социальную проблему региона в концепцию цифрового продукта или сервиса с измеримым эффектом и устойчивой моделью — по «методу Дегтярева». + +--- + +## 3. Задачи трека + +1. Показать метод как рабочий инструмент: пять шагов — пять артефактов. +2. Провести диагностику региона: собрать и верифицировать проблемы, отделить симптом от причины. +3. Собрать смешанные команды «технарь + социальщик + экономист» и распределить роли. +4. Разработать концепцию цифрового социального проекта: проблема, пользователь, решение, ценность, ресурсы, метрики, риски, устойчивость. +5. Оформить паспорт проекта и питч на 3 минуты. +6. Защитить проект перед экспертами и получить обратную связь и дорожную карту. +7. Отобрать проекты, готовые к пилоту или подаче на грантовый конкурс. + +--- + +## 4. Прикладной результат + +**Для участника:** +- паспорт проекта на 1 странице и питч на 3 минуты; +- обратная связь от экспертов и наставника; +- дорожная карта на 30 и 90 дней; +- методичка «5 шагов» и канвас, которые можно применять к любому проекту. + +**Паспорт проекта** = заполненный канвас + один слайд + питч на 3 минуты. + +**Для форума и региона:** +- банк проблем и решений — карта проблем региона; +- 5–7 проработанных концепций цифровых социальных проектов; +- 2–3 проекта, готовых к пилоту с партнёром или подаче на грант; +- тиражируемая методика трека для следующих смен и регионов. + +--- + +## 5. Метод: пять шагов + +| Шаг | Название | Вопрос | Артефакт | +|---|---|---|---| +| 1 | **Забой** | Что болит на самом деле? | Карта проблемы, интервью, данные | +| 2 | **Смета** | Кому и насколько станет лучше? | Портрет пользователя, 3 метрики эффекта | +| 3 | **Завод** | Что нужно, чтобы решалось системно? | Архитектура решения, ресурсы, партнёры | +| 4 | **Роза** | Как люди это почувствуют? | Ценностное предложение, сценарий, MVP | +| 5 | **Хозяин** | Кто останется после нас? | Модель устойчивости, дорожная карта 30/90 | + +**Почему это его метод, а не красивая метафора.** Забой — Дегтярев сам прошёл школу шахты и знал реальную цену работе. Смета — он считал ресурсы и строил кирпичные заводы, чтобы жильё перестало быть дефицитом. Завод — он создал научный центр, университеты и инфраструктуру, а не разовые акции. Роза — он подарил городу миллион роз и Ботанический сад, сделав результат видимым и любимым. Хозяин — он остался «хозяином Донбасса» в памяти людей, потому что отвечал за результат, а не за отчёт. + +### Шаг 1. Забой — «Что болит на самом деле?» + +Выйти из аудитории в реальность: интервью, наблюдение, данные, эксперты. Отделить симптом от причины. Проверить, что проблема существует не только в голове команды. + +**Артефакт:** карта проблемы, цитаты, цифры, доказательства. + +### Шаг 2. Смета — «Кому и насколько станет лучше?» + +Определить пользователя и социальный эффект. Не «людям», а конкретным группам. Не «станет лучше», а на сколько и как измерим. + +**Артефакт:** портрет пользователя, 3 метрики эффекта. + +### Шаг 3. Завод — «Что нужно, чтобы решалось системно?» + +Найти решение, которое меняет систему, а не закрашивает симптом. Понять, какие ресурсы, данные, партнёры и компетенции нужны. + +**Артефакт:** архитектура решения, карта ресурсов и партнёров. + +### Шаг 4. Роза — «Как люди это почувствуют?» + +Сформулировать ценность человеческим языком. Придумать сценарий использования и минимальную версию продукта. Сделать результат видимым и желанным. + +**Артефакт:** ценностное предложение, сценарий, MVP. + +### Шаг 5. Хозяин — «Кто останется после нас?» + +Продумать устойчивость: команда, модель, финансирование, первый шаг после форума. Проект не заканчивается защитой. + +**Артефакт:** модель устойчивости, дорожная карта 30/90. + +--- + +## 6. Как трек встроен в программу + +| Дата | Время | Формат | Задача | Артефакт | +|---|---|---|---|---| +| 10.11 | 19:30–20:00 | Установочная сессия | Презентация трека: зачем, как, что получится | 5–7 минут | +| 11.11 | 09:00–09:15 | Цифровой квиз | Разогрев и диагностика | — | +| 11.11 | 09:15–10:00 | Лекция А. Фахрутдинова | Контекст: цифровая трансформация социальной сферы | — | +| 11.11 | 10:45–12:00 | Лаборатория | Шаги 1–2: проблема и пользователь | Карта проблемы + портрет | +| 11.11 | 16:30–17:15 | Лекция RUTUBE | Ограничения как топливо | — | +| 11.11 | 17:15–18:00 | Лекция RUTUBE | Как сделать технологию человечной | — | +| 11.11 | 18:00–19:00 | Лаборатория | Шаги 3–4: решение и ценность | Решение + MVP | +| 12.11 | 09:00–09:45 | Лекция К. Бойко | Регион как лаборатория + ИИ-продукт | — | +| 12.11 | 09:45–10:30 | Лекция Л. Макольской | ИИ в действии: от запроса до решения | — | +| 12.11 | 10:30–11:30 | Лаборатория | Шаг 5: устойчивость и метрики | Модель устойчивости | +| 12.11 | 11:30–12:30 | Консультация | Индивидуальная доработка | — | +| 12.11 | 13:00–14:30 | Лаборатория | Сборка паспорта и питча | Паспорт + питч | +| 12.11 | 14:45–16:30 | Защита | Презентация проектов | Оценка экспертов; 3 мин питч + 2 мин вопросы | + +--- + +## 7. Формат лаборатории + +- Команды 5–7 человек, смешанные по специальностям. +- Каждая команда выбирает проблему из «карты проблем» или приносит свою. +- Каждый блок — один шаг метода и один артефакт на канвасе. +- На «Забое» команды работают с печатной «Картой проблемы» и карточкой «Гайд интервью». +- На «Смете» — с печатным листом «Смета»: пользователь, было → стало, три метрики, масштаб, цена эффекта. +- На «Розе» — с листом «Роза»: ценность, сценарий, MVP, отличие от альтернатив. +- На «Хозяине» — с листом «Хозяин»: команда, модель устойчивости, партнёры, дорожная карта 30/90, риски. +- «Доска хозяина» — визуальная карта прогресса команд. +- Консультации экспертов по запросу. +- Защита: 3 минуты питч + 2 минуты вопросы. + +--- + +## 8. Роли в команде + +| Роль | Кто это | За что отвечает | +|---|---|---| +| **Забойщик** | Исследователь | Поле, интервью, данные, доказательства | +| **Инженер** | Технарь / продукт | Решение, архитектура, MVP | +| **Хозяин** | Экономист / менеджер | Ресурсы, метрики, устойчивость | +| **Голос** | Коммуникатор / дизайнер | Питч, визуал, история | + +--- + +## 9. Критерии оценки + +| Критерий | Что проверяем | Баллы | +|---|---|---| +| Доказанность проблемы | Есть поле, данные, цитаты; причина, а не симптом | 0–2 | +| Социальный эффект | Кому, сколько, как измеряем | 0–2 | +| Цифровая суть | Сервис / платформа / ИИ, а не сайт-визитка | 0–2 | +| Реализуемость | Ресурсы, сроки, партнёры | 0–2 | +| Устойчивость | Кто «хозяин» после форума | 0–2 | +| Питч | Ясность, эмоция, ответы на вопросы | 0–2 | + +**Итого:** 12 баллов. + +**Номинации:** +- «Хозяин Донбасса» — лучший проект по сумме баллов. +- «Миллион роз» — самый яркий и масштабируемый. +- «Забой» — лучшая работа с проблемой и данными. +- «Кирпичный завод» — лучшая системная модель. +- Приз зрительских симпатий. + +--- + +## 10. Сценарий установочной сессии (7 минут) + +### 0:00–0:40 — Хук + +«В 1970-х ЮНЕСКО назвала Донецк самым зелёным промышленным городом планеты. Город, который мы привыкли называть всесоюзной кочегаркой. Это сделал человек, у которого не было ни интернета, ни смартфона, ни искусственного интеллекта. Его звали Владимир Дегтярев. И у него был метод. За три дня мы применим этот метод к цифре». + +### 0:40–2:00 — Кто он + +«Горный инженер. Начальник участка шахты. В 32 года — управляющий трестом. В 43 — первый секретарь Донецкого обкома. За 13 лет: жильё выросло в 3,1 раза, появился научный центр Академии наук, университеты, цирк «Космос», Дворец молодёжи «Юность», Ботанический сад и миллион роз. Его называли «хозяином Донбасса» — не за должность, а за то, что он отвечал за результат». + +### 2:00–3:00 — Метод + +«В чём метод? Пять шагов. **Забой**: спустись туда, где реально болит. **Смета**: посчитай в людях, а не в отчётах. **Завод**: построй систему, а не разовую акцию. **Роза**: сделай результат видимым и желанным. **Хозяин**: останься после запуска. Всё». + +### 3:00–4:30 — Что будет + +«За три дня вы пройдёте эти пять шагов. В первый день — проблема и пользователь. Во второй — решение и ценность. В третий — устойчивость, метрики и защита. Работаем в смешанных командах: технарь, социальщик, экономист, коммуникатор. У каждой команды — канвас и наставник». + +### 4:30–5:30 — Результат + +«На выходе у каждого — паспорт проекта на одну страницу и питч на три минуты. У региона — банк проблем и 5–7 концепций цифровых социальных проектов. Лучшие получат дорожную карту до пилота или гранта. Это не учебная игра: это заготовки реальных проектов». + +### 5:30–6:30 — Правила + +«Три правила. Первое: приходите с проблемой, а не с идеей. Второе: считайте в людях, а не в лайках. Третье: думайте, кто останется хозяином после форума. Всё остальное — на лабораториях». + +### 6:30–7:00 — Вызов + +«Завтра в 10:45 — спуск в забой. Зал «Жуков 2». Приходите с проблемой, а не с идеей. Дальше — метод Дегтярева». + +### Если регламент 5 минут + +- **0:00–0:30 — Хук.** «В 1970-х ЮНЕСКО назвала Донецк самым зелёным промышленным городом планеты. Это сделал человек без интернета и смартфона. Его звали Владимир Дегтярев. У него был метод. За три дня мы применим его к цифре». +- **0:30–1:20 — Кто он.** «Горный инженер. В 32 года — управляющий трестом. В 43 — первый секретарь обкома. За 13 лет: жильё, наука, культура, миллион роз. Его называли «хозяином» не за должность, а за метод». +- **1:20–2:10 — Метод.** «Пять шагов: Забой — найди реальную проблему. Смета — посчитай в людях. Завод — построй систему. Роза — сделай результат видимым. Хозяин — останься после запуска». +- **2:10–3:20 — Что будет.** «Три дня, смешанные команды, канвас, наставник. В первый день — проблема и пользователь. Во второй — решение и ценность. В третий — устойчивость и защита». +- **3:20–4:20 — Результат.** «Паспорт проекта, питч на три минуты, дорожная карта. У региона — банк проблем и 5–7 концепций. Лучшие — к пилоту или гранту». +- **4:20–5:00 — Вызов.** «Завтра в 10:45 — спуск в забой. Приходите с проблемой, а не с идеей». + +--- + +## 11. Структура презентации (8 слайдов) + +1. **Титул.** «Метод Дегтярева. Цифра, у которой есть хозяин». +2. **Парадокс.** «Всесоюзная кочегарка» → «самый зелёный промышленный город планеты». +3. **Человек.** 4 факта: 1920, шахта, трест в 32, обком 1963–1976. +4. **Метод.** 5 шагов: Забой → Смета → Завод → Роза → Хозяин. +5. **Карта трека.** 3 дня, 5 шагов, 1 защита. +6. **Команда и канвас.** 4 роли, 5–7 человек, один канвас. +7. **Прикладной результат.** Паспорт, питч, дорожная карта, методичка; банк проблем, концепции, грант/пилот. +8. **Вызов.** «Завтра в 10:45 — спуск в забой. Приходите с проблемой, а не с идеей». + +--- + +## 12. Вопросы и ответы + +**Почему трек назван в честь Дегтярева, если он не про IT?** +Именно поэтому. Он про метод, а не про инструмент. Дегтярев решал проблемы региона системно, а цифра — сегодняшний инструмент для того же. + +**Это исторический трек?** +История — вход. Результат — цифровой проект. Мы берём не биографию, а метод. + +**Участники не айтишники. Что они успеют?** +Мы делаем концепцию и прототип мышления, а не production. За три дня реально пройти путь от проблемы до питча, если работать по канвасу. + +**Не получится ли очередной агрегатор?** +Канвас и критерии не дадут: проблема должна быть доказана, эффект измерим, модель устойчива. «Ещё один маркетплейс» не пройдёт защиту. + +**Как отберёте лучших?** +Критерии, эксперты, защита. Шесть критериев по два балла. + +**Что останется после форума?** +Паспорта проектов, банк проблем, методичка, дорожные карты, сообщество команд и наставников. + +--- + +## 13. Что нужно от организаторов + +- 5–7 столов, флипчарты или ватманы, маркеры, стикеры. +- Проектор, экран, 4 микрофона. +- Печатные канвасы, «Карты проблемы», «Сметы», «Розы», «Хозяева» и «Гайды интервью» по числу команд. +- Список экспертов на консультации. +- Партнёры: Росмолодёжь.Гранты, IT-компании, вузы. +- Тайминг защиты и регламент. + +--- + +## 14. Открытые вопросы + +- Формат защиты 14:45–16:30: все треки в одном зале? Сколько команд от трека? Регламент — 3 минуты питч + 2 минуты вопросы. +- Есть ли доступ к данным региона (статистика, открытые данные) для шага «Забой»? +- Нужны ли командам ноутбуки на лабораториях или достаточно печатных канвасов? diff --git a/Метод_Дегтярева_концепция_трека.pdf b/Метод_Дегтярева_концепция_трека.pdf new file mode 100644 index 0000000..25e1fc3 Binary files /dev/null and b/Метод_Дегтярева_концепция_трека.pdf differ diff --git a/Метод_Дегтярева_презентация.pdf b/Метод_Дегтярева_презентация.pdf new file mode 100644 index 0000000..e4d3d7b Binary files /dev/null and b/Метод_Дегтярева_презентация.pdf differ diff --git a/Метод_Дегтярева_презентация.pptx b/Метод_Дегтярева_презентация.pptx new file mode 100644 index 0000000..fd773e5 Binary files /dev/null and b/Метод_Дегтярева_презентация.pptx differ diff --git a/Метод_Дегтярева_роза.docx b/Метод_Дегтярева_роза.docx new file mode 100644 index 0000000..f441d50 Binary files /dev/null and b/Метод_Дегтярева_роза.docx differ diff --git a/Метод_Дегтярева_роза.pdf b/Метод_Дегтярева_роза.pdf new file mode 100644 index 0000000..7ec3243 Binary files /dev/null and b/Метод_Дегтярева_роза.pdf differ diff --git a/Метод_Дегтярева_смета.docx b/Метод_Дегтярева_смета.docx new file mode 100644 index 0000000..d9b2cb8 Binary files /dev/null and b/Метод_Дегтярева_смета.docx differ diff --git a/Метод_Дегтярева_смета.pdf b/Метод_Дегтярева_смета.pdf new file mode 100644 index 0000000..89c0f76 Binary files /dev/null and b/Метод_Дегтярева_смета.pdf differ diff --git a/Метод_Дегтярева_хозяин.docx b/Метод_Дегтярева_хозяин.docx new file mode 100644 index 0000000..cede212 Binary files /dev/null and b/Метод_Дегтярева_хозяин.docx differ diff --git a/Метод_Дегтярева_хозяин.pdf b/Метод_Дегтярева_хозяин.pdf new file mode 100644 index 0000000..3cfac2b Binary files /dev/null and b/Метод_Дегтярева_хозяин.pdf differ