diff --git a/Minint.Core/Models/MinintDocument.cs b/Minint.Core/Models/MinintDocument.cs
index e076b47..6ec01e0 100644
--- a/Minint.Core/Models/MinintDocument.cs
+++ b/Minint.Core/Models/MinintDocument.cs
@@ -8,24 +8,12 @@ public sealed class MinintDocument
{
public string Name { get; set; }
- ///
- /// Delay before showing the next frame during animation playback (ms).
- ///
public uint FrameDelayMs { get; set; }
- ///
- /// Document palette. Index 0 is always .
- /// All layers reference colors by index into this list.
- ///
public List Palette { get; }
public List Layers { get; }
- ///
- /// Reverse lookup cache: RgbaColor → palette index. Built lazily, invalidated
- /// on structural palette changes (compact, clear). Call
- /// after bulk palette modifications.
- ///
private Dictionary? _paletteCache;
public MinintDocument(string name)
diff --git a/Report/lab2/newuml/dz-a1-contrast-activity.png b/Report/lab2/newuml/dz-a1-contrast-activity.png
new file mode 100644
index 0000000..5f0cb7d
Binary files /dev/null and b/Report/lab2/newuml/dz-a1-contrast-activity.png differ
diff --git a/Report/lab2/newuml/dz-a1-contrast-activity.puml b/Report/lab2/newuml/dz-a1-contrast-activity.puml
new file mode 100644
index 0000000..4c7c45e
--- /dev/null
+++ b/Report/lab2/newuml/dz-a1-contrast-activity.puml
@@ -0,0 +1,26 @@
+@startuml dz-a1-contrast-activity
+title ДЗ.А1 — алгоритм ApplyContrast (по палитре документа)
+
+start
+:Вход: **MinintDocument doc**, **double factor**;
+:i ← 1;
+
+while (i < doc.Palette.Count?) is (да)
+ :c <- doc.Palette[i];
+ :doc.Palette[i] <- новый RgbaColor\n(ContrastByte для R,G,B, c.A);
+ :i <- i + 1;
+endwhile (нет)
+
+:doc.InvalidatePaletteCache();
+
+floating note left
+ **ContrastByte(x, factor):**
+ v = ((x/255) - 0.5) * factor + 0.5
+ return Clamp( round(v * 255), 0, 255 )
+ --
+ Индекс палитры 0 не меняется.
+end note
+
+stop
+
+@enduml
diff --git a/Report/lab2/newuml/dz-a1-grayscale-activity.png b/Report/lab2/newuml/dz-a1-grayscale-activity.png
new file mode 100644
index 0000000..4b14c63
Binary files /dev/null and b/Report/lab2/newuml/dz-a1-grayscale-activity.png differ
diff --git a/Report/lab2/newuml/dz-a1-grayscale-activity.puml b/Report/lab2/newuml/dz-a1-grayscale-activity.puml
new file mode 100644
index 0000000..30c0e13
--- /dev/null
+++ b/Report/lab2/newuml/dz-a1-grayscale-activity.puml
@@ -0,0 +1,24 @@
+@startuml dz-a1-grayscale-activity
+title ДЗ.А1 — алгоритм ApplyGrayscale (по палитре документа)
+
+start
+:Вход: **MinintDocument doc**;
+:i ← 1;
+
+while (i < doc.Palette.Count?) is (да)
+ :c ← doc.Palette[i];
+ :Y ← 0.299×c.R + 0.587×c.G + 0.114×c.B + 0.5;
+ :gray ← (byte) Clamp((int)Y, 0, 255);
+ :doc.Palette[i] ← RgbaColor(gray, gray, gray, c.A);
+ :i ← i + 1;
+endwhile (нет)
+
+:doc.InvalidatePaletteCache();
+stop
+
+note right
+ Индекс палитры **0** (прозрачный) пропускается циклом.
+ Коэффициенты — типичная формула **яркости** (ITU-R BT.601).
+end note
+
+@enduml
diff --git a/Report/lab2/newuml/dz-a1-image-effects-classes.png b/Report/lab2/newuml/dz-a1-image-effects-classes.png
new file mode 100644
index 0000000..a9454a5
Binary files /dev/null and b/Report/lab2/newuml/dz-a1-image-effects-classes.png differ
diff --git a/Report/lab2/newuml/dz-a1-image-effects-classes.puml b/Report/lab2/newuml/dz-a1-image-effects-classes.puml
new file mode 100644
index 0000000..692ec59
--- /dev/null
+++ b/Report/lab2/newuml/dz-a1-image-effects-classes.puml
@@ -0,0 +1,40 @@
+@startuml dz-a1-image-effects-classes
+title ДЗ.А1 — сервис эффектов палитры (контраст, оттенки серого)
+
+skinparam classAttributeIconSize 0
+skinparam shadowing false
+
+package "Minint.Core.Services" {
+ interface IImageEffectsService {
+ + ApplyContrast(doc : MinintDocument, factor : double) : void
+ + ApplyGrayscale(doc : MinintDocument) : void
+ }
+}
+
+package "Minint.Core.Services.Impl" {
+ class ImageEffectsService {
+ + ApplyContrast(doc : MinintDocument, factor : double) : void
+ + ApplyGrayscale(doc : MinintDocument) : void
+ --
+ {static} - ContrastByte(value : byte, factor : double) : byte
+ }
+}
+
+package "Minint.Core.Models" <> {
+ class MinintDocument {
+ + Palette : List~RgbaColor~
+ + InvalidatePaletteCache() : void
+ }
+}
+
+IImageEffectsService <|.. ImageEffectsService : реализует
+ImageEffectsService ..> MinintDocument : изменяет Palette[i],\ni = 1..Count-1
+ImageEffectsService ..> MinintDocument : InvalidatePaletteCache()
+
+note bottom of ImageEffectsService
+ Индекс **0** палитры (прозрачный) не меняется.
+ Контраст: **factor** 0 → серое, 1 → без изменений, >1 → выше контраст.
+ Grayscale: яркость **0,299·R + 0,587·G + 0,114·B** (округление к byte).
+end note
+
+@enduml
diff --git a/Report/lab2/newuml/dz-v1-editor-animation-flow.png b/Report/lab2/newuml/dz-v1-editor-animation-flow.png
new file mode 100644
index 0000000..6451c5d
Binary files /dev/null and b/Report/lab2/newuml/dz-v1-editor-animation-flow.png differ
diff --git a/Report/lab2/newuml/dz-v1-editor-animation-flow.puml b/Report/lab2/newuml/dz-v1-editor-animation-flow.puml
new file mode 100644
index 0000000..9bd4352
--- /dev/null
+++ b/Report/lab2/newuml/dz-v1-editor-animation-flow.puml
@@ -0,0 +1,56 @@
+@startuml dz-v1-editor-animation-flow
+title ДЗ.В1 — анимация (EditorViewModel)
+
+skinparam shadowing false
+skinparam ActivityFontSize 11
+skinparam ActivityBackgroundColor #F8F8F8
+
+start
+
+partition PlayAnimation {
+ if (Container == null || Documents.Count < 2?) then (да)
+ stop
+ endif
+ if (IsPlaying?) then (да)
+ stop
+ endif
+ :IsPlaying = true;
+ :_animationFrameIndex = индекс ActiveDocument;
+}
+
+partition AdvanceAnimationFrame {
+ if (Container == null || !IsPlaying?) then (да)
+ :StopAnimation();
+ stop
+ endif
+ if (Documents.Count == 0?) then (да)
+ :StopAnimation();
+ stop
+ endif
+ :index %= Count; doc = Documents[index];
+ :suppress on; ActiveDocument = doc; suppress off;
+ :RefreshCanvasFor(doc);
+ :delay = max(FrameDelayMs, 10);
+ :новый DispatcherTimer(delay);
+ note right
+ Tick: Stop timer, index++,
+ снова AdvanceAnimationFrame
+ end note
+ :Start();
+}
+
+floating note left
+ Цикл: каждый Tick на UI-потоке
+ снова вызывает AdvanceAnimationFrame.
+ Пауза кадра — FrameDelayMs документа.
+end note
+
+stop
+
+legend right
+ StopAnimation: стоп таймера, IsPlaying=false,
+ SyncLayersAndCanvas. Команда Stop или
+ выход из Advance при ошибке состояния.
+end legend
+
+@enduml
diff --git a/Report/lab2/newuml/oz-p1-container-domain-classes.png b/Report/lab2/newuml/oz-p1-container-domain-classes.png
new file mode 100644
index 0000000..22101dd
Binary files /dev/null and b/Report/lab2/newuml/oz-p1-container-domain-classes.png differ
diff --git a/Report/lab2/newuml/oz-p1-container-domain-classes.puml b/Report/lab2/newuml/oz-p1-container-domain-classes.puml
new file mode 100644
index 0000000..94a0f3d
--- /dev/null
+++ b/Report/lab2/newuml/oz-p1-container-domain-classes.puml
@@ -0,0 +1,68 @@
+@startuml oz-p1-container-domain-classes
+title ОЗ.П1 — структура графического контейнера и представление цвета пикселя\n(модуль Minint.Core.Models)
+
+skinparam classAttributeIconSize 0
+skinparam shadowing false
+
+class MinintContainer <<графический контейнер>> {
+ + Width : int
+ + Height : int
+ + Documents : List~MinintDocument~ {readOnly}
+ + PixelCount : int <>
+ --
+ + MinintContainer(width, height)
+ + AddNewDocument(name : string) : MinintDocument
+}
+
+class MinintDocument <<кадр / документ>> {
+ + Name : string
+ + FrameDelayMs : uint
+ + Palette : List~RgbaColor~ {readOnly}
+ + Layers : List~MinintLayer~ {readOnly}
+ + IndexByteWidth : int <>
+ --
+ + MinintDocument(name : string)
+ + FindColorCached(color : RgbaColor) : int
+ + EnsureColorCached(color : RgbaColor) : int
+ + InvalidatePaletteCache() : void
+}
+
+class MinintLayer <<растровый слой>> {
+ + Name : string
+ + IsVisible : bool
+ + Opacity : byte
+ + Pixels : int[] {readOnly}
+ --
+ + MinintLayer(name, pixelCount)
+}
+
+class RgbaColor <> {
+ + R : byte
+ + G : byte
+ + B : byte
+ + A : byte
+ --
+ {static} Transparent : RgbaColor
+ + ToPackedRgba() : uint
+ + ToPackedArgb() : uint
+ {static} FromPackedRgba(packed : uint) : RgbaColor
+}
+
+MinintContainer "1" *-- "0..*" MinintDocument : содержит
+MinintDocument "1" *-- "0..*" MinintLayer : содержит
+MinintDocument "1" *-- "1..*" RgbaColor : Palette
+MinintLayer ..> RgbaColor : Pixels[i] — индекс\nв Palette документа
+
+note bottom of MinintLayer
+ Логический «пиксель» слоя в памяти —
+ целочисленный **индекс** в палитре документа.
+ Полное описание цвета — элемент **RgbaColor**
+ в **MinintDocument.Palette**.
+end note
+
+note right of MinintContainer
+ Общие для всех документов размеры холста (**Width**, **Height**).
+ Число ячеек растра: **PixelCount** = Width × Height.
+end note
+
+@enduml
diff --git a/Report/lab2/newuml/render-png.sh b/Report/lab2/newuml/render-png.sh
new file mode 100755
index 0000000..6ea24a1
--- /dev/null
+++ b/Report/lab2/newuml/render-png.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+# Rasterize PlantUML sources in this directory to PNG (ОЗ.Р1 / отчёт).
+# Requires one of: plantuml in PATH, or Java + plantuml.jar (see below).
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "$SCRIPT_DIR"
+
+# PNG рядом с исходником: oz-r1-foo.puml -> oz-r1-foo.png
+OUT_OPTS=(-tpng)
+
+run_plantuml() {
+ if command -v plantuml >/dev/null 2>&1; then
+ plantuml "${OUT_OPTS[@]}" "$@"
+ return 0
+ fi
+
+ local jar="${PLANTUML_JAR:-}"
+ if [[ -n "$jar" && -f "$jar" ]] && command -v java >/dev/null 2>&1; then
+ java -jar "$jar" "${OUT_OPTS[@]}" "$@"
+ return 0
+ fi
+
+ echo "plantuml не найден. Установите пакет (например plantuml) или задайте PLANTUML_JAR" >&2
+ echo " export PLANTUML_JAR=/path/to/plantuml.jar" >&2
+ echo "Скачать JAR: https://plantuml.com/download" >&2
+ return 127
+}
+
+shopt -s nullglob
+sources=(*.puml)
+if ((${#sources[@]} == 0)); then
+ echo "В $SCRIPT_DIR нет файлов *.puml" >&2
+ exit 0
+fi
+
+run_plantuml "${sources[@]}"
+echo "Готово: PNG рядом с исходниками в $SCRIPT_DIR"