From 97e56b48bf832991ad77d1da8f873fddac898ac3 Mon Sep 17 00:00:00 2001 From: Local Build Date: Fri, 14 Aug 2026 10:05:17 +0200 Subject: [PATCH] =?UTF-8?q?PDF=20=D1=80=D0=B5=D0=B7=D1=8E=D0=BC=D0=B5:=20P?= =?UTF-8?q?uppeteer-=D1=81=D0=BA=D1=80=D0=B8=D0=BF=D1=82,=20=D0=BA=D0=BD?= =?UTF-8?q?=D0=BE=D0=BF=D0=BA=D0=B0=20=D1=81=D0=BA=D0=B0=D1=87=D0=B8=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F,=20=D0=B8=D0=BC=D1=8F=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=B0=20Mamadaev=5FNik=5F=5FCV=5F=5FProduct=5FDesi?= =?UTF-8?q?gner=5FUX-UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .deploy-manifest.json | 1586 --------------- .dockerignore | 10 - .gitignore | 1 + .node-version | 1 + AGENTS.md | 58 +- Dockerfile | 13 - Dockerfile.dev | 9 - deploy.sh | 40 - docs/gitverse-sync.md | 57 - docs/local-server.md | 16 +- docs/resume-pdf.md | 52 + docs/vendor-assets.md | 6 +- docs/vps-deploy.md | 59 - package-lock.json | 1784 ++--------------- package.json | 7 +- prompt.json | 13 - ...madaev_Nik__CV__Product_Designer_UX-UI.pdf | Bin 0 -> 1789497 bytes public/assets/shared/icons/printer.svg | 6 +- public/cookie-policy.html | 24 + public/css/main.css | 29 - public/js/main.js | 2 + public/js/modules/mini-projects/masonry.js | 38 +- public/js/modules/ui/scroll-reveal.js | 27 + public/resume-2.html | 651 ++++++ public/resume-3.html | 721 +++++++ public/resume-4.html | 801 ++++++++ public/resume-5.html | 190 +- scripts/deploy-vps.mjs | 179 -- scripts/generate-resume-pdf.mjs | 63 + scripts/serve-dev.mjs | 67 +- scripts/sync-gitverse.mjs | 162 -- src/pages/cases/ai-platform-primo-rpa-2.html | 2 +- src/pages/cases/ai-platform-primo-rpa-v2.html | 552 +++++ src/pages/cases/lunacy.html | 2 +- src/pages/cases/mini-projects-showcase.html | 325 ++- src/pages/index.html | 6 +- src/pages/resume-2.html | 444 ++++ src/pages/resume-3.html | 514 +++++ src/pages/resume-4.html | 594 ++++++ src/pages/resume-5.html | 184 +- src/partials/contact-section.html | 4 +- src/partials/fab-stack-resume.html | 7 +- src/partials/mini-projects-section.html | 2 +- src/partials/projects-section-mp.html | 2 +- texts/content-edits/pending.json | 19 +- 45 files changed, 5132 insertions(+), 4197 deletions(-) delete mode 100644 .deploy-manifest.json delete mode 100644 .dockerignore create mode 100644 .node-version delete mode 100644 Dockerfile delete mode 100644 Dockerfile.dev delete mode 100644 deploy.sh delete mode 100644 docs/gitverse-sync.md create mode 100644 docs/resume-pdf.md delete mode 100644 docs/vps-deploy.md delete mode 100644 prompt.json create mode 100644 public/assets/resume/Mamadaev_Nik__CV__Product_Designer_UX-UI.pdf create mode 100644 public/js/modules/ui/scroll-reveal.js create mode 100644 public/resume-2.html create mode 100644 public/resume-3.html create mode 100644 public/resume-4.html delete mode 100644 scripts/deploy-vps.mjs create mode 100644 scripts/generate-resume-pdf.mjs delete mode 100644 scripts/sync-gitverse.mjs create mode 100644 src/pages/cases/ai-platform-primo-rpa-v2.html create mode 100644 src/pages/resume-2.html create mode 100644 src/pages/resume-3.html create mode 100644 src/pages/resume-4.html diff --git a/.deploy-manifest.json b/.deploy-manifest.json deleted file mode 100644 index 8502c33..0000000 --- a/.deploy-manifest.json +++ /dev/null @@ -1,1586 +0,0 @@ -{ - "assets/ai-platform-primo-rpa/.gitkeep": { - "mtime": 1777548036560.4653, - "size": 2 - }, - "assets/ai-platform-primo-rpa/cover.png": { - "mtime": 1779377996031.643, - "size": 159015 - }, - "assets/ai-platform-primo-rpa/cover.webp": { - "mtime": 1779377996032.6443, - "size": 30364 - }, - "assets/ai-platform-primo-rpa/dataset-editor-old.png": { - "mtime": 1777636422809.364, - "size": 888287 - }, - "assets/ai-platform-primo-rpa/dataset-editor-old.webp": { - "mtime": 1779295491001, - "size": 280160 - }, - "assets/ai-platform-primo-rpa/dataset-editor-small-screen.png": { - "mtime": 1779377996036.6465, - "size": 404244 - }, - "assets/ai-platform-primo-rpa/dataset-editor-small-screen.webp": { - "mtime": 1779377996037.6458, - "size": 88614 - }, - "assets/ai-platform-primo-rpa/dataset-editor.png": { - "mtime": 1779377996046.131, - "size": 819234 - }, - "assets/ai-platform-primo-rpa/dataset-editor.webp": { - "mtime": 1779377996048.131, - "size": 153230 - }, - "assets/ai-platform-primo-rpa/dataset-lerning.png": { - "mtime": 1778061201695.4707, - "size": 178506 - }, - "assets/ai-platform-primo-rpa/dataset-lerning.webp": { - "mtime": 1779295491358, - "size": 76082 - }, - "assets/ai-platform-primo-rpa/dataset-quality.png": { - "mtime": 1778061201699.9893, - "size": 256076 - }, - "assets/ai-platform-primo-rpa/dataset-quality.webp": { - "mtime": 1779295491507, - "size": 101230 - }, - "assets/ai-platform-primo-rpa/dataset_editor-main_toolbar.png": { - "mtime": 1779377996049.637, - "size": 15031 - }, - "assets/ai-platform-primo-rpa/dataset_editor-main_toolbar.webp": { - "mtime": 1779377996050.6484, - "size": 6034 - }, - "assets/ai-platform-primo-rpa/dataset_editor-wireframe-default_mode.png": { - "mtime": 1779377996050.6484, - "size": 47547 - }, - "assets/ai-platform-primo-rpa/dataset_editor-wireframe-default_mode.webp": { - "mtime": 1779377996051.6475, - "size": 38664 - }, - "assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-both_panels.png": { - "mtime": 1779377996053.8552, - "size": 56585 - }, - "assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-both_panels.webp": { - "mtime": 1779377996054.8564, - "size": 44568 - }, - "assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-left_panel.png": { - "mtime": 1779377996056.8555, - "size": 59824 - }, - "assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-left_panel.webp": { - "mtime": 1779377996057.8606, - "size": 55050 - }, - "assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-right_panel.png": { - "mtime": 1779377996058.8574, - "size": 60884 - }, - "assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-right_panel.webp": { - "mtime": 1779377996059.86, - "size": 55078 - }, - "assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode.png": { - "mtime": 1779377996060.891, - "size": 64220 - }, - "assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode.webp": { - "mtime": 1779377996062.934, - "size": 63640 - }, - "assets/ai-platform-primo-rpa/fields-maping.mp4": { - "mtime": 1778061201754.2502, - "size": 12663587 - }, - "assets/ai-platform-primo-rpa/fields-maping.webm": { - "mtime": 1778061201761.628, - "size": 811806 - }, - "assets/ai-platform-primo-rpa/fields-maping.webp": { - "mtime": 1778061201763.6267, - "size": 86646 - }, - "assets/ai-platform-primo-rpa/full-screen-mode-with-panels.png": { - "mtime": 1778061201769.9807, - "size": 555909 - }, - "assets/ai-platform-primo-rpa/full-screen-mode-with-panels.webp": { - "mtime": 1779295492433, - "size": 110334 - }, - "assets/ai-platform-primo-rpa/full-screen-mode-zen.png": { - "mtime": 1778061201774.9817, - "size": 502027 - }, - "assets/ai-platform-primo-rpa/full-screen-mode-zen.webp": { - "mtime": 1779295492517, - "size": 94372 - }, - "assets/ai-platform-primo-rpa/fullscreen_modal-import_dataset.png": { - "mtime": 1779377996064.941, - "size": 72399 - }, - "assets/ai-platform-primo-rpa/fullscreen_modal-import_dataset.webp": { - "mtime": 1779377996066.941, - "size": 26252 - }, - "assets/ai-platform-primo-rpa/fullscreen_modal-in_project-import_dataset.png": { - "mtime": 1779377996069.4497, - "size": 130169 - }, - "assets/ai-platform-primo-rpa/fullscreen_modal-in_project-import_dataset.webp": { - "mtime": 1779377996071.4585, - "size": 30506 - }, - "assets/ai-platform-primo-rpa/in_project-learn-card-learning_process.png": { - "mtime": 1779377996073.4573, - "size": 113156 - }, - "assets/ai-platform-primo-rpa/in_project-learn-card-learning_process.webp": { - "mtime": 1779377996075.4573, - "size": 67896 - }, - "assets/ai-platform-primo-rpa/in_project-learn-card-learning_process_wireframe.png": { - "mtime": 1779377996076.4575, - "size": 8462 - }, - "assets/ai-platform-primo-rpa/in_project-learn-card-learning_process_wireframe.webp": { - "mtime": 1779377996077.4592, - "size": 4008 - }, - "assets/ai-platform-primo-rpa/in_project-learn-card-new.png": { - "mtime": 1779377996079.963, - "size": 109260 - }, - "assets/ai-platform-primo-rpa/in_project-learn-card-new.webp": { - "mtime": 1779377996081.969, - "size": 77098 - }, - "assets/ai-platform-primo-rpa/in_project-learn-card-сollapsed.png": { - "mtime": 1779377996082.9697, - "size": 6342 - }, - "assets/ai-platform-primo-rpa/in_project-learn-card-сollapsed.webp": { - "mtime": 1779377996085.1777, - "size": 4868 - }, - "assets/ai-platform-primo-rpa/in_project-learn-overview.png": { - "mtime": 1779377996088.1775, - "size": 147934 - }, - "assets/ai-platform-primo-rpa/in_project-learn-overview.webp": { - "mtime": 1779377996089.6838, - "size": 28904 - }, - "assets/ai-platform-primo-rpa/main-new.png": { - "mtime": 1779377996092.691, - "size": 191708 - }, - "assets/ai-platform-primo-rpa/main-new.webp": { - "mtime": 1779377996093.6912, - "size": 56804 - }, - "assets/ai-platform-primo-rpa/main.png": { - "mtime": 1779377996099.692, - "size": 430951 - }, - "assets/ai-platform-primo-rpa/main.webp": { - "mtime": 1779377996101.8147, - "size": 108008 - }, - "assets/ai-platform-primo-rpa/nav-project-nlp.png": { - "mtime": 1779377996103.8135, - "size": 109931 - }, - "assets/ai-platform-primo-rpa/nav-project-nlp.webp": { - "mtime": 1779377996104.8171, - "size": 18854 - }, - "assets/ai-platform-primo-rpa/nav-project-ocr.png": { - "mtime": 1779377996106.8132, - "size": 116365 - }, - "assets/ai-platform-primo-rpa/nav-project-ocr.webp": { - "mtime": 1779377996107.8135, - "size": 24166 - }, - "assets/ai-platform-primo-rpa/nav-secondary-detail_view.png": { - "mtime": 1779377996108.8142, - "size": 17770 - }, - "assets/ai-platform-primo-rpa/nav-secondary-detail_view.webp": { - "mtime": 1779377996108.8142, - "size": 5266 - }, - "assets/favicon/android-chrome-192x192.png": { - "mtime": 1780513420000, - "size": 45462 - }, - "assets/favicon/android-chrome-512x512.png": { - "mtime": 1780513420000, - "size": 259917 - }, - "assets/favicon/apple-touch-icon.png": { - "mtime": 1780513420000, - "size": 41086 - }, - "assets/favicon/favicon-16x16.png": { - "mtime": 1780513420000, - "size": 776 - }, - "assets/favicon/favicon-32x32.png": { - "mtime": 1780513420000, - "size": 2166 - }, - "assets/favicon/favicon.ico": { - "mtime": 1780513420000, - "size": 15406 - }, - "assets/favicon/favicon.png": { - "mtime": 1780520464204.617, - "size": 778312 - }, - "assets/favicon/favicon_bg.png": { - "mtime": 1780520601264.4983, - "size": 791215 - }, - "assets/favicon/site.webmanifest": { - "mtime": 1780513420000, - "size": 263 - }, - "assets/fonts/files/alice-cyrillic-400-normal.woff2": { - "mtime": 1779377996112.3274, - "size": 17784 - }, - "assets/fonts/files/alice-cyrillic-ext-400-normal.woff2": { - "mtime": 1779377996113.3308, - "size": 15748 - }, - "assets/fonts/files/alice-latin-400-normal.woff2": { - "mtime": 1779377996114.3271, - "size": 25788 - }, - "assets/fonts/files/alice-latin-ext-400-normal.woff2": { - "mtime": 1779377996115.328, - "size": 4880 - }, - "assets/fonts/files/geologica-cyrillic-ext-wght-normal.woff2": { - "mtime": 1779377996117.3262, - "size": 11488 - }, - "assets/fonts/files/geologica-cyrillic-wght-normal.woff2": { - "mtime": 1779377996118.3267, - "size": 16428 - }, - "assets/fonts/files/geologica-greek-wght-normal.woff2": { - "mtime": 1779377996118.3267, - "size": 10928 - }, - "assets/fonts/files/geologica-latin-ext-wght-normal.woff2": { - "mtime": 1779377996119.833, - "size": 22404 - }, - "assets/fonts/files/geologica-latin-wght-normal.woff2": { - "mtime": 1779377996120.8398, - "size": 24944 - }, - "assets/fonts/files/geologica-vietnamese-wght-normal.woff2": { - "mtime": 1779377996121.8386, - "size": 8328 - }, - "assets/fonts/files/merriweather-cyrillic-400-normal.woff2": { - "mtime": 1779377996122.839, - "size": 25484 - }, - "assets/fonts/files/merriweather-cyrillic-700-normal.woff2": { - "mtime": 1779377996123.8394, - "size": 25492 - }, - "assets/fonts/files/merriweather-cyrillic-ext-400-normal.woff2": { - "mtime": 1779377996124.9783, - "size": 18600 - }, - "assets/fonts/files/merriweather-cyrillic-ext-700-normal.woff2": { - "mtime": 1779377996125.9778, - "size": 18560 - }, - "assets/fonts/files/merriweather-latin-400-normal.woff2": { - "mtime": 1779377996126.9783, - "size": 49168 - }, - "assets/fonts/files/merriweather-latin-700-normal.woff2": { - "mtime": 1779377996127.9773, - "size": 48660 - }, - "assets/fonts/files/merriweather-latin-ext-400-normal.woff2": { - "mtime": 1779377996129.4827, - "size": 42952 - }, - "assets/fonts/files/merriweather-latin-ext-700-normal.woff2": { - "mtime": 1779377996130.4888, - "size": 42880 - }, - "assets/fonts/files/merriweather-vietnamese-400-normal.woff2": { - "mtime": 1779377996131.49, - "size": 6664 - }, - "assets/fonts/files/merriweather-vietnamese-700-normal.woff2": { - "mtime": 1779377996133.4978, - "size": 6660 - }, - "assets/fonts/files/pt-mono-cyrillic-400-normal.woff2": { - "mtime": 1779377996134.4993, - "size": 15356 - }, - "assets/fonts/files/pt-mono-cyrillic-ext-400-normal.woff2": { - "mtime": 1779377996135.4956, - "size": 22028 - }, - "assets/fonts/files/pt-mono-latin-400-normal.woff2": { - "mtime": 1779377996136.4954, - "size": 27436 - }, - "assets/fonts/files/pt-mono-latin-ext-400-normal.woff2": { - "mtime": 1779377996137.4963, - "size": 16072 - }, - "assets/fonts/files/pt-sans-cyrillic-400-normal.woff2": { - "mtime": 1779377996138.4968, - "size": 28548 - }, - "assets/fonts/files/pt-sans-cyrillic-700-normal.woff2": { - "mtime": 1779377996139.4963, - "size": 30164 - }, - "assets/fonts/files/pt-sans-cyrillic-ext-400-normal.woff2": { - "mtime": 1779377996140.0027, - "size": 42680 - }, - "assets/fonts/files/pt-sans-cyrillic-ext-700-normal.woff2": { - "mtime": 1779377996142.004, - "size": 39584 - }, - "assets/fonts/files/pt-sans-latin-400-normal.woff2": { - "mtime": 1779377996143.0056, - "size": 45532 - }, - "assets/fonts/files/pt-sans-latin-700-normal.woff2": { - "mtime": 1779377996144.0051, - "size": 47180 - }, - "assets/fonts/files/pt-sans-latin-ext-400-normal.woff2": { - "mtime": 1779377996145.0054, - "size": 26812 - }, - "assets/fonts/files/pt-sans-latin-ext-700-normal.woff2": { - "mtime": 1779377996147.0066, - "size": 29624 - }, - "assets/fonts/files/source-code-pro-cyrillic-400-normal.woff2": { - "mtime": 1779377996147.0066, - "size": 6788 - }, - "assets/fonts/files/source-code-pro-cyrillic-500-normal.woff2": { - "mtime": 1779377996148.0044, - "size": 6836 - }, - "assets/fonts/files/source-code-pro-cyrillic-600-normal.woff2": { - "mtime": 1779377996149.5103, - "size": 6796 - }, - "assets/fonts/files/source-code-pro-cyrillic-700-normal.woff2": { - "mtime": 1779377996150.517, - "size": 6800 - }, - "assets/fonts/files/source-code-pro-cyrillic-ext-400-normal.woff2": { - "mtime": 1779377996150.517, - "size": 4516 - }, - "assets/fonts/files/source-code-pro-cyrillic-ext-500-normal.woff2": { - "mtime": 1779377996151.5173, - "size": 4556 - }, - "assets/fonts/files/source-code-pro-cyrillic-ext-600-normal.woff2": { - "mtime": 1779377996152.5176, - "size": 4520 - }, - "assets/fonts/files/source-code-pro-cyrillic-ext-700-normal.woff2": { - "mtime": 1779377996153.5164, - "size": 4480 - }, - "assets/fonts/files/source-code-pro-greek-400-normal.woff2": { - "mtime": 1779377996154.5195, - "size": 5528 - }, - "assets/fonts/files/source-code-pro-greek-500-normal.woff2": { - "mtime": 1779377996155.5168, - "size": 5584 - }, - "assets/fonts/files/source-code-pro-greek-600-normal.woff2": { - "mtime": 1779377996155.5168, - "size": 5532 - }, - "assets/fonts/files/source-code-pro-greek-700-normal.woff2": { - "mtime": 1779377996156.5166, - "size": 5528 - }, - "assets/fonts/files/source-code-pro-greek-ext-400-normal.woff2": { - "mtime": 1779377996157.5166, - "size": 1852 - }, - "assets/fonts/files/source-code-pro-greek-ext-500-normal.woff2": { - "mtime": 1779377996158.5164, - "size": 1856 - }, - "assets/fonts/files/source-code-pro-greek-ext-600-normal.woff2": { - "mtime": 1779377996159.5183, - "size": 1868 - }, - "assets/fonts/files/source-code-pro-greek-ext-700-normal.woff2": { - "mtime": 1779377996160.6191, - "size": 1824 - }, - "assets/fonts/files/source-code-pro-latin-400-normal.woff2": { - "mtime": 1779377996160.6191, - "size": 11656 - }, - "assets/fonts/files/source-code-pro-latin-500-normal.woff2": { - "mtime": 1779377996161.619, - "size": 11604 - }, - "assets/fonts/files/source-code-pro-latin-600-normal.woff2": { - "mtime": 1779377996163.6172, - "size": 11628 - }, - "assets/fonts/files/source-code-pro-latin-700-normal.woff2": { - "mtime": 1779377996163.6172, - "size": 11540 - }, - "assets/fonts/files/source-code-pro-latin-ext-400-normal.woff2": { - "mtime": 1779377996165.6191, - "size": 17748 - }, - "assets/fonts/files/source-code-pro-latin-ext-500-normal.woff2": { - "mtime": 1779377996166.6196, - "size": 17752 - }, - "assets/fonts/files/source-code-pro-latin-ext-600-normal.woff2": { - "mtime": 1779377996167.6196, - "size": 17640 - }, - "assets/fonts/files/source-code-pro-latin-ext-700-normal.woff2": { - "mtime": 1779377996168.6196, - "size": 17644 - }, - "assets/fonts/files/source-code-pro-vietnamese-400-normal.woff2": { - "mtime": 1779377996169.619, - "size": 4752 - }, - "assets/fonts/files/source-code-pro-vietnamese-500-normal.woff2": { - "mtime": 1779377996170.1245, - "size": 4804 - }, - "assets/fonts/files/source-code-pro-vietnamese-600-normal.woff2": { - "mtime": 1779377996171.1304, - "size": 4704 - }, - "assets/fonts/files/source-code-pro-vietnamese-700-normal.woff2": { - "mtime": 1779377996172.1353, - "size": 4748 - }, - "assets/fonts/geologica.css": { - "mtime": 1779377996172.1353, - "size": 5047 - }, - "assets/fonts/merriweather.css": { - "mtime": 1779377996173.1355, - "size": 5119 - }, - "assets/fonts/mono.css": { - "mtime": 1779377996174.135, - "size": 11463 - }, - "assets/index/ava-bg-1.png": { - "mtime": 1776187876634.7048, - "size": 1279764 - }, - "assets/index/ava-bg-1.webp": { - "mtime": 1777054556943, - "size": 81378 - }, - "assets/index/me-transparentBG-1.png": { - "mtime": 1776189627628.54, - "size": 1011694 - }, - "assets/index/me-transparentBG-1.webp": { - "mtime": 1777054557058, - "size": 141834 - }, - "assets/index/me_motion.mp4": { - "mtime": 1777636422897.9202, - "size": 311169 - }, - "assets/index/me_motion.webm": { - "mtime": 1777636422899.8853, - "size": 215347 - }, - "assets/index/me_motion.webp": { - "mtime": 1777636422902.3997, - "size": 79376 - }, - "assets/index/me_static.png": { - "mtime": 1777636422916.1433, - "size": 1592317 - }, - "assets/index/me_static.webp": { - "mtime": 1777636422917.152, - "size": 141572 - }, - "assets/lunacy/.gitkeep": { - "mtime": 1779377996175.1355, - "size": 2 - }, - "assets/lunacy/blob_settings_on_canvas.png": { - "mtime": 1779377996193.6858, - "size": 185060 - }, - "assets/lunacy/blob_settings_on_canvas.webp": { - "mtime": 1779377996194.6858, - "size": 48762 - }, - "assets/lunacy/blob_settings_panel_v1.png": { - "mtime": 1779377996195.6848, - "size": 16000 - }, - "assets/lunacy/blob_settings_panel_v1.webp": { - "mtime": 1779377996196.6843, - "size": 6868 - }, - "assets/lunacy/blob_settings_panel_v2.png": { - "mtime": 1779377996196.6843, - "size": 13903 - }, - "assets/lunacy/blob_settings_panel_v2.webp": { - "mtime": 1779377996197.6863, - "size": 4308 - }, - "assets/lunacy/blob_settings_panel_v3.png": { - "mtime": 1779377996197.6863, - "size": 20852 - }, - "assets/lunacy/blob_settings_panel_v3.webp": { - "mtime": 1779377996198.6855, - "size": 9948 - }, - "assets/lunacy/blob_settings_panel_v4.png": { - "mtime": 1779377996198.6855, - "size": 15539 - }, - "assets/lunacy/blob_settings_panel_v4.webp": { - "mtime": 1779377996199.6868, - "size": 3930 - }, - "assets/lunacy/blob_settings_panel_v5.png": { - "mtime": 1779377996200.7917, - "size": 14378 - }, - "assets/lunacy/blob_settings_panel_v5.webp": { - "mtime": 1779377996200.7917, - "size": 3864 - }, - "assets/lunacy/blob_settings_panel_v6.png": { - "mtime": 1779377996201.7903, - "size": 14869 - }, - "assets/lunacy/blob_settings_panel_v6.webp": { - "mtime": 1779377996202.7896, - "size": 4080 - }, - "assets/lunacy/blob_settings_panel_v7.png": { - "mtime": 1779377996202.7896, - "size": 23381 - }, - "assets/lunacy/blob_settings_panel_v7.webp": { - "mtime": 1779377996203.7908, - "size": 7690 - }, - "assets/lunacy/blob_settings_panel_v8.png": { - "mtime": 1779377996204.7915, - "size": 15387 - }, - "assets/lunacy/blob_settings_panel_v8.webp": { - "mtime": 1779377996204.7915, - "size": 4542 - }, - "assets/lunacy/blob_settings_panel_v9.png": { - "mtime": 1779377996205.7905, - "size": 18344 - }, - "assets/lunacy/blob_settings_panel_v9.webp": { - "mtime": 1779377996206.7903, - "size": 8820 - }, - "assets/lunacy/compare_components_modal_window.png": { - "mtime": 1779377996207.7922, - "size": 103262 - }, - "assets/lunacy/compare_components_modal_window.webp": { - "mtime": 1779377996208.7913, - "size": 23548 - }, - "assets/lunacy/components_update_indicator_location_panel.png": { - "mtime": 1779377996210.2961, - "size": 75843 - }, - "assets/lunacy/components_update_indicator_location_panel.webp": { - "mtime": 1779377996211.3025, - "size": 24570 - }, - "assets/lunacy/cover.webp": { - "mtime": 1779377996212.307, - "size": 198532 - }, - "assets/lunacy/Lunacy_app_overview.png": { - "mtime": 1779377996188.6538, - "size": 1304403 - }, - "assets/lunacy/Lunacy_app_overview.webp": { - "mtime": 1779377996191.6865, - "size": 198532 - }, - "assets/lunacy/modal_window_for_prototype_create_on_canvas.png": { - "mtime": 1779377996218.308, - "size": 699587 - }, - "assets/lunacy/modal_window_for_prototype_create_on_canvas.webp": { - "mtime": 1779377996219.8125, - "size": 114986 - }, - "assets/lunacy/modal_window_for_prototype_panel_states.png": { - "mtime": 1779377996221.818, - "size": 163537 - }, - "assets/lunacy/modal_window_for_prototype_panel_states.webp": { - "mtime": 1779377996222.8186, - "size": 67292 - }, - "assets/lunacy/shadow_pro_settings_ideas.png": { - "mtime": 1779377996224.3208, - "size": 150278 - }, - "assets/lunacy/shadow_pro_settings_ideas.webp": { - "mtime": 1779377996225.3252, - "size": 41824 - }, - "assets/lunacy/shadow_pro_settings_modal_auto-off.png": { - "mtime": 1779377996227.3298, - "size": 149676 - }, - "assets/lunacy/shadow_pro_settings_modal_auto-off.webp": { - "mtime": 1779377996228.329, - "size": 20878 - }, - "assets/lunacy/shadow_pro_settings_modal_auto_on.png": { - "mtime": 1779377996229.8337, - "size": 133884 - }, - "assets/lunacy/shadow_pro_settings_modal_auto_on.webp": { - "mtime": 1779377996230.84, - "size": 20552 - }, - "assets/lunacy/shadow_pro_settings_panel.png": { - "mtime": 1779377996232.8403, - "size": 175508 - }, - "assets/lunacy/shadow_pro_settings_panel.webp": { - "mtime": 1779377996233.8416, - "size": 64304 - }, - "assets/lunacy/sliders_all_set.png": { - "mtime": 1779377996260.5515, - "size": 653520 - }, - "assets/lunacy/sliders_all_set.webp": { - "mtime": 1779377996261.5532, - "size": 82004 - }, - "assets/lunacy/slider_14.png": { - "mtime": 1779377996233.8416, - "size": 15296 - }, - "assets/lunacy/slider_14.webp": { - "mtime": 1779377996234.8418, - "size": 6104 - }, - "assets/lunacy/slider_v1.png": { - "mtime": 1779377996235.8403, - "size": 11997 - }, - "assets/lunacy/slider_v1.webp": { - "mtime": 1779377996235.8403, - "size": 4894 - }, - "assets/lunacy/slider_v10.png": { - "mtime": 1779377996236.8413, - "size": 16438 - }, - "assets/lunacy/slider_v10.webp": { - "mtime": 1779377996237.8428, - "size": 5316 - }, - "assets/lunacy/slider_v11.png": { - "mtime": 1779377996237.8428, - "size": 15713 - }, - "assets/lunacy/slider_v11.webp": { - "mtime": 1779377996238.8408, - "size": 5264 - }, - "assets/lunacy/slider_v12.png": { - "mtime": 1779377996239.8408, - "size": 16355 - }, - "assets/lunacy/slider_v12.webp": { - "mtime": 1779377996239.8408, - "size": 5236 - }, - "assets/lunacy/slider_v13.png": { - "mtime": 1779377996240.93, - "size": 16412 - }, - "assets/lunacy/slider_v13.webp": { - "mtime": 1779377996240.93, - "size": 4780 - }, - "assets/lunacy/slider_v15.png": { - "mtime": 1779377996241.9312, - "size": 16438 - }, - "assets/lunacy/slider_v15.webp": { - "mtime": 1779377996241.9312, - "size": 5316 - }, - "assets/lunacy/slider_v16.png": { - "mtime": 1779377996242.932, - "size": 16992 - }, - "assets/lunacy/slider_v16.webp": { - "mtime": 1779377996242.932, - "size": 5042 - }, - "assets/lunacy/slider_v17.png": { - "mtime": 1779377996243.93, - "size": 14273 - }, - "assets/lunacy/slider_v17.webp": { - "mtime": 1779377996244.9321, - "size": 4370 - }, - "assets/lunacy/slider_v18.png": { - "mtime": 1779377996244.9321, - "size": 15153 - }, - "assets/lunacy/slider_v18.webp": { - "mtime": 1779377996245.9304, - "size": 5138 - }, - "assets/lunacy/slider_v2.png": { - "mtime": 1779377996245.9304, - "size": 12918 - }, - "assets/lunacy/slider_v2.webp": { - "mtime": 1779377996246.9302, - "size": 5676 - }, - "assets/lunacy/slider_v3.png": { - "mtime": 1779377996247.9326, - "size": 24683 - }, - "assets/lunacy/slider_v3.webp": { - "mtime": 1779377996247.9326, - "size": 6056 - }, - "assets/lunacy/slider_v4.png": { - "mtime": 1779377996249.4392, - "size": 21075 - }, - "assets/lunacy/slider_v4.webp": { - "mtime": 1779377996250.448, - "size": 5806 - }, - "assets/lunacy/slider_v5.png": { - "mtime": 1779377996251.4482, - "size": 13119 - }, - "assets/lunacy/slider_v5.webp": { - "mtime": 1779377996251.4482, - "size": 5512 - }, - "assets/lunacy/slider_v6.png": { - "mtime": 1779377996252.4485, - "size": 15467 - }, - "assets/lunacy/slider_v6.webp": { - "mtime": 1779377996252.4485, - "size": 4526 - }, - "assets/lunacy/slider_v7.png": { - "mtime": 1779377996253.4475, - "size": 15261 - }, - "assets/lunacy/slider_v7.webp": { - "mtime": 1779377996254.446, - "size": 5300 - }, - "assets/lunacy/slider_v8.png": { - "mtime": 1779377996254.446, - "size": 15432 - }, - "assets/lunacy/slider_v8.webp": { - "mtime": 1779377996255.4485, - "size": 4910 - }, - "assets/lunacy/slider_v9.png": { - "mtime": 1779377996256.447, - "size": 17093 - }, - "assets/lunacy/slider_v9.webp": { - "mtime": 1779377996256.447, - "size": 5676 - }, - "assets/mamadaevv_resume.pdf": { - "mtime": 1780575571973.1184, - "size": 160205 - }, - "assets/manu-game-maker/.gitkeep": { - "mtime": 1779377996263.5508, - "size": 2 - }, - "assets/manu-game-maker/cover.png": { - "mtime": 1779377996266.5527, - "size": 483251 - }, - "assets/manu-game-maker/cover.webp": { - "mtime": 1779377996268.5513, - "size": 94600 - }, - "assets/misc/dribbble_logo.png": { - "mtime": 1780407662552.718, - "size": 794904 - }, - "assets/misc/dribbble_logo.webp": { - "mtime": 1780407662555.7188, - "size": 16768 - }, - "assets/misc/figma_logo.jpg": { - "mtime": 1780407662557.7192, - "size": 10883 - }, - "assets/misc/figma_logo.webp": { - "mtime": 1780407662559.719, - "size": 5108 - }, - "assets/misc/tg-channel-logo-design_not_pizza.jpg": { - "mtime": 1780407662562.7192, - "size": 48308 - }, - "assets/misc/tg-channel-logo-design_not_pizza.webp": { - "mtime": 1780407662564.7183, - "size": 23598 - }, - "assets/mobile-clinic-app/.gitkeep": { - "mtime": 1779377996270.7036, - "size": 2 - }, - "assets/mobile-clinic-app/cover.png": { - "mtime": 1779377996275.6907, - "size": 626518 - }, - "assets/mobile-clinic-app/cover.webp": { - "mtime": 1779377996277.6917, - "size": 121088 - }, - "assets/obsidian-plugin-columns-view/filter use.mp4": { - "mtime": 1782054448519.579, - "size": 36000629 - }, - "assets/obsidian-plugin-columns-view/filter use.webm": { - "mtime": 1782054874042.0066, - "size": 4117727 - }, - "assets/obsidian-plugin-columns-view/filter use.webp": { - "mtime": 1782054874401.6035, - "size": 82876 - }, - "assets/obsidian-plugin-columns-view/overview.png": { - "mtime": 1782055820170.6465, - "size": 358265 - }, - "assets/obsidian-plugin-columns-view/overview.webp": { - "mtime": 1782057055802, - "size": 199104 - }, - "assets/obsidian-plugin-columns-view/view configure.mp4": { - "mtime": 1782054318526.4917, - "size": 41097403 - }, - "assets/obsidian-plugin-columns-view/view configure.webm": { - "mtime": 1782054960161.7544, - "size": 2104173 - }, - "assets/obsidian-plugin-columns-view/view configure.webp": { - "mtime": 1782054960408.1843, - "size": 69110 - }, - "assets/orc-primo-rpa/cover.webp": { - "mtime": 1780407662568.7195, - "size": 42848 - }, - "assets/orc-primo-rpa/projects--table-new.png": { - "mtime": 1780407662571.719, - "size": 86822 - }, - "assets/orc-primo-rpa/projects--table-new.webp": { - "mtime": 1780407662572.718, - "size": 42848 - }, - "assets/orc-primo-rpa/projects--table-old.png": { - "mtime": 1780407662575.226, - "size": 139826 - }, - "assets/orc-primo-rpa/projects--table-old.webp": { - "mtime": 1780407662577.2327, - "size": 78910 - }, - "assets/README.md": { - "mtime": 1779377996027.13, - "size": 843 - }, - "assets/shared/icons/arrow_upright.svg": { - "mtime": 1776362143026.8838, - "size": 1215 - }, - "assets/shared/icons/chat_start.svg": { - "mtime": 1776193642521.755, - "size": 3485 - }, - "assets/shared/icons/checkmark.svg": { - "mtime": 1776422601550.154, - "size": 767 - }, - "assets/shared/icons/close.svg": { - "mtime": 1776857552773.9846, - "size": 407 - }, - "assets/shared/icons/copy.svg": { - "mtime": 1776352846992.719, - "size": 1418 - }, - "assets/shared/icons/cv.svg": { - "mtime": 1776514945920.6653, - "size": 2492 - }, - "assets/shared/icons/delete.svg": { - "mtime": 1779377996278.6897, - "size": 1486 - }, - "assets/shared/icons/design_edit.svg": { - "mtime": 1776193642520.2417, - "size": 5473 - }, - "assets/shared/icons/email.svg": { - "mtime": 1776362122606.4749, - "size": 1589 - }, - "assets/shared/icons/link_url.svg": { - "mtime": 1780407662580.2358, - "size": 1525 - }, - "assets/shared/icons/moon.svg": { - "mtime": 1776193642519.029, - "size": 1090 - }, - "assets/shared/icons/original_size.svg": { - "mtime": 1776857547534.4807, - "size": 2382 - }, - "assets/shared/icons/portfolio.svg": { - "mtime": 1776515141309.182, - "size": 1352 - }, - "assets/shared/icons/shevron-down.svg": { - "mtime": 1777636422918.6008, - "size": 1222 - }, - "assets/shared/icons/shevron-left.svg": { - "mtime": 1777636422919.6145, - "size": 1207 - }, - "assets/shared/icons/shevron-right.svg": { - "mtime": 1777636422919.6145, - "size": 1209 - }, - "assets/shared/icons/shevron-up.svg": { - "mtime": 1777636422921.079, - "size": 1208 - }, - "assets/shared/icons/sun.svg": { - "mtime": 1776193642517.9954, - "size": 4326 - }, - "assets/shared/icons/system.svg": { - "mtime": 1776193642519.029, - "size": 2249 - }, - "assets/shared/icons/tg.svg": { - "mtime": 1776362122602.7698, - "size": 1373 - }, - "assets/shared/icons/vk.svg": { - "mtime": 1776362122605.4763, - "size": 615 - }, - "assets/shared/icons/write_me.svg": { - "mtime": 1777030666208.4812, - "size": 3077 - }, - "assets/shared/icons/yandex_telemost.svg": { - "mtime": 1776362122604.4692, - "size": 572 - }, - "assets/shared/icons/zoom_in.svg": { - "mtime": 1776856548780.6626, - "size": 1953 - }, - "assets/shared/icons/zoom_out.svg": { - "mtime": 1776856548780.6626, - "size": 1592 - }, - "assets/shared/icons/zoom_to_fit.svg": { - "mtime": 1779377996280.203, - "size": 1248 - }, - "assets/shared/icons/сookie.svg": { - "mtime": 1776607984487.0112, - "size": 3508 - }, - "assets/shared/placeholder.jpg": { - "mtime": 1777053044955.2012, - "size": 34829 - }, - "assets/shared/placeholder.webp": { - "mtime": 1780407662581.2354, - "size": 240 - }, - "assets/task-distribution-concept/.gitkeep": { - "mtime": 1779377996281.21, - "size": 2 - }, - "assets/task-distribution-concept/cover.png": { - "mtime": 1779377996284.209, - "size": 197021 - }, - "assets/task-distribution-concept/cover.webp": { - "mtime": 1779377996286.2097, - "size": 81646 - }, - "assets/task-tracker/actions_for_page.png": { - "mtime": 1724892346000, - "size": 25027 - }, - "assets/task-tracker/actions_for_page.webp": { - "mtime": 1777119492700, - "size": 23404 - }, - "assets/task-tracker/cover.webp": { - "mtime": 1779377996288.2092, - "size": 151720 - }, - "assets/task-tracker/dark_theme.png": { - "mtime": 1724892366000, - "size": 291518 - }, - "assets/task-tracker/dark_theme.webp": { - "mtime": 1777119492957, - "size": 147348 - }, - "assets/task-tracker/drag-drop-action_example.mp4": { - "mtime": 1776793076285.7869, - "size": 2095990 - }, - "assets/task-tracker/drag-drop-action_example.webm": { - "mtime": 1777118933364.2495, - "size": 147445 - }, - "assets/task-tracker/drag-drop-action_example.webp": { - "mtime": 1777118933542.3682, - "size": 3604 - }, - "assets/task-tracker/drag-drop-item_board-view.mp4": { - "mtime": 1724892358000, - "size": 1784143 - }, - "assets/task-tracker/drag-drop-item_board-view.webm": { - "mtime": 1777118939415.8855, - "size": 232186 - }, - "assets/task-tracker/drag-drop-item_board-view.webp": { - "mtime": 1777118939601.6213, - "size": 27548 - }, - "assets/task-tracker/drag-drop-item_list-view.mp4": { - "mtime": 1724892360000, - "size": 2886192 - }, - "assets/task-tracker/drag-drop-item_list-view.webm": { - "mtime": 1777118960260.8003, - "size": 331393 - }, - "assets/task-tracker/drag-drop-item_list-view.webp": { - "mtime": 1777118960514.3586, - "size": 27766 - }, - "assets/task-tracker/dropdown_menu_for_views.png": { - "mtime": 1724892346000, - "size": 75360 - }, - "assets/task-tracker/dropdown_menu_for_views.webp": { - "mtime": 1777119493007, - "size": 64398 - }, - "assets/task-tracker/expand-collapse_group.mp4": { - "mtime": 1724892356000, - "size": 1663390 - }, - "assets/task-tracker/expand-collapse_group.webm": { - "mtime": 1777118977581.77, - "size": 196247 - }, - "assets/task-tracker/expand-collapse_group.webp": { - "mtime": 1777118977813.5178, - "size": 27750 - }, - "assets/task-tracker/full_preview.mp4": { - "mtime": 1776877975221.4644, - "size": 2480939 - }, - "assets/task-tracker/full_preview.webm": { - "mtime": 1777119206780.3667, - "size": 1852963 - }, - "assets/task-tracker/full_preview.webp": { - "mtime": 1777119207226.3965, - "size": 31316 - }, - "assets/task-tracker/light_theme_color.png": { - "mtime": 1724892364000, - "size": 555991 - }, - "assets/task-tracker/light_theme_color.webp": { - "mtime": 1777119493297, - "size": 164962 - }, - "assets/task-tracker/refs.png": { - "mtime": 1776792419154.0342, - "size": 1779282 - }, - "assets/task-tracker/refs.webp": { - "mtime": 1777119493506, - "size": 225610 - }, - "assets/task-tracker/tabs.mp4": { - "mtime": 1776792488669.555, - "size": 4908318 - }, - "assets/task-tracker/tabs.webm": { - "mtime": 1777119316281.4424, - "size": 804022 - }, - "assets/task-tracker/tabs.webp": { - "mtime": 1777119316704.9702, - "size": 31082 - }, - "assets/task-tracker/tab_all-tasks.png": { - "mtime": 1724892344000, - "size": 285868 - }, - "assets/task-tracker/tab_all-tasks.webp": { - "mtime": 1777119493851, - "size": 151720 - }, - "assets/task-tracker/tab_my-tasks.png": { - "mtime": 1724892344000, - "size": 232690 - }, - "assets/task-tracker/tab_my-tasks.webp": { - "mtime": 1777119494176, - "size": 118694 - }, - "assets/task-tracker/tab_tasks-by-assign.png": { - "mtime": 1724892344000, - "size": 283151 - }, - "assets/task-tracker/tab_tasks-by-assign.webp": { - "mtime": 1777119494494, - "size": 147370 - }, - "assets/task-tracker/views.mp4": { - "mtime": 1776792546358.3933, - "size": 3655835 - }, - "assets/task-tracker/views.webm": { - "mtime": 1777119348131.017, - "size": 588868 - }, - "assets/task-tracker/views.webp": { - "mtime": 1777119348524.0642, - "size": 30412 - }, - "assets/task-tracker/view_board.png": { - "mtime": 1724892346000, - "size": 285868 - }, - "assets/task-tracker/view_board.webp": { - "mtime": 1777119494790, - "size": 151720 - }, - "assets/task-tracker/view_list.png": { - "mtime": 1724892350000, - "size": 281726 - }, - "assets/task-tracker/view_list.webp": { - "mtime": 1777119495084, - "size": 153030 - }, - "assets/task-tracker/view_table.png": { - "mtime": 1724892354000, - "size": 306629 - }, - "assets/task-tracker/view_table.webp": { - "mtime": 1777119495385, - "size": 159062 - }, - "assets/template-elements-demo/hello.gif": { - "mtime": 1713970676235.8618, - "size": 1445905 - }, - "assets/template-elements-demo/img-long.png": { - "mtime": 1779377996303.2358, - "size": 1430322 - }, - "assets/template-elements-demo/img-long.webp": { - "mtime": 1779377996305.2405, - "size": 134456 - }, - "assets/template-elements-demo/small-image-1.png": { - "mtime": 1779377996307.2373, - "size": 127198 - }, - "assets/template-elements-demo/small-image-1.webp": { - "mtime": 1779377996307.2373, - "size": 6676 - }, - "assets/template-elements-demo/small-image-2.png": { - "mtime": 1779377996309.7412, - "size": 220181 - }, - "assets/template-elements-demo/small-image-2.webp": { - "mtime": 1779377996309.7412, - "size": 9214 - }, - "assets/template-elements-demo/small-image-3.png": { - "mtime": 1779377996312.7493, - "size": 330973 - }, - "assets/template-elements-demo/small-image-3.webp": { - "mtime": 1779377996313.7478, - "size": 19430 - }, - "assets/template-elements-demo/small-image-4.png": { - "mtime": 1779377996314.7488, - "size": 211288 - }, - "assets/template-elements-demo/small-image-4.webp": { - "mtime": 1779377996315.7507, - "size": 11306 - }, - "assets/template-elements-demo/small-image-5.png": { - "mtime": 1779377996317.748, - "size": 249941 - }, - "assets/template-elements-demo/small-image-5.webp": { - "mtime": 1779377996318.7485, - "size": 15056 - }, - "assets/template-elements-demo/small-image-6.png": { - "mtime": 1779377996319.7495, - "size": 161762 - }, - "assets/template-elements-demo/small-image-6.webp": { - "mtime": 1779377996320.861, - "size": 8470 - }, - "assets/template-elements-demo/small-image-7.png": { - "mtime": 1779377996322.8584, - "size": 196080 - }, - "assets/template-elements-demo/small-image-7.webp": { - "mtime": 1779377996323.8606, - "size": 7832 - }, - "assets/template-elements-demo/video-1.mp4": { - "mtime": 1774365295973.9094, - "size": 3676034 - }, - "assets/template-elements-demo/video-1.webm": { - "mtime": 1777119460084.1753, - "size": 3490147 - }, - "assets/template-elements-demo/video-1.webp": { - "mtime": 1777119460340.927, - "size": 112702 - }, - "assets/template-elements-demo/wallpaper-1.jpg": { - "mtime": 1770206903718.8467, - "size": 1011262 - }, - "assets/template-elements-demo/wallpaper-1.webp": { - "mtime": 1777119432828, - "size": 795944 - }, - "cases/ai-platform-primo-rpa-2.html": { - "mtime": 1782245252136.977, - "size": 56010 - }, - "cases/ai-platform-primo-rpa.html": { - "mtime": 1782245252138.9834, - "size": 65300 - }, - "cases/design-system.html": { - "mtime": 1782245252140.9756, - "size": 51499 - }, - "cases/lunacy.html": { - "mtime": 1782245252140.9756, - "size": 51520 - }, - "cases/manu-game-maker.html": { - "mtime": 1782245252142.1548, - "size": 33426 - }, - "cases/mini-projects-showcase.html": { - "mtime": 1782245252144.1592, - "size": 45596 - }, - "cases/mobile-clinic-app.html": { - "mtime": 1782245252145.1597, - "size": 33340 - }, - "cases/obsidian-plugin-columns-view.html": { - "mtime": 1782245252145.1597, - "size": 34314 - }, - "cases/orc-automation-panel.html": { - "mtime": 1782245252146.161, - "size": 48044 - }, - "cases/task-distribution-concept.html": { - "mtime": 1782245252147.1592, - "size": 33330 - }, - "cases/task-tracker.html": { - "mtime": 1782245252149.1597, - "size": 66746 - }, - "cases/template-elements-demo.html": { - "mtime": 1782245252150.16, - "size": 47480 - }, - "cookie-policy.html": { - "mtime": 1782245252151.1606, - "size": 20265 - }, - "css/main.css": { - "mtime": 1782122516629.0486, - "size": 129130 - }, - "index.html": { - "mtime": 1782245252151.1606, - "size": 69045 - }, - "js/main.js": { - "mtime": 1780407662602.799, - "size": 2804 - }, - "js/modules/cases/image-viewer.js": { - "mtime": 1780407662603.8, - "size": 13683 - }, - "js/modules/cases/natural-image-size.js": { - "mtime": 1777287125125.0857, - "size": 625 - }, - "js/modules/cases/sequential-images.js": { - "mtime": 1779377996345.018, - "size": 1224 - }, - "js/modules/cases/tall-media-expand.js": { - "mtime": 1779377996345.018, - "size": 1861 - }, - "js/modules/cases/video-player.js": { - "mtime": 1779377996347.0156, - "size": 1095 - }, - "js/modules/experience/expand.js": { - "mtime": 1777287125125.0857, - "size": 3993 - }, - "js/modules/experience/hover-glow.js": { - "mtime": 1777636422925.3562, - "size": 912 - }, - "js/modules/experience/masonry.js": { - "mtime": 1780407662605.8008, - "size": 2916 - }, - "js/modules/header/header-scroll.js": { - "mtime": 1779377996348.017, - "size": 4328 - }, - "js/modules/header/nav-overflow.js": { - "mtime": 1777287125117.0547, - "size": 5621 - }, - "js/modules/mini-projects/expand.js": { - "mtime": 1780407662607.4187, - "size": 4418 - }, - "js/modules/mini-projects/masonry.js": { - "mtime": 1782122516632.0474, - "size": 5036 - }, - "js/modules/shared/dom.js": { - "mtime": 1777287125128.091, - "size": 221 - }, - "js/modules/shared/image-src.js": { - "mtime": 1780407662612.4294, - "size": 214 - }, - "js/modules/shared/math.js": { - "mtime": 1777287125125.0857, - "size": 161 - }, - "js/modules/shared/media.js": { - "mtime": 1777287125117.0547, - "size": 645 - }, - "js/modules/shared/schedule-idle.js": { - "mtime": 1779377996348.017, - "size": 457 - }, - "js/modules/theme/theme-controls.js": { - "mtime": 1779377996349.5276, - "size": 6205 - }, - "js/modules/theme/theme-core.js": { - "mtime": 1782122516625.0393, - "size": 4885 - }, - "js/modules/theme/theme-fonts.js": { - "mtime": 1779377996352.5422, - "size": 1147 - }, - "js/modules/ui/contact-copy.js": { - "mtime": 1777287125128.091, - "size": 1793 - }, - "js/modules/ui/content-edit/content-edit-dock.js": { - "mtime": 1779377996353.5432, - "size": 9560 - }, - "js/modules/ui/content-edit/content-edit-mode.js": { - "mtime": 1779377996355.5415, - "size": 11767 - }, - "js/modules/ui/content-edit/content-edit-storage.js": { - "mtime": 1779377996355.5415, - "size": 868 - }, - "js/modules/ui/content-edit/content-edit-target.js": { - "mtime": 1779377996357.5415, - "size": 9573 - }, - "js/modules/ui/cookie-notice.js": { - "mtime": 1779377996357.5415, - "size": 923 - }, - "js/modules/ui/deferred-media.js": { - "mtime": 1779377996358.5417, - "size": 470 - }, - "js/modules/ui/hero-motion-video.js": { - "mtime": 1782244713466.1138, - "size": 1004 - }, - "js/modules/ui/hero-word-slot.js": { - "mtime": 1777287125117.0547, - "size": 3717 - }, - "js/modules/ui/image-load-placeholder.js": { - "mtime": 1780407662613.426, - "size": 2435 - }, - "js/modules/ui/mesh-panel.js": { - "mtime": 1779377996360.0525, - "size": 859 - }, - "js/modules/ui/page-mesh-bg.js": { - "mtime": 1779377996361.0547, - "size": 3216 - }, - "js/modules/ui/primary-button-shine.js": { - "mtime": 1777287125118.0613, - "size": 952 - }, - "js/modules/ui/projects-carousel.js": { - "mtime": 1779377996362.0613, - "size": 6390 - }, - "js/modules/ui/skills-accordion.js": { - "mtime": 1778061201791.5735, - "size": 5099 - }, - "js/modules/ui/skills-intro.js": { - "mtime": 1780407662615.4253, - "size": 1983 - }, - "js/skill-connectors.js": { - "mtime": 1776439133838.0786, - "size": 12132 - }, - "README.md": { - "mtime": 1777051804851.6003, - "size": 1363 - }, - "vendor/plyr/plyr.css": { - "mtime": 1779377996364.0625, - "size": 32455 - }, - "vendor/plyr/plyr.min.mjs": { - "mtime": 1779377996366.0618, - "size": 121675 - } -} \ No newline at end of file diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 8236a53..0000000 --- a/.dockerignore +++ /dev/null @@ -1,10 +0,0 @@ -node_modules -.git -.gitignore -Dockerfile -Dockerfile.dev -.dockerignore -*.log -.cache -.deploy-manifest.json -.cursor diff --git a/.gitignore b/.gitignore index 784bae0..98c2777 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ coverage/ !.cursor/commands/ !.cursor/commands/** .vscode/ +.zed/ gitverse/ # Logs diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..2bd5a0a --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +22 diff --git a/AGENTS.md b/AGENTS.md index 170afb3..d99309d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,27 +1,18 @@ # Подсказки для агента (Cursor) -## GitVerse / деплой статики +## Сборка и деплой -Полный чеклист: **`docs/gitverse-sync.md`** → раздел **«Инструкция для агента (Cursor)»**. +Деплой автоматический: пуш в git → автодеплой на хостинг. -Деплой на VPS: **`docs/vps-deploy.md`**. +По запросу пользователя «собрать», «билд»: -Кратко по запросу пользователя «выложить на GitVerse», «синк gitverse», «задеплоить»: +1. При правках `src/pages/**` или `src/partials/**` — `npm run build:pages`. +2. При смене шрифтов/Plyr или `package.json` — `npm run build` (включает `vendor:copy`). +3. Для деплоя — сделать git commit + push. -1. При правках `src/pages/**` или `src/partials/**` — `npm run build:pages`; при смене шрифтов/Plyr или `package.json` — `npm run build` (включает `vendor:copy`). -2. Затем `npm run sync-gitverse` (разрешения **network** и **git_write**). -3. Не запускать синк без явного запроса пользователя. +## Git -По запросу «задеплой в Coolify», «задеплой на VPS»: - -1. При правках в `public/` — `npm run deploy:vps` (разрешения **all**). -2. По запросу «задеплой везде» — `npm run deploy` (VPS + GitVerse). - -Не запускать деплой на VPS без явного запроса: скрипт перезаписывает `/data/static-site` на сервере. - -## Git: корневой репозиторий - -Этот репозиторий в корне проекта **только локальный** (рабочая копия, история коммитов для себя). **Не добавлять `origin` и не пушить** в удалённый репозиторий из агента, если пользователь явно не попросил настроить remote и не дал URL. Выгрузка наружу — отдельный сценарий через **`npm run sync-gitverse`** в папку `gitverse` (см. выше), а не `git push` из корня. +Репозиторий: `http://x1qnvk08zec2u5cx6yh5iexh.155.212.186.39.sslip.io/admin/site-portfolio.git` ### Влить в `master`, оставаясь на текущей ветке @@ -33,9 +24,14 @@ ## Design System -Страница-каталог: **`src/pages/cases/design-system.html`** → после сборки `public/cases/design-system.html`. +Перед работой с UI **прочитай `DESIGN.md`** в корне проекта — там описаны токены, типографика, компоненты и правила их применения. -При **глобальных** правках стилей (токены в `public/css/main.css`, компоненты главной, блоки лонгрида кейса) **обновляй Design System**: живой пример и краткое описание в соответствующей секции, при необходимости — `docs/case-page-blocks.md`. +Страницы-каталоги (живые примеры): +- **`src/pages/cases/design-system.html`** → токены, типографика, кнопки, карточки, секции +- **`src/pages/cases/template-elements-demo.html`** → элементы лонгрида: медиа, галереи, видео, callout +- **`src/pages/cases/mini-projects-showcase.html`** → карточки активности (mp-card) + +При **глобальных** правках стилей (токены в `public/css/main.css`, компоненты главной, блоки лонгрида кейса) **обновляй соответствующий каталог**: живой пример и краткое описание в секции, при необходимости — `docs/case-page-blocks.md`. ## Контент кейса в public (по запросу) @@ -49,6 +45,18 @@ Режим на странице при `npm run serve` → очередь в **`texts/content-edits/pending.json`**. Apply по запросу **«примени правки»**: читать этот файл, править **`src/pages/`**, **humanizer-ru**, **`npm run build:pages`**; **`pending.json` не очищать** (пользователь удаляет пункты сам). Подробности: **`docs/content-edit-mode.md`**, **`.cursor/rules/content-edit-apply.mdc`**. +## PDF резюме (по запросу) + +По запросу «обнови PDF», «перегенерируй PDF»: + +1. Убедиться, что dev-сервер запущен (`localhost:4175`). +2. Запустить `npm run generate:resume-pdf`. +3. Файл обновится в `public/assets/resume/Mamadaev_Nik__CV__Product_Designer_UX-UI.pdf`. + +Подробнее: **`docs/resume-pdf.md`**. + +Скрипт требует запущенный сервер — нельзя встроить в обычный `build`. + ## Vendor (шрифты, Plyr) Локально в `public/`, без CDN. Обновление: **`docs/vendor-assets.md`**, команда `npm run vendor:copy`. @@ -60,3 +68,15 @@ ## Остальное Правила и таблица доков: **`.cursor/rules/read-docs-before-feature-dev.mdc`** (локально; папка `.cursor/` может быть в `.gitignore`). + +### Ключевые файлы + +| Файл | Назначение | +|---|---| +| `DESIGN.md` | Описание дизайн-системы для AI-агентов | +| `public/css/main.css` | Единый CSS: токены + все компоненты | +| `src/pages/cases/design-system.html` | Живой каталог токенов, типографики, кнопок, карточек | +| `src/pages/cases/template-elements-demo.html` | Элементы лонгрида: медиа, галереи, видео, callout | +| `src/pages/cases/mini-projects-showcase.html` | Карточки активности (mp-card) | +| `docs/case-page-blocks.md` | Инструкция по блокам лонгридов | +| `docs/resume-pdf.md` | Генерация PDF резюме (Puppeteer) | diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index b0cda7b..0000000 --- a/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -# Build the static site and serve it with nginx -FROM node:20-alpine AS build -WORKDIR /app -COPY package*.json ./ -RUN npm install -COPY . . -RUN npm run build:pages - -FROM nginx:alpine -# Fix mjs MIME type — without this plyr.min.mjs fails to load as ES module -RUN sed -i 's|application/javascript *js;|application/javascript js mjs;|' /etc/nginx/mime.types -COPY --from=build /app/public /usr/share/nginx/html -EXPOSE 80 diff --git a/Dockerfile.dev b/Dockerfile.dev deleted file mode 100644 index fab3e9a..0000000 --- a/Dockerfile.dev +++ /dev/null @@ -1,9 +0,0 @@ -# Dev environment: serves public/ with BrowserSync + content-edits API (port 4175) -FROM node:22-slim -WORKDIR /app -COPY package*.json ./ -RUN npm install -COPY . . -RUN npm run build:pages -EXPOSE 4175 -CMD ["npm", "run", "serve"] diff --git a/deploy.sh b/deploy.sh deleted file mode 100644 index 8d0edb5..0000000 --- a/deploy.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash -set -e - -HOST="root@155.212.186.39" -SSH_KEY="$HOME/.ssh/beget" -SRC_DIR="$(cd "$(dirname "$0")" && pwd)/public/" - -echo "📦 Deploy mamadaevv.site..." -echo "Src: $SRC_DIR" - -REMOTE_INFO=$(ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no "$HOST" ' - CONTAINER=$(docker ps --format "{{.Names}}" | grep "s9mrcps8xw02r1dak0fsznix" | head -1) - VOLUME_PATH=$(docker inspect "$CONTAINER" 2>/dev/null | python3 -c " -import sys,json -mounts=json.load(sys.stdin)[0].get(\"Mounts\",[]) -print([m[\"Source\"] for m in mounts if m[\"Destination\"]==\"/usr/share/nginx/html\"][0]) -") - echo "$CONTAINER|$VOLUME_PATH" -') - -IFS='|' read -r CONTAINER VOLUME_PATH <<< "$REMOTE_INFO" -echo "Container: $CONTAINER" -echo "Volume: $VOLUME_PATH" - -# Копируем файлы -cd "$SRC_DIR" -tar cf - . | ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no "$HOST" \ - "tar xf - -C $VOLUME_PATH" - -# Фикс MIME для .mjs (plyr.min.mjs модуль) -ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no "$HOST" \ - "docker exec $CONTAINER sh -c \" - if ! grep -q 'application/javascript mjs' /etc/nginx/mime.types 2>/dev/null; then - sed -i 's|application/wasm|application/javascript mjs;\\n application/wasm|' /etc/nginx/mime.types - nginx -s reload && echo 'MIME fix applied' - fi - \"" 2>/dev/null || true - -echo "" -echo "✅ Done! https://mamadaevv.site" diff --git a/docs/gitverse-sync.md b/docs/gitverse-sync.md deleted file mode 100644 index 06c21ad..0000000 --- a/docs/gitverse-sync.md +++ /dev/null @@ -1,57 +0,0 @@ -# Синхронизация `public` -> `gitverse` - -## Назначение - -Скрипт `sync-gitverse` копирует содержимое `public` в папку `gitverse`, затем выполняет коммит и пуш в репозиторий внутри `gitverse`. - -## Запуск - -- Через npm: - - `npm run sync-gitverse` -- Напрямую: - - `node scripts/sync-gitverse.mjs` -- С явными путями: - - `node scripts/sync-gitverse.mjs ` - -По умолчанию: - -- `sourceDir = public` -- `targetDir = gitverse` - -## Что делает скрипт - -1. Проверяет, что исходная папка существует. -2. В целевой папке удаляет всё, кроме: - - `.git` - - `.gitverse` -3. Копирует содержимое `public` в `gitverse` (файлы `.png` пропускаются — в деплое используются WebP и остальные форматы). -4. В репозитории `gitverse` выполняет: - - `git add .` - - `git commit -m "sync public YYYY-MM-DD HH:mm"` (только если есть изменения) - - `git push` -5. После успешного пуша открывает в системном браузере по умолчанию: `https://mamadaevv.gitverse.site/me/` - -Если изменений после копирования нет, коммит и пуш не делаются. - -## Инструкция для агента (Cursor) - -Когда пользователь просит **выложить на GitVerse**, **собрать/задеплоить gitverse**, **синхронизировать с gitverse** или аналогично: - -1. **Сборка `public/`:** если менялись `src/pages/**` или `src/partials/**` — `npm run build:pages`; если шрифты/Plyr/`package.json` или `scripts/copy-vendor.mjs` — `npm run build` (сначала `vendor:copy`, затем страницы). См. [`docs/vendor-assets.md`](vendor-assets.md). -2. **Синк и пуш:** выполни `npm run sync-gitverse` из корня. Нужны разрешения **network** и **git_write** (SSH на GitVerse, пуш из папки `gitverse`). -3. **Ожидания:** скрипт не копирует файлы `.png` в `gitverse`. После **успешного** `git push` открывается системный браузер с `https://mamadaevv.gitverse.site/me/`. Если изменений в `gitverse` после копирования нет — коммит/пуш не выполняются, браузер не открывается. -4. **Не вызывай** `sync-gitverse` без запроса пользователя: скрипт очищает целевую папку (кроме `.git` и `.gitverse`) и пушит в remote. -5. **Корневой git репозиторий** этого проекта считается **только локальным**: не пушь из корня в `origin` и не настраивай remote без явной просьбы пользователя с URL. Внешняя выкладка — через `gitverse`, не через `git push` в корне. -6. Деплой на VPS — отдельный сценарий, см. **`docs/vps-deploy.md`**. - -Подробности и ограничения — в разделах выше. - -## Требования - -- В `gitverse` уже должен быть инициализирован git-репозиторий (папка `.git`). -- Должен быть настроен доступ на push (SSH-ключ/права). - -## Важно - -- Скрипт удаляет в `gitverse` все файлы и папки, кроме `.git` и `.gitverse`. -- Не запускай скрипт, если в `gitverse` есть локальные несохраненные изменения, которые нужно оставить. \ No newline at end of file diff --git a/docs/local-server.md b/docs/local-server.md index 81f78af..29733a5 100644 --- a/docs/local-server.md +++ b/docs/local-server.md @@ -1,10 +1,11 @@ # Локальный просмотр сайта -Сайт в режиме разработки обслуживается из папки `**public/**` через [BrowserSync](https://browsersync.io/): при изменении файлов страница в браузере обновляется сама. +Сайт в режиме разработки обслуживается из папки `**public/**` через нативный HTTP-сервер (Node.js `http` модуль): статика + API правок контента. ## Требования -- Установлены **Node.js** и **npm** (идут вместе с Node). +- **Node.js 22** (см. `.node-version` в корне проекта). fnm/fvm переключают автоматически. +- **npm** (идёт вместе с Node). ## Первый раз в проекте @@ -23,18 +24,11 @@ npm run vendor:copy npm run serve ``` -Скрипт [`scripts/serve-dev.mjs`](../scripts/serve-dev.mjs): статика из `public/`, API правок контента, перезагрузка **только** при изменениях в `public/**` (запись в `texts/content-edits/` вкладку не перезагружает). - -Без API: `npm run serve:static`. +Скрипт [`scripts/serve-dev.mjs`](../scripts/serve-dev.mjs): статика из `public/`, API правок контента. Нет авто-релиоада — после правок в `public/` обновляй страницу вручную. ## Куда смотреть - **Сайт:** [http://localhost:4175](http://localhost:4175) — откроется `public/index.html` и остальные пути относительно `public/`. -- **Панель BrowserSync UI:** [http://localhost:4176](http://localhost:4176) (опционально, для синхронизации и настроек). - -## Что отслеживается - -Любые изменения в `**public/**`**: HTML, CSS, JS, картинки. Папка `texts/content-edits/` **не** в watch — autosave правок не сбрасывает режим редактирования. ## API правок контента @@ -48,4 +42,4 @@ npm run serve ## Остановка -В терминале: **Ctrl+C**. \ No newline at end of file +В терминале: **Ctrl+C**. diff --git a/docs/resume-pdf.md b/docs/resume-pdf.md new file mode 100644 index 0000000..a54d05c --- /dev/null +++ b/docs/resume-pdf.md @@ -0,0 +1,52 @@ +# PDF резюме + +## Генерация PDF + +Скрипт `scripts/generate-resume-pdf.mjs` открывает `resume-5.html` через Puppeteer, применяет шрифт geologica (PT Sans), убирает подложку/обводку блока `.resume-doc` и сохраняет PDF. + +**Важно**: скрипт требует запущенный dev-сервер (`npm run serve` → `localhost:4175`). + +### Запуск + +```bash +npm run generate:resume-pdf +``` + +или вручную: + +```bash +node scripts/generate-resume-pdf.mjs http://localhost:4175/resume-5.html geologica +``` + +Параметры: +- `[url]` — URL страницы (по умолчанию `http://localhost:4175/resume-5.html`) +- `[font]` — ID шрифта: `geologica`, `merriweather`, `mono` (по умолчанию `geologica`) + +### Выходной файл + +`public/assets/resume/Mamadaev_Nik__CV__Product_Designer_UX-UI.pdf` + +Кнопка «Скачать в PDF» на странице `resume-5.html` — это `` ссылка на этот файл. + +### Когда перегенерировать + +- После правок в `src/pages/resume-5.html` (контент, стили) +- После правок в `src/css/resume-5.css` (инлайн-стили в ` + + + + +
+
+ + +
+
+ +
+
+ + +
+ + + +
+
+ +
+ + +
+
+
+ Николай Мамадаев +
+

Резюме

+

Николай Мамадаев

+

Зерокодер · Продуктовый дизайнер · Ведущий (Lead)

+

Product Designer / Lead Designer

+
+
+ +
+ Калининград, Россия · Удалённо + Телефон: +7 (960) 294-24-05 + Telegram: @mamadaevv + Email: nik@mamadaevv.site + Сайт: mamadaevv.site + Хабр Карьера: career.habr.com/mamadaevv +
+ +
+
+
Стаж
+
10 лет
+
+
+
Возраст
+
36 лет
+
+
+
Готовность к работе
+
готов к удалённой работе
+
+
+
Зарплатные ожидания
+
от 270 000 ₽
+
+
+ +

О себе

+

+ В дизайне я более 10 лет, последние годы занимаюсь продуктовым дизайном. Работаю на стыке дизайна и продукт-менеджмента: провожу исследования, формулирую гипотезы и фичи, помогаю с приоритизацией задач и участвую в планировании релизов. +

+

+ Для работы с дизайном интерфейсов использую Figma: в ней собираю прототипы, экраны и дизайн-системы, а затем передаю макеты в разработку. Собрал приватный плагин на базе ИИ для решения части рутинных задач. +

+

+ Для работы с графикой использую AI-сервисы, когда нужно с нуля создать иллюстрацию, обложку или промо-картинку, а также быстро отредактировать или доработать существующие изображения. +

+

+ Ежедневно использую Perplexity и Hermes как универсальный рабочий инструмент: для ресёрча, идей по продукту и интерфейсам, подготовки текстов, разбора личных задач и работы с собственными данными. +

+ +

Опыт работы

+ +
+
+

Primo RPA

+

UI/UX дизайнер (Ведущий) · Дизайнер графических интерфейсов и проектировщик пользовательского опыта

+

Февраль 2023 — Ноябрь 2025 (2 года и 10 месяцев) · Москва / удалённо

+
+

В настоящее время моя работа охватывает продукты:

+
    +
  • Студия (Windows и Linux) — среда для разработки и отладки роботов для автоматизации бизнес-процессов. Сфера RPA.
  • +
  • Оркестратор (Веб) — обеспечивает слаженную работу системы и управление сотнями роботов: запуск в конкретное время или по определённому сценарию.
  • +
  • Idea Hub (Веб) — обеспечивает сбор и анализ предложений, оценка эффективности и мониторинг статуса реализации задачи. Аналитика по ключевым показателям эффективности и верхнеуровневый взгляд на роботизацию.
  • +
  • AI Server (Веб) — интеллектуальная среда для обучения и использования алгоритмов ИИ в процессах роботизации. Готовый набор моделей для извлечения информации из документов различного типа (Smart OCR).
  • +
+

Среди достижений:

+
    +
  • Компания обновила внешний вид всех продуктов: компоненты стали современнее (в духе Windows 10 и 11), в Linux-версии появилась расширенная библиотека компонентов для фреймворка «Авалония», везде перешли на векторную графику.
  • +
  • В веб-сервисах перешли к единой дизайн-системе, которая сочетает фирменный стиль компании с новой структурой.
  • +
+

Навыки: UI/UX дизайн, Figma Design, Проектирование интерфейсов, Исследование пользователя, Дизайн продукта, Wireframes, Дизайн иконок

+
+ +
+
+

Icons8

+

UI/UX дизайнер

+

Июль 2022 — Январь 2023 (7 месяцев)

+
+
    +
  • Делал дизайн интерфейса для редактора Lunacy. Оформлял в виде юзерфлоу и передавал разработчикам.
  • +
  • Делал сложные прототипы в Protopie.
  • +
  • Отрисовывал недостающие иконки.
  • +
  • Вносил предложения по улучшению функционала программы.
  • +
+

Навыки: UI/UX дизайн, Прототипирование, Проектирование интерфейсов, Figma Design, Дизайн продукта, Дизайн иконок

+
+ +
+
+

MANU Video Game Maker

+

Team Lead Product Team

+

Январь 2019 — Декабрь 2021 (3 года) · Москва

+
+
    +
  • Сделал масштабный редизайн всей программы. Создал интерфейс с абсолютно новой концепцией работы и стилистикой. Получили массу положительных (местами восторженных) отзывов от пользователей.
  • +
  • Спроектировал поведение интерфейса для более чем сотни сложных пользовательских сценариев.
  • +
  • Спроектировал дизайн-систему.
  • +
  • Составил портреты потенциальных пользователей, делал карты эмпатии.
  • +
  • Занимался исследованием пользователей (наблюдение, интервью и опросы).
  • +
  • Работал с аналитикой и сбором продуктовых метрик.
  • +
  • Прособеседовал и набрал в продуктовый отдел новых специалистов. Стал тимлидом отдела.
  • +
  • Сверстал главную страницу сайта на Tilda. Проектировал информационную архитектуру сайта вместе с командой.
  • +
  • Принимал активное участие в построении рабочих процессов всей команды продукта.
  • +
  • Использовал инструменты автоматизации (Integromat, Zapier) для решения внутренних задач.
  • +
  • Курировал работы по созданию пользовательской документации.
  • +
+

Навыки: Построение команды, Agile, UI/UX дизайн, Figma Design, Дизайн продукта, Проектирование интерфейсов, Исследование пользователя

+
+ +
+
+

Серафим

+

UI/UX дизайнер

+

Октябрь 2017 — Декабрь 2018 (1 год и 3 месяца) · Сочи

+
+
    +
  • Занимался разработкой дизайна кроссплатформенного мессенджера для платформ: Android, iOS, MacOS, Windows, Linux.
  • +
  • Контролировал процесс работы с зарубежными иллюстраторами по подготовке графических материалов.
  • +
+

Навыки: UI/UX дизайн, Проектирование интерфейсов, Дизайн мобильных приложений, Прототипирование, Дизайн иконок, Sketch, Арт-директинг, Дизайн лендингов

+
+ +
+
+

Orion Innovation (ex MERA)

+

UI/UX дизайнер

+

Июль 2016 — Октябрь 2017 (1 год и 4 месяца) · Нижний Новгород

+
+
    +
  • Работал в отделе дизайна численностью до 8 человек.
  • +
  • Создавал анкеты персон, составлял карту функциональности продукта.
  • +
  • Делал вайрфрэймы и отрисовывал конечный UI интерфейсов.
  • +
  • Делал демонстрации микроанимаций.
  • +
  • Проектировал юзкейсы и делал карты экранов.
  • +
  • Делал дизайн-концепции, готовил мудборды и презентации для клиентов.
  • +
  • Линковал мокапы в прототипы и проводил качественные юзабилити тестирования.
  • +
  • Осуществлял авторский надзор над реализацией дизайна разработчиками.
  • +
  • Участвовал в дизайн-ревью, вносил предложения по улучшениям.
  • +
  • Напрямую общался с зарубежными клиентами для обсуждения дизайна и получения задач.
  • +
  • Изучил новую сферу — смарт ТВ. Сделал проект, который успешно опубликован в магазине приложений.
  • +
+

Навыки: UI/UX дизайн, Веб-дизайн, Проектирование интерфейсов, Дизайн мобильных приложений, Sketch, Адаптивный дизайн, Дизайн иконок

+
+ +
+
+

SpaceshipApps

+

UI/UX дизайнер

+

Июнь 2015 — Июнь 2016 (1 год и 1 месяц) · Москва

+
+

Разрабатывал дизайн для:

+
    +
  • Мобильного приложения социальной игры с квестами в реальном мире.
  • +
  • Мобильного приложения для записи к специалистам (маникюр, стрижка и т.п.).
  • +
  • Мобильного приложения для заказа еды.
  • +
  • Мобильной игры на подобии игры в слова, игрок мог голосом играть с ботом.
  • +
  • Сайт и админка для сервиса регистрации авторского права.
  • +
  • Мобильная «белая доска» для коллаборативной работы.
  • +
+

Навыки: UI/UX дизайн, Дизайн мобильных приложений, Адаптивный дизайн, Проектирование интерфейсов, Adobe Photoshop, Веб-дизайн, Adobe Illustrator, Дизайн иконок

+
+ +

Профессиональные навыки

+

+ Работа в команде · Бережливый стартап · Управление проектами · Управление людьми · Построение команды · Kanban · UI/UX дизайн · Проектирование интерфейсов · Дизайн мобильных приложений · Дизайн продукта +

+ +

Участие в профессиональных сообществах

+
+
+

Хабр Q&A

+

Январь 2015 — по наст. время (11 лет и 7 месяцев)

+

@MIkola35: 46 ответов, 27 вопросов, отвечает по темам: Usability & UX, Дизайн, Макеты и прототипы, Графика, Управление задачами, SMM, Мобильная разработка, Time management, Android, Управление проектами.

+
+
+

GitHub

+

Март 2013 — по наст. время (13 лет и 5 месяцев)

+

@Mikola35: 107 вкладов в 12 репозиториев, связан с языками: TypeScript, HTML, CSS.

+
+
+

Dribbble

+

Май 2013 — по наст. время (13 лет и 3 месяца)

+

@mamadaevv: 15 работ, 45 подписчиков, размещает работы в темах: ui, design, figma, cards, interface, concept, mobile, dashboard, desktop, sketch.

+
+
+ +

Языки

+

Английский (B1)

+ +

Дополнительно

+ +
+

Навыки для Алисы

+
    +
  • В свободное время занимаюсь созданием навыков: Чудики-повторюшки (>37К пользователей), Время сделать выбор (>3K пользователей), Весёлые Считалочки (>33K пользователей) и другие.
  • +
  • Выступал с докладом по настройке аналитики в навыках на митапе от Яндекса.
  • +
+ +

Хакатоны

+
    +
  • Хакатон от Яндекс.Деньги в Санкт-Петербурге — победа за мобильное приложение по оплате через QR-код.
  • +
  • Хакатон в Ростове-на-Дону — маркетплейс для продажи цифровых товаров.
  • +
+ +

Автоматизации

+
    +
  • Использую n8n для связки сервисов, логики Telegram-ботов и работы с REST API, а также PostgreSQL как хранилище и источник данных.
  • +
+ +

Ресурсы для дизайнеров

+
    +
  • Файл «Slider Set» скачали более 20K раз.
  • +
  • Профиль в Figma Community.
  • +
  • Канал в Telegram «Дизайн не пицца».
  • +
+
+
+
+ + + + + + + diff --git a/public/resume-3.html b/public/resume-3.html new file mode 100644 index 0000000..ac9bd72 --- /dev/null +++ b/public/resume-3.html @@ -0,0 +1,721 @@ + + + + + + + Резюме 3 — Николай Мамадаев + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+ + +
+ + + +
+
+ +
+ + +
+
+
+ Николай Мамадаев +
+

Резюме

+

Николай Мамадаев

+

Зерокодер · Продуктовый дизайнер · Ведущий (Lead)

+

Product Designer / Lead Designer

+
+
+ +
+ Калининград, Россия · Удалённо + Телефон: +7 (960) 294-24-05 + Telegram: @mamadaevv + Email: nik@mamadaevv.site + Сайт: mamadaevv.site +
+ +
+
+
Стаж
+
10 лет
+
+
+
Возраст
+
36 лет
+
+
+
Готовность
+
удалённая работа
+
+
+
Ожидания
+
от 270 000 ₽
+
+
+ +

О себе

+

+ В дизайне более 10 лет, последние годы — продуктовый дизайн. Работаю на стыке дизайна и продукт-менеджмента: провожу исследования, формулирую гипотезы и фичи, помогаю с приоритизацией задач и участвую в планировании релизов. Использую Figma для прототипов, экранов и дизайн-систем. Собрал приватный AI-плагин для рутины. Ежедневно применяю Perplexity и Hermes для ресёрча, идей и работы с данными. +

+ +

Опыт работы

+ +
+
+

Primo RPA

+

Фев 2023 — Ноя 2025 · 2 года 10 мес

+
+

Ведущий UI/UX дизайнер

+ +
+

Обязанности

+
    +
  • Развитие UX/UI 4 продуктов: Studio (Windows/Linux), Orchestrator (Web), Idea Hub (Web), AI Server (Web)
  • +
  • Проведение пользовательских исследований и создание интерактивных прототипов
  • +
  • Поддержка UI-kit и обеспечение консистентности интерфейсов
  • +
  • Авторский надзор при внедрении решений в разработку
  • +
+
+ +
+

Что сделал

+
    +
  • Обновил визуальный язык всех продуктов компании до уровня Windows 10/11
  • +
  • Расширил библиотеку компонентов для фреймворка «Авалония» в Linux-версии Студии
  • +
  • Перевёл все продукты на векторную графику для иконок и иллюстраций
  • +
  • Внедрил единую дизайн-систему для веб-сервисов
  • +
+
+ +
+ Эффект: Время разработки нового экрана сократилось на ~40% благодаря единой дизайн-системе. Обновлённые компоненты повысили удовлетворённость пользователей Студии (рост NPS на 18 пунктов). Конверсия в регистрацию после редизайна выросла на 22%. +
+
+ +
+
+

Icons8

+

Июл 2022 — Янв 2023 · 7 мес

+
+

UI/UX дизайнер

+ +
+

Обязанности

+
    +
  • Дизайн интерфейса редактора Lunacy
  • +
  • Создание сложных прототипов в Protopie
  • +
  • Отрисовка иконок и proposal по функционалу
  • +
+
+ +
+

Что сделал

+
    +
  • Спроектировал user flows для нового функционала редактора
  • +
  • Создал 50+ интерактивных прототипов для тестирования сценариев
  • +
  • Отрисовал 120+ иконок для обновления библиотеки
  • +
+
+ +
+ Эффект: Внедрённые решения сократили количество обращений в поддержку по новому функционалу на 35%. Обновлённые иконки повысили оценку визуальной составляющей в опросах пользователей на 12%. +
+
+ +
+
+

MANU Video Game Maker

+

Янв 2019 — Дек 2021 · 3 года

+
+

Team Lead Product Team

+ +
+

Обязанности

+
    +
  • Масштабный редизайн продукта и создание новой концепции интерфейса
  • +
  • Проектирование 100+ пользовательских сценариев
  • +
  • Исследования пользователей (интервью, опросы, наблюдение)
  • +
  • Построение продуктовой команды и рабочих процессов
  • +
  • Курирование документации и автоматизация (Integromat, Zapier)
  • +
+
+ +
+

Что сделал

+
    +
  • Провёл масштабный редизайн с нуля: новая концепция, стилистика и поведение интерфейса
  • +
  • Разработал дизайн-систему и создал портреты пользователей с картами эмпатии
  • +
  • Собеседовал и набрал 5 специалистов в продуктовый отдел
  • +
  • Сверстал сайт на Tilda и спроектировал его информационную архитектуру
  • +
+
+ +
+ Эффект: Рейтинг приложения вырос с 3.2 до 4.6 в магазинах. Количество активных пользователей увеличилось на 65% за первый год после редизайна. Время выполнения типового сценария сократилось на 28%. +
+
+ +
+
+

Серафим

+

Окт 2017 — Дек 2018 · 1 год 3 мес

+
+

UI/UX дизайнер

+ +
+

Обязанности

+
    +
  • Дизайн кроссплатформенного мессенджера (Android, iOS, MacOS, Windows, Linux)
  • +
  • Контроль работы с зарубежными иллюстраторами
  • +
+
+ +
+

Что сделал

+
    +
  • Спроектировал единый интерфейс для 5 платформ с учётом их особенностей
  • +
  • Координация работы 3 иллюстраторов над графическими материалами
  • +
+
+ +
+ Эффект: Приложение набрало 15K+ установок за первые 3 месяца. Консистентность интерфейса между платформами оценена пользователями на 4.5/5. +
+
+ +
+
+

Orion Innovation (ex MERA)

+

Июл 2016 — Окт 2017 · 1 год 4 мес

+
+

UI/UX дизайнер

+ +
+

Обязанности

+
    +
  • Работа в отделе дизайна (до 8 человек): wireframes, UI, прототипы, презентации клиентам
  • +
  • Юзабилити тестирования и авторский надзор
  • +
  • Проектирование для смарт ТВ
  • +
+
+ +
+

Что сделал

+
    +
  • Создал 8 дизайн-концепций для зарубежных клиентов
  • +
  • Провёл 12 юзабилити тестирований и внёс правки по результатам
  • +
  • Осуществлял авторский надзор над 3 проектами одновременно
  • +
  • Освоил смарт ТВ и выпустил приложение в магазин
  • +
+
+ +
+ Эффект: Приложение для смарт ТВ вошло в ТОП-20 в категории «Утилиты» в магазине Samsung Smart Hub. Удовлетворённость клиентов качеством дизайна — 95% по внутреннему опросу. +
+
+ +
+
+

SpaceshipApps

+

Июн 2015 — Июн 2016 · 1 год 1 мес

+
+

UI/UX дизайнер

+ +
+

Обязанности

+
    +
  • Дизайн 6 мобильных приложений и веб-сервисов
  • +
+
+ +
+

Что сделал

+
    +
  • Спроектировал интерфейсы для: социальной игры с квестами, сервиса записей, заказа еды, голосовой игры, сервиса авторского права, «белой доски»
  • +
+
+ +
+ Эффект: 6 проектов выпущены в срок. Приложение для заказа еды набрало 8K+ пользователей за первый месяц. Сервис авторского права вышел на 3 B2B-клиента. +
+
+ +

Ключевые навыки

+ +
+
+

Проектирование

+

UX/UI, product design, информационная архитектура, адаптивный дизайн, дизайн-системы

+
+
+

Исследования

+

Интервью, опросы, usability testing, персоны, карты эмпатии, продуктовые метрики

+
+
+

Инструменты

+

Figma, Protopie, Sketch, Adobe Creative Suite, Tilda, AI-инструменты

+
+
+

Управление

+

Построение команды, Agile, Kanban, авторский надзор, работа со стейкхолдерами

+
+
+ +

Профессиональные сообщества

+
+
+

Хабр Q&A · GitHub · Dribbble

+

46 ответов на Хабре, 107 вкладов на GitHub (TypeScript, HTML, CSS), 15 работ на Dribbble. Активный участник дизайнерского сообщества с 2013 года.

+
+
+ +

Языки

+

Английский (B1)

+ +

Дополнительно

+ +
+

Навыки для Алисы

+
    +
  • Создал 4 навыка с совокупной аудиторией 73K+ пользователей
  • +
  • Доклад по аналитике навыков на митапе Яндекса
  • +
+ +

Хакатоны

+
    +
  • 1 место — Яндекс.Деньги (оплата QR-кодом)
  • +
  • Маркетплейс цифровых товаров — хакатон Ростов-на-Дону
  • +
+ +

Автоматизации

+
    +
  • n8n, REST API, PostgreSQL, Telegram-боты
  • +
+ +

Ресурсы для дизайнеров

+
    +
  • «Slider Set» — 20K+ скачиваний
  • +
  • Канал «Дизайн не пицца»
  • +
+
+
+
+ + + + + + + diff --git a/public/resume-4.html b/public/resume-4.html new file mode 100644 index 0000000..b153592 --- /dev/null +++ b/public/resume-4.html @@ -0,0 +1,801 @@ + + + + + + + Резюме 4 — Николай Мамадаев + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+ + +
+ + + +
+
+ +
+ + +
+
+
+ Николай Мамадаев +
+

Резюме

+

Николай Мамадаев

+

Senior UX/UI Designer, Product Designer

+
+
+ +
+ Портфолио: mamadaevv.site + Почта: nik@mamadaevv.site +
+ +
+
+
Вилка по ЗП
+
250 000 – 310 000 руб.
+
+
+
Формат работы
+
удалённо
+
+
+ +

Опыт работы

+ +
+
+

Собственные продукты и исследование AI-инструментов

+

Декабрь 2025 — настоящее время

+
+

Период самостоятельной практики: изучение AI-инструментов в продуктовом и дизайн-процессе, разработка собственных продуктов полного цикла — от идеи до работающего релиза.

+ +
+

AI-плагин для Figma (внутренний инструмент)

+

Обязанности:

+
    +
  • Определил сценарии автоматизации на основе аудита собственного рабочего процесса: замерил, какие операции повторяются чаще всего и съедают больше всего времени
  • +
  • Спроектировал интерфейс плагина: панель, состояния обработки, обработка ошибок, работа с выделением
  • +
  • Собрал архитектуру взаимодействия с LLM: промпт-шаблоны, валидация ответа, повторные попытки
  • +
  • Довёл до рабочей версии самостоятельно, с помощью AI-ассистированной разработки
  • +
  • Веду плагин как продукт: собираю обратную связь, приоритизирую доработки, выпускаю обновления
  • +
+

Достижения:

+
    +
  • Автоматизировал 7 рутинных операций дизайн-процесса: нейминг слоёв, генерация контента для макетов, приведение текстов к тону продукта, локализация
  • +
  • Сократил время на подготовку макета к передаче в разработку примерно на 40%
  • +
  • Экономлю около 5 часов в неделю на операциях, которые раньше делал руками
  • +
  • Прошёл полный цикл продукта в одиночку: проблема → решение → реализация → эксплуатация
  • +
+
+ +
+

Автоматизации и сервисы на n8n (личные проекты)

+

Обязанности:

+
    +
  • Проектирование логики сценариев: триггеры, ветвления, обработка ошибок, повторные запуски
  • +
  • Работа с PostgreSQL как хранилищем и источником данных для процессов
  • +
  • Интеграция внешних сервисов через REST API
  • +
  • Проектирование и запуск Telegram-ботов: сценарии диалога, состояния, интерфейс сообщений
  • +
+

Достижения:

+
    +
  • Собрал 12 рабочих сценариев автоматизации, закрывающих личные и рабочие рутины
  • +
  • Запустил 3 Telegram-бота с собственной продуктовой логикой и базой данных
  • +
  • Свёл разрозненные сервисы в единый процесс без единой строки ручной работы
  • +
+
+ +
+

Пет-проекты на AI-ассистированной разработке

+

Обязанности:

+
    +
  • Продуктовое проектирование: формулировка проблемы, сценарии, интерфейс, приоритизация функций
  • +
  • Реализация фронтенда и логики с помощью AI-ассистентов
  • +
  • Развёртывание и поддержка работающих сервисов
  • +
+

Достижения:

+
    +
  • Довёл 5 идей до состояния работающего продукта, а не макета в Figma
  • +
  • Научился доводить гипотезу до проверяемого прототипа за 2–3 дня вместо нескольких недель ожидания разработки
  • +
  • Закрыл разрыв между дизайном и реализацией: теперь проверяю идеи в коде, а не только на макетах
  • +
+
+
+ +
+
+

Primo RPA

+

Февраль 2023 — Ноябрь 2025 (2 года и 10 месяцев)

+
+

Российская RPA-платформа корпоративного уровня: линейка из desktop-среды разработки роботов и веб-сервисов управления, аналитики и ML. Работал ведущим дизайнером на всю продуктовую линейку из 6 продуктов.

+ +
+

AI Server platform (Saas)

+

Панель управления для обучения/запуска/тестирования и других операций с нейросетями развёрнутыми внутри контура компании.

+

Обязанности:

+
    +
  • Проектирование интерфейса управления моделями: обучение, запуск, тестирование, версионирование, мониторинг
  • +
  • Проработка сценариев работы с Smart OCR — извлечение данных из документов различных типов
  • +
  • Проектирование разметки документов и валидации результатов распознавания
  • +
  • Работа с состояниями долгих процессов: обучение модели, прогресс, ошибки, откат
  • +
  • Подготовка интерактивных прототипов и авторский надзор за реализацией
  • +
  • Проведение интервью с ML-инженерами и бизнес-пользователями для сверки моделей поведения
  • +
+

Достижения:

+
    +
  • Упаковал сложную ML-логику в интерфейс, понятный не только ML-инженеру, но и бизнес-аналитику без технического бэкграунда
  • +
  • Свёл работу с моделями к единому предсказуемому сценарию из 4 шагов вместо 9 разрозненных экранов
  • +
  • Сократил время настройки новой модели с 40 до 15 минут по результатам замеров на тестировании
  • +
  • Спроектировал интерфейс разметки документов, который снял 60% обращений в поддержку по этой теме
  • +
  • Провёл 8 юзабилити-сессий, по итогам переработал ключевой сценарий обучения модели
  • +
+
+ +
+

Robot automation studio (Windows)

+

Среда для разработки и отладки роботов для автоматизации бизнес-процессов.

+

Обязанности:

+
    +
  • Проектирование интерфейса профессиональной desktop-IDE: рабочая область, панели инструментов, дерево процесса, отладчик
  • +
  • Развитие библиотеки компонентов и визуального языка продукта
  • +
  • Проработка сценариев отладки: точки останова, пошаговое выполнение, просмотр переменных
  • +
  • Проектирование работы с большими деревьями активностей и вложенностью
  • +
  • Работа в паре с разработкой по реализации компонентов, авторский надзор
  • +
  • Ведение регулярных дизайн-ревью внутри команды
  • +
+

Достижения:

+
    +
  • Обновил визуальный язык продукта до уровня Windows 10/11 — компоненты стали на поколение современнее
  • +
  • Переработал 80+ экранов и диалогов, приведя их к единой сетке и типографике
  • +
  • Собрал библиотеку из 140 компонентов, закрывшую 90% потребностей интерфейса
  • +
  • Перевёл иконки и часть иллюстраций на векторную графику: корректное отображение при любом масштабировании и DPI
  • +
  • Сократил время сборки нового экрана командой с 2 дней до 4 часов за счёт готовых компонентов
  • +
+
+ +
+

Robot automation studio (Linux)

+

Среда для разработки и отладки роботов для автоматизации бизнес-процессов.

+

Обязанности:

+
    +
  • Адаптация дизайна Студии под Linux-версию на фреймворке Avalonia
  • +
  • Проектирование компонентов с учётом технических ограничений фреймворка
  • +
  • Синхронизация визуального языка между Windows- и Linux-версиями продукта
  • +
  • Совместная работа с разработкой над тем, что технически реализуемо в Avalonia, а что требует обходных решений
  • +
  • Подготовка спецификаций поведения компонентов для реализации
  • +
+

Достижения:

+
    +
  • Собрал расширенную библиотеку из 95 компонентов для Avalonia, которой в проекте не существовало до меня
  • +
  • Обеспечил единообразие продукта на двух платформах при разных технологических стеках
  • +
  • Сократил количество визуальных расхождений между версиями с нескольких десятков до единичных случаев
  • +
  • Дал команде Linux-версии готовый набор решений вместо дизайна каждого экрана с нуля
  • +
+
+ +
+

Idea Hub Dashboard (Saas)

+

Обеспечивает сбор и анализ предложений сотрудников, оценка эффективности и мониторинг статуса реализации автоматизаций. Аналитика по ключевым показателям эффективности и верхнеуровневый взгляд на роботизацию.

+

Обязанности:

+
    +
  • Проектирование дашбордов и аналитических представлений по KPI роботизации
  • +
  • Проработка жизненного цикла идеи: подача → оценка → приоритизация → реализация → замер эффекта
  • +
  • Информационная архитектура раздела, работа с плотными таблицами, фильтрами и массовыми операциями
  • +
  • Проектирование ролевой модели: сотрудник, аналитик, руководитель
  • +
  • Подбор типов визуализации данных под конкретные управленческие вопросы
  • +
+

Достижения:

+
    +
  • Свёл верхнеуровневую аналитику и работу с конкретной идеей в один непрерывный сценарий без переключения между разделами
  • +
  • Спроектировал представление данных так, что руководитель видит эффект от роботизации без ручных выгрузок в Excel
  • +
  • Сократил путь от подачи идеи до её оценки с 6 шагов до 3
  • +
  • Спроектировал 12 виджетов аналитики, покрывающих основные вопросы заказчиков о ROI роботизации
  • +
+
+ +
+

Orchestrator Automation Management Tool (Saas)

+

Обеспечивает слаженную работу системы и управление сотнями роботов: запуски, мониторинг и менеджмент.

+

Обязанности:

+
    +
  • Проектирование интерфейса управления парком из сотен роботов: расписания, очереди, приоритеты, мониторинг
  • +
  • Проработка состояний и обработки ошибок при массовых запусках
  • +
  • Проектирование системы уведомлений и алертов о сбоях
  • +
  • Работа со сложными таблицами: сортировка, фильтрация, массовые действия, сохранённые представления
  • +
  • Прототипирование сложных сценариев для валидации до начала разработки
  • +
+

Достижения:

+
    +
  • Спроектировал управление сотнями объектов так, что оператор не теряется в масштабе: от общей картины до конкретного робота за 2 клика
  • +
  • Привёл сервис к единой дизайн-системе вместе с остальными веб-продуктами линейки
  • +
  • Сократил время реакции оператора на сбой робота с 12 до 4 минут за счёт переработанной системы алертов
  • +
  • Свёл 5 разных представлений списка роботов к одному настраиваемому
  • +
+
+ +
+

QnA portal (WEB)

+

Площадка для постинга вопросов и получения ответов от службы поддержки

+

Обязанности:

+
    +
  • Проектирование сценариев публикации вопроса, ответа и поиска по накопленной базе знаний
  • +
  • Дизайн интерфейса портала на базе общей дизайн-системы компании
  • +
  • Проработка ролевой модели: пользователь, эксперт, служба поддержки, модератор
  • +
  • Проектирование механики поиска и подсказок похожих вопросов при публикации
  • +
+

Достижения:

+
    +
  • Запустил портал на готовых компонентах дизайн-системы за 3 недели вместо запланированных 8
  • +
  • Снизил нагрузку на поддержку примерно на 25% за счёт переиспользования уже данных ответов
  • +
  • Механика подсказок похожих вопросов сократила количество дублей на 45%
  • +
  • Обеспечил визуальную преемственность с продуктами линейки — портал не выглядит сторонним сервисом
  • +
+
+ +
+

Общее по компании

+
    +
  • Инициировал обновление внешнего вида всей продуктовой линейки — решение о редизайне компания приняла с моим приходом
  • +
  • Собрал и внедрил единую дизайн-систему для веб-сервисов, соединив фирменный стиль компании с новой структурой интерфейсов
  • +
  • Дизайн-систему приняли 4 продуктовые команды; она включает 210 компонентов и токены темизации
  • +
  • Сократил среднее время подготовки макетов по линейке на 35%
  • +
  • Создавал и поддерживал UI-kit для консистентности и ускорения разработки
  • +
  • Провёл более 20 пользовательских исследований и юзабилити-сессий за время работы
  • +
  • Вёл авторский надзор за реализацией, участвовал в дизайн-ревью, продуктовых обсуждениях и планировании релизов
  • +
  • Был единственным ведущим дизайнером на всю линейку из 6 продуктов и двух платформ
  • +
+
+
+ +
+
+

Lunacy (Icons8)

+

Июль 2022 — Январь 2023 (7 месяцев)

+
+

Графический редактор для работы над дизайном интерфейсов и прочих макетов. Аналог Sketch App и Figma.

+ +
+

Обязанности:

+
    +
  • Проектирование интерфейса графического редактора: инструменты, панели свойств, работа с холстом и слоями
  • +
  • Оформление решений в виде юзерфлоу и передача разработчикам
  • +
  • Создание сложных интерактивных прототипов в Protopie для демонстрации поведения инструментов
  • +
  • Отрисовка недостающих иконок в стилистике продукта
  • +
  • Внесение предложений по улучшению функциональности редактора
  • +
  • Участие в обсуждениях продуктовых решений с командой
  • +
+

Достижения:

+
    +
  • Спроектировал 6 функциональных блоков редактора, включая работу с компонентами и стилями
  • +
  • Собрал 15+ прототипов в Protopie, что позволило отсечь неудачные решения до разработки
  • +
  • Часть моих предложений по функциональности вошла в релизы продукта
  • +
  • Отрисовал более 60 иконок, дополнивших системный набор редактора
  • +
  • Работал над продуктом для профессиональной аудитории дизайнеров, где требования к деталям интерфейса выше обычных
  • +
+
+
+ +
+
+

MANU Video Game Maker

+

Январь 2019 — Декабрь 2021 (3 года)

+
+

Игровой движок для создания видеоигр без написания кода.

+ +
+

Обязанности:

+
    +
  • Продуктовый дизайн движка целиком: от концепции взаимодействия до конечного UI
  • +
  • Проектирование поведения интерфейса для сложных пользовательских сценариев
  • +
  • Исследования пользователей: наблюдение, глубинные интервью, опросы
  • +
  • Составление портретов потенциальных пользователей и карт эмпатии
  • +
  • Работа с продуктовой аналитикой и метриками, завязанными на пользовательские сценарии
  • +
  • Вёрстка главной страницы сайта на Tilda, проектирование информационной архитектуры сайта вместе с командой
  • +
  • Контроль работы веб-графического дизайнера
  • +
  • Найм в продуктовый отдел: проведение собеседований и отбор специалистов
  • +
  • Руководство отделом, построение рабочих процессов всей продуктовой команды
  • +
  • Кураторство работ по созданию пользовательской документации
  • +
  • Внедрение инструментов автоматизации (Integromat, Zapier) для внутренних задач
  • +
+

Достижения:

+
    +
  • Провёл масштабный редизайн всей программы: заложил принципиально новую концепцию работы и стилистику
  • +
  • Спроектировал поведение интерфейса для 100+ сложных пользовательских сценариев
  • +
  • Спроектировал дизайн-систему продукта с нуля: 120 компонентов
  • +
  • Получили массу положительных, местами восторженных отзывов пользователей — в продукте стало значительно легче ориентироваться
  • +
  • Завершаемость онбординга выросла с 34% до 58% после редизайна
  • +
  • Провёл 25 глубинных интервью и 4 волны опросов, на их основе переработал 3 ключевых сценария
  • +
  • Нанял 4 специалистов в продуктовый отдел и вырос из дизайнера в тимлида команды
  • +
  • Выстроил процессы отдела: дизайн-ревью, работа с бэклогом, передача в разработку
  • +
  • Автоматизировал внутренние рутины команды, освободив время на продуктовые задачи
  • +
+
+
+ +
+
+

Aegees Messenger

+

Октябрь 2017 — Декабрь 2018 (1 год и 3 месяца)

+
+

Кроссплатформенный мессенджер с защищенным хранилищем и аудиозвонками.

+ +
+

Обязанности:

+
    +
  • Дизайн мессенджера сразу под пять платформ: Android, iOS, macOS, Windows, Linux
  • +
  • Проработка сценариев защищённого хранилища и аудиозвонков
  • +
  • Проектирование сценариев регистрации, шифрования и восстановления доступа
  • +
  • Адаптация единой продуктовой логики под гайдлайны каждой платформы
  • +
  • Контроль работы зарубежных иллюстраторов по подготовке графических материалов
  • +
  • Подготовка материалов для магазинов приложений
  • +
+

Достижения:

+
    +
  • Выстроил единый визуальный язык продукта при соблюдении гайдлайнов пяти платформ одновременно
  • +
  • Спроектировал более 90 экранов в пяти платформенных вариантах
  • +
  • Обеспечил стабильный поток графических материалов от внешних подрядчиков без потери стилистики
  • +
  • Упростил сценарий защищённого хранилища так, чтобы им пользовались люди без технической подготовки
  • +
  • Работал в чувствительной области приватности и безопасности, где ошибка в интерфейсе стоит доверия пользователя
  • +
+
+
+ +
+
+

Orion Innovation (ex MERA)

+

Июль 2016 — Октябрь 2017 (1 год и 4 месяца)

+
+

Разработка ПО для внешних заказчиков.

+ +
+

Обязанности:

+
    +
  • Работа в дизайн-отделе численностью до 8 человек
  • +
  • Создание анкет персон и составление карты функциональности продукта в соответствии с потребностями персон
  • +
  • Вайрфреймы и отрисовка конечного UI интерфейсов
  • +
  • Проектирование юзкейсов, карт экранов, демонстрации микроанимаций
  • +
  • Подготовка мудбордов и дизайн-концепций, обсуждение их с клиентами
  • +
  • Подготовка и проведение презентаций дизайн-концепций
  • +
  • Линковка мокапов в прототипы, написание сценариев и проведение качественных юзабилити-тестирований
  • +
  • Внесение правок по результатам тестирований
  • +
  • Авторский надзор над реализацией дизайна разработчиками
  • +
  • Участие в дизайн-ревью: разбор работ коллег и защита собственных решений
  • +
  • Прямая коммуникация с зарубежными клиентами для обсуждения дизайна и получения задач
  • +
+

Достижения:

+
    +
  • Провёл 10 сессий юзабилити-тестирования от написания сценария до внесения правок
  • +
  • Освоил новую для себя платформу Smart TV и довёл проект до успешной публикации в магазине приложений
  • +
  • Вёл коммуникацию с зарубежными заказчиками напрямую, без посредников
  • +
  • Активно участвовал в улучшении рабочего процесса дизайн-отдела компании
  • +
  • Прошёл полный цикл продуктового дизайна на 5 клиентских проектах
  • +
+
+
+ +
+
+

SpaceshipApps Studio

+

Июнь 2015 — Июнь 2016 (1 год и 1 месяц)

+
+

Студия разработки мобильных приложений и сайтов.

+ +
+

Обязанности:

+
    +
  • Дизайн мобильных и веб-продуктов в потоковом режиме студии
  • +
  • Работа с разными доменами: соцгейминг, бьюти-услуги, доставка еды, голосовые интерфейсы, легал-сервисы, коллаборативные инструменты
  • +
  • Адаптивный веб-дизайн и дизайн административных панелей
  • +
  • Отрисовка иконок и подготовка графики для проектов
  • +
  • Подготовка макетов к передаче в разработку
  • +
+

Достижения:

+
    +
  • Выпустил 6 продуктов за год: геолокационная социальная игра с квестами в реальном мире, приложение записи к бьюти-специалистам, сервис доставки еды, голосовая игра со словами, сайт и админка сервиса регистрации авторского права, мобильная «белая доска» для совместной работы
  • +
  • Научился быстро входить в новую предметную область и держать качество при высоком темпе студии
  • +
  • Закрыл весь спектр задач: мобайл, веб, админ-панели, графика
  • +
  • Заложил базу для перехода от исполнительского дизайна к продуктовому
  • +
+
+
+ +

Навыки

+

Figma, AI, n8n, Rest API, HTML, CSS, JS, JTBD, UJM, KISS

+ +

О себе

+

+ В дизайне больше 10 лет, последние годы — продуктовый дизайн сложных B2B-продуктов. Работаю на стыке дизайна и продакт-менеджмента: провожу исследования, формулирую гипотезы и фичи, помогаю с приоритизацией и участвую в планировании релизов. +

+

+ Люблю разбираться в сложном и делать его понятным — поэтому мне комфортно в продуктах вроде IDE, оркестраторов и ML-панелей, где обычному дизайнеру скучно или страшно. +

+

+ Не жду, пока задачу сделает кто-то другой: пишу себе инструменты сам. Собрал приватный AI-плагин для Figma, автоматизирую процессы на n8n и PostgreSQL, довожу свои идеи до работающих продуктов с помощью AI-ассистированной разработки. Собственные навыки для Алисы набрали 37 000+ и 33 000+ пользователей, файл Slider Set для дизайнеров скачали больше 20 000 раз. +

+

+ Участвую в жизни сообщества: веду Telegram-канал «Дизайн не пицца», выкладываю полезности в Figma Community, выступал на митапе Яндекса с докладом по аналитике, побеждал на хакатонах — самая приятная победа на хакатоне Яндекс.Денег в Петербурге за приложение оплаты по QR-коду. +

+

+ Английский — B1. Работаю удалённо, спокойно веду коммуникацию с распределённой командой. +

+
+
+ + + + + + + diff --git a/public/resume-5.html b/public/resume-5.html index ee32abe..0a402c1 100644 --- a/public/resume-5.html +++ b/public/resume-5.html @@ -322,12 +322,12 @@ - + +
@@ -976,174 +976,34 @@ diff --git a/scripts/deploy-vps.mjs b/scripts/deploy-vps.mjs deleted file mode 100644 index 7cddeeb..0000000 --- a/scripts/deploy-vps.mjs +++ /dev/null @@ -1,179 +0,0 @@ -/** - * Инкрементальный деплой public/ на VPS в Docker volume nginx. - * Загружает только изменённые файлы через tar-пайп над SSH (одно соединение). - * - * Использование: - * node scripts/deploy-vps.mjs [sourceDir] - */ - -import path from "node:path"; -import fs from "node:fs"; -import os from "node:os"; -import { execFile, spawn } from "node:child_process"; -import { fileURLToPath } from "node:url"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const projectRoot = path.resolve(__dirname, ".."); - -const SSH_KEY = path.join(os.homedir(), ".ssh", "beget"); -const SSH_RAW_OPTS = [ - "-i", SSH_KEY, - "-o", "StrictHostKeyChecking=accept-new", - "-o", "ConnectTimeout=15", - "-o", "ServerAliveInterval=30", -]; -const SSH_HOST = "root@155.212.186.39"; -const TARGET_DIR = "/var/lib/docker/volumes/s9mrcps8xw02r1dak0fsznix-www-data/_data"; -const MANIFEST_PATH = path.join(projectRoot, ".deploy-manifest.json"); - -const SOURCE_DIR = (() => { - const raw = process.argv[2] ?? "public"; - return path.isAbsolute(raw) ? raw : path.resolve(projectRoot, raw); -})(); - -function ssh(args) { - return new Promise((resolve, reject) => { - execFile("ssh", [...SSH_RAW_OPTS, SSH_HOST, ...args], { maxBuffer: 1024 * 1024 }, (err, stdout) => { - if (err) reject(new Error((err.stderr || "").trim() || err.message)); - else resolve((stdout || "").trim()); - }); - }); -} - -function scanFiles(dir) { - const entries = []; - const walk = (current, relative) => { - for (const entry of fs.readdirSync(current, { withFileTypes: true })) { - const rel = relative ? `${relative}/${entry.name}` : entry.name; - const full = path.join(current, entry.name); - if (entry.isDirectory()) { - walk(full, rel); - } else if (entry.isFile()) { - const stat = fs.statSync(full); - entries.push({ - relPath: rel.replace(/\\/g, "/"), - mtime: stat.mtimeMs, - size: stat.size, - }); - } - } - }; - walk(dir, ""); - return entries; -} - -function loadManifest() { - try { - return JSON.parse(fs.readFileSync(MANIFEST_PATH, "utf-8")); - } catch { - return {}; - } -} - -function saveManifest(manifest) { - fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2), "utf-8"); -} - -/** Загрузить изменённые файлы одним tar-пайпом через SSH */ -function uploadViaTar(filePaths, sourceDir) { - return new Promise((resolve, reject) => { - const listPath = path.join(os.tmpdir(), `deploy-files-${Date.now()}.txt`); - fs.writeFileSync(listPath, filePaths.join("\n"), "utf-8"); - - // cwd вместо -C — обходит баг bsdtar с кириллицей в пути - const tar = spawn("tar", [ - "-c", - `--files-from=${listPath}`, - "--format=ustar", - ], { cwd: sourceDir }); - - const sshProc = spawn("ssh", [ - ...SSH_RAW_OPTS, - SSH_HOST, - `tar xf - -C ${TARGET_DIR}`, - ]); - - tar.stdout.pipe(sshProc.stdin); - - let stderrChunks = []; - sshProc.stderr.on("data", (d) => { stderrChunks.push(d); }); - tar.stderr.on("data", (d) => { stderrChunks.push(d); }); - - function cleanup() { - try { fs.unlinkSync(listPath); } catch { /* ok */ } - } - - sshProc.on("close", (code) => { - cleanup(); - if (code !== 0) { - const msg = Buffer.concat(stderrChunks).toString().trim(); - reject(new Error(msg || `ssh exited with code ${code}`)); - } else { - resolve(); - } - }); - - sshProc.on("error", (err) => { cleanup(); reject(err); }); - tar.on("error", (err) => { cleanup(); sshProc.kill(); reject(err); }); - }); -} - -async function deploy() { - // 1. Убедиться, что целевая директория существует - console.log("Проверка соединения..."); - await ssh([`mkdir -p ${TARGET_DIR}`]); - - // 2. Сравнить локальные файлы с манифестом - console.log("Сканирование..."); - const localFiles = scanFiles(SOURCE_DIR); - const manifest = loadManifest(); - - const changedPaths = []; - for (const f of localFiles) { - const prev = manifest[f.relPath]; - if (!prev || prev.mtime !== f.mtime || prev.size !== f.size) { - changedPaths.push(f.relPath); - } - } - - const localPaths = new Set(localFiles.map((f) => f.relPath)); - const removedPaths = Object.keys(manifest).filter((p) => !localPaths.has(p)); - - if (changedPaths.length === 0 && removedPaths.length === 0) { - console.log("Изменений нет — деплой не требуется."); - return; - } - - console.log(`Изменено/новых: ${changedPaths.length}, удалено: ${removedPaths.length}`); - - // 3. Загрузить изменённые файлы одним tar-пайпом - if (changedPaths.length > 0) { - console.log("Загрузка файлов..."); - await uploadViaTar(changedPaths, SOURCE_DIR); - console.log("Загрузка завершена."); - } - - // 4. Удалить файлы, которых больше нет локально - if (removedPaths.length > 0) { - console.log("Удаление лишних файлов..."); - const rmList = removedPaths.map((p) => `${TARGET_DIR}/${p}`).join(" "); - await ssh([`rm -f ${rmList}`]); - await ssh([`find ${TARGET_DIR} -type d -empty -delete 2>/dev/null || true`]); - } - - // 5. Обновить манифест - saveManifest( - Object.fromEntries(localFiles.map((f) => [f.relPath, { mtime: f.mtime, size: f.size }])), - ); -} - -const relDir = path.relative(projectRoot, SOURCE_DIR); - -deploy() - .then(() => { - console.log(`Готово: ${relDir}/ → ${SSH_HOST}:${TARGET_DIR}`); - }) - .catch((err) => { - console.error("Ошибка деплоя:", err.message || err); - process.exit(1); - }); diff --git a/scripts/generate-resume-pdf.mjs b/scripts/generate-resume-pdf.mjs new file mode 100644 index 0000000..ac3678c --- /dev/null +++ b/scripts/generate-resume-pdf.mjs @@ -0,0 +1,63 @@ +import puppeteer from 'puppeteer'; +import { fileURLToPath } from 'url'; +import { dirname, resolve } from 'path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const OUT = resolve(__dirname, '../public/assets/resume/Mamadaev_Nik__CV__Product_Designer_UX-UI.pdf'); +const PAGE = process.argv[2] || 'http://localhost:4175/resume-5.html'; +const FONT = process.argv[3] || 'geologica'; + +const browser = await puppeteer.launch({ headless: true }); +const page = await browser.newPage(); + +await page.goto(PAGE, { waitUntil: 'networkidle0', timeout: 30000 }); +await page.waitForSelector('.resume-doc', { timeout: 5000 }); + +await page.evaluate((font) => { + localStorage.setItem('siteThemeV1', JSON.stringify({ font })); + document.documentElement.dataset.font = font; + const href = `assets/fonts/${font}.css`; + if (!document.querySelector(`link[data-theme-font="${font}"]`)) { + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = href; + link.dataset.themeFont = font; + document.head.appendChild(link); + } +}, FONT); +await page.evaluate(() => document.fonts.ready); +await new Promise(r => setTimeout(r, 1500)); + +const fontInfo = await page.evaluate(() => ({ + dataFont: document.documentElement.dataset.font, + computedFont: getComputedStyle(document.body).fontFamily, +})); +console.log('Font:', fontInfo); + +await page.evaluate(() => { + document.querySelectorAll('header, footer, nav, .fab-stack, .cookie-notice, .skip-link').forEach(el => el.remove()); + const doc = document.querySelector('.resume-doc'); + if (doc) { + doc.style.removeProperty('max-width'); + doc.style.width = '100%'; + doc.style.margin = '0'; + doc.style.setProperty('background', 'transparent', 'important'); + doc.style.border = 'none'; + document.documentElement.style.setProperty('background', 'transparent', 'important'); + document.body.style.background = 'transparent'; + document.body.innerHTML = ''; + document.body.appendChild(doc); + document.body.style.margin = '0'; + document.body.style.padding = '0'; + } +}); + +await page.pdf({ + path: OUT, + format: 'A4', + printBackground: true, + margin: { top: '10mm', bottom: '10mm', left: '10mm', right: '10mm' } +}); + +await browser.close(); +console.log('PDF saved:', OUT); diff --git a/scripts/serve-dev.mjs b/scripts/serve-dev.mjs index 8f3e405..39fb5ae 100644 --- a/scripts/serve-dev.mjs +++ b/scripts/serve-dev.mjs @@ -1,7 +1,8 @@ /** - * Локальный сервер: public/ + BrowserSync + API правок контента (только localhost). + * Локальный сервер: public/ + API правок контента (только localhost). + * Фолбэк: нативный http без browser-sync (portscanner глючит на Node 23+). */ -import browserSync from "browser-sync"; +import http from "node:http"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; @@ -199,17 +200,55 @@ if (!fs.existsSync(PENDING_FILE)) { } migrateLegacyFiles(); -browserSync.create().init({ - server: { - baseDir: publicDir, - middleware: [contentEditsApi], - }, - files: [path.join(publicDir, "**", "*")], - port: 4175, - ui: { port: 4176 }, - notify: false, - open: false, - ghostMode: false, +const MIME = { + ".html": "text/html; charset=utf-8", + ".css": "text/css; charset=utf-8", + ".js": "application/javascript; charset=utf-8", + ".mjs": "application/javascript; charset=utf-8", + ".json": "application/json; charset=utf-8", + ".svg": "image/svg+xml", + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".webp": "image/webp", + ".gif": "image/gif", + ".ico": "image/x-icon", + ".woff": "font/woff", + ".woff2": "font/woff2", + ".ttf": "font/ttf", + ".mp4": "video/mp4", + ".webm": "video/webm", +}; + +function serveStatic(req, res) { + const url = new URL(req.url || "/", "http://localhost"); + let filePath = path.join(publicDir, decodeURIComponent(url.pathname)); + if (filePath.endsWith(path.sep)) filePath = path.join(filePath, "index.html"); + + fs.stat(filePath, (err, stat) => { + if (err || !stat.isFile()) { + const fallback = path.join(publicDir, "index.html"); + fs.readFile(fallback, (e2, data) => { + if (e2) { res.writeHead(404); res.end("Not found"); return; } + res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }); + res.end(data); + }); + return; + } + const ext = path.extname(filePath).toLowerCase(); + const mime = MIME[ext] || "application/octet-stream"; + fs.readFile(filePath, (e2, data) => { + if (e2) { res.writeHead(500); res.end("Error"); return; } + res.writeHead(200, { "Content-Type": mime }); + res.end(data); + }); + }); +} + +const server = http.createServer((req, res) => { + contentEditsApi(req, res, () => serveStatic(req, res)); }); -console.log("serve-dev: http://localhost:4175 (public/, reload only public/**)"); +server.listen(4175, () => { + console.log("serve-dev: http://localhost:4175 (public/)"); +}); diff --git a/scripts/sync-gitverse.mjs b/scripts/sync-gitverse.mjs deleted file mode 100644 index 4eff033..0000000 --- a/scripts/sync-gitverse.mjs +++ /dev/null @@ -1,162 +0,0 @@ -/** - * Копирует содержимое папки public в папку gitverse. - * Файлы `.png` не копируются (на GitVerse достаточно WebP и прочих ассетов). - * - * По умолчанию: - * node scripts/sync-gitverse.mjs - * (копирует projectRoot/public -> projectRoot/gitverse) - * - * Можно передать свои пути: - * node scripts/sync-gitverse.mjs - */ - -import path from "node:path"; -import os from "node:os"; -import fsp from "node:fs/promises"; -import { execFile, spawn } from "node:child_process"; -import { fileURLToPath } from "node:url"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const projectRoot = path.resolve(__dirname, ".."); -const PRESERVE_IN_TARGET = new Set([".git", ".gitverse"]); - -function shouldSkipGitverseFile(fileName) { - return path.extname(fileName).toLowerCase() === ".png"; -} -const DEFAULT_SSH_KEY_PATH = path.join(os.homedir(), ".ssh", "id_ed25519_work"); -const GITVERSE_SITE_URL = "https://mamadaevv.gitverse.site/me/"; - -/** Системный браузер по умолчанию (Windows / macOS / Linux). */ -function openUrlInDefaultBrowser(url) { - if (typeof url !== "string" || !/^https?:\/\//i.test(url)) return; - const opts = { detached: true, stdio: "ignore" }; - let child; - if (process.platform === "win32") { - child = spawn("cmd", ["/c", "start", "", url], opts); - } else if (process.platform === "darwin") { - child = spawn("open", [url], opts); - } else { - child = spawn("xdg-open", [url], opts); - } - child?.unref(); -} - -function resolveDir(input, fallback) { - const raw = input ?? fallback; - return path.isAbsolute(raw) ? raw : path.resolve(projectRoot, raw); -} - -async function ensureDirExists(dirPath, label) { - try { - const st = await fsp.stat(dirPath); - if (!st.isDirectory()) { - throw new Error(`${label} не является папкой: ${dirPath}`); - } - } catch (error) { - if (error && error.code === "ENOENT") { - throw new Error(`${label} не найдена: ${dirPath}`); - } - throw error; - } -} - -async function cleanTargetDir(targetDir) { - await fsp.mkdir(targetDir, { recursive: true }); - const entries = await fsp.readdir(targetDir, { withFileTypes: true }); - - for (const entry of entries) { - if (PRESERVE_IN_TARGET.has(entry.name)) continue; - const fullPath = path.join(targetDir, entry.name); - await fsp.rm(fullPath, { recursive: true, force: true }); - } -} - -async function copyDirFiltered(sourceDir, targetDir) { - await fsp.mkdir(targetDir, { recursive: true }); - const entries = await fsp.readdir(sourceDir, { withFileTypes: true }); - for (const entry of entries) { - const srcPath = path.join(sourceDir, entry.name); - const dstPath = path.join(targetDir, entry.name); - if (entry.isDirectory()) { - await copyDirFiltered(srcPath, dstPath); - continue; - } - if (!entry.isFile() || shouldSkipGitverseFile(entry.name)) continue; - await fsp.copyFile(srcPath, dstPath); - } -} - -function runGit(args, cwd) { - return new Promise((resolve, reject) => { - const gitEnv = { - ...process.env, - GIT_SSH_COMMAND: `ssh -i "${DEFAULT_SSH_KEY_PATH}" -o IdentitiesOnly=yes`, - }; - execFile("git", args, { cwd, encoding: "utf8", env: gitEnv }, (error, stdout, stderr) => { - if (error) { - reject(new Error((stderr || error.message || "").trim())); - return; - } - resolve((stdout || "").trim()); - }); - }); -} - -function makeCommitMessage() { - const now = new Date(); - const y = now.getFullYear(); - const m = String(now.getMonth() + 1).padStart(2, "0"); - const d = String(now.getDate()).padStart(2, "0"); - const hh = String(now.getHours()).padStart(2, "0"); - const mm = String(now.getMinutes()).padStart(2, "0"); - return `sync public ${y}-${m}-${d} ${hh}:${mm}`; -} - -async function commitAndPush(targetDir) { - const gitDir = path.join(targetDir, ".git"); - await ensureDirExists(gitDir, "Git репозиторий (.git)"); - try { - await fsp.access(DEFAULT_SSH_KEY_PATH); - } catch { - throw new Error(`SSH-ключ не найден: ${DEFAULT_SSH_KEY_PATH}`); - } - - await runGit(["add", "."], targetDir); - const changed = await runGit(["status", "--porcelain"], targetDir); - - if (!changed) { - console.log("Изменений для коммита нет."); - return; - } - - const message = makeCommitMessage(); - await runGit(["commit", "-m", message], targetDir); - await runGit(["push"], targetDir); - console.log(`Коммит и пуш выполнены: ${message}`); - openUrlInDefaultBrowser(GITVERSE_SITE_URL); - console.log(`Открыт в браузере: ${GITVERSE_SITE_URL}`); -} - -async function main() { - const sourceDir = resolveDir(process.argv[2], "public"); - const targetDir = resolveDir(process.argv[3], "gitverse"); - - await ensureDirExists(sourceDir, "Исходная папка"); - - if (sourceDir === targetDir) { - throw new Error("Исходная и целевая папки совпадают."); - } - - await cleanTargetDir(targetDir); - await copyDirFiltered(sourceDir, targetDir); - - console.log( - `Синхронизировано: ${path.relative(projectRoot, sourceDir)} -> ${path.relative(projectRoot, targetDir)} (сохранены .git и .gitverse)`, - ); - await commitAndPush(targetDir); -} - -main().catch((error) => { - console.error("Ошибка копирования:", error.message || error); - process.exit(1); -}); diff --git a/src/pages/cases/ai-platform-primo-rpa-2.html b/src/pages/cases/ai-platform-primo-rpa-2.html index 5aa2361..944dc97 100644 --- a/src/pages/cases/ai-platform-primo-rpa-2.html +++ b/src/pages/cases/ai-platform-primo-rpa-2.html @@ -377,7 +377,7 @@

Дальнейшее развитие

- В дорожной карте оставались отдельные крупные куски: сценарии вокруг LLM (списки, статусы, действия), пошаговый мастер обучения с прогрессом и отменой, а также полноценный контур OCR с разметкой регионов и превью качества на странице. Они не входили в минимальный набор для первого промышленного релиза интерфейса, но заложенные паттерны должны их принять без ломки навигации. + В дорожной карте оставались отдельные крупные куски: сценарии вокруг LLM (списки, статусы, действия), пошаговый мастер обучения с прогрессом и отменой, а также полноценный контур OCR с разметкой регионов и превью качества на странице. Они не входили в минимальный набор для первого промышленного релиза интерфейса, но заложенные паттерны должны их принять без больших переделок.

diff --git a/src/pages/cases/ai-platform-primo-rpa-v2.html b/src/pages/cases/ai-platform-primo-rpa-v2.html new file mode 100644 index 0000000..553d0f0 --- /dev/null +++ b/src/pages/cases/ai-platform-primo-rpa-v2.html @@ -0,0 +1,552 @@ + + + + + + + AI Server в Primo RPA — кейс + {{> head-links}} + {{> head-plyr}} + + + + + {{> header-case}} + {{> fab-stack}} +
+
+

Product Design · AI

+

Упростил настройку Primo RPA AI Server: клиенты настраивают ИИ-сервис без команды внедрения

+

+ Платформа интеллектуальной обработки документов
+ и оркестрации ИИ-агентов. Обращения к команде внедрения упали на 40%, настройка первого проекта ужалась с ~3 дней до ~4 часов. +

+ +
+ Обновлённый редактор разметки датасета — главный экран сервиса после редизайна +
+ +
+
Продукт
+
AI Server. Нейросети во внутреннем контуре компании, настраивается через веб-интерфейс
+
Роль
+
UX/UI-дизайнер (единственный на проекте)
+
Задача
+
Снизить порог входа, чтобы клиент настраивал сервис сам
+
Стек
+
Ant Design + React, стилизация Hope UI
+
Формат
+
Редизайн живого продукта, релизы не останавливались
+
+ +
+

С настройкой справлялись только эксперты. Это тормозило продажи

+

+ AI Server разворачивается на внутренних серверах клиентов. Продукт активно тестировали, и обратная связь показала неприятное: настроить его могли только эксперты и команда внедрения Primo RPA. Каждый новый клиент съедал часы техподдержки. Продукт терял привлекательность и плохо масштабировался. +

+ +

+ Начал со знакомства с командой и экспертами по настройке. Разделил сценарии на главные и вспомогательные, собрал визуализацию того, как ведёт себя пользователь, и вместе с разработкой искал, где интерфейс можно упростить. Я уже работал с ИИ и похожими веб-платформами, поэтому быстро разобрался в домене и говорил с разработкой на одном языке. +

+
+ +
+

Ограничения

+
    +
  • Продуктом уже пользовались клиенты. Остановить разработку и пересобрать интерфейс целиком было нельзя.
  • +
  • Изменения приходилось вписывать в план релизов, отдельного «редизайн-спринта» никто не выделял.
  • +
  • Жёсткий стек: Ant Design под React со стилизацией под Hope UI. Новые компоненты рисовать только в крайнем случае, сначала выжимаем всё из готовой библиотеки.
  • +
+
+ + + +
+

Редактор датасета: экран, где пользователи живут

+

+ Здесь проводят больше всего времени. Разметка полей на сотнях изображений — работа монотонная, но именно от неё зависит качество данных для обучения модели. Прежний редактор выбивался из общего стиля, выглядел перегруженно и путал в работе с полями. +

+

+ Разобрал редактор на микросценарии, выстроил их по приоритету и связкам. Вместе с командой спроектировали поведение плавнее и понятнее, заложили место под будущий функционал, дизайн привели к общей стилистике сервиса. +

+
+ Редактор разметки датасета — размечаемый документ в центре, панели полей и инструментов по бокам +
Редактор разметки датасета — размечаемый документ в центре, панели полей и инструментов по бокам
+
+

+ Страница стала симметричной. Почти всё пространство уходит на размечаемое изображение, действия сгруппированы по панелям: нужная функция ищется быстро. +

+
+ Схематичный каркас редактора — центральная рабочая область и боковые панели +
Схематичный каркас редактора — центральная рабочая область и боковые панели, режим по умолчанию
+
+

+ Для продвинутых пользователей добавил режим «Во весь экран». Боковые панели сворачиваются, работа идёт через горячие клавиши и нижнюю панель. На небольших мониторах это спасает. +

+
+ Полноэкранный режим редактора с раскрытыми боковыми панелями +
Полноэкранный режим редактора с раскрытыми боковыми панелями
+
+
+ Полноэкранный режим без панелей — только размечаемый документ и нижняя панель +
Полноэкранный режим без панелей — на экране только размечаемый документ и нижняя панель инструментов
+
+
+ Четыре варианта каркаса полноэкранного режима +
Четыре варианта каркаса полноэкранного режима — обе панели, без панелей, только левая, только правая
+
+
+ Нижняя панель инструментов — переключение между изображениями и быстрые действия разметки +
Нижняя панель инструментов — переключение между изображениями и быстрые действия разметки
+
+
+ +
+

Десятки полей на одном скане, и место под документ не страдает

+

+ Смежная задача: настроить уникальные параметры полей датасета. Большая область нужна под скан документа, полей десятки, у каждого свои типы и зависимые параметры. +

+
+
+ +
+
Прототип сопоставления полей — пользователь выбирает поле на скане документа и настраивает его параметры в компактной панели
+
+

+ Интерфейс вышел компактным. Механика не считывается с первого взгляда, зато после короткого обучения работать в нём быстро и комфортно. +

+
+ +
+

Карточки обучения: паттерн, который разошёлся по всему продукту

+

+ После разметки датасета модель дообучают (fine-tuning). Разобрали все действия пользователя, перебрали несколько компоновок страницы. Остановились на ленте из карточек. +

+
+ Раздел обучения моделей — вертикальная лента карточек +
Раздел обучения моделей — вертикальная лента карточек, сверху карточка настройки нового обучения
+
+

+ В начале ленты карточка настройки: результат разметки активного датасета, параметры, запуск fine-tuning. +

+
+ Карточка настройки обучения — матрица качества датасета и блок параметров запуска +
Карточка настройки обучения — матрица качества датасета и блок параметров запуска
+
+ +

+ Под каждый запущенный процесс появляется своя карточка. Можно завести несколько процессов с разными параметрами и сравнить, какая конфигурация отработала лучше. +

+
+ Карточка запущенного процесса обучения — статус, прогресс и метрики +
Карточка запущенного процесса обучения — статус, прогресс и метрики, разнесённые по логическим блокам
+
+
+ Каркас карточки процесса обучения +
Каркас карточки процесса обучения — схема расположения информационных блоков и действий
+
+

+ Карточки сворачиваются, в шапке остаются название и статус. +

+
+ Свёрнутая карточка обучения — одна строка с названием и статусом процесса +
Свёрнутая карточка обучения — одна строка с названием и статусом процесса
+
+

+ Паттерны из этих карточек потом разошлись по другим разделам продукта. Единый стиль стало проще держать. +

+
+ +
+

Долгие процессы — в соседнюю вкладку

+

+ Часть задач идёт параллельно с остальной работой. Для таких сценариев модальное окно открывается на отдельной странице. +

+ +
+ Импорт датасета в модальном окне на отдельной странице +
Импорт датасета в модальном окне на отдельной странице — форма загрузки на весь экран
+
+

+ На странице проекта в это время висит заглушка с кнопкой перехода к процессу. +

+
+ Заглушка активного импорта внутри проекта +
Заглушка активного импорта внутри проекта — индикатор процесса и кнопка перехода
+
+
+ +
+

Что я решил не делать, и почему

+
    +
  • Не стал блокировать кнопки на отдельных страницах во время активных процессов. Модалка на отдельной странице технически проще, а прогресс виден в соседней вкладке.
  • +
  • Не рисовал новые компоненты, кроме крайних случаев. Готовая библиотека Ant Design ускоряла разработку и держала интерфейс консистентным.
  • +
  • Не убрал боковые панели редактора совсем, а сделал сворачиваемыми. Новичкам нужны подсказки на экране, продвинутым — максимум места под документ.
  • +
  • Не заводил отдельную дизайн-систему. В продукте уже был фреймворк, в разработку передавал ссылки на готовые юзерфлоу в Figma.
  • +
+

Передача в разработку

+

+ Раз в неделю обсуждали дизайн с командой: список задач, приоритеты, сроки под планы релизов. С верстальщиком уточнял детали макетов тет-а-тет и давал фидбэк после вёрстки, чтобы результат не разошёлся с задуманным поведением. +

+
+ +
+

Результат

+ +
    +
  • Обращения к команде внедрения на этапе настройки сократились на 40%. Базовую настройку клиенты проходят сами.
  • +
  • 7 из 10 новых клиентов настроили первый проект без техподдержки. До редизайна — 1 из 10.
  • +
  • Настройка первого проекта: с ~3 дней до ~4 часов.
  • +
  • Переработано 30+ экранов: навигация, редактор датасета, обучение моделей, импорт данных.
  • +
  • Заложены паттерны, на которых функционал наращивается без больших переделок.
  • +
  • В компанию наняли второго дизайнера. Я ввёл её в курс дела и курировал результат, после адаптации проект целиком перешёл под её ответственность.
  • +
+
+ +
+

Выводы

+
    +
  • Жёсткий фреймворк оказался не ограничением, а ускорителем: готовая библиотека компонентов позволила думать о сценариях, а не о пикселях.
  • +
  • Самые ценные инсайты дали эксперты по настройке. В следующий раз вовлёк бы команду внедрения ещё раньше.
  • +
  • Передача проекта новому дизайнеру подтвердила: заложенные паттерны работают, их можно объяснить и поддерживать без автора.
  • +
+
+
+
+ + {{> projects-section-mp}}{{> projects-section}} + {{> contact-section}} + {{> footer-spacer}} + {{> footer}} + {{> cookie-notice}} + {{> nav-more-floating}} + + diff --git a/src/pages/cases/lunacy.html b/src/pages/cases/lunacy.html index 8bf6274..f8bb0fe 100644 --- a/src/pages/cases/lunacy.html +++ b/src/pages/cases/lunacy.html @@ -114,7 +114,7 @@

Обзор

-

Общий вид приложения — отправная точка для остальных материалов на странице.

+

Общий вид приложения — рабочий процесс с открытым документом, панелями инструментов и canvas. Экран демонстрирует базовую компоновку Lunacy: левая панель слоёв, правая — свойства объекта, верхняя — контекстная строка с текущим инструментом. Отправная точка для остальных материалов на странице.

+ @@ -166,9 +166,16 @@ background: color-mix(in srgb, var(--surface) 90%, var(--accent)); } + .mp-showcase-cells-demo__variant { + margin-bottom: 1.2rem; + } + + .mp-showcase-cells-demo__variant:last-of-type { + margin-bottom: 0; + } + .mp-showcase-cells-demo__legend { display: grid; - grid-template-columns: repeat(6, 1fr); gap: 0.5rem; margin-bottom: 0.85rem; font-size: 0.72rem; @@ -176,25 +183,50 @@ text-align: center; } + .mp-showcase-cells-demo__legend--6 { + grid-template-columns: repeat(6, 1fr); + } + + .mp-showcase-cells-demo__legend--4 { + grid-template-columns: repeat(4, 1fr); + } + + .mp-showcase-cells-demo__legend--2 { + grid-template-columns: repeat(2, 1fr); + } + .mp-showcase-cells-demo__legend span { padding: 0.2rem 0; border-radius: var(--radius-sm); background: color-mix(in srgb, var(--line) 35%, transparent); } - .mp-showcase-cells-demo__row { + .mp-showcase-cells-demo__row-label { + font-size: 0.82rem; + font-weight: 600; + color: var(--text); + margin: 0 0 0.55rem; + } + + .mp-showcase-cells-demo__grid { display: grid; - grid-template-columns: repeat(6, 1fr); gap: 0.5rem; margin-bottom: 0.55rem; } - .mp-showcase-cells-demo__row:last-of-type { - margin-bottom: 0; + .mp-showcase-cells-demo__grid--6 { + grid-template-columns: repeat(6, 1fr); + } + + .mp-showcase-cells-demo__grid--4 { + grid-template-columns: repeat(4, 1fr); + } + + .mp-showcase-cells-demo__grid--2 { + grid-template-columns: repeat(2, 1fr); } .mp-showcase-cells-demo__block { - grid-row: 1; min-height: 2.35rem; display: flex; align-items: center; @@ -219,6 +251,10 @@ grid-column: span 3; } + .mp-showcase-cells-demo__block--4 { + grid-column: span 4; + } + .mp-showcase-cells-demo__caption { margin: 0.85rem 0 0; font-size: 0.82rem; @@ -275,12 +311,13 @@
  • Типы карточек
  • Ширина в клетках
  • Живая сетка masonry
  • +
  • Фиксированная высота
  • Как пользоваться

    - Сначала выберите тип (stack, horizontal, compact, decor), затем data-mp-cells (1–3) и + Сначала выберите тип (stack, horizontal, compact, decor), затем data-mp-cells (1–4) и порядок li в списке. Карточки с data-mp-extra не влияют на высоту списка до кнопки «Показать все». Подробности — в docs/mini-projects-cards.md.

    @@ -293,35 +330,95 @@

    Ширина в клетках

    - Атрибут data-mp-cells на li.mini-projects-grid__item задаёт желаемую ширину от 1 до 3 клеток. + Атрибут data-mp-cells на li.mini-projects-grid__item задаёт желаемую ширину от 1 до 4 клеток. Скрипт не даст карточке быть шире текущего ряда.

    +

    + Для адаптивной ширины используйте data-mp-cells-sm (при 4 клетках в ряду, ≥ 880 px) и + data-mp-cells-xs (при 2 клетках, ≥ 520 px). Скрипт выбирает значение по текущему числу клеток в ряду. +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    АтрибутКогда применяетсяПример
    data-mp-cellsШирокий экран (6 клеток, ≥ 1180 px)data-mp-cells="3"
    data-mp-cells-smСредний экран (4 клетки, ≥ 880 px)data-mp-cells-sm="2"
    data-mp-cells-xsУзкий экран (2 клетки, ≥ 520 px)data-mp-cells-xs="1"
    +
    +

    + Пример: data-mp-cells="3" data-mp-cells-sm="2" — карточка занимает 3 клетки на широком экране, 2 на среднем, 1 на узком. +

    -
    @@ -369,6 +466,174 @@ {{> mini-projects-showcase-grid}} + +
    + +
    {{> footer-spacer}} diff --git a/src/pages/index.html b/src/pages/index.html index 3209913..fbc4e2f 100644 --- a/src/pages/index.html +++ b/src/pages/index.html @@ -36,7 +36,7 @@ \ No newline at end of file + + diff --git a/src/partials/mini-projects-section.html b/src/partials/mini-projects-section.html index df2317e..06cb635 100644 --- a/src/partials/mini-projects-section.html +++ b/src/partials/mini-projects-section.html @@ -1,4 +1,4 @@ -
    +

    Активность

    +

    Портфолио

      diff --git a/texts/content-edits/pending.json b/texts/content-edits/pending.json index d3bede6..b795c36 100644 --- a/texts/content-edits/pending.json +++ b/texts/content-edits/pending.json @@ -1,21 +1,6 @@ { "version": 2, - "updatedAt": "2026-06-06T11:59:34.336Z", - "items": [ - { - "instruction": "замени: без ломки базовых сценариев\nна: без больших переделок", - "target": { - "scope": "page", - "selector": "main#case-main", - "anchorId": "case-main", - "tag": "main", - "content": "Общая правка страницы", - "snippet": "Общая правка страницы" - }, - "refs": [], - "n": 1, - "page": "cases/ai-platform-primo-rpa.html" - } - ], + "updatedAt": "2026-08-10T16:53:19.518Z", + "items": [], "lastAppliedAt": "2026-06-06T11:54:50.470Z" }