From 6d3e7aad20d91f63aab90fa9b94ae0332da5f730 Mon Sep 17 00:00:00 2001 From: Yarila Date: Fri, 16 Oct 2026 00:03:58 +0500 Subject: [PATCH 1/7] M7: isolate presenter tab and device controls --- ATTRIBUTION.md | 2 + ROADMAP.md | 3 +- crates/doc/src/proto.rs | 93 +++++++++++- crates/ui-egui/locales/en.toml | 6 +- crates/ui-egui/locales/es.toml | 4 + crates/ui-egui/src/comments_tests.rs | 2 +- crates/ui-egui/src/lib.rs | 14 +- crates/ui-egui/src/present.rs | 146 ++++++++++++++++++- crates/ui-egui/src/present_view_tests.rs | 32 +++- crates/ui-egui/src/proto_responsive_tests.rs | 4 +- crates/ui-egui/src/tabs.rs | 65 ++++++++- docs/gaps.md | 6 +- docs/images/shot-8-presenter-tab.png | Bin 0 -> 75341 bytes docs/images/shot-9-device-picker.png | Bin 0 -> 106019 bytes 14 files changed, 352 insertions(+), 25 deletions(-) create mode 100644 docs/images/shot-8-presenter-tab.png create mode 100644 docs/images/shot-9-device-picker.png diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index 1f72aeb7..cf2e7e63 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -14,6 +14,8 @@ MIT OR Apache-2.0. No third-party icon sets are used. | `assets/app-icon/` (all files: `figcraft.svg`, `figcraft-small.svg`, `figcraft-*.png`, `figcraft.ico`, `hicolor/`) | The project owner (engraving-style drawing, vectorised) | Original work, see [`assets/app-icon/README.md`](assets/app-icon/README.md); derived files rendered by `cargo xtask icon` | MIT OR Apache-2.0, [`assets/app-icon/LICENSE.txt`](assets/app-icon/LICENSE.txt) | FigCraft app icon (chameleon) | | `docs/brand/artcraft-logo.svg`, `docs/brand/artcraft-logo.png`, `docs/brand/artcraft-logo-white.svg`, `docs/brand/artcraft-logo-white.png`, `docs/brand/artcraft-mark.svg`, `docs/brand/artcraft-mark.png`, `docs/brand/artcraft-mark-black.svg`, `docs/brand/artcraft-mark-black.png` | ArtCraft Team | storytold/craftrules `assets/brand/` | ArtCraft brand terms (`docs/brand/LICENSE-brand.txt`), not open source | Trademarks; unmodified use within FigCraft only | | `docs/images/` (all screenshots and exports: `shot-*.png`, `art-*.png`) | FigCraft contributors | Screenshots of FigCraft showing synthetic demo documents made in FigCraft, and PNG exports of those documents by FigCraft's renderer | MIT OR Apache-2.0 | No third-party artwork | +| `docs/images/shot-8-presenter-tab.png` | @YarilaFox | Original screenshot of FigCraft presenting a synthetic document made in FigCraft | MIT OR Apache-2.0 | Presenter tab and top bar; no third-party artwork | +| `docs/images/shot-9-device-picker.png` | @YarilaFox | Original screenshot of FigCraft presenting a synthetic document made in FigCraft | MIT OR Apache-2.0 | Device and scale controls; no third-party artwork | | `examples/*.figcraft` | FigCraft contributors | Synthetic demo documents built through FigCraft's command API; invented copy, shapes and vectors drawn from scratch, no images or embedded fonts | MIT OR Apache-2.0 | Text uses Inter (OFL, from craft-fonts or the system); no third-party artwork | ## Fonts (build input, not in this repository) diff --git a/ROADMAP.md b/ROADMAP.md index c3c12085..25439517 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ **Stage: alpha** · next: beta, ~26 points and ~162–292 h away (one Opus 5.5 agent; ~33–67 h wall-clock with 5 agents) -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-16 · **Change:** minor (bounded canvas pan overscan; community fixes from #478 up and a control-channel fix (#589); bounded canvas pan overscan; Typography spacing icons support scrubbing (#373); font scans skip named pipes; system theme on first run; recent files as cards with thumbnails on the home screen; community fixes: lost images reported on loading (#207), SVG import budgets (#190), Leptos code (#223), full screen (#227), server snapshots readable again (#188), owner-only preferences (#200), ruzstd 0.9.1 (#182), layer cycle repair (#205), batch rollback, Direct3D 12 on Windows, plugin metering (#192); vector edit mode regions: hover hatch, selection and drag; SVG/PDF exports refuse over-depth documents (#208); bounded MCP/control framing, connections and queues (#201); plugin log limits (#191); live-session revert guard (#198); attached MCP no longer replays after a lost reply (#194); repeat command recursion fix; the Layout panel's constrain-proportions link scales the other side, #220; core editor leftovers: component playground, auto gap handles, variables inside styles, inner shadows and background blur on groups, command-made text readable on dark pages, a one-step frame/group convert, delays on mouse triggers and manual overlay offsets, wrapped-line alignment; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; starter templates, a Templates tab and Getting started tips on the home screen; your online files; everyday editing partials: number fields, outline options, Hide when publishing, cursors, panel widths, dark pages; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; a public figcraft-server: open hosting, owner tokens, per-address limits, idle expiry, moderation, install.sh; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · **Target:** Figma Design (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-16 · **Change:** minor (presenter tab, device picker and thumbnail; bounded canvas pan overscan; community fixes from #478 up and a control-channel fix (#589); bounded canvas pan overscan; Typography spacing icons support scrubbing (#373); font scans skip named pipes; system theme on first run; recent files as cards with thumbnails on the home screen; community fixes: lost images reported on loading (#207), SVG import budgets (#190), Leptos code (#223), full screen (#227), server snapshots readable again (#188), owner-only preferences (#200), ruzstd 0.9.1 (#182), layer cycle repair (#205), batch rollback, Direct3D 12 on Windows, plugin metering (#192); vector edit mode regions: hover hatch, selection and drag; SVG/PDF exports refuse over-depth documents (#208); bounded MCP/control framing, connections and queues (#201); plugin log limits (#191); live-session revert guard (#198); attached MCP no longer replays after a lost reply (#194); repeat command recursion fix; the Layout panel's constrain-proportions link scales the other side, #220; core editor leftovers: component playground, auto gap handles, variables inside styles, inner shadows and background blur on groups, command-made text readable on dark pages, a one-step frame/group convert, delays on mouse triggers and manual overlay offsets, wrapped-line alignment; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; starter templates, a Templates tab and Getting started tips on the home screen; your online files; everyday editing partials: number fields, outline options, Hide when publishing, cursors, panel widths, dark pages; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; a public figcraft-server: open hosting, owner tokens, per-address limits, idle expiry, moderation, install.sh; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · **Target:** Figma Design (desktop app 126.10.7) FigCraft is a clean-room, open-source, pure-Rust reimplementation of the Figma design workflow, native on macOS, Windows, Linux and FreeBSD and in the browser, fully drivable by agents through @@ -313,6 +313,7 @@ Ranked; detail and milestones in [`docs/roadmap.md`](docs/roadmap.md). | Date | Change | Summary | |---|---|---| +| 2026-10-15 | minor | Presenter has a separate tab, keeps its current screen when returning to design, and adds a frame thumbnail, device picker and scale controls. Numbers unchanged. | | 2026-10-16 | minor | Community fixes from #478 up (batches #591, #598, #602; 69 PRs) and a control-channel fix: a line that isn't JSON now ends a `--control` connection, so a web page can't drive the app through a browser request (#589). Highlights: page copies keep navigation, flows, prototype settings and guides; Find and Replace keeps line endings and case-insensitive matches; text hyperlinks survive import and export; recent colours record only what was picked; MCP screenshots respect `maxSize`; Swedish catalog (UI strings), Czech plurals; bounded canvas overscan while panning; Korean fallback at the run's weight; many vector-edit, guide, page and .fig round-trip fixes. Numbers unchanged | | 2026-10-15 | minor | Drop files anywhere to open them (M7): dragging files over the window shows a "Drop to open" (home) or "Drop to import" (canvas) overlay. On the home screen each supported file opens as a document of its own and other files are turned away with a toast; on the canvas the files import at the drop point. Both wait behind a small card that is on screen before a large file blocks the window. A canvas import stays with the document and page that received the drop even if the tab or page changes meanwhile, and is cancelled with a message if that document or page is gone. Numbers unchanged. | | 2026-10-15 | minor | M7: system font discovery skips entries observed as non-regular files before opening them, avoiding the reproduced named-pipe stall. Regular-file symlinks remain supported; directory depth, font limits and priorities are unchanged. Numbers unchanged. | diff --git a/crates/doc/src/proto.rs b/crates/doc/src/proto.rs index 91d2e8eb..a844774c 100644 --- a/crates/doc/src/proto.rs +++ b/crates/doc/src/proto.rs @@ -860,7 +860,35 @@ pub struct Device { impl PrototypeSettings { /// The devices to pick from ("None" presents the frame at its own size). - pub const DEVICES: [Device; 6] = [ + pub const DEVICES: [Device; 19] = [ + Device { + name: "iPhone 17", + width: 402.0, + height: 874.0, + rotates: true, + colors: &[c("Black", 0x38, 0x39, 0x3D), c("White", 0xE9, 0xE9, 0xE5)], + }, + Device { + name: "iPhone 17 Pro", + width: 402.0, + height: 874.0, + rotates: true, + colors: &[c("Black", 0x38, 0x39, 0x3D), c("Silver", 0xD7, 0xD7, 0xD5)], + }, + Device { + name: "iPhone 17 Pro Max", + width: 440.0, + height: 956.0, + rotates: true, + colors: &[c("Black", 0x38, 0x39, 0x3D), c("Silver", 0xD7, 0xD7, 0xD5)], + }, + Device { + name: "iPhone Air", + width: 420.0, + height: 912.0, + rotates: true, + colors: &[c("Black", 0x38, 0x39, 0x3D), c("Silver", 0xD7, 0xD7, 0xD5)], + }, Device { name: "iPhone 16", width: 393.0, @@ -874,6 +902,13 @@ impl PrototypeSettings { c("Blue", 0x72, 0x84, 0xD4), ], }, + Device { + name: "iPhone 16 Pro", + width: 402.0, + height: 874.0, + rotates: true, + colors: &[c("Black", 0x3B, 0x3A, 0x38), c("White", 0xEC, 0xEB, 0xE6)], + }, Device { name: "iPhone 16 Pro Max", width: 440.0, @@ -881,6 +916,55 @@ impl PrototypeSettings { rotates: true, colors: &[c("Black", 0x3B, 0x3A, 0x38), c("White", 0xEC, 0xEB, 0xE6), c("Natural", 0xBF, 0xB9, 0xAF), c("Sand", 0xC6, 0xAC, 0x8F)], }, + Device { + name: "iPhone 16 Plus", + width: 430.0, + height: 932.0, + rotates: true, + colors: &[c("Black", 0x3A, 0x3B, 0x3F), c("White", 0xEE, 0xED, 0xE8)], + }, + Device { + name: "iPhone 15 Pro", + width: 393.0, + height: 852.0, + rotates: true, + colors: &[c("Black", 0x3B, 0x3A, 0x38), c("Silver", 0xD7, 0xD7, 0xD5)], + }, + Device { + name: "iPhone 15 Pro Max", + width: 430.0, + height: 932.0, + rotates: true, + colors: &[c("Black", 0x3B, 0x3A, 0x38), c("Silver", 0xD7, 0xD7, 0xD5)], + }, + Device { + name: "iPhone 15 Plus", + width: 430.0, + height: 932.0, + rotates: true, + colors: &[c("Black", 0x3A, 0x3B, 0x3F), c("White", 0xEE, 0xED, 0xE8)], + }, + Device { + name: "iPhone 14 Pro", + width: 393.0, + height: 852.0, + rotates: true, + colors: &[c("Black", 0x3B, 0x3A, 0x38), c("Silver", 0xD7, 0xD7, 0xD5)], + }, + Device { + name: "iPhone 14 Pro Max", + width: 430.0, + height: 932.0, + rotates: true, + colors: &[c("Black", 0x3B, 0x3A, 0x38), c("Silver", 0xD7, 0xD7, 0xD5)], + }, + Device { + name: "iPhone 14", + width: 390.0, + height: 844.0, + rotates: true, + colors: &[c("Black", 0x3A, 0x3B, 0x3F), c("White", 0xEE, 0xED, 0xE8)], + }, Device { name: "Android Compact", width: 412.0, @@ -888,6 +972,13 @@ impl PrototypeSettings { rotates: true, colors: &[c("Black", 0x2E, 0x2F, 0x33), c("Silver", 0xD6, 0xD8, 0xDB), c("Green", 0xA6, 0xC0, 0xA3)], }, + Device { + name: "Android Medium", + width: 700.0, + height: 840.0, + rotates: true, + colors: &[c("Black", 0x2E, 0x2F, 0x33), c("Silver", 0xD6, 0xD8, 0xDB)], + }, Device { name: "iPad mini", width: 744.0, diff --git a/crates/ui-egui/locales/en.toml b/crates/ui-egui/locales/en.toml index 3c127fc6..961b3c70 100644 --- a/crates/ui-egui/locales/en.toml +++ b/crates/ui-egui/locales/en.toml @@ -337,6 +337,7 @@ name = "English" "Current version" = "Current version" "Cursor chat" = "Cursor chat" "Custom" = "Custom" +"Custom size" = "Custom size" "Cut" = "Cut" "Dark" = "Dark" "Darken" = "Darken" @@ -801,6 +802,7 @@ name = "English" "New design file" = "New design file" "Newest first" = "Newest first" "Next or previous control in the focused region" = "Next or previous control in the focused region" +"Next frame" = "Next frame" "Next ready for dev" = "Next ready for dev" "Next size option" = "Next size option" "No assets: no export settings, icons or images. Add export settings in the Design tab." = "No assets: no export settings, icons or images. Add export settings in the Design tab." @@ -815,6 +817,7 @@ name = "English" "No components yet. Select layers and press {keys}." = "No components yet. Select layers and press {keys}." "No conflicts." = "No conflicts." "No contributor data was built into this copy." = "No contributor data was built into this copy." +"No device" = "No device" "No fonts match" = "No fonts match" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." "No layer changes to show." = "No layer changes to show." @@ -996,6 +999,7 @@ name = "English" "Preview" = "Preview" "Preview this flow" = "Preview this flow" "Preview this frame" = "Preview this frame" +"Previous frame" = "Previous frame" "Previous ready for dev" = "Previous ready for dev" "Progressive" = "Progressive" "Properties" = "Properties" @@ -1603,4 +1607,4 @@ name = "English" "⌘ arrows" = "⌘ arrows" "⌘ click" = "⌘ click" "⌘ scroll" = "⌘ scroll" -"⌥ drag" = "⌥ drag" \ No newline at end of file +"⌥ drag" = "⌥ drag" diff --git a/crates/ui-egui/locales/es.toml b/crates/ui-egui/locales/es.toml index 901283f1..557add9b 100644 --- a/crates/ui-egui/locales/es.toml +++ b/crates/ui-egui/locales/es.toml @@ -338,6 +338,7 @@ status = "draft — needs native review" "Current version" = "Versión actual" "Cursor chat" = "Chat del cursor" "Custom" = "Personalizado" +"Custom size" = "Tamaño personalizado" "Cut" = "Cortar" "Dark" = "Oscuro" "Darken" = "Oscurecer" @@ -802,6 +803,7 @@ status = "draft — needs native review" "New design file" = "Nuevo archivo de diseño" "Newest first" = "Más recientes primero" "Next or previous control in the focused region" = "Control siguiente o anterior de la región enfocada" +"Next frame" = "Marco siguiente" "Next ready for dev" = "Siguiente listo para desarrollo" "Next size option" = "Siguiente opción de tamaño" "No assets: no export settings, icons or images. Add export settings in the Design tab." = "No hay recursos: ni ajustes de exportación, ni iconos, ni imágenes. Añade ajustes de exportación en la pestaña Diseño." @@ -816,6 +818,7 @@ status = "draft — needs native review" "No components yet. Select layers and press {keys}." = "Aún no hay componentes. Selecciona capas y pulsa {keys}." "No conflicts." = "Sin conflictos." "No contributor data was built into this copy." = "Esta copia no incluye datos de colaboradores." +"No device" = "Sin dispositivo" "No fonts match" = "Ninguna fuente coincide" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "Aquí no hay código para unirse (el servidor es anterior a los códigos, o esta dirección no cabe en uno): comparte el enlace." "No layer changes to show." = "No hay cambios de capas que mostrar." @@ -997,6 +1000,7 @@ status = "draft — needs native review" "Preview" = "Vista previa" "Preview this flow" = "Vista previa de este flujo" "Preview this frame" = "Vista previa de este marco" +"Previous frame" = "Marco anterior" "Previous ready for dev" = "Anterior listo para desarrollo" "Progressive" = "Progresivo" "Properties" = "Propiedades" diff --git a/crates/ui-egui/src/comments_tests.rs b/crates/ui-egui/src/comments_tests.rs index bf30d5e5..696ff322 100644 --- a/crates/ui-egui/src/comments_tests.rs +++ b/crates/ui-egui/src/comments_tests.rs @@ -213,7 +213,7 @@ fn the_presenter_shows_the_frames_comments() { key(&mut u, Key::C, Modifiers::SHIFT); assert_eq!(u.app.inspect()["presenter"]["comments"], true); // The frame is presented at 100% (Fit never scales up), centred under the bar. - let screen = egui::Rect::from_min_size(pos2(0.0, 40.0), vec2(1440.0, 860.0)); + let screen = egui::Rect::from_min_size(pos2(0.0, 80.0), vec2(1440.0, 820.0)); let frame_min = screen.center() - vec2(200.0, 150.0); let pin = frame_min + vec2(100.0, 100.0) + vec2(14.0, -14.0); click(&mut u, pin); diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 20a8a77c..91f7a56b 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -426,6 +426,10 @@ pub struct UiState { /// A message at the bottom of the window and how long it has been showing. pub toast: Option<(String, ToastClock)>, pub present: Option, + /// A presentation kept alive while its design tab or Home is in front. + pub paused_present: Option, + /// The file that owns the presentation tab. + pub present_uid: Option, /// The full-window presenter's options (how it sizes the prototype), kept between /// presentations. pub present_view: present::PresentView, @@ -547,6 +551,8 @@ impl Default for UiState { icon_gallery: false, toast: None, present: None, + paused_present: None, + present_uid: None, present_view: present::PresentView::default(), preview: None, picker: None, @@ -837,6 +843,9 @@ impl FigApp { let mut p = present::Presenter::new(start); p.view = self.ui.present_view; self.ui.present = Some(p); + self.ui.paused_present = None; + self.ui.present_uid = self.session.docs.get(self.session.active).map(|d| d.uid); + self.ui.home = false; } } "present.options" => { @@ -1301,6 +1310,7 @@ impl FigApp { // The Inspect tab measures on hover without Alt. self.session.tool.redlines = self.ui.right_tab == RightTab::Inspect; self.end_pen_outside_design(); + tabs::tab_bar(self, ui); if self.ui.present.is_some() { present::show(self, ui); // What went wrong while presenting (a widget's plugin failing) shows over it. @@ -1308,7 +1318,6 @@ impl FigApp { return; } if !self.has_files() || self.ui.home { - tabs::tab_bar(self, ui); home::show(self, ui); dialogs::keys(self, &ctx); dialogs::show(self, &ctx); @@ -1317,7 +1326,6 @@ impl FigApp { return; } let hidden = self.session.ds().map(|d| d.view.ui_hidden).unwrap_or(false); - tabs::tab_bar(self, ui); if !hidden { egui::Panel::left("left_rail") .exact_size(56.0) @@ -1480,7 +1488,7 @@ impl FigApp { "focus": {"region": self.ui.nav.region.id(), "keyboard": self.ui.nav.keyboard}, "reduceMotion": self.reduce_motion(), "presenting": self.ui.present.is_some(), - "presenter": self.ui.present.as_ref().map(present::Presenter::inspect), + "presenter": self.ui.present.as_ref().or(self.ui.paused_present.as_ref()).map(present::Presenter::inspect), "presentOptions": {"scale": self.ui.present_view.scale.id(), "deviceFrame": self.ui.present_view.device_frame, "comments": self.ui.present_view.comments, "hotspotHints": self.ui.present_view.hotspot_hints, "inspect": self.ui.present_view.inspect}, "preview": self.ui.preview.as_ref().map(|p| p.player.inspect()), "mainMenu": self.ui.main_menu, diff --git a/crates/ui-egui/src/present.rs b/crates/ui-egui/src/present.rs index b5f177af..bb611588 100644 --- a/crates/ui-egui/src/present.rs +++ b/crates/ui-egui/src/present.rs @@ -270,6 +270,8 @@ pub struct Presenter { anim_tex: Option, temp: Option, textures: HashMap, + /// Small current-screen preview in the full-window bar, cached until its content changes. + bar_thumb: Option<(NodeId, usize, egui::TextureHandle)>, arrived: f64, delays_fired: HashSet<(NodeId, usize)>, /// Mouse triggers waiting out their delay. @@ -348,6 +350,7 @@ impl Presenter { anim_tex: None, temp: None, textures: HashMap::new(), + bar_thumb: None, arrived: -1.0, delays_fired: HashSet::new(), waiting: Vec::new(), @@ -1651,6 +1654,7 @@ pub fn show(app: &mut FigApp, ui: &mut Ui) { egui::CentralPanel::default().frame(egui::Frame::NONE).show(ui, |ui| { action = player(&mut pres, ui, ui.max_rect(), now, Chrome { keys: !typing, ..FULL }).or(action); }); + let picked_device = navigation_bar(&mut pres, &ctx, now); // Keys the prototype left alone: C shows the comments, F fills the screen. if !typing { if ctx.input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::C)) { @@ -1679,12 +1683,123 @@ pub fn show(app: &mut FigApp, ui: &mut Ui) { if let Some(BarAction::Responsive(on)) = action { app.run("proto.settings", json!({"responsive": on})); } + if let Some(device) = picked_device { + app.run("proto.settings", json!({"device": device})); + } if action == Some(BarAction::Close) || ctx.input(|i| i.key_pressed(egui::Key::Escape)) { + app.ui.present_uid = None; return; } app.ui.present = Some(pres); } +/// Controls that stay in reach while viewing a prototype, including screen stepping, device and +/// scale. The selected device is returned to the caller so it can go through the normal document +/// command (and undo/save) rather than changing only the player's copy. +fn navigation_bar(p: &mut Presenter, ctx: &egui::Context, now: f64) -> Option { + let t = Tokens::get(ctx); + let doc = p.doc.as_ref()?; + let frames = doc.top_frames(doc.page_of(p.current).unwrap_or(p.current)); + let index = frames.iter().position(|id| *id == p.current); + let settings = page_settings(doc, p.current); + let mut navigate = None; + let mut device_choice = None; + egui::Area::new(Id::new("present_navigation")).anchor(Align2::CENTER_BOTTOM, vec2(0.0, -18.0)).order(egui::Order::Foreground).show(ctx, |ui| { + egui::Frame::NONE + .fill(t.panel) + .stroke(Stroke::new(1.0, t.border)) + .corner_radius(CornerRadius::same(9)) + .inner_margin(egui::Margin::symmetric(8, 5)) + .show(ui, |ui| { + ui.horizontal(|ui| { + let prev = index.and_then(|i| i.checked_sub(1)).and_then(|i| frames.get(i)).copied(); + let next = index.and_then(|i| frames.get(i + 1)).copied(); + let previous = + ui.add_enabled(prev.is_some(), egui::Button::new("").min_size(vec2(26.0, 24.0))).on_hover_text(tr("Previous frame")); + icons::paint( + ui.painter(), + Rect::from_center_size(previous.rect.center(), vec2(21.0, 21.0)), + Icon::ChevronLeft, + if prev.is_some() { t.icon } else { t.icon_secondary }, + ); + if previous.clicked() { + navigate = prev; + } + ui.label(egui::RichText::new(format!("{} / {}", index.map_or(0, |i| i + 1), frames.len())).color(t.text)); + let following = ui.add_enabled(next.is_some(), egui::Button::new("").min_size(vec2(26.0, 24.0))).on_hover_text(tr("Next frame")); + icons::paint( + ui.painter(), + Rect::from_center_size(following.rect.center(), vec2(21.0, 21.0)), + Icon::ChevronRight, + if next.is_some() { t.icon } else { t.icon_secondary }, + ); + if following.clicked() { + navigate = next; + } + ui.separator(); + let model = if settings.device.is_empty() || settings.device == "None" { tr("No device") } else { &settings.device }; + let device_menu = ui.menu_button(format!("{model} "), |ui| { + navigation_menu(ui, |ui| { + egui::ScrollArea::vertical().max_height(410.0).show(ui, |ui| { + if ui.selectable_label(settings.device.is_empty() || settings.device == "None", tr("No device")).clicked() { + device_choice = Some("None".to_owned()); + ui.close(); + } + ui.separator(); + for device in PrototypeSettings::DEVICES { + let label = format!("{} {}×{}", device.name, device.width as u32, device.height as u32); + if ui.selectable_label(settings.device == device.name, label).clicked() { + device_choice = Some(device.name.to_owned()); + ui.close(); + } + } + ui.separator(); + if ui.selectable_label(settings.device == PrototypeSettings::CUSTOM_DEVICE, tr("Custom size")).clicked() { + device_choice = Some(PrototypeSettings::CUSTOM_DEVICE.to_owned()); + ui.close(); + } + }); + }); + }); + paint_menu_chevron(ui.painter(), device_menu.response.rect, t.icon_secondary); + let scale_menu = ui.menu_button(format!("{} ", tr(p.view.scale.label(settings.device().is_some()))), |ui| { + navigation_menu(ui, |ui| { + for scale in PresentScale::options(settings.device().is_some()) { + let label = egui::RichText::new(tr(scale.label(settings.device().is_some()))).color(t.menu_text); + if ui.selectable_label(p.view.scale == *scale, label).clicked() { + p.set_scale(*scale); + ui.close(); + } + } + }); + }); + paint_menu_chevron(ui.painter(), scale_menu.response.rect, t.icon_secondary); + }); + }); + }); + if let Some(id) = navigate { + p.go(id, Transition::Instant, 0.0, Easing::Linear, now, true, false); + } + device_choice +} + +fn paint_menu_chevron(painter: &egui::Painter, button: Rect, color: Color32) { + let icon = Rect::from_center_size(pos2(button.right() - 11.0, button.center().y), vec2(17.0, 17.0)); + icons::paint(painter, icon, Icon::Chevron, color); +} + +fn navigation_menu(ui: &mut Ui, add: impl FnOnce(&mut Ui)) { + let t = Tokens::get(ui.ctx()); + ui.visuals_mut().override_text_color = Some(t.menu_text); + egui::Frame::NONE.fill(t.menu).stroke(Stroke::new(1.0, t.border)).corner_radius(CornerRadius::same(7)).inner_margin(egui::Margin::same(6)).show( + ui, + |ui| { + ui.set_min_width(212.0); + add(ui); + }, + ); +} + /// How often the player polls the controllers while its prototype has gamepad triggers (seconds). const PAD_POLL_SECS: f64 = 1.0 / 30.0; @@ -2045,16 +2160,17 @@ fn inspect_hover(p: &mut Presenter, painter: &egui::Painter, ctx: &egui::Context /// the right (text on the dark full-window bar, icons in the pane, which follows the theme). fn top_bar(p: &mut Presenter, ui: &mut Ui, bar: Rect, now: f64, chrome: Chrome) -> Option { let t = Tokens::get(ui.ctx()); - let (fill, text, dim, hover) = if chrome.pane { - (t.panel, t.text, t.text_secondary, t.hover) - } else { - (Color32::from_rgb(0x2C, 0x2C, 0x2C), Color32::WHITE, Color32::from_gray(140), Color32::from_white_alpha(28)) - }; + let (fill, text, dim, hover) = (t.panel, t.text, t.text_secondary, t.hover); let r = chrome.round; ui.painter().rect_filled(bar, CornerRadius { nw: r, ne: r, sw: 0, se: 0 }, fill); if chrome.pane { ui.painter().line_segment([bar.left_bottom(), bar.right_bottom()], Stroke::new(1.0, t.border)); } + let source_key = p.source.as_ref().map_or(0, |s| Arc::as_ptr(s) as usize); + if !chrome.pane && p.bar_thumb.as_ref().is_none_or(|(id, source, _)| *id != p.current || *source != source_key) { + p.bar_thumb = + p.source.as_ref().and_then(|d| crate::assets_panel::thumbnail(ui.ctx(), d, p.current, 38.0)).map(|tex| (p.current, source_key, tex)); + } let doc = p.doc.as_ref()?; let name = doc.node(p.current).map(|n| n.name.clone()).unwrap_or_default(); let flows = match doc.page_of(p.start).and_then(|pg| doc.node(pg)).map(|n| &n.kind) { @@ -2117,19 +2233,33 @@ fn top_bar(p: &mut Presenter, ui: &mut Ui, bar: Rect, now: f64, chrome: Chrome) // Left: the flow picker and the frame's name, clipped before the buttons. let left = ui.painter().with_clip_rect(Rect::from_min_max(bar.min, pos2(x, bar.max.y))); let mut lx = bar.min.x + if chrome.pane { 8.0 } else { 12.0 }; + if !chrome.pane { + let thumb = Rect::from_center_size(pos2(lx + 15.0, bar.center().y), vec2(28.0, 28.0)); + left.rect_filled(thumb, CornerRadius::same(4), t.field); + if let Some((_, _, tex)) = &p.bar_thumb { + let size = tex.size_vec2(); + if size.x > 0.0 && size.y > 0.0 { + let scaled = size * (26.0 / size.x.max(size.y)); + let dst = Rect::from_center_size(thumb.center(), scaled); + left.image(tex.id(), dst, Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)), Color32::WHITE); + } + } + lx += 38.0; + } // The flow playing: its name on the picker, its description on hover; the menu lists each // flow with its description. let playing = flows.iter().find(|f| f.start == p.start); if !flows.is_empty() { - let label = format!("{} ▾", playing.map_or(tr("Flows"), |f| f.name.as_str())); + let label = playing.map_or(tr("Flows"), |f| f.name.as_str()).to_owned(); let tip = playing.map(|f| f.description.trim()).filter(|d| !d.is_empty()).unwrap_or(tr("Flows")).to_string(); let galley = left.layout_no_wrap(label, semibold(11.5), text); - let fr = Rect::from_min_size(pos2(lx, bar.center().y - 12.0), vec2(galley.size().x + 16.0, 24.0)); + let fr = Rect::from_min_size(pos2(lx, bar.center().y - 12.0), vec2(galley.size().x + 30.0, 24.0)); let resp = ui.interact(fr.intersect(left.clip_rect()), ui.id().with("pflows"), Sense::click()).tip(tip); if resp.hovered() { left.rect_filled(fr, CornerRadius::same(5), hover); } left.galley(pos2(fr.min.x + 8.0, fr.center().y - galley.size().y / 2.0), galley, text); + paint_menu_chevron(&left, fr, t.icon_secondary); crate::right::menu_popup(&resp).width(240.0).show(|ui| { let t = Tokens::get(ui.ctx()); for f in &flows { @@ -2149,7 +2279,7 @@ fn top_bar(p: &mut Presenter, ui: &mut Ui, bar: Rect, now: f64, chrome: Chrome) left.text(pos2(lx, bar.center().y), Align2::LEFT_CENTER, "/", regular(11.5), dim); lx += 14.0; } - left.text(pos2(lx, bar.center().y), Align2::LEFT_CENTER, name, regular(11.5), if chrome.pane { text } else { Color32::from_gray(220) }); + left.text(pos2(lx, bar.center().y), Align2::LEFT_CENTER, name, regular(11.5), text); action } diff --git a/crates/ui-egui/src/present_view_tests.rs b/crates/ui-egui/src/present_view_tests.rs index 3571b2ad..8fdd5eb0 100644 --- a/crates/ui-egui/src/present_view_tests.rs +++ b/crates/ui-egui/src/present_view_tests.rs @@ -95,6 +95,28 @@ fn scale_options_match_the_command_and_cycle() { assert!(!PresentScale::options(true).contains(&PresentScale::FitWidth)); } +#[test] +fn presentation_tab_keeps_the_current_screen_when_returning_to_the_editor() { + let (mut u, a, b, _) = setup(); + u.run("proto.present", json!({"start": a})); + u.key(pos2(720.0, 470.0), Key::ArrowRight); + assert_eq!(presenter(&u)["current"], json!(b)); + + let design_tab = pos2(100.0, 20.0); + u.button(design_tab, true); + u.button(design_tab, false); + assert!(u.app.ui.present.is_none()); + assert_eq!(u.app.ui.paused_present.as_ref().map(|p| p.current), Some(b)); + + let name_len = u.app.session.doc().unwrap().name.chars().count() as f32; + let design_w = (12.0 * 0.6 * name_len + 64.0).clamp(120.0, 220.0); + let preview_tab = pos2(8.0 + 44.0 + design_w + 40.0, 20.0); + u.button(preview_tab, true); + u.button(preview_tab, false); + assert!(u.app.ui.paused_present.is_none()); + assert_eq!(presenter(&u)["current"], json!(b)); +} + /// No device: a big screen (2000×3000) and a small one, presenting the big one. fn big() -> (Ui, NodeId) { let mut s = Session::new(); @@ -117,10 +139,10 @@ fn num(v: &Value) -> f64 { fn presenter_scales_by_its_options_and_pans_what_overflows() { let (mut u, big) = big(); let at = pos2(720.0, 470.0); - // Fit: scaled down to the 1376×796 inside the padding; nothing pans. + // Fit: the tab strip leaves 1376×756 inside the presenter's padding; nothing pans. let p = presenter(&u); assert_eq!(p["scale"], "fit"); - assert!((num(&p["zoom"]) - 796.0 / 3000.0).abs() < 1e-3, "{p}"); + assert!((num(&p["zoom"]) - 756.0 / 3000.0).abs() < 1e-3, "{p}"); assert_eq!(p["panRange"], json!([0.0, 0.0])); // Z: fit width (the whole 1440 width; the rest of the height pans). u.key(at, Key::Z); @@ -128,14 +150,14 @@ fn presenter_scales_by_its_options_and_pans_what_overflows() { assert_eq!(p["scale"], "fitWidth"); assert!((num(&p["zoom"]) - 0.72).abs() < 1e-3, "{p}"); assert_eq!(p["panRange"][0], 0.0); - assert!((num(&p["panRange"][1]) - (2160.0 - 860.0)).abs() < 1.0, "{p}"); + assert!((num(&p["panRange"][1]) - (2160.0 - 820.0)).abs() < 1.0, "{p}"); // Z: fill (here the width decides too), then 100%: both ways overflow, centred across at the top. u.key(at, Key::Z); assert_eq!(presenter(&u)["scale"], "fill"); u.key(at, Key::Z); let p = presenter(&u); assert_eq!((p["scale"].as_str(), num(&p["zoom"])), (Some("actual"), 1.0)); - assert_eq!(p["panRange"], json!([624.0, 2204.0])); + assert_eq!(p["panRange"], json!([624.0, 2244.0])); assert_eq!(p["pan"], json!([312.0, 0.0])); // The wheel pans down; a drag pans with the pointer. let wheel = move || { @@ -192,7 +214,7 @@ fn devices_turn_and_their_frame_can_hide() { let with_body = num(&presenter(&u)["zoom"]); u.run("proto.presentOptions", json!({"deviceFrame": false})); let bare = num(&presenter(&u)["zoom"]); - assert!(bare > with_body && (bare - 796.0 / 852.0).abs() < 1e-3, "{with_body} {bare}"); + assert!(bare > with_body && (bare - 756.0 / 852.0).abs() < 1e-3, "{with_body} {bare}"); // A device offers no fit width: Z goes fit → fill → 100%. u.key(pos2(720.0, 470.0), Key::Z); assert_eq!(presenter(&u)["scale"], "fill"); diff --git a/crates/ui-egui/src/proto_responsive_tests.rs b/crates/ui-egui/src/proto_responsive_tests.rs index fc9ccda2..f0ead8e9 100644 --- a/crates/ui-egui/src/proto_responsive_tests.rs +++ b/crates/ui-egui/src/proto_responsive_tests.rs @@ -69,8 +69,8 @@ fn without_a_device_a_responsive_frame_fills_the_window_at_100_percent() { let mut u = Ui::new(s); u.run("proto.present", json!({"start": w})); let p = presenter(&u); - // The window is 1440×900; the bar takes 40. - assert_eq!(size(&p["frameSize"]), (1440.0, 860.0), "{p}"); + // The window is 1440×900; the title and tab bars take 80. + assert_eq!(size(&p["frameSize"]), (1440.0, 820.0), "{p}"); assert_eq!(p["zoom"], json!(1.0)); assert_eq!(size(&p["panRange"]), (0.0, 0.0)); // Z has nothing to cycle: the size options don't apply. diff --git a/crates/ui-egui/src/tabs.rs b/crates/ui-egui/src/tabs.rs index 27ff085c..534881fc 100644 --- a/crates/ui-egui/src/tabs.rs +++ b/crates/ui-egui/src/tabs.rs @@ -33,7 +33,7 @@ pub fn tab_bar(app: &mut FigApp, ui: &mut Ui) { // Home. let hr = Rect::from_min_size(pos2(x, rect.min.y), vec2(44.0, HEIGHT)); let hresp = ui.interact(hr, ui.id().with("home"), Sense::click()).tip(tr("Home")); - let home_active = app.ui.home || !app.has_files(); + let home_active = (app.ui.home || !app.has_files()) && app.ui.present.is_none(); crate::a11y::tab(&hresp, tr("Home"), home_active); if home_active { ui.painter().rect_filled(hr, CornerRadius::ZERO, t.tab_active); @@ -42,6 +42,9 @@ pub fn tab_bar(app: &mut FigApp, ui: &mut Ui) { } icons::paint(ui.painter(), Rect::from_center_size(hr.center(), vec2(16.0, 16.0)), Icon::Home, t.icon); if hresp.clicked() { + if let Some(p) = app.ui.present.take() { + app.ui.paused_present = Some(p); + } app.ui.home = true; } x += 44.0; @@ -52,7 +55,7 @@ pub fn tab_bar(app: &mut FigApp, ui: &mut Ui) { let mut detach = None; let several = !ui.ctx().embed_viewports(); for (i, d) in app.session.docs.iter().enumerate().filter(|(_, d)| app.shows(d.uid)) { - let active = i == app.session.active && !app.ui.home; + let active = i == app.session.active && !app.ui.home && app.ui.present.is_none(); let name = d.doc.name.clone(); // In a live session: a mark after the name says whether others get in. let live = live_mark(app, d.uid); @@ -132,6 +135,41 @@ pub fn tab_bar(app: &mut FigApp, ui: &mut Ui) { x += w; ui.painter().line_segment([pos2(x, rect.min.y + 10.0), pos2(x, rect.max.y - 10.0)], Stroke::new(1.0, t.border)); } + // Presentations live in their own tab. Switching back to the design keeps the player + // state (current screen, navigation history and scroll position) for the return trip. + if app.ui.present.is_some() || app.ui.paused_present.is_some() { + let w = 128.0; + let r = Rect::from_min_size(pos2(x, rect.min.y), vec2(w, HEIGHT)); + let resp = ui.interact(r, ui.id().with("presentation_tab"), Sense::click()).tip(tr("Present")); + let active = app.ui.present.is_some(); + crate::a11y::tab(&resp, tr("Present"), active); + if active { + ui.painter().rect_filled(r, CornerRadius::ZERO, t.tab_active); + } else if resp.hovered() { + ui.painter().rect_filled(r, CornerRadius::ZERO, t.hover); + } + icons::paint(ui.painter(), Rect::from_center_size(pos2(x + 19.0, r.center().y), vec2(14.0, 14.0)), Icon::Play, t.icon); + ui.painter().text(pos2(x + 34.0, r.center().y), Align2::LEFT_CENTER, tr("Present"), regular(12.0), t.text); + let cr = Rect::from_center_size(pos2(r.max.x - 16.0, r.center().y), vec2(18.0, 18.0)); + if resp.hovered() || active { + let close_resp = ui.interact(cr, ui.id().with("presentation_close"), Sense::click()).tip(tr("Close preview")); + if close_resp.hovered() { + ui.painter().rect_filled(cr, CornerRadius::same(4), t.pressed); + } + icons::paint(ui.painter(), cr.shrink(4.0), Icon::Close, t.icon_secondary); + if close_resp.clicked() { + app.ui.present = None; + app.ui.paused_present = None; + app.ui.present_uid = None; + } else if resp.clicked() && !active { + resume_presentation(app); + } + } else if resp.clicked() && !active { + resume_presentation(app); + } + x += w; + ui.painter().line_segment([pos2(x, rect.min.y + 10.0), pos2(x, rect.max.y - 10.0)], Stroke::new(1.0, t.border)); + } // New tab. let nr = Rect::from_center_size(pos2(x + 20.0, rect.center().y), vec2(28.0, 28.0)); let nresp = ui.interact(nr, ui.id().with("newtab"), Sense::click()).tip(crate::shortcuts::tip(tr("New design file"), "file.new")); @@ -140,6 +178,9 @@ pub fn tab_bar(app: &mut FigApp, ui: &mut Ui) { } icons::paint(ui.painter(), nr.shrink(7.0), Icon::Plus, t.icon); if nresp.clicked() { + if let Some(p) = app.ui.present.take() { + app.ui.paused_present = Some(p); + } app.run("file.new", json!({})); app.ui.home = false; } @@ -155,6 +196,9 @@ pub fn tab_bar(app: &mut FigApp, ui: &mut Ui) { app.run(cmd, json!({})); } if let Some(i) = switch { + if let Some(p) = app.ui.present.take() { + app.ui.paused_present = Some(p); + } app.run("doc.switch", json!({"index": i})); app.ui.home = false; } @@ -180,12 +224,29 @@ pub fn tab_bar(app: &mut FigApp, ui: &mut Ui) { } else { app.run("file.close", json!({"index": i})); } + if app.ui.present_uid.is_some_and(|uid| !app.session.docs.iter().any(|d| d.uid == uid)) { + app.ui.present = None; + app.ui.paused_present = None; + app.ui.present_uid = None; + } } let _ = Color32::TRANSPARENT; let _ = Align2::LEFT_TOP; }); } +fn resume_presentation(app: &mut FigApp) { + let Some(uid) = app.ui.present_uid else { return }; + let Some(index) = app.session.docs.iter().position(|d| d.uid == uid) else { + app.ui.paused_present = None; + app.ui.present_uid = None; + return; + }; + app.run("doc.switch", json!({"index": index})); + app.ui.home = false; + app.ui.present = app.ui.paused_present.take(); +} + /// What the tab of document `uid` says about its live session: others get in (`true`: a session /// this app hosts or joined, a file shared online), only you do (`false`: a file of yours on a /// server, not shared now), or it has none. diff --git a/docs/gaps.md b/docs/gaps.md index e8b111a8..95962a5c 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -1,6 +1,6 @@ # Where FigCraft falls short of Figma -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-15 · **Change:** minor (bounded canvas pan overscan; reviewed Russian catalog and integer plurals; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; `.fig` import: editable vector networks, more layer kinds, variable prototype actions; `.fig` import, best effort: gap 1 down to its tail; Windows QA pass: everyday workflows on Windows 11, eight fixes incl. unsaved work kept after a crash or a forced quit; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings: gap 14 down to its tail) · **Target:** Figma Design (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-15 · **Change:** minor (presenter navigation and device controls; bounded canvas pan overscan; reviewed Russian catalog and integer plurals; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; `.fig` import: editable vector networks, more layer kinds, variable prototype actions; `.fig` import, best effort: gap 1 down to its tail; Windows QA pass: everyday workflows on Windows 11, eight fixes incl. unsaved work kept after a crash or a forced quit; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings: gap 14 down to its tail) · **Target:** Figma Design (desktop app 126.10.7) Every known shortfall against Figma, one entry each, ranked by how much it stops a Figma user from doing real work in FigCraft. Agents: pick work from the top unless the owner says otherwise. The @@ -138,6 +138,9 @@ No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passe cursor for every tool and modifier, panel widths, dark pages (`field_tests`, `cursor_tests`, `cursors_tests`, `outline_options_tests`, `hide_publishing_tests`, `panel_width_tests`, `theme_pages_tests`). +- **Landed (2026-10-15):** presentation keeps its own tab beside the design, preserves the + current screen when switching back to edit, shows a small current-screen preview and offers + screen, device and scale controls (`present_view_tests`). - **Evidence:** ROADMAP item 7 ("Left: tool by tool, panel by panel against the incumbent"). - **Impact:** Figma users notice the feel within minutes; it decides whether they stay. - **Estimate:** 40–60 h. Detail in [`ui-parity.md`](ui-parity.md). @@ -400,6 +403,7 @@ No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passe | Date | Change | Summary | |---|---|---| +| 2026-10-15 | minor | Gap 4: presenter tab, thumbnail, device picker and scale controls. Estimates and ranking unchanged. | | 2026-10-15 | minor | Gap 7: bounded canvas overscan for smoother panning. Estimates and ranking unchanged. | | 2026-10-14 | minor | Russian catalog (M9), reviewed and approved by VanTan: all 2,165 current entries, Русский in Preferences and regional ru tags. Russian integer plurals use one/few/many; contributor display name VanTan added. Existing estimates unchanged. | | 2026-10-13 | minor | Gap 1: the experimental `.fig` export writes instance sizes (resized, filling an auto layout, scaled), variables with modes and bindings, shared styles and variable-width strokes, and the import reads them back. Checked by opening written files in other software: resized and scaled instances keep their size and lay their layers out for it, variables with their modes and colour bindings resolve there (a frame set to another mode shows that mode's colours, also inside instances), colour, text, effect and grid styles are listed, and variable-width strokes that are the same on both sides of the path draw with their width; number, string and boolean bindings and bindings on effects, layout guides and gradient stops come across as the values they give but did not show as bound there (their entries now also name the layer field they set, not yet checked there), and strokes wider on one side of the path are written as filled outlines, no longer editable strokes there (the stroke itself is kept as plugin data and our own import puts it back; not yet checked there). Hours and the ranking unchanged | diff --git a/docs/images/shot-8-presenter-tab.png b/docs/images/shot-8-presenter-tab.png new file mode 100644 index 0000000000000000000000000000000000000000..d5cee8e179bebf78e69afdb7311d460c4a5a072c GIT binary patch literal 75341 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 E02Al^oB#j- literal 0 HcmV?d00001 diff --git a/docs/images/shot-9-device-picker.png b/docs/images/shot-9-device-picker.png new file mode 100644 index 0000000000000000000000000000000000000000..2f4805154b9cef0c9e122acc1c8c7ed484c1d72e GIT binary patch literal 106019 zcmeFa3s{Wl8$UkDImtOhIYbUih(c+cb68q-+t#T;s}_-j&b>KSLe5DvyDWCKq-~R^ zMoOVFYe`X>P73KTjWkm;^ZxGpnZx@=_WS++4*%=-zpnpv?bUXedFFZUNUi??TwtE7+G*)|-r zdArcQ>}rg1c+LCw+wy3hpP%3Aop}z9Yd-nX7(0Jk8^6}PiWYaie*4|km@jd?Nw z7|R~mZEsUPf`R`>k1j~_ORe&2aH?x`lG~qrHL^G<8u$HYLc)Cq`p%2W&qSk4^pTgF z2pt?1R>P&{AJa_aX~~L0!3_7NUG7=I{ttrdx%Z_v@?Gc|frl3JrBiot%fgdBJfYGW z`il6tbUl97>PA6?sq&(YQXF3O`A1kJS8h%nY5rhy%Ja=0c@9l}*YbVGIUUXSy_R3b z?U6?P5>89Qs}guE2|j`*KW=fIqBxxVv7DibR%bHQ^VN*UpSn}4Mnoh~Hs2oSC(Xn?=`Q`v&lfQvUy^hJ&H6)}Y36=^kzmr;hM@ld1WzzhM z$)lzKQImK~Y{MA2pF(UxPo$c>s4S5@S5#juP*(dtF%0P0GmVPy3as*~EEFgTW&Fxz z;l6!@HBZ6=Cx2$DjnosAgLs^%VO;X_%_;pjSC*bH%X6y9<9MT7Qe{zsNOJnC^bg^b zyqxH#+=TWvrlnaDX%;s+i>nk9QG0~@4WfIepmcFRIb`7?C&?7v33p|sd*u|KWQxpS zc0I4c!nWMPJIC2Ly(P7-W&6kXD;`JB$j0v*&Scpf5K0dTO9YFp72A#!OC@hjXuUx# z&#iu@lkq*%RbQc7JoR&_R8|FCNwNJZ(N?7u{gOszi|csKKV=sUZaD2^Omh! zmoF-vHzg`p8ru*fXpUL!SCf!j*OF>(-n893>q_9eD-D&fG5>t807HWh6HO!&i+1L( zNq!lVG7yD84=?1{G#m@B!1u~N*wZ_fo}YeS;Bf5}s%5 z&dlt%CSS~bc+o`hQ*ld*D9Vo8{G_N36##ZwcOQTMc@(10ie%?SrF*&3y*`KYz4cQY zR|!t>Ws&^Ss=(SR>2r6*_fFLbPGJVh5`#)q?5%g)VrOGXe`Cp+ta=n#mQCeE_%FP4 zVz^JY<5K<`FE9()&j!syR0{OZ&94ZIZCn|9KhZxsu^#*5;!G}9Pv=xhrU^bQ7Gyl-D|Z+--O3WL0JB+8w!64=aPjWk+$9)3!bOT#qStbn zL|$R9G~p!8}^)=zVje)dc|A&s=*@h zV42|kxZ<*L(m0criDYFeW^u%Lk8RuT;tm_|CCSn-!Bh?e7(tduStDvdg(X+tNgXSZ zox{zRyVD=tWe{?lZDl98ku3q)iT-+&BA?17FYn6}_vH|cqdiE$(N}@E1NWkOD*~zd zPSjlz6L4Ai6B9*G2pF;V6iy#E@J%FdE7Ljpu6*r&u=AhDKr8YVTb|K7dvdw*##HP!q9#zP7IEcg1!D%tea7V7Ik z(ay5l{6o)MPFgDu`8J7;Uoq}FbI_U!(Rx?c;C!F+`K5bp-|UsP2xvbJm{+X)QEX0j z>ig^l4BP%7xEWR=e+v_3smWtI>Vuu+=T0+1VwD?u#u0h14 zqWx-1uZfzk$zH}PRu+SIMyezm?q4z7=kLA785olr5~-F%e~|SAjGDtNrcp{814^1M zgShNr+)|L$5DAuOQ`R%QBr5f76i0g5y?JDG^Rp`rU1RIJl2GI>?&qHN@uQ`|2NaF` zAz$7l@}cf4PvMLrzq*v<+UnHtoLKR|*felU48J4}6_@B22N_o67QfFeC@L}?<_#&p zOBq{OR8&E7)M*!?~EU`JI65K^Qs_=**&;H<}2 zxu={WLQLn%(|s;l`3~Q;YnS(fImY)Er#xFM_Kj`wO}@V>xr6BA7E#B$7yuCFiIMnStn!^)Sx4LQn|%0L3T1;ieLTWDG@@jLQ`rb9 zzl_)&8W;fxm}C9n5LWj7WxZvwA6umrvg^-MkLPE2hVHpE+U8+cN;ot9*Zb52FK+K!z^MrB^khb(SAlfD{d(_bM)AJ6;lH#5 z^XF9uD5o^1Rt*q(cjS~$Z7`!6%=|ytQIk2>rqm`?8P_%)jFlerFUkrS1d&3}b*4*$ z51ibF3t?#xH}IUJ&nd@s{W~g~W9hSol-RK9JUEaHr5|00+K^o0HDB_VMNrdlk2yTL zk>@GUGaSFo+xvlm{I0=`#KbJafG37J_1htN4YJ;KDA7ACu>_O~5!*2!&ry8gU}ui4 zvYZ=@3$!muZK*9s8z#{R{C`<=p}DfmyaB^2#MwYF+N1PhQ}Mk8Wju(B5Db*vgFFVw z!UR%13^)UVo)2t#?3_j`ozXtV{0F3z=0@VZ+6!o&chn7o60H@UM6^=_>>kg}Q&g`k3XWY`7wcozhJ=-1pfH&@)-2bE)6>1=x-r{a{;+fzTp<|j{xT)0^uw0NnH@`?|p zQ4-;2K(H^Ugng#SK$Tmgr5R?QR|a$h5o=($Us1U?Kvw%y$Onc&P5#2B3JjpPww1OE z4|wk^sK$zjQ971H31m^S5(DL0NKS#l^vw3Oz80&{U77{5iJa5!AExC{ zE!hR~x8Xkmkbe9;oZ_q!H7)&VXDIzO_z0DT7B9|pmuHgD!>46@A=+HKZK8lC@$J}_ z+iqL7h&RQ4+%(A8c>CLbMg+bI4h)I#{XL?LM6vVvK7#|_X9ac(+Phb`xGJDH_=K5# z13C~#{w7>Giq|lLckk`fD>8^=TWXtdp`vZ+`Zn*Dg_j{1mBJ~EIOrNj%$qNmm#ry& zy#~=mtYms@x@QY|)#>aJ0sw3G(F?Y}dp5clQh79bZxt31NnrNU2jTJs#3(W0bei#I zmd%@424(l1-rv6^tBjf!&^(#uD~g1QL3Q=r>+Xgt3c|(w8jN`a&mw|H;Nhgm;|&gS z&N@OOD=5O>fZzN({}G0}IDtS|S~^tJxJGn8CiPv+_H=zK5+~$~w+a-yj2n&yZ^I=p z_d`BV-hm7sUdGr!{XVn$3^UtfXs5(9h`D@L5-WHlM-_Qw4Nis_H=TftI$BvL!C+5* zjnE%T3;`(^THAmY;mQDWyAU`_&wK+2Vj}&JhzGp7V~{2o=#-!Y(2F_VSP&BDNWnU` z;a9U6q155V?37M+?sD15c>DDq4Y+$h)@Jq}dZ_36>59(3d0Gb6cyc87Y{a4V6{PkN zV&K4pyj^gAeOkEuL3n*Hb8#;YR4H(6cSXXf9Ij(Y$8eZ6}^ zN=j}l-5e`HQGxfkS74NpHc2I1+S5t-nipMFWv{HT_rB!lJEGR>eZj=ka_iK+b^ui7 zwl^HVx`foeuN?z7Kom+1UEbBs&Q6sv0S7%?oLaHC0ZTbRy%1Z1r`(ldZl`514L;UeE7|7#z8Y%aj1MVrVB#&aPN`& z5^9^z`3?FQF&zwol?3m-5-HX|eh)Q$%;yS8^#?l5C7=v|r6An_kQi2~s!TzhZNoG> z`R3;PFG+p9Ds{iM!jc*UZB2UJPr`ryxgl~sx7Sip^|5e&Q+wZkPDt|y8h?EG2d{BX z%PDcywM4fl{-g&Y&{WRCb;^xhpfP%ccq?Q_`?zZwzx2kw-4e1)8iVV!569_kT zAKe)Q%DtOwB_hm$1U>0}ZEXXU`}lEp`g_0>$*&4i1{2)wKwE1C_jv|2Bjg4N!YzbK zK!fIxLJ-X!(9cAfijmU_XZ7mX zzW;+025HNV8PP_`@@#<(+3@5gq?Gh3_A#SZ6qnB^-fQ0Sr+K-=woW3wYapLlEIlkb z6BGRu6UpbQbzIZPe~Wd4_mG7}b*%~r^9N*uCY@h>nH$Vs<24xN-!@st+yB4B!;Mi9 zCn?|j%O@QEU;2dq9ZX-_9Or+cH!n6&hqioP<7tek+1>6n-GAYidCEr7k$*q=FNkoh zXdSoVp)txv_-dGGdE9#)d_&u-e*!`yc#Ek=9@V{YLD|)+AB`3!Pq=w3L(kc0;p)b7 z+86PJ>Nhg$+G|hjQ>Xs0?EbjJrq_L!YL|_5 zRey>D?W_Hz=ChhMYgy%GGA}3$f35S|bWLt|_Ht;WZ!Xl2pOJr> zlQ=43=e`!bk&4TAtjUsi26{dI_y=cxubapAZQ&ffn|b%i)a~nCD|T_i^^NhoF%;S)?>GytR|6kiETq(9j`1%J8CF)7pXzk}jkl$4S<;e?N5-}LmzMJRN1f99THk~<@uw}ppCYlKv#bwv#+9JbZ-4w>giQC@L$~i` zK0WG7%TPC~uirVsZNA7YyGp;nnll`ELtVfsFDHvH^k|nsoy3e^iFii#map81sQZwW zU%XX0bu;q`xr%RjKz zeK>4`^C3V;5BW~1yPz!aW>Vuq>anb4Yp3@8O>Z3Ar@wY)!Nb!1SK=(Hd>{&$UnPtO zmPiDvCwW$RpK|o+TYIa#yV4BNf708_Q9oS!J~_=OSx4}3vmmoA%cQ3m85x~iE){+l z0ToL!yv&jZP#)_d_ig2et$^5rW`KQST->bD`{_+kEAk#AUn#+t%Yi)Z7w(-goK)Yy zRt6r(53I=_Y2h;q3igoB%EaFj8W6w#k-ymqir7d(WP@0r%H%@YUpWN?A{sXA&Fv%f z*Q8$B4EvO9fDOQ>%R5>Xdk-hfB9?e*rg3qe2hM+M74P|O$*#FlTik)|13K6wvf6Lj`~u#Y z88PO=hbPQr7tEW71p@bSoG=gZw$<@xa$WrM90U3Sd(6FWp!nNBjOJNXchUCUMX(}i z7Xpxlv|MP{i$nI0hT4GVlS{+tsR)7&nMM}^YuF+IY#Qbd^{N@E#M)8?bs4#q*SMYx zDOX~8r1r0Pc!J{(<>x5sqbrq(C4+b@u;3gy6v0C%i4~PjeuvzTKVbG@O@1wjl%Mjw zPhi# zSRqO-f_I+dQqkl+s{qP!fFAPJQ^Fa~kl$fB>hshp;9HJUqXX|0mzHp=2*aE$kS|UZ z8wrk)s+If-%U;Bx?St&4`|L}=IAW#XAl6FI%~AZR5?7OvUqN$V53-=0*4pwV&fJgA zaww+9k*1efz&~a>^;dyomCN|_GS^nLKdyz5{YX`y^l9vMM z!;6cHOQZg}UhNI^Z9wtc^TnXjP=3k1{d$Bcb#J-p9<~L6rfv`kPh|Vrty%>s>P_r0OFmS%e%4i@`*3c)a1EGXKX& zDc9pqq-=DTSh}ZEr-9dxTX{{26oQI=@P8Q5z65@(kzu(7>Qf#dt(;N=YAVO%<2sW} zv|hsZ6N^92A$1v{8F2rdN{D%pQy^>V6_D@Mp#=GU)q+Sz;HEctdY-s;Z5(+YF$+Q| zhClmvv$&C~fW}1e9^k~el|)?FVgMq!xLc5;|9!^_VqC z|1k^bMeB4{_UOZ>u`*)d01EEyQGh9m0A8kRbgRbPD1CSiAq|?7Y{?d#@Fzq`5k_3M%4w zp9n7>LsGzb`Db|nA^!8qu_WmIV$wV`5K3}B90cpRwi2Z>el?|NM52<^Kj>5oTpE6d zkj+W1@=G-%94o0T$?uAGJY7Plds0PVvXG3gYZ#xLw<@Kt>*I5!!)?okOMzbc$*E~4 zF9J5lEk{ybM+#|bSMBZU@g&QUZh~XrYe$Y0JY)=z;!b-=Tao(`lhrnH**xTKq6;G} zT&2JctqufoI1-Jo3STC}#^cg+Q_~vrc>q(3(l-MWU;h}w8L7sIPmxHy3^>E&Cq^kf zp=cx&rYi&}A1wTBVP{c<@<)I4fhg)g3>dkBjwSfJq{io~d|u@Ttg)4+bI)1%oUmF4 ztro-rezi%#`QC@~OY}wc`VYUhh3MOtQ%E8)&?@F>B>i;Z*LNWuH0-iGvV*4CwjDb% zsJ{po?&THX3T-}{L})i~EBZQ>_T@m1A=|-LG@;~D>-7XjzrC_lryd)+q{oZV=do@I zP;OJ8IplsHE9iRUq|aG<9l>y*TS90Y2ya3>f&}|{$eSlm1{9n>H1lmZbzR|RG?_i z7;U|^JIv6$0oBXFMigg38EkxA!b*sB-XAWSg-_K4{a_n=L3$QtEJ63=BtKi6 z(#P7`IvH~A#3sM+CU1k<)RwJK2Ne_+mc#1)kSDFt#B_p8jo%<(kcEUxI~yzB*hx0> zKW>zJZMx>6l=~pxMP?Wf{w2SNN*Q3DvkJ&)34S4qaKL2h(or-MqH=GbP^Lm_0hvJ= z(umL}a0(?z>J^ZgQVf-VsBFXHU4;$&UsOGzBP|MuH0?w{+&sXJ=XMk#5@jev4rym0 zp;?0cFxfxmisc+P$xQ5#%AnKbd&Gp>eWuHH0n}(8o0?vTM6Q-mV*co1-pi7KSRCyt zjDGD2jBA{#jgBakNCjY+-~q;qdhAErxBO+VTY~+u7ceMu7`Bom@=MP0tH*EU*5Amy zpumsbn-R8X^*W=4Fcd?;hO&x!Oj@)^!^#25+5p0|;oeN*&8?pY4POw7yo6%cZjA>hf|UhT~H zfOuX%^El_|zAa8?($nWyT3IEDCUpC%pI&s~gl^dSD|8nOhQ=H3X-|+U2asMi$St`OwsoZ8(7pU%hrLPClfZGM-K2$2 z^eLO>RXYeyHEd560O#X3a`ocDirp;BamI%vJ`9HvgdG0Rdm4`5;4$@=#~>dJgB+4b zLViw|pTCo|v7yqk71ogX7LrdOUz{TDw$rI<=h3;N_qPO;8U_x9#75mmBpm<4S5i=; zPc%PgZm%}P16@m*4BTmHV0B_(n7MS1c?o)$4|>zEJ>kv2g_l_Yc9R**t*9^!ql3=KjY)molRPP z00rnA%}|iOJvhlP$w1u>%{nr;{IyflHX*UA3*BPO`Nd`vJBEz!j4itF6 z#8hm7zPS(Vb#pP$_Gc4e+b)m+agU!5r~yXd?lpyhG&ClA`hz`bqyY>=hLcm*e7)`w z#Bc(Sh=pU>LXhMYdwwPQlTSgqaVGBE_~VUWj6PG3Kq~O>fW;clK;VeNG_YF2{9+*g zuqYPtGLS?BhM$0Xi!|KKmYyp?zL-QwEaN?(!)06Z)b?;NS6=G>+%=$|nSFExq8MpJ zK_!nE2Z@^)+ez07Mh|p3KxD{1`#gejU?2vq&=XE3hCz#$ayz3eRUv}E_Q4Vfd-r2g z{uxUgk>d|p)r14WMQp#p&o7GfBoSJZpz$K!)d#tJWZ4np7{9>*DsOBAlKx)=fb$9* zI7xyIW_9Dhg*HdGaIi5+5Gi)-VT?=O4u&0Kv#6V7W`g8uESv}cvv7S}k12{kDU^+Y zUqL#@8;zQDwy}TUVj1O8laRk1TK9KS3h#K7Wpu$-&cKDxrJQtRc=^=hkv81&ssA+1 zz#eLnIMWCVzsJdL?%>-Y9ZOS3a_QLVBr=SUMe4}f?b5{?D%YooM060!L zmX?$RA&RTKey6sK^m2;IjkEA&V#x3x5tkG2#^s!%+h?ci?NAKjIPaSbdJoC;Ms%Gl`mg8Gb3)l5i2fv! zqSza7%8b;+m^YD(AwEr-csC)5CqvT-q|xAE(&SOJt8j~aF=-j#T-XQ;pPzZs{k)PT z!1$0ciMD||kh~n8{5~&decakXb_D2K*CqE3LIM z#1FWc)KYtgL?hcOPupO7*-3jcb}xyXEu~QoSJEK!zWs_}=lWZ{0<}1cZ2n z5j2EI3MQ!l!amkhD5~{QaH12?TXZkwrepaf!77B*V5C6|O-X2W>td>(1F2RBl!8m# z4>zDB#dM6bDWuheqoZYL6bJ!M0cDXS!XjP*^?Mlsx|jOY-l?;-Ezz|NGOWbOCm+Zj zuBIM1zmqNy%o)Kv z2}VaOdI)I1R9=oGnhdA32)rllNt~6tk$Y)zg!imKsPxa{j6uf|v@I!&)pS)34|rx5 z&L5z!37JnRuQ;1nQ{E8+ndtdI=?V$gO!7J?OT-h_~0Qbct)n}f(CF891w z@k6Y?Zon8azN~%#v~)>0Bh62oi}IR{(=uC?ryif1magZS^6X4+WkpwG7DC#v5y^THodLx)C3O*An5H^w-BxYX**}4oQ`fh zI~Dxn-w5vC?Ym_p@jH-q*-fXYHZhLv+?f#VEc0oCPg5Q_BU(-&ihK-RQn{rd&9(3uoc# zb-&(?95pv;q?<)T=*B@zGq2fvK5J3#G1KN3=a!G@xm*9{vAHK_&+XB5Sl6N7blDfu zV+aTO;}9ELUJMb>elY}k<-2vn_kaWPm~^;(=Gqe*-A+XQIP%i29~U1q3gDXc37Y6K z(C)yx{j7wdJn;?F!fS>kBJSl zc-WLbCXEQC1{;|={oGk+Nc%mVoqpSR_QC0|x0o&(vFOrVot&vl4wWBtJFM03RcNm< zaa(!5IdEx>-|Sf~%kLanIrdVY+b>~FzIx5;%~lhJI8D{XOJV`0$~k!}f0=DBRAg@a zHQ_+!vE^NV8FK#X^0VuHV5Wr|>t?bfCi=Oq>Vu-2=R8pp^tNwDg9?t`dM8>S&(07W z(T6z#vx!5l`v%^A`6Ta%%&q&~$wv;AFBtWvd0M*z9=SK1m>}HxRRW!!U8I^WF@-4SO@_X$jT8t;uTl)3?t3^M^cXw79Wi zoWaIxtc8dD%nWEYn!jn8rf^%jxpx5fVx8}%d@;RSD+&AcGa;b~!ZQR5%IM_fdSSQI z*6Tc-`ls>p5AphoMt@y?chk-cCZX%iVr{s?4{mPD76(rZ5Lrak3<)(HX|W>K@h{7X z-G@J&{N!cEvw<&;=X8Xj<{~!`4>uGfGs6%-3K^+r&W~45SX`xMfSN}c4V&5P_|dMH zI*#ai={p!2xPI~Zk<_};m+Iy4?XJN_Mh|`abK+kOcHPuF`=TzR>S%)<+2ayf2&q#+ zLBZ^vbAQiij!xx^3MQ_WUgyY^8m?x93TiOkqtO7rFz|v!hQO7!K_P!GdQi6f-vh}(_ zGXJF_;VseRC4&aN_q-v!|Tb33D#5$gw(OURmUxvNA5wD^#JFp&Sb(oTH-Z21-`A zZZFuUB0@8;Be?hcd3PXMoGtmDg1k-lxBJZ9H`S(~oHFG1Hen1=k4HVRR=I5uk12g~NeY0tuvvco-hsy8X2O@WBK^1R34o9)4 zn3%i)f}}gDhnnQP#Ds+0&=Y2FZyOg58a#O7lHujITz-hvW)Y?R94Pd|w832|d|C8z z=uFMUSb@_!GHq$GhHtUvtmfrHY7vq@Nt#|5~FSUQ8 zN6TxD|AsH)XejXhldfKRW`?@p8FUYg%ah%uN zVU9DRR9*%9zx_^dlH~$8O$O%j>~UQAIop7aK^HI1$@KVf&}pbUv}OQPJKB6jpOpFQ z&f8$SYC@C{hB?l0y-a{w;*dyasuZ5c5FEgd3Y%ZX1IdxOHymFhK}*V8(u?i|YIGkS zN`+0FN#%V_{h|#i$ z0(rP+ZBf8EYd@1U`SB?!OGfWMd~LAioYGOR6g%F22{a1SRU(O36_aRmTf}L5_rB>UaubBF!ml2>Kd0T$gp%=GgNHy z7)1v$!w%ME{oeezcfUgUVz=wQJ-b!!zEgMm#JZIAew(9~k6mS*#rSakFy?#5mqkUt zoP6}WvS0S=<9@ZNC!P;9KLp}AF3rD@>tH@TlxH0dv< zI9aF|S}-))_IOC=+t=ZC6p(yj_uGMP=&Vgs>P2a)#Oyly(l&*@)swtO$~4<8o4$%* z#k{dUw~l$`xm8A^xmV%B)X9w_SBh^ztfn*SsTWE3X?u=-*Wb z9FTPkFQGzb*n#$g6tqn)_1JU`4kd&`ar4&4J#4fpx;wS|AmhQ4{`mgur%bft4rHPo zm3*Byfj{oermUp+rnuF{V(t_FV$VFi$eF z_=$O11O0!0KE`Yi?TXt_YvUgq`qbO`dM?adBPl$~;|V;UmSw zuQ?zZiH{Iuv<75{v#ia68ju|h$>h=Q@F)Lb34cj1^MjJA$L($;C585c+@}RVCZXEN z>t>VR>#6{^jJgEdT=Bem3jL~I*Z^GHv8JvL?aP7Y4uV7AcaFK_W2r>Q*D^^}$SBzM zKaHMDL_Wp}Tpk#>7Ok_5^4#J5p!m`ncd7szMU6~7vU+FVyRchP z%|EsCj&wJGXB#|w8JColu1%WU?kpWYa=Xb{8<*4tR9WS-te}#c?q6)dZ-OwR*yZH~ zvcH1H3Xf+19|6@<22oT*n4wVj#t&{mYb{r?1UsAc{qj4}_t(!_uzD(WWZe&v3r8{c zDn}40%=p_krIJ81YWno)>%r&p91JG&o8+q&g4%6@Au8Y3s|xKAc6iCAdM+ zvc%hSQ%zj%`czIy8BDc#ff0iil3u8H3K#M3L3U^?0uj*T?--hMZk#b+5VaCtq_P6K zCwr|*Ne81a{R@4_U`auh0E7xh5el~_L6T9>E>W+y<4ssDNQ4SjC;|YnUg%@l&nU;x zhzan+8Df;Kaf$D+Ag9uk^Ra1{EZjvhTV**8jwwT+7>l{y4z3!)JM|{WD0bckn6hpMN!T&v zH&p4OmX-({d>REK^Pp$Vb6<=Y046wm0j4)Nz{o?nM>T0yEEV^5irJ9@q^<-h@BEo#=-!b_|;#UzKL0#OxZBTCD^0 z2Xm-tEGez#Mm=q^;IxMxYr};<5mN~vbb{^E-$VHi+kspFb}Gn&2qiC&2TzAWI}n%@ zZWQC{5e##vTzqQzPuHN)bW8N4)YyCsiS_7&a6Y^Z45Rt9$TaSUuK;vW;gFY-Fo;y{ zpEezqjZeLjFn{!ZMqYgwdGR(`ir`*`sm=|jYXh=Sar~vdV7?pDa3Ksk;+#Ic6^aC? zI8s*X4C$~Y-y+JL32+fCl(%^y&>NU+OSpxqqxOWpH>AZx7z+jC;NHXBu?0X`AYnkX zS;L%_mLei^EBF1pYjD%5Yp3O|DkJ4SaW{@dRb7g7TVb$#${-(UxOnyRp0Io z*Zd!AHOV``(&V?B?eiOp%q>=oj{tGgBXLdwayCo?!5eUhi#qUn`$A|`Ua$T=K|A}< zY(9rMWB#!>cLp@Aip|&VXJ!6QY+A#9ronW7!uNQ%m;S|o-F~u+xc2?n+I%kys1MZ# zRA#f{*NEF&JBBRRgXK=+e&)j%BwQNy$fFJLJ9l@qkf;T#E&p&Vihb5Dv#>L7~~*v-!hDl>#q=0+;e_AxbFRZ#rG``FZ)+<&1pT z`+7RM>$NGH@;wC42SRhLZiLuIWuvh;sD<;P4s;@l4lX`pP;`L58fIWT@=vfl7FiTq zJ$;hVr9MnF+`%xf^bX03b1!$={5_!?O0F+VEWr#C$ntZg5Zx_hJ zOrwz)5c#G+|9P8Wx%DQiD+x>kj{c6l^s+JVn4Fo{4&%xr628a7LUx9^1xN@`m(c#l z0Zpylyg3YzJxakWwA0zkJz?4F)eoLCY_7uWqLv(0M2s2(WY{4aDs~mweI&yh@mWq{ zpV#EM=$cL9^MTq}rssjf1~mE7cWnJg=8oRimHCi?tPeSC3Nvh3 z+9!=QyMH$Jx2()v-plaC^AVtkF#PZly+3;5(q>p)qEVp z8MfpHX3JLrlS;pGu?~Mt89DFsUU#Tx88Dl=W&16LKu%V7Nvd29^)Np)aW?XXGi|Ok z7MDv!U-yb+#ADA2#8ngLhERHhoXQZuxBAY?5tVc&v3YNLdL~dmr1K!5_x7NB4OL!@ zq)jsD8StSR<6>Lhl{oznIy;9pm@QunofTOGyn3HBe?lb>cuu}Ff1>sqdXi@z)nQdo z+ba6qO=;g-=#nGIfHpx7dJ^YAkNh3M~w|{(R3}g#C{ZIabqv?~5k0Ea zN{s4M`-xqb16&el0JO1sCl^(*p_1YbRgRb~x3i!pf#g_nU&b==?<#pNkn$M)3HHk9 zSs+@XF|}!tU7>N{2GJ_CfWw>xg1!xmKxUkb#mqs%^+Ma@mh!q@*ZVGQg9TB`9z>X zGX!7TM1eDDq2^V(59>(Ymb5wAUl}i5`{8PxY4)X66>(-~MmA3E*$Y9B#;A)}l!gKj z9GFP=f>+LlCTV;m6`AxdkeC-9+hDdfayq7TW(%f$=IX`^5IFE0O})WmGpNZDa|^l! z6o?*04kNEV6Qi_vp``DXUPVH=)#3XKdfpb&XOgd#QxM`nRSKh|W5!VE)( zW&>S5@z7W}o2tL8iEUGe6=-Ec^=9%5H5sr3oNJQU?bDNSL#V+JfQUKgPXvD;ky48< z*EG7bsfCfyw3I;50$Dh|vM2p#l}~7G7;O+X0#-~JgZHQ-8fC(4<|@rmnF+*a`Qk%K z@4Bj-@+u11+meVIPg}-4OCqqT(!mW3N$c>`q*iNzR+T$dF@ivG+K zSrrj+GDCRSCz$JzPjtqPY!IZfG@iGU>B!~@1~6ff2Tc^1UQ=#?h{z80ZAfjPI`T2` zRdh&OsN9BTu_`Qt&_8Kq##pE-r|blmU)?ANE?AS(cnskNOU$&1(w+xQ7cG#45VQu3 z0?>`Y+2~FzOf;5li`J+SOsE?7P$fhXKiQdwm;|FM2YNr_8?=L)lBWp{;FSYD2@fQI zse-;HiUNQb%4nPF3qtJ;V;Y~@2)Y+Lu4 zYbMM%(2KO;2u_Y(tV%FMevnsM#a03yAc8XWl`AVR6k?}{?EOEeMY}8`m@vjpnz1jZ zuX6F}044NWWjPX!h@v#n6JsKKA%-9l957W{_wPX`Y`QyT)u~{9?X6vR{&Dp1H+K8b zj?*5WU33q=B+U*Y|A#M}9&1%I*%KfmhlgpRspk?L1=3vunG`g8ON&hUK`XZQEq z&(Upns7Ge!b=^3fCk(mUc^&+)dZ_CEs$b6TuX!c;KYZb+U)OnEPG9w#J7!pPnLu9I zzlYFN^>!OG)dpZA@C*mCRoLB3)mHy?%dl^b`gJ|;of-St?k5b1UZ`3|hoe~=U#31g zyjMs2(L@GqFF5oNy!}7RNSD*DTjvSEdz1cJbl_pp9j>^-Q`gnt_~=~P5GP4ANS1OxlIsk}=mO0mjBL7#L!JDV#?B z{h%L~xJ)}67n$O)y{R~3aKuQZGI|O{HJ#P7dr0rZNnM<|U;>Lfdm4v(Mup0x$@S~= z8gBdgjf#U<-S4C+Jh+^n1mX`(U}mt-l+qa z*?usysRNHY-tu`Y5~WmzyRQ;AdBwh1GXjeOr5BK*?0Q0vspK5!Tw{;hRrI&tLFvz>KTL_(NibcUd5F%}56i{FPG)+HiOnB1G zD*LUg#MSoG%ibE!cj^zmbBL)N9n6QZKXA#W5W_pytFH0iXC`m!m_fT7mm0!@3h-$T zs%^k58;tC!HWBMQQ|>w~X_`4(K)d+dip{V?NvIi(tbXw*)eVwYOgl&O-6R{Gu59*oi_#T za-%`w(GWe0;CVZ+w@Frylm7bpJ_Fn0JB^3Uzuf1gc2YxKu&+`+$D{b9g`aJ=*SE?eFtQ!N}qnj2W1~JrBc$ zz37PZFRm7CPyX{sCt9qs5;6s88%S^O&1 zLE`S29r|dTnYGdkT6b{uPfSYXG0?l(41R+G$K4MDr$^8h1Dk00x%VkrAL>7ix3T{z zfX3J%(O5P2&8kWZ^{JuPF)b39bW)1P!;3^!e2XL-Zjf`Kdny&W(m2Y zXtkz0y2!!QgQ*?y)Qz!20VIRsfTJX~4HXg0hOkW!pkYg+!wxNq1?bg*IX2ZHiq5;~ zy8l`v4!J-yCuj#Wk9QRxRI;$U$$~OLFcbwv?ymjb=jZ{CL+UUszubX=Qgqi|bWHA; zoET}{5LJPNFa?}@9^4gyDFdw7VA~G#KsBcNF@8*?L-GV9LbQPDdb1&8T8=3pP*5JIw+T6IWm^Rlo)x3WP-cEF*7P@8p^Ec+p`NeQ;uSvw^GGRKn=na#EB#)f!aZ! zby#)t(g7DA%ffjGef`&VKt~RLq$~_q>k+BWh5goYIG*7P2 zLt29&UfA9xf|RDu$_lJHdQBtm?io51;^{GVfL5?9gDF|H2D+w^?#%X14l-FR$79DF zV(~DYI|uZDQlF&7aIFYD@Nv#ir~X4{0(MX@)h|lJm0(q^^&hoy4QHVgN{7)J)hCKN zmWu`bX25#UShqJ~07A#m1VywkvKy6sY3UP3g&|{2O1onKWo*K>5N{*QDP}PPRcY4p z0%+4Hw!k;AO7K=2ngZEq0zG}UTr>iFS1qZ}VzY|jTnCpLBn8?H(X3nrj8X{Q4QAdT zJ^>t7j!=iCXmvhP5W|&1W z=&5yvQ7mbIWRHp^WEcw}YcTK%$_iyn1MOvkSc#P;RCfM}VqnonSRt|n!o+*{kX*ThQ7 z0$oeHA5kklgYcZfB_T8))rP#}6g3-P!-_5{_7b|lI)`aeW_mv({NDII%^}PqK+-=x*wGrZbDN8+@tLXD?#@qkOSk^SF`2r!^B^y z@PdX>Guh21;FTpf* zL<@Te8V0Nt4Pffiy|2?IyBOsfMul{*UUVtU;PzwXD6RBJlSV5$>UGggGE{s=*LFyRXT z7uiPKCS$S&Y%I$(gyA+4nE70rs5Tu~9p)w%A_~F|QY|#8kL4=Z0MUG=*7X$OYspx2 zc7Kj)6r7+Z0yMEbBRD{;jaUR^FVZC0r7Et0(bg)DWnYSLz*so^OrjKd58xfzSk;0= zbgYH&1Y11@@|Z<0&`TL{(Tf0*%?+XbR4$D2ZH?KXcL`n&)1UUkGw8mS^e~2C7j)8^ z6C`yVXQv5mXG|>D05J-NK%-8LS-n{oU<_H&ZdJkR#;+I|AnYfJT^sT=JR??qe*Gmy zDmbjQOnNqRG)hm6`RFLfRCZv_OixCQGs0Z}c`&B_C-w!9me#Ja_0BO8{GsbNeW)^p1z-d?N~T$Ue-8}2w(;jS9uWx^`^kSby8)J4!9X=dUuO>20p*~eAdk`bE&eXZ@pMap}2 zi3mlJ&CyRPty4^3h*9eGm%tc+7T2rpCW6S=<-4|;u*|eMimZOED+^wQ1+l~>24G`t(5F~W8pw=(*oIMdv=gF zfgX9r8QMl2R9f!<^E=@|RBFXL1%0(yhrNy>+*uQkFnA9`qiP*jv^{amZ3|c#(2+HV zl?4prl-Y8jy5`3EhvYj}ajUKy2r{LHLt180C0+~@rwES9wUW|zk-+Rcp^`EOmuS*l zWE{gm%m}0vP_dS%o=DSG{nHpEG$Xe{b%k9yuSAU zR*dJd%^mu1**WoD#MCKL)v)sdKsHj0IzoA@#qOH8(#&H9NU;@%f$!5AMr9sfpnN=g zYYnv()NT|#!T~vOW2gW$5CJf5+kl-^7sA{#;3C?92Zc7v4#q<13)Mp<+M-_w5LXz~ z?c%@0Q?RqE0UJ3CgAN_Ug)eA`a11al!e10Z*R+}kq0HIpY7g;eqA(l!_y7-CG@~j+ z!_KrJ8t+j6B(G6jw_<{5N9Jq}beDZ#V$l(*)UM^15bUWFYU?l!T*XC_tL?S^P3tqU zl(zhoOG3;361^j#BYTi4(@h(>pcY`Yof9EF0f%VVU&1354e%5yzKczp5ULK54Y^LH z-Iim@17=?_$__|3^4Y{8V1-td4$Ft-t`JWwRE&|@Z4`+N)daK}4kwlF^IrNNnI=t; zP9C)n2et63pmr#+hS?xJ$&z*-AUXHnGEQJEq<5*smJYNFqgHAFWCIu-X&qH~_f>@z z>KfIe!LNyvI?hy$?r3c!M%kCOw>)SF05>&I!+QZM%v6l%@2q+eGMdK0VY z-4?8$G}OhHh$fN{RJC1q(Sl&{9`w8Ahk-<}cQ$8` z{=+9nZ74z*se>d<6Pzw~-XoDRkGs9=po+A2Q$$VhB^^MyV`TP4Hfa5&mx-<&zc6LrZ93A zoRdZ@EThj}IcFlvwtoKp+Hrcds+emdE3!Bpx^Kky4@E^&>Obi9ru(sciO2p2Z$xRy zZ@NE!$SaDg?9!w!uN%%X*H%r1))AKb@ECF_Fgj{MFEs9iZ!1$FsF{Y?r-DVDw_g_X9H!pcH5)qo|gdI|=f00N(hX?uurM(xWeX`|U-@n)DBxfwQ`8K;j? zS~JIk=l=A9&G#Q#oBvOduSbQeQWH>4cBr$$g8ErE(nh)X^h%4qq`)@6| zwDpX5yH&2whbe>2th&+@VH~DK)%Rv33sbtP=l^KW8G9mQ|HTS%(=}O)^>caS`ORAk z2d_9%DSFf&DmHE80Xm!g=_jBqcGy&D4lfLC(l7GaSms{4TKw~g83xl<_+&&zZ@$@8 zGVp!QeHRmXHD+%z=3}L9sglPsVT2`d3Li+Z2nPFl;8=_3?Y0FUzjv83qNrcs{p ztx&({rnN`arO>@Q8=!3}n9Gt!*l*e&=xTV<&{cR%M*PDQ!o!1B^|@X+eo&O*?V!W9 zXB;^2Tq~SMI|QR*9M$OAaG31kkY8nXhHePWSyTkAw9gf#W=s{#`2cCGbjsy$`VJ@1d+IPSj z;o(@?ixn(R(t%#6YMT7}L@XJ-RE-#G(+WJ$jA4`$|HP+Ns75X^ag*A&g*Cyf3X$M1 zIQ-8lzzw@FVO_KcA28GtXU0C6$t73-%Ne+&VS=|KfFsq~wqwcy2BF6|wZ{Um&AD~M z^RNW;a8x%#u%99Us!Jo6R*#W1#D{f#a<2i{8JO_K0dq|4I3LX#t%nUUoj2N>!3kJ- z!ypZelBwqKNpk~+H`FaE)mSx*SqL&zl|D>XYqtasm}3@#85>ukiq*I`tWHQ`*E7fUIavJrLGCu6w+9>J!r$5qK>(3L^^lO%^eu^VfV#m!I-vs zo?AO44rKtdQd6t?np}EN4Y_Mg1h0Moa}Bi%)UGNDo7@WtX(7|ny!EYSiCdUbh~5Aw z0H6W3oXCU_42Nrnn#s*2&2=MYc$$0ygLl~@>?Y$a9=h3BiOn&Z19_`u^3(=IZVW+g zQ`sW|I?Xiq7uMUFG991%C4k&+-P(w>io-igWKNk3l&h{Yz_lTSTLK4e6g+F_GJhNs z8s;#E$1Xkio%WI!SOUR@+D(z>DEfH>;kG(q^FY>KkX+!6lpQ?7_v# zfORQ~@e8UGv%#yhE*wd7>8kbB1TxzKNm1kRctwoGq;zK-118!T(&WpERW+EkzD0X7 zDOOd7lY!BtePB_>x@rJ9B^ru4Og9di`0+P6x|~kIz|}}mk6l8HvV|F zW9GVt4QsxU}DcnZBmOFsq1e*aC+bhdd1W^#HH{`; zC$GJKEkA9O8X_O@U#r*#BI19OEe3mSxP6l`~5>}xmS6z4m?1EB6eQcM1 zIBWxiH=Fqy!$dZ?7c8gZ3yMmcR~e^=T38K*f3uyGS*`h8Lf4Y1EOILk`d|Q~Tu)@c zJ3L-3316RDP$^o(U@k=rLm4`z^ne#TO*V^7+HYZHbLeHRls_Mf7o4`xq#?vTq%}mC zP0e5F9}+&U_AF1I=98N%cgL%yn#*$ftO#$Yy1-Z!yUXIp`Q+WX=f5S{^J`4G_yI5* zLK3K|nSr0GV&ln0&}^_d4-gTUEd4!eI5nT)W3R(Aa-#(`&R1Sc^U&|v0h~!SSxM5V z#;QnGh93y`4CBojRjfGq=wqCP+gAQvHgNlqQ2@OF$p?Ch$^Re`{*|b4Z(Q`0 zu`s!ytzOu2hN-!E%Qo5lJ{YYF?;t}A0iv0~_bLxktqXO8`hzEV&Ko^AVV9gYf`Jr5 z##?cqg*uyrR-(RUOAxxs`qak3o`@z=z!=H0=Q|9NqRGv0)~z%YD=}v>g!GA6RTh{A zFJPfQBc`em97nWA8Hoj91ltk1NOf6Uy{_tJFs){hKzm@vE6b=(*q74y!&N$o2^v6V zgL5U_lZ!Cus;nFbJ;)q3{-{D~$l#M_0FXWmg#*83D*#F|fr5Rp@G7mn5smm8#G~dc z)iwj`tEP)IMmxQ7TIBy=>`TC!I=8hqqT-B-3W^dHD)pcSMF9m29no6lw4O?j13|G; zD;kk1b2ds9sY)Db5mD%=RgbkAtwo>=0YPv8)0S#bh9H4NMF=5=BxKnC`u0w;H@5fw z_jzv56(!l<{)Y9f^{#ilOYxami%<*OL=LER+yey;t4cn%E{ZipW(jmG@ucN3@b$#> z+!OKPq+7^1O87W>E)i>1l1)sd0))RA5gGcy`5||eH4e1R;Q;mwAkWB}TkZ_RcCl_Y zGB~jAJu0>VQzndJe9sD|^*e~7L9LTGkKAKqUfjCF{--Il%@_1QpzF!{9sP26sd^km zsFq6;U1h{l`lcNKks77WZJj@a&BGx)v+9AypLtyMakGW~R@b_oBMgec4{<78-azSPJoJ#yXi{r+99T z1HW+&eF=%a(G$y!jTV!KOcV8*^pwHisr^JE!lT6J`~ zElmfMjAbNY*?KYm|F6`}Y$AopQ)FTTEN}=1!JughC;3VwDG=-jIv8Xsggoz7N7Z_{ z^|P5qeG|!2tRWFnwBl4H#%n}a(rQ|K4RY3K>js({j9d6k#AUji>xgUv#Ym;DA2MG6 zroxi1w%z=qtc2f(+pZhX0ANzBcoF8^Rm2AC%aE@{zRX{2BoJfz3mBVTL9ZYzClKxs z@`JJ$mMR*!ldRQQr0pj2ls3Z-8<0q1B%~4;M{yzCsc^Q(6634}*Sd>n7m2ymNE@}i zb|kuptqTCO31X7b%lF*sKsI6S5f$ zcyt7PEFr@CDt?E2vCXZ1Z6jHYk*yF5jz0t2G&|962c&x-!K3SldH-9_I%NqNt|s!| z<11<>BB>JFTW-)WUehFi@(W1Ly=4@;Tm3BNUGW$HJ#HM~`?fLe8tweX(OlxIi8Fu* z5dqLNIV78%8E}EnKfncyqEp+ZAbglE$5?m_$a)&4b!Uu_7e_h5+j=D(l;)|Hp|f!XTc+=H?{aD zv^!3IxosY)>Pu@7Q$x?!)&4k&*<@QmhEcEth4h=l>5OtB;+EUutbSG+eRM9H?I|WE`9ubML4Bb$ zRzkrAZ1tK2L=q|xB$;v6J=(}H5GIH5;ykF^rQM2wK8CFpnkwD33|>hVM$_YCu<-H4 z15Yv|B4$7@wo5JC-|n?L&2*WurX5uTN6tB5^`LEgpS;D$BW}eoY#35aAgT^zfcK0# z-cN`jRaS}&yfHatbQnx-FFFuL?ijsuMI)Ggz*uy#(~bip+OVQMw!j319}F}pjOo@n z&J6dC-A`gBRQPDU#s0=NTZ0qZopE)b6C6o8!S8{lhc%}CKfopyH7ncQ?MiPALWacS zt|l&}Vn^%97>oECex~%uT?z3hGXP}xIxzLML^ujstnSU6s#8=(L+gtE$NDko5k$d#)bADI`)*!vwhho1QKkv!kZJw>>D(4AkP4Gw&2aJ zF&GuJS}r391G5=5DEM&tdw#_2VatN?QI01aRd8Wpr<1WDorXs@18MxhUkrlA+BRse zhPi3|EPUMoK(NKBhG`jSt0`Ahyuv7j7EZR8n#vd$F-T5s3Tht65m9I#a?Z#jX$Akt zFNaZ={4b#hREq~2Ymnze=5^^v7ybC!MNEbg=n&JsMdC5~0D#(^Wkb+wM}|UHQ*BvD z8+A5`L8T(bGhA2pAd0AvFkMY*!cd?G%(QI;6l`k21<qq-5r#f65KF;%nptI^ z;rxIy)r?&FvuEi z7ZD82gX~nI9IBHFG~%(c^N8#8gNV<7B$ihjONN@1GLDoKy8wF!{}SO_9pNoskVEVM z9EQwd#t!=`xNR@+1ISU}c{Zq6!xGRbKkoa+PLMAOqZ-9Q zr#$DA;Ji)Gb##r4j&${Iz)nT|td~+~K?&8oPbWpSn};4y^YEF6_b~6&uf{H0_VzFj ztoAht%{sKLK)oYF~rca?WT#{34C@@kjHVde56h&6d2HS|eDa(bUrm^9mY{ZPR=x?bn|=;x=%81ohzRIjr`Cw`&5`X-erfxh z*s;c-^}edzDm(6bC4Q1Ul$DcnjPiBBU`mBvL5J*AycuJ~AHO*B2V@o+=j^!}b$$0V zf4vl<1EgYQ1sb5mfNdgSvzRnaAMN{igyv=aGehRq#WNs(Nh<)6OYF~qM?!DW^=F^%l?(WL3@^vY9DaYg^)N|y-L|A2F4z;n^o>*-5 ze!H==RNwq^Y5pkt%b#3Z+SH-jBl~>vPY%It`uXoO3=!_m90fuxQJR{(j?nEyt(PdY zltj#IMsxeuRJ(6M)p&i(h5 zHB+Zeh30z8Gg@~}T!yvnWfo|}(TY_jvP4=h4Y5MdS!WxzXuCyE+nNQko@ZklBO)<^ELFc`yx7C88j~*=er^7sz4Nau8q=qJ4C>*rEis@`202?-(Cf18ql5wb z$i=;CWaME|!wg_=i>R9EWtFdkBJbY$q`dN{zt31@Up>@2A{vY3G_K#0d)El8H?#*p zSC~AER}*)TGYu5au?^GbodCu_@Uo%yz7f&T%x^Qad;0d;ltFh>q5hbT*77oJ+e(uM zDr6#r%~O(xROWjJX;8`Y2hB9m_`G0H+XLI$n(<0BrpQsgFx&R2N9;yLV2AZeWE^0p zA@C-M1GX?X$L{Em)X~ERPrvro`i;RZV?#nhK=}T~6sLfrpde?P58RVpaU98ox-KvA zMmlcq%Q@eY(Kh+ARNkAsWH+Di-7NbfB{U*`$@eRrhF-Iaw0FT8Be2L?NC%6Ny@NE< z<2ku^@7x;ZecXGfD`tP|mq#uK7UkT?tvq>szwL0rfpTW>0R~%`L(p2mnetyi%dWBY zhn4mQMc%E%eAr;H2x&*`q7U1_b_+a#t^^G)GI#kPSG(zR?BAaRJkeN={jHzYcdKR*|6{#$ZatBW!0+a8%?4^F)mvlmk&L>9lLhj z?(lq<@~>u%I5Ny0DY|P|m6P`T_T~>>)91LSjl&wI+eKiW&?ocZJ@4W6u$pOvrYwwJ5Mr){7V(9UbYp=jSJ)teC0r%(~BRR$$dG(bJzV^j_&TW{uZ{ ztuxml7P6`4;P^k+W{VYH?tV};YTc*P%jF|nJ+M*G6!0hEsB>>cjLaZ@XJF`p_h=z_ z$0$e~uuZgSYIyQwOY@f2@O=*M6|D2+J;4;H?u**@*n*Zj3muNU<*+=&N`!IB;ys`Fb;Vlwdsg~B)KjCe1x`aE?1#E~ zpHj?V?p|gYD=Kog=wOo(6^^+ETp#V*;DSZQW^ccS9@8*k*0&)mFzO-d$@b6zWcG&< zk>$SP3VBhs7sD49(e%~b4-bLbQAWJEN{x_YDx*Mxp}P;mmo_$JoW)WrhNjJT83jW; zzV$T7pMXsS=~VyB;6X!2rEbq<**Cy%jG|F$5P+d43HQh$oNY5i!bA|g{rgD-SeT(; zuWM81V-eTvuB{xl))!d~VrtZbGxFN(`asTH*BRGF%k?*kZUq+nV)OsO=cM6DfZTMP z+eWdCaA_Xm`}6$ZS=ABXdSp#5kMIt2v5!Enu94Q9@~VX@j=)hvy-#@|C0!eSYEm*a zE5K(b$w(x|tc*NNc^1)Fw7q;p+Gxy|L^lchhEvWb?b1fOcoPqyGsOTsGDeagLV!ES zgQb0SPak;oRIoA$JLDrGF>-92y}<0wWxIMus+wtYj9;Zz!f<(C+d0yX(rPk-;m?5AR?{k*7}WRN=lxWtKEoQ6Q z*r+*^=0kZl1gcns8k$>LWIAjW@&hI1|0ZncI-Ib#7C*Jti)A{-x+j;Pbhn)6#^&C=`;&WmI4+C+da`;;CD+-1;)o?r;ggEqr3Yj6OE#|qYSL8xQ_v^mW9 zINnf@;^hX4h7Ze>2K%RE2a^e}vXSiC;#4WEQtPI*;A;|tV7h^U7k zl8Lz3F|Nc;)UKB5dyVq`m>OU^^pI9liy|oD-s-&SQf*86b}an)L~d@UusD-zJkR~i zw=SM9N=chn$<*WiDK91nbtBj{dFIF59tp0Fi{25v zv;Wm>H}$g+m5HNs$4VZqE13*!lc1d~N~W45*PwB_#jEMhJ7ile@GFcEZ8@h{?bFkv9d3HVMmCl}>)?(TqoxB_?sa+xRzbA`&6i_Omj#DrAnz;;>m-T4d*{g$Dv=A)n7(` z(lhM&I;63HxE=xrLRBTJdPPaq zA=RCbrDr??pDqvl?L@9|LU{LQ+|yaf8O|3wm-Jt?Z_NlzULXmNJrIWHhi#0FP0Qi^ znqe?KWtoPv)qk+>Y9t$KxI~@QF2Z$rpm}&``+po0yakDWx}Op&)+co>3Vb>|wC%~Z z2R&a1`|p9XyGy;&4|WH^Wn6vE!)cdO1dJzJw0oPXU#MNO z*>{ZNm?CYNL3dx&?@GR8Sn~d?sHqNRW>?X~#-=1`$~PbT$C(3f+8zCB`-9w|8m>tr z?U}`UHT2yH&|yjcKxtlTejy~j&BBYao}LU>O?0W*D>NM7K{psPhjE12;|I1(=lmI6 zW_RGt{m^@}*BID!DOAq6hq{1$c2oT+Muu1*0-t2qk zNbUPuD&Y^^3BBx?t#Qtg(P>BK|1f`O?f0(!aotnVp2RbKqE^}O?0dO5HxCZ=jj2gv zwDWcr;&#|r>^O${L1{NE`vKcK_RX=WgN6rVKWW`+@Cy&WXdME-yV&_~9Cql)cC!%K?|r}sgF{OOqNLAC1u#SolCe#zQZM=m zH5;=Wn%PYBcjQ3@&|*-+g2byRY9w4y#4$h*Xp6z<3A{lg0^Q)A@5-2%J zGA(PpN-eK@iGE$;Bj}E^03sR&amA85fmtTpneG9j%1Qt+0aViXSP(`_P68c#!kx)f zVSGe5OC{Q;lcFafsNZ6xxRnFFEas~yH&cuhtD{AZo&d51uxG4W0B0%1SdD}tIQ>m)EFk2Jsz?gU@yA1Wc`D_NF&mi6nc-WpTYZ9W7`xSIvqwhe^(O=qTm z&%Fy?V(bFKKv@aETp`j%qaZkxvY_=TxCiZ9Ta*?NPGsXuQqVGrGvdf>wC#O}WegCQ zxC<^hBWXvGN(mODwww4Ti6 z(YE7ET4t&n00EP@jl-83S~{x6@}8T+@S)!l!91mOLEVMuY(35e9<5NWl^vNZ{Kl;ASxk z5Nwc6JU%10jTl&*bQ7x5)p(cPSKfz$Tm_v>t zWnk`mh%#wQKao9zY;$0H9{7GvboRp9P>VWMl#zz}Y#J%4W*Z@`vjv|%HlO_u^*&_K z$>j0n@T1V@uSHSXGL0k^0RIBzJguG*QAB&wWVa;NTb8PCRIWl5V)bP%+s;3n*3Yz%=qF47tLxX4UC%#bj&r{xkR@b@?u6{Sx^0cev zbPlg98?<^o`Mnp5y7~g*H@29!OHZ%9xT<%qwC^l-X6f#);}UBMB7O5>x?e6XBOLIr zYTFlaWe?*YXC=&@P;q;tv%ZX_+qiaHiMO&3zCK^F;gFC15coNKt=62Hm3Y@#p$XUS zj{mNP^K`iJ4>mDHn}j|aZpi1J5E_3JqJExC2yuWR+Jmse&)VLjOfUoGIz@aMCrxpb zn$Jq@%d0n4C`~P_UO(Irw;ng`F1hPkx>S%{Raqo^Pz)}S*=x?E*p~h)E&F6OnK97e zyIUK{QPnr`08WkL*A&2Sb<6iBpqRQf;vo18@t?>Ty;rniHswhbAjN93@NYXQjXP#xOfcObl z7vN&4u}c~&(xxc2t!$!~S13K=w_bd|^yU3)fopd?B)BLVw>lkRCT3MUD1o9*8AjeF zGh7$c%9CED4BBk>T!lC;*$~HfyqSIBSj^O-uA7be6C6`)cy~wmfq?FkLszb>Tq-}u zncCPCr%W-nIub6}q1*f7QWS9!iiR=J=Ce_xPBJ!2P4;Z_CP9aWtIW@Mv*9jsA$!q3 zVI}>SOGmJYUF@{&xw;=b)n4F*Hb4Lao9ynl#!8u6&8F+E`h?2`$v%7-h~Uu__MPYT z7vo=@bGsXtEYbG9#p)?*;$8o=#~y+>%qZuX=CL&&vn$AW%z*cVG%4?fCj3LPKK6j~ zg+K54ubetuu$w$IuErxFNpZ)Zi@%4TQ?tG&semX8Oy#TuUhX0Fc zZ)pCjNeC*0V-Une=FsVsEPixwst4)?T$<=**lL}fAUAfxP(kijBiQW4#Ti^EQ+QljT z6VL~Bds+P-@mtgR-?;Kh_QIyHH<_fIOqTw7Uh9y>vGRpC$`t68*|j;M=dS9JqE}uG z)xKE%nh)kSDYu4-PS#&sr3!{-qt5vCn%;E$l_wUcd#j-5eV(o#D>2?Log?h&WjmBh zjdfDMiPQN#4n5&Y)z!eK8KJj)q1YjkrT(1XCBY9FN-H`=^FkAQR~N>|WWoI;Wi*B+ zKBw<|vez73gQZ#VO`bUW|E?lOPXFBgN(R#v*N%Jr{s zXX$rBliGMeT#|FQb^+UToIEk?AIVkcnY)z<8{PVUOTV^OSY+r~4anF1ax-*$*5H(J>^8&(JjJ{3pXj37rYI7L~Iqv^6;4q;Kb| z3-~!AbB;(>w7iXf`Qg`B*I?1=;NzJ4aBO+QmeaHP%g%jsD@faN-_g_~Q1N!xW&0Rk ziH(8m+7%_b$RhKvow^2rd04mBPN{7n$Flv4CgocNO|?a8MUk{v)ES`Cc?KTim~Mz# zp_ThyFrDFNJ(oV8ZR}GT-O!`!98$^+yDBx37)i4h>w(QU-l$>`v$aXOO1FD`eZDNi z@2mW!$T*DM+b_0~}kJaKkUf-K-N3hb2kP5;+2_u=tL! z#32vPiprHHGpje)k^kG=GfQ@Vt?bWLDmu8`pC# zpKDz%W*DY5K7KkoGzG36qf_o3v_-qM6)YV;8P?7LR-QdDZD~gb^>|9X?-@3rWsNi*a47Yi=tSMyAL%IoW|UaO0}QCF&MuHl*=N_%#(4GRzy z6)5xX*)8pvTQdD-!gmfF-6ZHOuTrXzJuQ(1l*|<*x4Zk}-GO+Y0v}%P?xykv(5145 z|0)FY&a_9i=GGN);gNNDF|HW7?@fG-1V5oo*2X zMH9z;w{Az#ZQCV7%%0@hc*Z~GxI(ctG-UzRk$cXKvo(W2X9ckij6wb9x#=OLuR3== zR8zzOoD~o=D|>X5`;B9dch1T_l9X#)vHnT(Z5K$Rj@o+I?#8pB56%YEAa6ZS2B1E6 zCMYRWp?LMYeojqpW$DPN-CPVq);DunKy`}q_}RhJ2ag#1UGSi>SZ8UCDsOB46rC2Z zx1ZCOz8n|Gab|}{B>W<_d3<~(9O*dGubTs++ z5fV87F}iWK_=3q36CEa795`o_u(O5Q3KK%H0nsdcNybFB%`#9p{xjtM7rv0%>SxKx zC#OQfOa}Wfy?J{z1k!OR9%PYeT^N|94T@!bO#)_w&qMq)n@S-y9ji!bL@JzynPf5R zgYfAPnOdux5NXFY%T$1+8K9dEm?LyOLcxnAP_jA+WC(YMo^Xgl=$EjzHMFE-3?$Y- zxHB7AO{2HVW%J3y(9nbMqjs8YA*k0SJQ-{+lNWTcc_Z8(y#ge8{tlSwpuZUDni89) zNItAQ?ffo<&X9>VG9`&n2mD;E$64b#Ms)8??;DL28aqRm9qAWS*L)~DO?+V4Lx^;R zrX02pXRlApEMg7AuVU(;3ZXa~`BmYC8$Vs}lR%eeEpbMCNHl+W({DVD9#|;NXi$V& z;2}Uv+}ZO-!kE4Xu^g&goaFP9XCznTJNm==JE&P2QmV8@Q&Q&X=bVZUPd7L}mX->9 zk6_Td)5_w9gGpjdL*B`Gf32&Y7|@cAUdkVdLC`KfFwQfnSlin~MP!zKDm6y!lZJ-Y zl$OqBlDeb${(khR%JFB6>jsu!*mB{Z_j~8|je=O|w9qZF1`kto8d8tbflX&+k-TMCN5%Xny)fI94P?6C~G$wfVkVa!zq9iUMWZwG1ayD^K zXy4PvGpuRab$@Q)Z=uHaQ1#))9SS~ACFk9O3u0&Vjli|N@K>@dzFwje?5bN76)%b7 zJMcRs{InX5IRh(so>MXdq1tyJ>GGwzxo+A*&ujTbcZ*BZ0oU?NZ~GrMs`8AJ$@^ra z`d~=l89zuAefQ0+-p}u9P34X;@$psZ{5uZbd36cC>XQ%_Gzq`CNCj`37BD3p`64lTa9YkdzOWU3{#V9ry!%mB%O1c_LCf4lPQ@Hc#AguwtMRx(D zL5fT28)FUA;(CK~TwRSVO4AJ7Ns@_Q3(-?_B(#02Hwbb za?gmFdg?+(RG`e)+#X7t$w~saKQlnNDJkiYK>y6qp|vbYDRbaI3$bf}9e!4->hkBe z`9lo2PGl^mltug zYSCZ_gu0}vDMIs)AQx2l0cJ9cW*7$U>$a*=Lrfe2vo6#&So~o1C6^IQJmUb_dqn@f92n ze|~!nf1h*vtLLk0qkM9W-(2i%g7n;4FTdt5-BHATzbIBQ`@HukcP?>6dJAol*xvTx zkpBtK<>>1gQi;(R?c!?eR&O2_#>HTFgAt6`BgMa#LQg?}AM|Xh;Cw)=3XJ`-j z<8am>AD!?9;2qrYseUOkzjg?uu~se7Do8LCBzd)ToR#i{L60+5^US`EuTc7|X^)}n zC&@OfzfAENd=UI*(+~{m_HdtfZf0zqa_14lePX|Fv#kBBcK~N~&v32=k(u2WVp_`r z@@f}eDbhbXU({C}@>|^`fS*YwGh&7kv5(~>)>JA!=dXXQleyHz6u)t9i7t42Z75UdsAkYQP_onNgdarb<^!6TQkHVtc zDN*9y8oW0OLuvadyuJ&(+L66agr+IRKSPN?vA`qzXjV#gmi#vN<@My6xD>Y5P|4|c zLb%nLEZ7h2Vxm`AsD4n46+%L^sPk%Z#>c1X6lWHvoUW{FER-G+HAEsXZbr8jr40cZ zFi)#r7z0W{zE@WM;(PoGBl{vvwdJ%m9MFDvV?42KWqo;3ao&R$pXaS`?ta?u5Og5Y z^Xj=jGm&CPCNPxo!Hw9mHb1$imZOgA6{jFQcaLl?4KEU6h)ZRGt!r~S0p$4C6C0| zs`2dV&XT@uy&I%z69!?;nMYI7(*arfHiy^tyCBg+*!QFGmZ{~{%9ewOYVh<&;_U;` zN21*yPkG*s`!Fe;XPLlj07>Z#4iwf_x7<$p_q489)yrv90}`eMcwXJ8sLHREuY08) z{e_|fHY%~bZ>1anTTYN5T9n?zhUNeBVYc5Z8eD$NS_XE;EqodjK>WK7cbMuO(n3}Wi4i==;o=bQE z=K(V2E4J(sWyPzUNkndMnSPxp%>W=~$-;uBWG9hsh3M8N#NFs<@8vn~pSip6YRs%^ zQ1XU^pev(r&YcOXfY=ImCb*I*Rr(~}XIkUgTIa@Ezdg^QMt;zBDZdi*zs5IUK*gK^ zZ8fIv9ZhzrwjVTVS%f{=IXZQ)@Bi(O)W_kw-XCW9IBE(FN@jz7$&S&?uWx7=dc3x3 zN5qL$%T`|~F8Xq-vwcK#+UV5nga4GpUf8(b&W>zdJ!;XNGoaA)cot-y(K zi~{}#_seQms1eQ#>`Mv1%kQW!>MrfQ(tZ02^4kNSUFa+VPpAIcE$G9Yn!0t$*7`gC zKaGvJdg_bcp4?gZllM+>b6jr-FbjagBbxc2)~2FZqfu;{D)XLM4)Zt&nsTqr`CL}+ z|5M@49YE%IwYlYam-N85N4WZv+{h_wrgCD=T&Ww~qD+xG*$p*=MNj1zWt^vRd_~;Y zh}I~)FKYhuR`gQ>SlE>uY;BK^W-6>GP2Bh2; z_n8!cq3t?kgYe9&=lI@S9Mk48v?@07$?CjXdpMlLBz1xq|Mu~NNPQl~jJ|B1J8Bpf zX}@YzYn98W=j~5URGeRtgyxFlLm{$w+}gg>efY% z_9C6qG$UpeWKRny*BD|lxa80cX%^D){3pZ?8rJxP7y&8a8D^x#h%`#5n5mhR=C=j$ zL?pBH%nQYt79qwrs2K3?qikl0GUpi7ELb%Z8E`=egWblN%1DzzUT!1^iIVD2NE4If z&r!mu@H(JJgJ`bIaGRDq(1`X`fjY)(GNkAdGf7dQEfZ;=KLuP06uzV9{4M07Wt5Xy zn#YQ&P!$|-T&*J^#0>C=A*T*Pv^HT%P@8=l3V0w*AbpFmcA zP_1a?13~>wp{xjnLD1}-fSzO^md}S@DycGoq%c$jp&Tgw540N8E_)yPP^Riaolc%% zxhrb!JYM#bRwrPPHkg3kW%Ch8jgub~pyENoIcxHE!;)MU>Zhf4hex2(BsxpVoI-z_ zYUq2wN1GSg-J%njhvaqPbNa10lHhEHd&L>dh~#j0sKB#K$oTUMa(MICMXv^Vv7m7i zJ-{xe*-@ICa2G`cgSsZDOM=~ZLF$^(N5N{28cJzemJi#Ak^k!I@jv|WfB!iBq%$r% zeW6w>s?udac4zpSa}`h`;4>L(eD~73mjXH44O3>0AXcL(2Wq2jT}cth*aa}X)h_=| zJ@#%6%b}a05rAWi!jAydw4E%6SJ!Jsf~4H_h9z%t8o%pwes}hp{}{L5QiF0Cs!CMA zE5UAF2iCq*)F#gd2eu~{hDd~V<<-6shbypI-;ez$o`2!7@7K2ow0)3VG>Df%{R(jj zVK#`FMDa0Iz{LPm>F19ooZ9X*&i}}KvNFrI*VqjGD)2|<_%18?Cln(Ioj*FobBj{6 zkB*K$`$MPmoBQx-Ou9;LT_6tIaNWPmu+TxI! zKsy>bF+oj_*600$(E5Vh`{*C4U7%M8B|Pw9lh_4%Cs`FcRjdzY{_EOTP76-ZJS3+6 z%O}LpYU4V1er)ehP}=;bJje6k$9huF9Z_cxe(VUMC$8$rtXB_s)zGFfZ$4CD!j?x| zC1L|9XKS4mbW8{&W;Nj8e1Cl3!4KZ;!OzmRi{r>V81^&Fb0<`Qp5#jJ(htiu)WQN%a;#V>Nx{FZaQ?)NY1>Xn7*d4@X9`{VN` z!0AQC0D6eR>;*~tHAOqO=H(GrICcPdyxbjsXQjmM=&H9X9L+{v@8JNYjL$O+6;_{f zOZ2(9c>UEv&4VO;k<=JzzOuA8NP3!M?yON?#0~GdJv-N;zM`+=m|e}?%R?2M53cNY zOp+9|UcKS0yUy+3fPMAf{GN@<{z*-{`v!6PR)|KHui(fxmQ-9Wo%6;%QPLmv`u$S# z>hM!1Y6=p>1&Jwgs9<{dwUT%)ZEb6@!&rSgcoh#G&BA00RUJ~5EY%Kx3*GUOSCOnS z*}=HxOUIIEPb^#E*xHxV=g3U$d&YD!S~pnl2J0 zO*PrGgCamdnzt7JrMNpl>}PHj+g&S~uP89L^K^$q_yWK1q_6$(vtjbz9ZRztl}n*l z-Nqau`q1OUaf$VkHeKH=XYH6msUvZV7c1%lA5wjVD}diipZ_-0*wms~+h*=%<=#3X z$!)9SDo!T6dWR=hg%*#dPV{%*-o0PeP^qsMrOebOW!Eg7>X8Z2AM1H@OWW?nqGEAu zlEe?6_CVPknPVvJ_7W`=snYS=MTe3~)Hx!6;A-%?U5k1EIC3pn5?a(Xk8cPizV%Dg zWGQxs>(A?e&S2lIeNWn32?`B+c)Ax&JG*A{J44Nd<4^wM5sIH?Ld5oPzhh?1Nz@Ru{QBnMDlN;@vh(8t9SRn5!Rz@bpR(O^X0n;;z#o?_$1U9Y< zBg(zX+Rr8QPt*2{Q>xZ{nSb1u+k1s`>vCCbWI}#c()#C*AI&ds9EvXRNkP-4nO2uj^}n#5$2 zqY=)7W1_-O7JwVW{QcMV8cTXta1Lm^d;e_gZhOlw{Jtr?<1@GW-m3yNH;dzY;KW|L zekx|?FYRoWb^?~0+<7)ozOkSui|CmUel)VtH5n?5mvnAyzsT2U_20$ueY&%J#oME{ zoyfV$sg&S^_>Z+Ri}@}Z4wBtp#c#BjRwCnv;Bjvb3eaomGxQ02Je?@ON1;MO)W6g) z_vWf=*Hcb|nJyx8jR|I3b5#CTfZawEH0>NMG=40Qzudne7#5k=|DQZXBmbrI;)Lj& zn!uM^u$I2j+_N#KbuD@3-R3q{Zmny{lly;YPr^F{cJ&qOdzHHR{I)Q@AS>Zz<)!mG z>n=G3_C0lMgNe%0cjp-w?I`OWm2+sZ<14?=_$gB2hNxoXE_r**mXwZ+P*Ive0G3an|N1SOemoRZEFF~I9#r>tuRHdc;+R- zs@M~)5~4?#a6T(>0_Iq%U(z>5&=BCiXh#S) z=Dv(jMVIv1qWE+_{z|h>$P$}>A14<7q>L|e#s_oy?u!oDEyrs6GqX~zr>kY6-Xv-} zX7xE1NjGTEDmE50VddLOj4L2VZXQ-%($QJAz>kX$O+D9fx*)kUY~!}bib__p`yu^d z!}jfSbU!%8hb(R1&~gSwFr>Va^`-rdGMP-O?b5Y7CVRG+k8snRPmPG_U>p z-ke4_Gh~+-1?>9YQg5tWom;W!Vy5Z}r+39mmRpP@MUn95JAgqs z77a;_IpcC6<6@v}-Wb7}GfS^mo?|8Y)ZFw-AmZYky0t&E%{%!@u{l=}G9KER*!3g| zd;c)rmU6P;FLtzo;*ca16zsGpf|;YN4vv_>dF0|Iv6=G_Uuxu$*hETz%@oP@sDJ z5DbIG8iuxN%|>Os!H++h{MI~kms63c`-Y49kVt*8#N;X(%2K)UZu_r1EUPk=^(En_ z(LH!RD|w-^XO{3by5M%ntHx+^i|>fd)vTCaNSCOG3h&iP@}Bk;i+efL!Y)Dw*N1)d z-ETg~dB5DqgT_sxndseG+Q|Y5zJrQ|IlMo_1xNQqSqtnfWELxzN2i=Md^zBnS-4WH zzg!cv-{E+b{j|A~FH_z-2*=6$rrp><5iTLWUj2S-TvKeO(vZznytmO6o6#LtcS&Y^ z#s)Im9U;tnk2BHZ0bbJfaF^wQ1zmMRt}Mb}HHlom#3NarK8ur{j&IBv*?)CV&j_|^ z86O@99K+o#u(U#`gX+J!;6tYkbHB{@KI|kGr|l^Dwq~jEt&&GxWggn3%aWvt=uo?< zudR!}5|+HYTf0W6{fF@h%lrnL*d)M$4|a;rv~Mkt)&cGq{C1%1szLX)(m4EZ!jY_` z7`HDg^P6}lDXP9ZH;bVPOY5)8IceJg z_7&Ipju%(>Vv2d)sxiFYDaKx(OLhSD=*yrFqhSc4Fgm(R)ojj^MT|`@&sZ30zpS+(gW2j zp?*YDjCirz=i6f6+BUr0DR)l*ukVTQ4$Igf!#=$d^6T0{Y2ukXA6|G=C~Xv}wn43x z-hWF3 zrdF~2PB7tL44=3DiQ>9r@&2n5F3e77TFp~vxSG$3^!+|?VzN&J82?bVpmymNNq!aa z(SN`Dc)F_?dbYutu=*+>j>&LVSS#CzuMU1N`y}CSpP$fGVi6ruSx`&ACSF{?w_m%0FLNZm?)U=!ZKEr663&fv)~iMMc;vLSeZrMrA0@jJ z#+QU{$^jf((f3=9Ffxuvb$)mJ&4e8Y27eG{N9@ldfZo_45ygc2PXykwapuQZV ztqub?bOE!!nh?l=$+VpaxIu6{ zK)s-illC|03W8h)#OP!^EjhEquDsicI7L#gUUnZD)#+ZnaX1s1{5bWm$RzKxw5l6{ zuQm!=^+oZjLHEz4P|ICb5IbkLTr?!Ms3dFnwqLW11t)Qb) z0AipI3(wQCV1UX1^VgFMjq!yxlocwO8Ffd3&!|4Vc>rocSW79Xk-A7zcF9nKWvdq< z7C_{UU{CA&f$K+sL!6IS8AIsI@qos+#HS=*2_K^39JSPdQ5+?BkmR?WRRA|qf%aW% zOhe^YfzF{yKdS$K?UCS;*baR%8CU8rLK*_s7bq7|8Y zCF|%@hNSGQGGn9W+3t zmYNq~PDl7XO)w+jSYjMgu9hyVhx#UuT+}tpu1bV@n3I)lGB7tTIZ z0`(&a%F(q?qW74XyeD%$hD4fIRuOMec?PP!3ch$h&=6^}$tcc(*#LTHM#2mm$-?$} zmJgeFs8f9WB-_z8In%RZUe~Z*GY5<`WhuxBp+F9pS$HE2euyMU+HAOnOBZ1F^JY-0 zUUGbqibd71!*5%~9;uJRd8To-0mWfdw`EY!NjpV69T+E)8|A$yM!nN(4Mc!c%C_Q~ z@JR9r#AQnZEc#6g7+3KEW~23ai0Yb4ksFh@-JsRIneR&asz*j2qEDXEggI!S8>ltLdIhKO?7WToS8YwcU>q%T)O*$L~tZIIG@$W_D$ zl7M9&$uhV=Nl&=o$?m2kWofchON_k(9tFsvJG(IQgAZ~vD+l9kX9JyA!3@T zx|O$3ffMF^#7XAgdpN48nnkGcdQp84A`85H`LajF(*BM$#fpQH2}h$hS!{$C#K{}3 zM?wnxh}5_psyfWMWMxagkofh_wV%%gLW$WG6;e2)l7$~o<==6w&MCL&UH>w)AqbzX_{ivxDtI% z>2OY8Be;$Ld0P?PSc&^em(ol~w?WA_x7K#lMvGgL27%n0Ebh zgIl8!SoQXp$dH7W9}4Q5PYO4T6U0N|f`~BGT)%$3l`k?Bi^Qf}U6p4n)OFZWt;lHN z7{dS()88%$mS>ap0GS@@pjr?l^cTx++Fcus3R05QE1_7REHFx(J0zlLeeV@%|FmRD z9M1L(J=1z!kgyQrsUPv~`e(v9F%QEvVR&VysHO8aZBRhX9;kv5w{9!zbJYWlBO&|+ z@JrTuA%&g!@IfgcKvm@N0wn|Bpxlj3dY;8!4*7gsAk{ZZWp8lXZWrYNtq0yLr%d0d zJHRte%8hC43gqx!9T197b`NEQryf3 z)9riK@bvQaan1R_HEA(-wHzo@PCl^rYA52YOom+wT!Dq2tEM`%Dq%C||ARzEjy{gA zJ|xmbl8b9|JdxeuV06*|pX%xn{wCy?SX73WP8gu-9O?>8S_X8^<8UzWY2k#1oBrr{ zardt|T!TisIWjUWX6oZcsY5HOR*`V=AOVzw_(MgORKG!5X*S!%HK+Iq;Hbs7ySrs> zuim)XWoT~ypBI4!d*{+>&xAkSSrt(Hr39UkYE!uUJojrUk;ZA~BYloiw+1N(gCe8Y zu6)T(WvO-sAPc`d0^PRuAe?7AGIxq@Bi2z*FqB)GzP&tg!xao--{o(Q zcU-vADSyq(5kSjjb9&M^z*t)gWJ-|7n7s6E+>Q-RyILD}{ zsGLxpP9W#Ah!|E~7JfU-9?H}7I|92^p{=3jc5$J!o|iHdrhgi4D8L=c`yTm*CiJcb zl11uvw`T(Lvrrv*#9O*HNVC`FsYaRKP-=3Oh-o?))dhWnSmp!zv9Xz#()*->9wx`< zQ&$rRo2bWIyTC1igH|^Z;#I}1{UZ^Dc#)`Yo2a7F&HPVPiPpP1_ul=omn-b24{rpW zOQfa)wXQ(60uh{(sMe~ZJwpa`#%Y1Sp$bk3zuE74xX|udai*i`H^;Xj?)}IFHIZTt zylj*59ZtKwzM9v+1`F>v$<2sWJWv+{pEmF}ux%cQXmdzpXcQ@`b9O}d0+i^E@yuIz zw~)QwrD~gpXyVmSA0_q~WuGF6F^!g}fu?ou<;!TbGp-6N@rECSRS+S<;WeRP4Ihsx z#KAGMT-TuEZp-4M3S`&@4hzVXIoYlUZf%R^OQQx}%2Z6c2>rK^D+2iKsA((3;$h_H~k~N-$^~TjLQ{c~*dG7+8x<4Iy?0oB!*cTuIkT??K0%TSREbb1!%M$7o=}0(K&GCmKeRdd zs9Xd6I2pH{F$<;vs#ZwJU~2ZrDMbGh&b)t}_oAlCltQq@vA%p22|(DcY@(F$ zQsIM9#|`z=TJ=Ui5=aqf@fOqs1)&NSIR@N413y-EgLaKyYuADljb4jDY(WfqA3^}4 zG4$g{(~n05K3SkWGFZh5CLK&F{IIMD`UpWVBP}O-)kQ~u%nKrU6-Gy-Ou>90e2l$> z5qq%cPyI+>a$+PH%fGxN@sErs=;~X=I934zKG(*bo{NGhSZ&MrV8pceh7{D$#xuB| zU5vL};7j1yB)DT6CO{IT{u4qlsQ09&_eY#jPbNBCh5P3a0QXSUN3ZQYwApYDgOS68 zeURKtnvRO>EQNfq9&maFH`2@D#pKEbK+og_>_Mn?7D9?h|5<~dWU$0e((eU;4A9+x zEJ2I*SwpP996&Z^Lsm4L11K8CJyjs3X;H{ZSbH2)5zV7(iMOc-lCTjxG79QuOQeP}X9{v)^o5EVAU+D}ETg8Ihd`ej`)Y#0M{@z%ZMjCBe{nNm}!6tn{P|6niMg2=rfca{;_*54_Vp=ehJ@^$ZE;N^y= za}7tNZJ7bxz;by$jg+1{k^5?MuIg}Oe6`OGSyPd^q_R;o7gaA+3(Ze>K$d_~h6$hr z!RwdvWKXsUpI(u^n5!#=m}kL>GNpb$*EkWX#cI^SNl6A2HBV2Gs{43a->Dq_VIYUE z*AOQ_Rf(RL_vm>c+`)HZ9|rP?=(yey?Pdm(2ja>PQ|&M{>oai2<4|n4PSh1}z0Uve zhxJugAadiFWtp)eN}$z`%QtF|4H>guF&9?_?a z&v3@)x3of}|M9*L)nT|sg0v>aVB{-<^xFN6h-tqZiIDsQ0DwxC*?WO2(c>tH0&zG) z*UMn%8=G& zy@hNhT;9{o1qfMTy00jE338?9$Pnk+O37}dR7b{(hHqH@gvgDHzi+vA#3zo_z8=J(YnLwBJA$?BRtE`=E zRWT?)RzVQ_jtkN?{C3Wyk(rs9g;J@hS*nH-4J{O0l+Hp^>DK>GDD8<{+V76VzW{MZ zRPoV!E4e)+`OWhaz@y`jN!{r3-~3(_$CFXOX`d*604KCbm45L-C{Eo6{-VAZ%`l24 zRsRJoL{wxZn;8DI<7ic$`FS3!sL8LS7Rn@8s*S8#bA=s>-L8!;2li_`l{IZ)6EKtT$Rl)=6;srkeKEdzX5Hl ztPf*rpsa8kL;)}p)iIlSI4kvHkZH|TkvY*#tMlCX;?Lz}oyDRo6R?d+I_J5m4yMEZ zaYm(TzNmw;6(nE?_V0veD5>=rS+gfzs7>^P^xMx+A!IbOj5EY5$2)!rG8Ui;xs-2q z=4Ze!_pafowjf-fiEo%zGM!6kq*dowrZ-#Kp_m2Pn6$KaK=09fN|Ia`27D*QqU;OR zsPfK)BtTAxKsT^$w6s-|&kJ}kQY-|js#p$j2#eC7ZNw1NFFkR>mIB3&}{u+pMzR&xT1$b>{cPlZ-E&<|uEKQH>>@<~L4IDYgik7%Ej zPAO9NA#u&S9myaR+!4nwLFwY!r*j&bORKuO-{=lV%Iv&a`fVdml;*tIB?J^B%(+>K zm$F(v5+r)y05jfZnLy$c8Bh!bH$G_7H;H`}Vs5JfCOSS(o9GyRN&+Bb+wjo%nIcW2 z=)Ta@&+7%bSi7d3m71pAlIC9?p;}Yer1%{qcZqaONXdz=uDKwmBt3w{KHIMrD{YuI z@4B#JXt`hVYDEk{VBKY%ZooZ|z2*4p{+`bhnWbb0wV5BNAUPaxx)Ew4 z5M#rS$A7eJP^%~YA}T=}mlS0UAfX(oZdXxz(Q**M0bNpZ-Mv6B2f}3I2*{#`;dK)A z_n%);Re5suBfJ>^DB@|%nSi)llqy{f!o#9B&JPB<9MopkY>1PNE>9|z6yE@>4C&Yu zq!{92L}4i)$NOt12#mJ2rlMViwIa9?ohb}(`yZZ%y6QoHhe$(g5fTZ}8w{5VC&LRodMJx5mw_p5+GN+T+M z1L0p7EPZS1nNOQzuP;h$Ooagc=1zAe*&V_{J9D$A0ND)GmAuBjR92D$Yk zhA9g|VQ};ZG%&Rmi$Ls3h63dOFbXX+2D)Sijm(FOfckf$klddAuE40v~AJukn3S)wpN|(U4rg3H}zl;>;Y|>?r;7DJPC(M0bUPqxJfH^>;1m6fh&9Z_Y)9_3+^C#scCckU2?sLz(y%J% zaS{XCp}jBXR+NlIN|sbBD6|8Ke=uT2Ml&{0z{|kr{;k3Mi_iy~QApKDcH4||N(Bo` z<*IFIe#@Gmu!xuoS$1ZolbH;Jj&6`%67;Ysl1yYwNHqQHP+U}Nf6%%7HJSst#fVQp2*!4)^s{LW0|@QB3*d{j6&FOq zXm?UYK+^~F@(J^nXsh3F?1RYHIkAI(bnxj zDy)&y$gF8%wCLTSnduGa6RG<_W||QgWywKJWOn+ZyB}UnM4(Xo3<`g-YPeYny39hR z3Z$DYf`$m*bpVC|)n*p`Oim-pUTOayYwrRVRk^l}FAjp{0mTvv1r*fE10F%;Fs2ro zDZBcNwg*5dsZf!~0D&1iA}Qi2QBi2uF5jJ7(MS;m1_eb@9L*FIWH@7@48w>s12eP! z*ZmC4EIPcq{r$h+Z*L)BX02K4SU9vyyWX?8L4v|}XbY-2BT|t`kUK;j_qA!4swjGz=sB=9xB@q5^c-TP3fmd@>gubTb5IsqDck1Gf05ZJ{`Pra z&E~2M+Bjx({41m3d;ZrV>9$F;&DSKaw{VXfFp=MZA>3^g9&GrAH9MQ(agOHR5mumP z8Xko+`-6R+;yH94>#$RX=(oI4RDoXP6M4&;>7TDogl|~uEb>6O0joF}tB4`+{<7&T z1kvIA4Mkg-L=O^mVLQ2&45Ip&Raw#ixV=57$bZ4Xy=7#dgeOndIBB;hsy2%>u9csu zl36P>CAP8-+ujFJ@bS-tVvR8_YJrP9us*_5#knqyu~GlAVx;vSSq z2CGrhITtR-t6$JMOQBn&D1cK3n!2NjWHr(-Do}Sh8a0W}n|&si2I=nvsmQ&fyph>*YGFS?79GAx zOy$0jN|4+4i$w5gyjTAIIw?BOYjYY_!_2$)U4haiI1~_^*jyham;F3JQLsGkom=cV|m3WH+YpaKHTJ8>gf-oRjLH zpYmL>Xd{g+`hQnH6#{d@QaIRjl**YK2PpLszy3Ums!13cz;AJ=om&#!u4=D*RqQ!A zb*a(xfPDRS%+1Yf$*24q%0qQAL3(<%neK72!vQ=e@Ph4Wo@Y>Z7njSt@CKE7;1DqB z`1L!-7+j^l!=%HuU_&0ThjuT`NrfSh{0Kvw^e=M^d-?bfc18CiK* zrR3EUq@N})@aM0~l<&B=@5RH0_90bF8UrvWc%+KAQ}GFNSEq-j_GWs;9Ot%yFrB0t z8GVb+kE))nsrrHl`>^Yf#|_TZAcg_0oR`0a0iO17rv8om28ipa{QD{M>2tag*xQIY zz7gHPZZRka=+1q4u&^0pYr&1Z58c2DL$&QH#>OOO{F-(g@)B6f@JOqWPFK@;p#|T6e&pGxu_u^cDB3&AB(iXx6yR5d?EK#s%#* zvAg#Nc_AH=DW|9xP=+W0GL$ZQwRJBHz0#nKAz zUz7YTtEuiITc4{@;xaY-KHYb^k%4FHw4l!ZTyFh>eCtfr%*@N=m&Ae5;4+1lC@~>V zgvCZD2S^sTs3~_sr*qc{h?N0)>0Gl23sErq@P6Att(5L(kGx9{+BrWH*g?y)6Do8Cl$5-~lsXDIdyNX!9~0i%3W@#L#IuuUcDG58DhcMeYuVdO$A6bL0S& zy;`#YlzF#*?BDbl5G=v!5;gpQlYt+^O$t3SnhR`#6S6{Er3lSgrks`e3>F{+f@bLc zl~KcfJ4>JfcP&1zT1BZ^B&wF&lTRq4}amSxx>BDeF2q{ML1B^K1Ru1Z2^o&pWWKQA;Qyx(34^ zla<+tDWOqO4&3V1R#yJPXSa ze{=wEiXCs}vb{10Dat~cO=i27vG_NF<;_OOYg z_=gSRL8imB%dfBoak_Cs&PvhlO2E{qq?%M}HZ?_rx_Mh*sGt;Sgmp>WRnAN--sRSA zJOftj2s>o_Kg=i1PlNx4f0wyGi!+xQO#}?bSs<9Po91P1NrO5!MV1&n!I;co>Z7vK z5CuyQKJ{;%41KRh4nn1343q-)+@r}XD2T@k&Tj}S;!OF;!m`$gG4N(V0(|(lnwX!U zw^G8DK{k-T%y0n#35|dPDg*dzVS8B+eegXp@DSx%ptCc^c#=S#(apPxhplT&wJ<-; ze747d`d~~lNCWM3590v+qjFAaHuc9|qgNNo)6Hq`5*nB*6;`(C1-)86?4C|!%o6IR zLz~ltF^nZU1l4WNZm2yUd$79|YPMBn56x16kFGF}4(#iRjjxY1z~PnPq^=>_bqOw+ z3-*l7rptf+k^D7sUg^Sq&HGdnLI59XGdv@*H9rp&aVc_T-Xd;f6;*uxCC-a+zfK=fB-*d^3`8`w5#cTriq-cva%T>oA;bfSid z+yFbf7_>g1In-R!EscMe80R8+7Am>OQn+S0Kl_Js5pBuQyaG4X4@|n(-~wG4FY|%5 zrlFtuc-Id==7lMnejMkn-Rpjll9=9ovxeBj%;BnUWLr_6s)prNd$4o5b!!k>u%b)Y zL2h_Kr#M;yLBc#I56iuBT=_Gq1dbJ%aIP6`gp=mM*uflb$&VB^Oa><*eb0j} zDyE{+Ox23YX>Pfo1>1K5=i%w8LFmJB19-Ft9M_&p_l)1?SxY-G+Ar{5HmYWXtIvj) zCJiozpl77rQ(|RSM%VS%RVjE2e{tKpF>4(i`!WJ3kpLUEIi55Y7q}G{seNo1KY3p& zIJl^yb?)cn3-W$}Wa?;$m(FiPQ`81qkgtibceG0RgsiFTp2BJI5#x(B$(C0Suc}$2 zJ%Qcffom_gUtO99b4UV8*bT5j=ROzQK^u`OOC;0hKfWeC-1Ll{AIg7Si$d>9=a=(H zbil%xe{BYH-31%L@KDG3x{T3*bGs-EX1@p~;RT_79@Wvs7o>fu{eb^AOo!Y6Y<1T*KX#}iWKgU;N_3-?gVI=|LJ7rV=ev$j=c>d%;7ip)o(OEYLuiEGqA&(D5 zc^3b%q0OCtDS^2M(kNY;md52)Ud!v3**P;ac}+`xr*XTF7_Zi~ijGCdrxV-mjpo&{ z;b`zl5(*3Fq-O-gT}}-}`}oIWqNB8j?93w;a^b{Q`hl&_!y#z94;kh(TuB%W=iTs% ze*=8=o~QD&urFOdJHySCA5gmz^SFwSm!~0EB!{}{s!~s-v8xU|G#w>N7urS(jUdTN z3gv`s3ZL9#QNkSOmxbDq`{aa)84dp}E3)$M!HhQAYZ5aWj72ju8jtRjw9@h!XA5tK z=Y5%JI2>LbDt^|4j6CrxpPV={Bl57HsN-!i>Eu{zaiM3G(O#3<+svj@_N2xxb||P1 zr=3-M;wp>9&r=BF<;Z>3#MUM*M;BZB+x?d&_KPcpttpMPizrTG$R`sqeTFS)6FG$Z7|;Ds+OC9K8RQQN%P>e;hr_bTsOSEKc4&t46ZeRft>Rw?0Ra0=6QN+rVx zwYpf5_hhNENn%JH=H%3-dm1mJR-W=*kvlnDS9&8BwjRyRqUOA+ zFcoI3nLi$&o+?5U^)_Ik{1skyTzw%{2_r9im|r(9o31p%MlKQzppKP#fyB(r^bjqQ zs9SL3$P8HVS6!3wm)s-T>gQK=0DetddwvhWZnhgtEb+G@n~p{)yPEq;!uk~!Ozek; zD1WND5}ibp8aniz>Bo&(GdSk=Nf_3< zZw43s>)m6Fze+Q;Z>wIO3jc>J5#Kj(w`bhuvbu2estZxc+#4n zIrg$OVPX3|KFr}W!}gQ_+w1k9Ev*h;b8Gzz3CzqmRNUAUO$+=6m{8+(g>T zG}-7UWE2q0(e@_b#LD$e4{~og=KDrf#W>jgc;?LOOd#Jnm$HvCL>+Y^i{LYXx79xC zr6=F}VDyPm>e#gGn6U^tGVIi@zEY9*V5w>jMy9t&{38b!zSO$dlR6Hs#(8v=jBFEZA*SaxpRMtUl@S0gb3 z(_>!06!9;v+OrDH1P+h!!dHOFPiQ+>?ES@(u`o%}0BQaMaK;1?(*{+La04FoZjHP& zw>K6T+CZZiG`f2rPwNne^kOaa5P5FOuOV9}yz>CzqP1YwFNdeLyyJ;{1=bvR52VMo zG$6t$lRagD0LS;N7)pSxP2j-!mF|eh1uyKkkjEttM(pVUd))o$UREercA8O6ABCL$ z>dX~ABeHi6cXE0=tQUw0h6uv{2it#en9Q2%D4rCNKx2G_wh-n4#q5eFu5 zM=tW6UbP1$pCC}~=90Q3fAMqF0!eVgR+--jmb(xP;6HkJVCh=(8ZP%!!2La{zCGcfU67&IB&1|dLkt(bhU9!Ox_~t7a-r7${{{U zSi6D?zM!b@iuC#Dt^Q89#fmK+tn1g!8&rQm3RNn!(u{4un%t~RWc@`}EB+3>NHYTp z{I?jQ6nM?|sg)W9JdDDRe^}8-2j+*E2YY+Cu;Lq?#Q*EMbd%Qk&90$tGAm*#gXaj! zH=;m%v-y}^ZFZERT~1b#;q2BE*V*umfGeLPxITuly@{pX?HUJgg^En$bvbTEvH4{} zr0Iq0(ykbY9yDn>nx5~9N@3)wQsI$+S^QQ|%?q2(@}0suyFfQK3H|gQgmORtUuT)f zYKA7Ek`{f7nI7&5=oxii0A>r&P1z7y7z-2CKL%I5k?*DanobUP8C_>V$xOGH7eu?| z%`<->ek!UKD$V&XizI`MG>EPdLibhAyPD9Hf2*%`39<{1szS@P?9>!KB#lO{Hj%6`_jB#b`nkD?jq=}L45RJy6b`8KEGP! z{O#SJh@=*QrM{Iq(sQkyJ4QHPT{&sYZPs%nvSaT8;t-~y;P1G%6U%`zPp;nl!D#oZ zC4*G2S?2<7Xw|0si?2k~9+NaSool}viiq+O5?yDZR-E2X zcPm5pilpP1jso6~%D8Pq(+#)B{1X*g1=)f!rW zjWzcJw33KfpMl&*^x2q(aPXL2s!G<^CF-{30orZ(dawMnrnB!~hjm7J7 zd&6%I$b0GYQ2ZtK&SS2R))^aFy_?ego4M!g}k^FH_1yLI$8M1u#QqxWHA zL9$0iWUOEi4>s#y0mQA`g#4kyM8YcdIyLTIpA9gRG&rTOh%r%L|>?8wS0ES6OI zg`}Z*lS}3J~Ha zAN=l0I2ijDts4;-scTKqP5;(fVOXoU6z3aq_@$usJ3+;L+rG%uw4pYmYM$P^Q!k+D zf6+O9NMDlf_fDYZW$m{?h?-zDi{0Q?P&u-{eM70tQ0d+(R;U6QbtfB{p%^8A$}U_; zg)7v1kX!04IYs~tLn|CB68|39S03}sE2iE&g#+0hVE}GyY$*t!^tF4rhv#=uok_q- z)8l(t+_=;Q`5>5X1~pkxSDyrDzey=JjNv=9c#m_(Kb#wg1RbLu7gq&o2&!fO6LZix3yHlEn7JUdbJcm>4%#p3IJ zZKh&fma+x}1XTR>B%+^z4ED2owt!1aL4_Ps%^)#>aLOs7XLX{IzCWvdkX+|pN@RX; zdAx7>iHj23D1#Dr$v|!PX=?LFHC9y)47C3sqLApmAvLj;a?CAn$s=yaOYNoqVVEHq^>yTUu*`ZrpkWn zwl#sNutG@Fd>N#j#_0W!Fu-ZmcCR%?e7p@LrgeI`A}^n{xj#-{j7FHiXhaV@~R{Xao>12FIUh zBGD^wSrOpXhe-W|G7{0BXfdRQXS9X2x2I0Zkik~~<_0?wMNdZ{4s&n5;$LSh*MYPD zDTHKFWQtw+^h_;1a9XB9XE3{aXIo|?`>>ShL9iH{EG~kc6pUGiAy;65pX)psOS2(k zy&PL~w7xxvUr((SBV>8|m_OpCAp(e%#}nv1j2m=u8j@bp@{vRRCZ=ezGqC4K;ScwT zRiUAY#G#sPf2dDEbN-DmrH{N*KQ47Fwzu-11a#OQ=8e=fwkYDQgvh=|I@?~o5Bi8S zLP`+8`L7Ja46y&J_C&>(MSTr+0;Zhu%LoO5s=jl-`-YC*#Pe982_;7Tc=LRbP#o~<&cZ#p-^s)Hp#H59T z*^Ia&uRP>*DPm`t*lEWl4~~Eq;L+n>83i{JJat|z=R4POY(o--sO5T+p-^rFu@O1U z>oU>|SS5(`NMRDQEFc0#o~hN~f$*@*YCyPI}R z6$nEWK-FfoFZ)NHB-q;rUDP=yHLdK&jAW)V+-p0YDSxQVjY|3vT( zJit`B@q${JAL7BgvsQRlm;d**qV%#r@yrLCKNg8%UPyy8t;B^ubw+Gf6VHSC&U7>$ z-jF~~j0f(p6Vz0hE||8p&MY_1=)Zuht=ll4Ge6Eo+r6KXG9wqVq)xB zcOwEtS>aMO(nUjg_cf5~nUrw6WB3oDb@}fJ|t9d3(@}W$ml! zx$jCt<=KCb2_T&_&kHV*WSY5Dl^)SZuIe0^#d$Y7-Kaz8QA!)`m}l?fhOyiEi$+AS z3&H5Rg2L+YIl(7G;s!9J-}5aN_pBYwgbNJo?O?J`q0GykW?MaV0o@f)`!e(C@excf zX4}on>3)N*s+DdCT}%iVOuJKHIA%bHuOkYKA!-o+dKc>1RYDn`Afdd-#yr#(!`6$B z_?=gq=>$c6h1Y|l2n-5j67!$_0nD40vM_YgB-Nb&!tyb+= zV^A>qgpi0e&2yOqmfOhh%obNfwcQPGA3~_?9D4}XD?4^pFdiKD2g3Ny_?x!*&Pb{3 zc2DVI(o+m5CuB|NV)L$q<-UZTaVA#)dIH)`@@t=*895Ru>ym(zIgR}w1YRK39rv#3 ziz2_QzejwUQzHDo!emJ1G^R?AHog|L|ZagTNfSOyMTJ+gGO*IIZc67 zXKiQrF)7;O<&khmlIeBsj9+_)A9pDE`W1c}dU1V21lswnW)K9@i$OAvlPT|K4k*9= z#@rgMiB)IP;X;E!g6F97M0p@10dB~S8Pd*JsVvCQ5X9u#tfNY23mW}gdwwx-9{A70 z3(*Xuc0$v$4}%PMa$U%kjYtK|FN>P0Y^Q=`zfFXv>tem@z&Ro2I~wdUiP@5+C`kg7 zgY;+Q)n|g5r#(FXlV`jtyX~Q$&lhFbr!|m9^u#pQ+l35sKGQ7Fbzs`izVNN)&+E|R z9PJ-}|29HK#S2(tg*crSBpYNtP#fQTMF-a8G}c0AWx&i#{bA-$7oeBzMZz{;1}&Uf zUc|37(?s~Gpx&Tx=FeZh@~G9mxxsfwX&rb{zcFGUK*`AH)TW%pHZK-Zgx2vW@8_)? z_QrP~*HZtbhl3k!O^pt2-ClXzZ-fYF-lR$O6;c?0{Z@#O1};69+lbMJ28ny(8uCR0 zljrGJ@0&DCm!xSDCDGov7v6tc)#m=4 zqqcDF?n7NVevAuPL4f!+VfpzYJQdXVLM*4%S9gCxw>6ta0r|VxRA-AjqX24&{Z4jd zTwZj4s%4+;lCiJ@GR+%70{V$D41#yKwt2^}mZRThtohp~GKS7W>)eBp%#5&u4O8xY z*E|!_>6eh*7nDviSW?eID(d`Ivlo!6s-$Ay##@Y8jKsk4sH2=g_h9aUndvAnGBP@Ig6dmhTWWIVe|`5S%E_f|Cz<=b@ygZ}LxJ9Oya#oEeaSuq z%jH=zrO45!s*<$)UmY2vfk7r+l`JF?_RDh5U872jTL*td@U#Mt9P@4ec&@cdyAw#k zr_UbG;C$O$efMvtOu42U`SHB_$4?>1I2BI<)5oG3mY}CvS)$MzoLdJdT0e)MU>^Bi z5%S0#@s8L8VMHr2GGOT#uhaPJp2u~x-9VQDb1T2=xFPiP!m~*dcOhhKUVgB{_&4)Pe*}SUozOc@m30H ztRX(AN>+inG$VyEFhBR2u>5{qfaHlM zhmPcmq0^^NuSQttBotwPr_SttY5_A0xDlb3TPbdGAu>AhaXO?%kUy6|UCh_*75YHM zMG~pqZ1+J;(j=w|yeLx#BnI`xY@F=B*?Bj|lcB4nhw4NHkrLj#ats&WO|- z4_-SlWysQEV_WtD-H$GPgTxi407N`uanLM!blHjjIm1!(Xi_KS-h~rkfcVb3vgM4u zRhav-n{rm+#C3#fXNlB(nG;2P864Ks`-(F4_rswyQ)Po>!6G%k{-IQ>a?s?!j<2dI zugWT+;nNc4a!DQ-R9*I|s0@dx0Chtd8_r}ZV1-}^d%O6Da~S^2VXOyjDvN(m*60Np z6Gu1wWB3eaKlt3sx#Oa9fu5}b$;rLsYFIHY<|E7JuPQXxzl-^;=B*#n3wkScXk>0}B4gOh#70D_eR zZm@g0WsL8hu#+CSprS`bv0jL z7kP&t_W9luE5^t&O!W*H+(KXrS=;=(lgA8jKRRk@$jtSwX~j4G_GYn>4A2$yL1T`n zmoa@N1{~!35uyb@3jB`)K~z7E(CF(I@|(Tj5Jc+)0FrsN8v)RnR1jeBeHhb21rfQg z$jayGKkRBKK6wx9>X<199&Lvr549IS2g=1I1@iCr#)<*OA1xNuByofZWs94$|GEFGGxcPBat?bXBWw5{zr1<%N#f*Sd6SA*+cibDD<`r7*8!NuD~8v*^tY>b|&hYZSKZt9FdXzn>g^`xF2DKk?)t4VNoQU?WRh+5_+-979f>PG0l4 zp0|fL+H192e|XKbJLpiDeSA=-xD-jITGf8xkv!~4M(Fx;3w~YonSK)@HD=H4g^a&> z!JDl;Y_?FwpMAN@#$*eMNyU%m1&7Q+*lhvgZtcs54x~81-~4HRuIoqhf+M$fzogPX z;Wf$+oa91*sw_XSUvElRW%+?tvlA``+lO2&O32#dQNCK8`o8m%71uxX;I0HuxR$)| zhlR!@R_^yXtTr6IpD>Y?Ge)%vV_S#*r5ECLoH6fJnEm?uxBJ}@|LP0TJN?feAT4zA z*_aiS@XsG^|VJo-b2#D@b-~+nA1c%zej-C zc$$0KhGJ;k`4|KP06-zLeq-^?pBB2uo6F$k?TQarN1FNI`*rK<+a;-PhG~MAq|7p@ z0`L+yLf0tcGV;y~Mzn<;gtkkr`U?F&-`^(Pou@Y<}3L< zA8dqUgmI;;B$14ve6k3U0EZi3J}3Dl>@Jub2Dka(@fK3;n7kFs$j3zPZ~8dU!kR{h zKAXhv9(1{~2nTHZek=h<&FoG~W-`!G=$MfpfK#_lx_fM}NxD{hFaX zCg})8BQ>rlQCWfhBSPBsKK$FCoQS)c7&j0kT~E>hl+1Bz3#J|WHt-y$x4jFsvA6!$ zY|B>Co1-d`I=%gzgvYLjEO(Wcj(ErHMSU0bAtdTcCZK`PY4LefRLs>mPS-2)pH%!U z?89Mx;z!5ChmVQ$?~x&Z3LNHDznmm5vJCy9jJjuV4g4P4@IMiKN!;)l4`w?f#*AX2 zE~49D&t9f0W_b#GNQD9J4U2=?r@=^$x3t@Eb8|F20bmO4rVLsE;(NM6+XCOfVe`Fr zugQlBcqb`q>c+y z;a!6gj~l}J2x`hqGZ=swP(lvNWR>xK)7djQC9%0p7gP)7Psbziabv`=9FSmIizT`- zq!_S_s)`s>QBe^G--U5|&o#Bgl7*$kYIsduypUIM;ZvO^Vo4ZbNH)YpxV8XStrfj@ zo4Kz{H(I)Rf<|i*eWGl`!oXi&2-d#+N7FTtECq{Q~LZvC&@!#C#a|WO2~em$w>eKAn14GD5MN z-`P?}lv6E)RSP(%R04OAsTCXj1QsYa0G=ps1c{}wGhbmlef=Xha*zJW6IIs8YAaEz zUVBo};WS`?U5q&J*DnM2z!2}@zX=pk9t_0TC8x)#Kys%}k?b{v=5 zRF^;uOxkcQ4m1{VkHw#p3*>9CnZ|P=Dzp_BbXu)j7k!n?B_?Oc{(ilQB9vOm1B2`y zIS_6PL&#bECv*1W^!vU4a|XR;PZj!yZBXnEsQ5P& zOASl&lNCBN{(*;hcibWd2e?i^Y6x|yCt`5)<}!&7@Fp)WFYhP6`Zv)i*Fr}9G4qRG zG8W#|{Zr!cfyi}&IqZ>NL}@AfBFM&)^gSceGvF!bs~qgRi@JUF;4U=f+_U+rdFI+2 z?J9N!J6pUKjNiHBU-@ejlgYL6#Fk0<~_wtpF(nBF$UL+8MY5OVrUbR$J&6qx&Q31HRiIW!&_K*4LU9u|x ziG&CUtD4FuRjDC#!vEEc<;oD!Tn%&I?&kC`3|1OijM5RXfm~bl>(Q!>z$rX2Fq%R{ z&%TK{M%p>xko2iWBppD8BQYDGfWMpr-#RVqBj&8V@PyIylE890Wc&S@mBHX`M+{}N zdYJTXSeqlL9mAZ4VZ>XILH&!q)mBw0cAcl}R)j?ELx0|?70xCVN2ZI9TwZx2Lw_$L z1eW*703fu-!AMyW2C9Yn0$HkdWOmw+f^eG}4>4B&eY^|GT~Y|ziLY+fCfG%b)?Uzm zzE)Z{fHkzin8-gw2ZCu`ZRw#Ubz*g8q#fu1@&cMf;q>3`6iY+2V#o0XkV7gb>r<-a<5uubXG4J68l#QUGL@ z|7@N)yY_~cqMp22W8Q{A{oTR>TA0vhUmo|1U%Yj^96mC3Pw9pb*#3gu2WgTMCr*sN zKh>fY0wG(7Zt^V-l>qh!+2=b&EKP1fyE0&VKvtJ^59CjlpYA_PuI^ViE5Pgg$q>Xr zWRTFoNmX79&7bzAO2v42ZK)P9E-~DIlwEkxGz(eq#`fwY|2QVpxTZe|htPDx)1{ES zq$9-P!4=Z=ajlYJ%L1<* z&;4mEah_D)g?Eguj43|qeG@FNcf&YpD}4|axsQ?!tdL;x^PK^lMd7K@Q$D_TP7dWr zMQbARYjjFyzK^2yS$LvbdIrgquqmj&rrGPRoy;!8F(?cPSN1Mj9z`6I8la{aS%Im$ zufBzDSNZ))M(;bPZA^=yU>pjI;R5UK1SN-7cJ#xxCx0`IQ_QS=u#S_vF&5&5Y=t9Q zhf@O0TT?=Bz;a;#Ojt7)%tKN~{G;a~&+JR+T)|>qB1nu4N;cUnP>@0wLTTIy9qy8m z5W42ReNB2sh9)Va9y_}S(JAU^Pjp#4;okKAgw#rZ`?JtU5x$F!n_+K2+}6}4WGH+I zAFs@gN12yB5RYm1v^7z*GXRY$*O8c_f;!IxHIbnu#6c}lEtNAU|6)r(?45vr{K5nz zP}scg^wH^ZCLpODD?QwK;=qFQh#4iw9|Ds6zI)e=rq&+920H$RWywGK(qN0|%K>pQ z%$VgD@Q~0JVdhP2rQ_bJyGk2Nl9W7=H}=O~X!|?VxEbc>=VzQ4)SZNtl240a6(xQ& z{aob)os66qZ5*xD#Quu`-_wfrBi04Xs62NSjGc0_L$-33Zt07T>sE4O zt^}Xj7q-X-6TBr@Rl!_AFj!Uly3H*aLj}`oUl-1T14)f5-Zi`~zi-m>E(0xlS^mw% zqIW`jRh>rmVI}Eks)@`lkLGsO_xvrv+Zy@{t6^63W6}`( zHR^eHbG@z4{sA><e=VXT!B}zKi11f!QKMg6!S~l&7Yrt z$0$iKYCJ^b8pfD31Yhte2;CDbQaI?leEsjAkIK%ZMI9AVWp7(df}2nryC^`40sj z_U+Y%AW8=$dp}5@x=1)(Xi_`+ls%-_tIP-DUna(LfX_aBf^Jy~LzcSg|36Pwh`1ve zX}s-xU-nqTY!NOlCa$SoX2uu@v|_hSgku;#H;;iP-~>s8#-_<2|D%f6q=W)Zstqbc zR-##jX50|+C4x^6aZNYiW*#UakmLqZ-g7T9FanJbt~=C3A__EOh3C`6us0gy?cLqK zR&F9nD|U6*j0nE1#Ov@PZ%-rT70f|k(z}tPj@RKYg}*i)OK@1@w|{gn(@eO$UDVqQ z!*!B=6(BJZpZLm^O~Cin4I5zzjSOB#=!g;B#CWBM;H5uF09%qdMpHyD zc<{7k1)Ez$TjRbf@dEZv#&4<9LCYA{A&!2JU4$_nm<*>m)(A2EI_5PxB)S+N{tCYR z-7)bx)3X?$w=;KS0Faj$b%77M9^#z?-C-lg?^}a7Je#Vgus2s|ZYUaQgGJt58`m80 z^8-mH6ozb?YrQunyRD8CRm{8Ou@~G&;)CJ~9ItGDpf7zujv!n3oal&D=m3JQU}Gy) z$2uc4VAmR~$+RQHc8o+Jdtt5gkGa-~wzl5j25Zp#dST?;c^{1K@qS57#U9Jclm-Q# zkDhZL`GfR>m1e7zJOe$cBPGs!Nk$v(Y>=dW=r&4?yulzcM~2GUKuMnS<6YyqbsqJO z*%XCV7uDt86wVQA{KPwv|HJ$$p&H5l=iQ&sIlV5^jgvv>j7?b^3g;W>$xcchOr7`Z zWM#qy!&(!B@;yb2R}L0G+MPt^M@TavEc6AxxBGy70q>vvT*UqYJ;nd+mB{+;u^`Ve zF~f1Y=691xER>QAnj4&D37U+BwLieMGL3GPC4DTp_KCcPWbMSs0FhSgO06sMwGMXl zqLZ|6i8xd=o7M&#W{WkdOJ`-`_)cPx|R>HWG}UN_j2!# z8-lvT;KT?sWN!|?FUQua@H&Kzoh{eLExlwOM<32Qq3iAOZGl&QVMRoZuGf;Vc{lGD zW#|xBNF7iJq|-g)3O(x)HDqwdp}Qsdry`rxjYNnZT<^Vqw{u4}}lIC9J>NKoA0Wpy+(>NDU><1cN0Z*9JI^ehhbq5g$4LpsD)KFKMv83=D%XTu)n%N|ky zBbUkgrWJG*hlEoWMK4$eBQiwZaYDYrryuz$jHGxvi|yYu>?O<%HXI!%L*W1B2#|`B zZmbKKHU}mIkMQy>{aw=caqO$pRhxkx^o~~dxJ&dc)XcNW>09{0t>#u(^>&=KY()2W zT!QgctGS4+-QQs^i_3x+E~2medxG7Fpg93Zd^St8>PGUt(`ZNFp4Go#>NI4Z4`o`V z+&!tVlc~w?ykSXz8YuN@_*JO&0B(;E9Ls^6llKaUHe_egM8GTH$GHCIPyPT1hivvp zb#;jp1#K%+;`^O>Z_!cj5?5zsZ)P@07qbo~%Ap}47Fblk2{5EPcPcaB61W!3AUht2 zLSB{XK@KpWQ>9k-Zcc`{!7=>YMs`v#PvriI#b~ml8YfNWDG|}@3J70h_&8%WOl^)u z4?AdQMyECi6##-sAZ@g5otde+Z%l&u_W6I}=h;;o#=?4%t0vtHl{cqKuSwzmh!Bo< zpa~m~Uik(q7@&~z>GMe$u-IoO;a@Xiqcx^C?mCv@Fj5WL{phj6u>w>0rf~gPMK#@Aq-hbCtC z+_3(A3g(TRvIowb;dPZ-6^M*d+{W};cm7ePg$i(3+A_(5^|`WG=@@#<3#KQ};~F2| z>(uN*exU*D_Qt5_#OyhiecYm9MlqkcWlsTZ31_g=+J2sk#ZVl8djr4UjUNPKRl@1f z5Af;s-~!+W_!D+5{_tD+v;X`~=3=YEd6N)R*feQ&?!+s-BVOq83L%RS#c7KzN6Y*4 zuF&1UvPV%xg&r9GLkGGXxHc+YZuRwVL(>H#s|#9BwDZ@=9&mF{2Rf_8$0vRm+}QzCmpao zVpt5^%VimMJR7s<>oe8`9%oBdb08t_@r;4f55Dzu)@HF`uKI^MO*#_SU}Q zU-R@|?_xfa4g)b3L}JL34)q7!?U#~$B-2>2N)SO8G}lL&xq^y|NwuN_)@Lmy zx@bR~3qSp9(`V*P@c+ z5-j1_7v#@dQH4P#fwmug`CtF6RAqcQFj@A8qQCsg|MCET@%&uUGtlvY6|}=F?mzkE zXi{ME=Ci2@DPDcYr92Z{-M^W>Ke=JV&Ox=W8mYOLh61A;k)B3#u5wn_WclYCSGx~r z(~9|XW7q!GdpCQfj!mwz6v2P|$)B#U+HU)UagP5_$E($1h3xP07tV&CYzz)J5tVqc z8Sh%`z6InE__)9<23sz+ISw&o+9xD)7M9k%2jc5$d~unTfUm)>_<|n?yK;{7+k!VZ z56e@7x_>G7A$y7GmlpV=zx0L!UGN^|#>3%j!5efq_F8rl?3aJ|Lw16uS9G1(e{~W# zS|dNXJ4>{S)zuMh#_aT|6Dda*NGJ&jPk za}{Q2o*z||MFB+JJTfC?)}Mn5MuASBbw-CM~Fj1^#$*%X6hOp$5N@aqjUXY;@=^l9i8^pgprD{x_G zm2BleObxC{p_6(OW>u7B{Da!R_nS>CgmRqC2wG?G*QyZ5`N8au2_E{d-*78hZ4-$? z|AsvdA;v^)JOUQeKYiD(vlz(N2n=bYFPV^7^!_#z49yQ{y8ryK>K@=m;F~=x2I)T29d8%en2mNM*07h8 z!DVM;dg;&+fkT0mJ;x-bRIb?+Nqm)Tf_JASqNp#e2}(@L>G*uZ_ps zK?hS!HmdoB_DWJK(`W`|mB=)FUvwI&IoZu1uH8CFR(en}n2Oy?oW0HNi3wC7ui*Mv z%^OOUFn+Mb!mXbR705%4e?mX*XZ#cTF}((VLcl@yYXsl^w=c&@%yZeu4vCZagR^31 zVm^A;x&Fb4{Kt0^e7@@>4cWp8Hl&JKCN#Vw2u@)-MfG@Q^*tDQlJbS20_d(cP z>q8}xSuqnBqIc^5`s-*0|6$wIc!(9eD^$z=e|~+-ct#dmN~ZuCpm)w;d$m9NO5xi_ zN_Nbx?KPNRyn1)^KZL;X`h^6UDEbXPV}oQdZG3? zbOyP3x`2He2SKVq4`&6(K8V|*4*7akUCTdyKZUY#s6D#@SwZceRQD1z{e&?S{O5?0 zdwq=2GJtL4w(}EfCr7^i(#TB?^Va>i?A@;?X2@uZYiPz>zWMxt;}%7#Q7$9rsg4w> zJ~ZtMj|(&WBwq7%VW5Ga#ZSsWOl}5=eZcmy*7ICk2D?$`a1=KoaAt61$Yvnl)X~of z_W+|Ur=;auD{dC+4vrjb?J^LrDaz`hJr_(d!&%s~(d!+REBco3_9`13oW6rQXpcPA zy8w5u>+k<^?p$oajb}Ds_1*d8^7LIFjHbS?WaoBhSmS)hJiqMRIoZ@{>HDJBe*65D zRkISJooXe|qw4JLPj@)~#@v_s+05^QnmLHm;Q{MdG#=_#uwkNO{D(+Ea_O@g25!2o zJ|07+!1}E;x&PPCvwJc0#I*1Jb$ZEwaRFAck;+T3nyNW$JJ4k}XHhFbbaj|8sH;pU z_sf`zy(7xxvMUmcZg$t77-*R;sn1GC_5vJ!;UnU%pK?pZA5hKPGWgYBH`f>V_LUfq4g9CaO z@o<)-WGY7Z6s1##*wq>skhiA=##w{Q&z9)rMh_8KQ3hHI3I;y0i~B<_JYn72ZOg3L z%T6ylbh7!CZ%LKt?~?9L8V@69zKh(hvvUJ-Pq9S%-vI*G@Dta2mZi15%dAR&0rlF! z!aOv-hiNHWXQYed7oTk_U$*_^;8Euu@d;Co4PlR#&yuj6At5=-vZ79XFl-D?f43Xw zMt(jQ?I-uLN4m*&{;2Sw?GzSygNSkdDG7=dn1N@e4^{3N|(=t zt`f#gOV`dUtg0H+G~qFXg4894DE!~sg3s7kTkhsITH|`YDWFccn|Fw?f}5wy99`7+ z=f&p?Z>?CSK!)}OhHlm=n=~gdq&lLEZq_`?22i#724IgLc{%OsnUX%A3D;GngF|hes!-%rwk;CTC zTM34IPR`|9uTEcL+1m||WdiP;Y2C->u8-i-^Rq)26-*s=3Ov~^cEL2*w1W~{xc=Dm zWs8QLxUO9=e@X9+TR68_E*7(ECH;O|Va_nK5sn*nd^UVoh5dyK7mUsD_Mot+sMLG^ zJ|*dG>vv_yY<4byCkOKH8dGaLNF-!DFq{&EcG5u~gw6qhci*99?b1RdJYOSwbLks$ zHANL%UisQ9TVWme(Fxcf<$U(5Jyfvp2RT#%YF1iW-}ef845ukX)-SxAzwOw}pGoZx*c^_df&o3Hu5f2tZ zvg%=UH*DB2I^?y6y+=cq9+6IGR|q40?)K20>L{}p1pgtVSbH_n@0*LJ?^@O_xxLz> z4j#}zvnKCy4bV5wtCcQY^(mYvrtcz5G-BA_Nth@phS~VhS+hBN7i-)B%Yi-8d<1-! z#k@^pP^L9T!z2DXP#{1cgogk>&X}Pi$%q&>W9H12ki;K1gnxYE?HvOx`wYam9$~Sa z{}{%orv)2cv$zJsWg{_Y^g-Ep-jF0H+Q&RZ%HSL$3(E`4!cQ0Te)D^e=;JnP9#<OEiZ*1MOXun39;k8~vlVHLKqZ0Z^T3r$^LUQ-Y@22CzdvB!*XvoH-ED51<|D!4FvC-M7! zSwcCBF~oG-M0lq2ujI$5%@TD^2|P$)V$^m}#C%2SU=Rr#!;w?3TR`ppP5jFeuvV`@ zEOShyh5iOOvPxP4(#H-J>>T%Taeyo*L4Y8+>I^<=TVJpY;~GQ7qt(rw>7DayrI*lg z$W|T7&>pH(H0QT8YrYY6xRUT;J4GngQpX={XGx6HLwZjwJoe`pz?a`0q}du&jh@gH zts38HdR0AnP?g;D3_SD&xwtqp_$7NO3{QMkE4zv0MKt^isj;ghl0EE23=_iJ-wVHt zW--JXNG@v|tBV4gUt^J9-8VnMwgbj=@8EM9woy;G8tm!uAjHB-LzODgrb4}->yOWx zA=BrBr@oIYHX4pWw{uP|<8?9>n6Z0xsrv+SL3g2cA=9mhcO%yg86r?iiDE4IXLjs` z>^f*#!eAHR06*48Cp2dfUg7kRbQ;U68kTDk>@-|p^O->M=|qG$KDnrnZbe(Kpw?cx z@HV0rA?P80JO{6gCa7i{V;+>nFZXSV^i2$a*J<_oAoY3>wGGD~KYrZ$1OX{f4cSGZcKt2&JlisDA7Wh;?eM9Hh z2{FOTzU}WKWVQ(b=5Qm_anP4fvHPsBzh~?D%+B+<5OvwgTl>ok#(*UoDNX4-mr_T= zA_kNV5lBe#{m4xLEMEGJQ~S&0%aDHb=y3L|p{3&4@bk9|bok)oWlu)f#q@T+dM)?* zHIs~PdArowTy7!I?0d;E2LwJ^k-fV@oAL~UrX>#K+{w^+ZNj#c7C|Um z4xLY55ZxsOL_2cnlRzmjP$7hnJ;MkZWu*`bEVXK-XOInI$x}Z`5uKk3y7OB|exDM$ahuNi?Z<}qucgnT=&Ya^ZHbZj%`#maXij79uDK8 zp_>@P9#rJnit6d!bI~_9JHdbUXZO?Zk1MaNWYRpykDgawXgIJ`^P_*~R5BOc*Yu2@ zpSU8wIBR!A_*|5HcfB6n82FO>i?n;Ap!#sW24~FTPo?Jhh~@>@KgeH5kn?&u_&R8h z)zYV&fdh~@=_frA&68>3tf8@|#T4@qmk-kQ4(ggT+8L_t$RODP^elPXc=;vMY=Iz| z_+iXh=h}tbz7X$8is|81%_0Gt3=uZyyo|GZ3O|l3uu{}nviXpD{GYB{2hN`j<#_0{ zDjg2^vc%9Nxk1mElKz}4AB|{8`Y3J4j4kobrv7Q%MTa;G4ED@xk+ER(zeq%E@G1_a z)=16$m6IFxnAr#X8e_(27VI|1Bj>Xn#0p(6{zb|h*~Vtktubf~`$NHE_`;zc-Lr-q z+#}7Ipw4NAZ{lI>4BExa%tFLIEmcbIV0S>Xe+)ioRC?R~W5H?I@v-+pBP*&2oyD5| zcnB>tKfnzItQqH43+DoVShd3BrSmlCZxJxHRMLWw+tQprfeeF~xbf%p!^zp2Tvx4# z*qDm{s~bKKHaEMc7=&4*t;B-~jnO(7Rcr9Dt_j?Ya*d{S6+M6yX7mq5EPCqf z>R05JRxk-7(YG2eKnJDWo}%gf`RAW&z{`6JO{9F>`@`fo*{d2(tzVLrE@@zJQ@Co9 z6PSH3F+pIxy+2AcR~@UKF&`~9`gldds?*33qX?ZVTgu%T&I&d+!{pUr}@Cv4sW zJ%3?Uoln(fT0g7`Jm_x!M00N|jW6$;?6!~=!#g`5{!TyxJuv6wKI+Os_I5P!BHwp- zrGid3=1f5BG>}ptol3vt4;9%DQmG8lIAhx&(A!fHE?sna{5ya2XP*bLR1!&x z8f)dxahJx#SrT{iCyKdN%3n8cXY#HJHjiQ09&R>vde<*HGW{aOoGAS;jlt1ZlA4XU ztNJ?VYGcHRf+=pr2t5PKGs#5kwZ3_xP_UZ;B4C`Azog@~77OxH1BD;)(Z0~)rr&*u zt@Ekz_fjLE$;8-HKZtVX*d$4pOGWEE9x=NbT2ap_@;k9F(bz(56O>lA;Y68bHDtD^ z*J(nHgfWYguG*I3k2=tnJcHmVvAa4pF)G@YgoRrj?%=hFD$qCH&2@ne&8>o(<4fZ%p3>^3133Tcb&`?Vn?Ol1LJJ$pc1C8P_nYHYsO;HdjG3RZ6Ev;LDrr z1GC@LV}Mo029C5?I-L|sr(c$wE`{QFAThFb(G$=#MqE1vG!V*HErK9rXQ=mPcg-gE zYSOf5X-*|Z(E*yao4|%@HeNF?@PG10QxG<_q{p{J)g^n9gl|DE)}t|OIio*Tv03RR zZOhu|{dCwLj#S6epmWkc^i$D>s8T_t1ULuP;*4h>XIvQzkJ*8P%Hg%czfjegCwEME z=Q)~SZ;Xlmd5jVq%_bla$KvlFQ>sL~s#5W*zhowRA^x^g$@VhkDf*$L%ehLcNgLTJ z=_JUGGmR*|?rn4Xv%{f_gd-}W@GaUsQqap*Ht)e)xkh^b?%g3MfxVSU{`EO9&Y6b1 zF7a4rb%b*<+kIrzObe`=1{#va#`ozQ(SEj@lcdoc&#rFtTCmevS|$K%Kup?3w-J5j zm)lfhMFN+2%iUScUi#*X7eH0g7_1V5Es`J zB_2Zq$A4AZkH>tH!%pTv`fO3)B~^K;=s_nD+$boao9O;xUd zQ3Y(=WYrr-ZXzC5^-_%NXfblhf({h>K0BR@aXt!Vuntc+ynKtKSJ)mNqo7uYhi*Do z78pC8D3=#e13thG9I=Bm_rQ_L*83)Hh}-DH#8umhUFhJY8HQgo+9o-xCXv|QTlRz= zifFb=RSp*Ip{)V=s%Pdr=LQmpz$T%G*X%@PP#xV^8q=_xi+O>(ccA!}b>`Z!iBzS6 zx_vQQN7AmJEjHAVgz6hlIOQOj*-+<$^-A0%R@mR?sfrX3vj1u>3+c#HqIN zz6rbC7q?j?Kyew=^vl2Ah3sBGjDz%P<>~j=N%i`8*pwX}-J+(2hK&h19))XEXSgOg z)YF=)-Q=#ZWRE=m>L9w-w8wUCf7|&osbkw{UE|mmQK3y&l+aTd`RJEdXy0p}U`(vj z^_96xjll?5L#^jX`-8$@bZ_rhka)98Pv{48Dqw4mY$oKT>L@mw{JY zLw}wl$ID5{S4=aY1&sd|5F>jZTUclSXwl%1z}2ElEYmJG)9>0v2Z;3E_j5&_nmGK4 zMB#pwojhSHk}o}D_IcJ6`aXtFd}J()4KCAip!^WqUXE@4i7sW2yM?AXvW2~n%VJv=F0GJJ7z5fv1BzZRWW5z@d0EDw*%&5w2rPwbGS@P3wZNU zDtFjuBAL-AnQlf6NO*c=m(sE+(;ku4Y@|gGS!D{U#&YD}E=WBnYvS1BKu_vha6yEt zWV|yS_@`&jJZQh#r{F^FwF|9aXMK-5r-Kpwlyqf3!|@MBlN|$!?iq(l@J5;=GVL%i zYHOQ>OqizEd<$tS_WzoGzRg*_JJ>u$%igI{no(6WXkh=CKU(&LIGrROeGx!{n48Z| zCPVpR#zj^ezld*H#fHa?XOmN;loiD!yrv!Y9#F4rs_9l3cbQbXV>wHu!!!kb3Q;K0 zmD1S9f}QC-2%IYw^w4Rb%lJPq)}-fwB4fo=(_gjI-?W2g7sSNJaRIeXB*{*aL1t0E zHKyZs#tn%LBuG02T0HlWpFs?3_O%gRUKx^x%BfA~{p4T%jiR68s#F;to>jeX_{O{K zwXNWzzo-i(6L&K1TFhz`I$eG>sSK&GjKM?TV;IZUNLFo<^MaBl1zjkq-p@gb9sM@j zM*u=Yi}u!BKGOO9gMzn;Yb?Qe`-PppDj-$@&YUc@OfW4t1SZ!9t$vFUZ8OY-g)lbDSTQv2plHtjXz{Q z{o{t=B<&k}&3_^Igcdy(C;KlPQX$!_SrZ( zBYxbVimLP`*B{ki2eWE@XwrK6T z+Y8gk7h~Ck7mN1***3me#g}N+{C{noPe>b45XLPCR!hynLlluvYVqdLYrsFCv?vrL zCmSJ9C|D3m&>mu-Dky?bEkp{&Lm`CCbOEy9th-0t~be+*@|x!t_mBJYiE3<6Z|({~+dMJQy%z$ZOh@D|^DX?5SYJL^ z047Z`*+v=uq_qOg1)`0Sx0JOXuyMA_J9Wxhjyp}=CYXn{8PkBxl#g1;%3$hcmnX^b ztfUhK&SfyT)jdi@}RppI|=E; zT!_&bK&o}_AKK0u4R@pQlKPhtWRSlIS8dSM{N4`G@O{gmI-m(~cLIeXEj{IENKP8# ze_*=ByDlj>3(vQ^8ED>Td?dgU`m@jK5*$o5=8u~NfjNSiDYWWg<*uc+w1tYxLLM@{ ze9BXJl3;rf91S{nUoc2di7G3L(oa>|J#oJn)gYydIOowQ<)MK ILUZqjTh)0r*Z=?k literal 0 HcmV?d00001 From be3912f9868726e195c1fe9e3478405065e30386 Mon Sep 17 00:00:00 2001 From: Yarila Date: Fri, 16 Oct 2026 15:05:13 +0500 Subject: [PATCH 2/7] M7: Reflow presenter device screens and simplify tablet and desktop previews --- ROADMAP.md | 3 +- crates/ui-egui/src/present.rs | 96 +++++++++++++++++++++++++++++++++-- docs/gaps.md | 7 ++- 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 25439517..b54a43ec 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ **Stage: alpha** · next: beta, ~26 points and ~162–292 h away (one Opus 5.5 agent; ~33–67 h wall-clock with 5 agents) -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-16 · **Change:** minor (presenter tab, device picker and thumbnail; bounded canvas pan overscan; community fixes from #478 up and a control-channel fix (#589); bounded canvas pan overscan; Typography spacing icons support scrubbing (#373); font scans skip named pipes; system theme on first run; recent files as cards with thumbnails on the home screen; community fixes: lost images reported on loading (#207), SVG import budgets (#190), Leptos code (#223), full screen (#227), server snapshots readable again (#188), owner-only preferences (#200), ruzstd 0.9.1 (#182), layer cycle repair (#205), batch rollback, Direct3D 12 on Windows, plugin metering (#192); vector edit mode regions: hover hatch, selection and drag; SVG/PDF exports refuse over-depth documents (#208); bounded MCP/control framing, connections and queues (#201); plugin log limits (#191); live-session revert guard (#198); attached MCP no longer replays after a lost reply (#194); repeat command recursion fix; the Layout panel's constrain-proportions link scales the other side, #220; core editor leftovers: component playground, auto gap handles, variables inside styles, inner shadows and background blur on groups, command-made text readable on dark pages, a one-step frame/group convert, delays on mouse triggers and manual overlay offsets, wrapped-line alignment; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; starter templates, a Templates tab and Getting started tips on the home screen; your online files; everyday editing partials: number fields, outline options, Hide when publishing, cursors, panel widths, dark pages; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; a public figcraft-server: open hosting, owner tokens, per-address limits, idle expiry, moderation, install.sh; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · **Target:** Figma Design (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-16 · **Change:** minor (responsive presenter device sizing, bare tablet and computer screens; presenter tab, device picker and thumbnail; bounded canvas pan overscan; community fixes from #478 up and a control-channel fix (#589); bounded canvas pan overscan; Typography spacing icons support scrubbing (#373); font scans skip named pipes; system theme on first run; recent files as cards with thumbnails on the home screen; community fixes: lost images reported on loading (#207), SVG import budgets (#190), Leptos code (#223), full screen (#227), server snapshots readable again (#188), owner-only preferences (#200), ruzstd 0.9.1 (#182), layer cycle repair (#205), batch rollback, Direct3D 12 on Windows, plugin metering (#192); vector edit mode regions: hover hatch, selection and drag; SVG/PDF exports refuse over-depth documents (#208); bounded MCP/control framing, connections and queues (#201); plugin log limits (#191); live-session revert guard (#198); attached MCP no longer replays after a lost reply (#194); repeat command recursion fix; the Layout panel's constrain-proportions link scales the other side, #220; core editor leftovers: component playground, auto gap handles, variables inside styles, inner shadows and background blur on groups, command-made text readable on dark pages, a one-step frame/group convert, delays on mouse triggers and manual overlay offsets, wrapped-line alignment; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; starter templates, a Templates tab and Getting started tips on the home screen; your online files; everyday editing partials: number fields, outline options, Hide when publishing, cursors, panel widths, dark pages; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; a public figcraft-server: open hosting, owner tokens, per-address limits, idle expiry, moderation, install.sh; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · **Target:** Figma Design (desktop app 126.10.7) FigCraft is a clean-room, open-source, pure-Rust reimplementation of the Figma design workflow, native on macOS, Windows, Linux and FreeBSD and in the browser, fully drivable by agents through @@ -313,6 +313,7 @@ Ranked; detail and milestones in [`docs/roadmap.md`](docs/roadmap.md). | Date | Change | Summary | |---|---|---| +| 2026-10-16 | minor | Choosing a device in the presenter now enables responsive layout at that device's screen size, clears offsets from the previous screen, and lets No device restore the design's frame size. Tablet and computer presets show a bare screen at their resolution; phones keep their device body. The saved frame geometry is unchanged. Numbers unchanged. | | 2026-10-15 | minor | Presenter has a separate tab, keeps its current screen when returning to design, and adds a frame thumbnail, device picker and scale controls. Numbers unchanged. | | 2026-10-16 | minor | Community fixes from #478 up (batches #591, #598, #602; 69 PRs) and a control-channel fix: a line that isn't JSON now ends a `--control` connection, so a web page can't drive the app through a browser request (#589). Highlights: page copies keep navigation, flows, prototype settings and guides; Find and Replace keeps line endings and case-insensitive matches; text hyperlinks survive import and export; recent colours record only what was picked; MCP screenshots respect `maxSize`; Swedish catalog (UI strings), Czech plurals; bounded canvas overscan while panning; Korean fallback at the run's weight; many vector-edit, guide, page and .fig round-trip fixes. Numbers unchanged | | 2026-10-15 | minor | Drop files anywhere to open them (M7): dragging files over the window shows a "Drop to open" (home) or "Drop to import" (canvas) overlay. On the home screen each supported file opens as a document of its own and other files are turned away with a toast; on the canvas the files import at the drop point. Both wait behind a small card that is on screen before a large file blocks the window. A canvas import stays with the document and page that received the drop even if the tab or page changes meanwhile, and is cancelled with a message if that document or page is gone. Numbers unchanged. | diff --git a/crates/ui-egui/src/present.rs b/crates/ui-egui/src/present.rs index bb611588..9fc85337 100644 --- a/crates/ui-egui/src/present.rs +++ b/crates/ui-egui/src/present.rs @@ -393,6 +393,18 @@ impl Presenter { self.stop_scrolling(); } + /// A new device changes the viewport and may relayout every frame. Start at its top instead + /// of carrying scroll offsets or a drag from the old screen into the new one. + fn reset_for_device(&mut self) { + self.pan = None; + self.scroll.clear(); + self.scroll_anim = None; + self.press = None; + self.dragged = false; + self.stop_scrolling(); + self.rev += 1; + } + /// The current offset of `t` (a frame's scroll, else the view's pan). fn offset(&self, t: Scroller) -> (f64, f64) { match t { @@ -1523,6 +1535,11 @@ fn body_outset(device: &str, size: Vec2, landscape: bool) -> (f32, f32, f32) { } } +/// Tablet and computer presets size the screen without drawing a hardware shell around it. +fn has_device_body(device: Device) -> bool { + !device.name.starts_with("iPad") && !matches!(device.name, "MacBook Air" | "Desktop") +} + /// Place the presented frame in `area`: on its device's screen (the whole device sized by the /// view's scale option), else the frame itself. Fit and 100% keep the chrome's padding from the /// edges; Fit never goes above 100%. What doesn't fit the window pans (`Presenter::pan`). The @@ -1538,7 +1555,7 @@ fn layout(p: &mut Presenter, area: Rect, chrome: Chrome) -> Option { let fb = disp.world_bounds(p.current)?; let view = if chrome.pane { PresentView::default() } else { p.view }; // Custom sizes are just a screen: no body. - let body = device.filter(|d| view.device_frame && !d.colors.is_empty()); + let body = device.filter(|d| view.device_frame && has_device_body(*d) && !d.colors.is_empty()); let pad = if !fills && matches!(view.scale, PresentScale::Fit | PresentScale::Actual) { chrome.pad } else { 0.0 }; let avail = area.shrink(pad); let (sw, sh) = device.map_or((fb.width(), fb.height()), |d| (d.width, d.height)); @@ -1684,7 +1701,7 @@ pub fn show(app: &mut FigApp, ui: &mut Ui) { app.run("proto.settings", json!({"responsive": on})); } if let Some(device) = picked_device { - app.run("proto.settings", json!({"device": device})); + choose_device(app, &mut pres, &device); } if action == Some(BarAction::Close) || ctx.input(|i| i.key_pressed(egui::Key::Escape)) { app.ui.present_uid = None; @@ -1693,6 +1710,15 @@ pub fn show(app: &mut FigApp, ui: &mut Ui) { app.ui.present = Some(pres); } +/// Device choices in the presenter use the screen's real dimensions and reflow a copy of the +/// design through constraints and auto layout. "No device" returns to the original frame size. +fn choose_device(app: &mut FigApp, p: &mut Presenter, device: &str) { + let responsive = device != "None"; + if app.run("proto.settings", json!({"device": device, "responsive": responsive})).is_some() { + p.reset_for_device(); + } +} + /// Controls that stay in reach while viewing a prototype, including screen stepping, device and /// scale. The selected device is returned to the caller so it can go through the normal document /// command (and undo/save) rather than changing only the player's copy. @@ -2320,7 +2346,7 @@ fn options_menu(p: &mut Presenter, ui: &mut Ui, device: Option, responsi } ui.separator(); } - if device.is_some_and(|d| !d.colors.is_empty()) && menu_check(ui, p.view.device_frame, tr("Show device frame"), "") { + if device.is_some_and(|d| has_device_body(d) && !d.colors.is_empty()) && menu_check(ui, p.view.device_frame, tr("Show device frame"), "") { p.view.device_frame = !p.view.device_frame; ui.close(); } @@ -2815,6 +2841,70 @@ mod tests { use super::*; use figcraft_doc::NodeKind; + use crate::present_tests::{Ui, id}; + + #[test] + fn device_picker_reflows_without_resizing_the_saved_frame_and_can_revert() { + let mut session = figcraft_engine::Session::new(); + let frame = id(&session.execute("node.create", &json!({"type": "frame", "width": 894, "height": 844})).unwrap()); + let right = id(&session + .execute("node.create", &json!({"type": "rectangle", "parent": frame, "x": 804, "y": 20, "width": 80, "height": 40})) + .unwrap()); + session.execute("node.set", &json!({"id": right, "props": {"constraints": {"horizontal": "right", "vertical": "top"}}})).unwrap(); + let mut ui = Ui::new(session); + ui.run("proto.present", json!({"start": frame})); + + let mut presenter = ui.app.ui.present.take().unwrap(); + presenter.pan = Some((100.0, 200.0)); + presenter.scroll.insert(frame, (75.0, 50.0)); + choose_device(&mut ui.app, &mut presenter, "iPhone 17"); + assert!(presenter.pan.is_none() && presenter.scroll.is_empty()); + ui.app.ui.present = Some(presenter); + ui.frame(vec![]); + + let shown = &ui.app.ui.present.as_ref().unwrap().doc.as_ref().unwrap(); + assert_eq!((shown.node(frame).unwrap().width, shown.node(frame).unwrap().height), (402.0, 874.0)); + assert_eq!(shown.world_bounds(right).unwrap().x0, 312.0, "right constraint follows the phone edge"); + assert_eq!(ui.app.inspect()["presenter"]["viewport"], json!([402.0, 874.0])); + assert_eq!(ui.app.inspect()["presenter"]["scrollRange"], json!([0.0, 0.0])); + assert_eq!(ui.app.session.doc().unwrap().node(frame).unwrap().width, 894.0, "the saved design keeps its geometry"); + + let mut presenter = ui.app.ui.present.take().unwrap(); + choose_device(&mut ui.app, &mut presenter, "None"); + ui.app.ui.present = Some(presenter); + ui.frame(vec![]); + assert_eq!(ui.app.inspect()["presenter"]["frameSize"], json!([894.0, 844.0])); + assert_eq!(ui.app.inspect()["presenter"]["responsive"], Value::Null); + } + + #[test] + fn tablet_and_computer_presets_show_only_their_screen_at_the_real_resolution() { + let mut session = figcraft_engine::Session::new(); + let frame = id(&session.execute("node.create", &json!({"type": "frame", "width": 894, "height": 844})).unwrap()); + let mut ui = Ui::new(session); + ui.run("proto.present", json!({"start": frame})); + let area = Rect::from_min_max(pos2(0.0, 40.0), pos2(1440.0, 860.0)); + + for (name, width, height, body) in [ + ("iPad mini", 744.0, 1133.0, false), + ("MacBook Air", 1280.0, 832.0, false), + ("Desktop", 1440.0, 1024.0, false), + ("iPhone 17", 402.0, 874.0, true), + ] { + let mut presenter = ui.app.ui.present.take().unwrap(); + choose_device(&mut ui.app, &mut presenter, name); + ui.app.ui.present = Some(presenter); + ui.frame(vec![]); + + let presenter = ui.app.ui.present.as_mut().unwrap(); + let laid = layout(presenter, area, FULL).unwrap(); + assert_eq!(laid.color.is_some(), body, "{name}: body visibility"); + assert!((f64::from(laid.screen.width()) / laid.scale - width).abs() < 0.1, "{name}: width"); + assert!((f64::from(laid.screen.height()) / laid.scale - height).abs() < 0.1, "{name}: height"); + assert_eq!(ui.app.session.doc().unwrap().node(frame).unwrap().width, 894.0); + } + } + fn doc_with_two_frames() -> (Document, NodeId, NodeId) { let mut d = Document::new("t"); let page = d.add_page("Page 1"); diff --git a/docs/gaps.md b/docs/gaps.md index 95962a5c..1e2cd114 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -1,6 +1,6 @@ # Where FigCraft falls short of Figma -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-15 · **Change:** minor (presenter navigation and device controls; bounded canvas pan overscan; reviewed Russian catalog and integer plurals; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; `.fig` import: editable vector networks, more layer kinds, variable prototype actions; `.fig` import, best effort: gap 1 down to its tail; Windows QA pass: everyday workflows on Windows 11, eight fixes incl. unsaved work kept after a crash or a forced quit; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings: gap 14 down to its tail) · **Target:** Figma Design (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-16 · **Change:** minor (responsive presenter device sizing and bare tablet and computer screens; presenter navigation and device controls; bounded canvas pan overscan; reviewed Russian catalog and integer plurals; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; `.fig` import: editable vector networks, more layer kinds, variable prototype actions; `.fig` import, best effort: gap 1 down to its tail; Windows QA pass: everyday workflows on Windows 11, eight fixes incl. unsaved work kept after a crash or a forced quit; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings: gap 14 down to its tail) · **Target:** Figma Design (desktop app 126.10.7) Every known shortfall against Figma, one entry each, ranked by how much it stops a Figma user from doing real work in FigCraft. Agents: pick work from the top unless the owner says otherwise. The @@ -141,6 +141,10 @@ No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passe - **Landed (2026-10-15):** presentation keeps its own tab beside the design, preserves the current screen when switching back to edit, shows a small current-screen preview and offers screen, device and scale controls (`present_view_tests`). +- **Landed (2026-10-16):** choosing a presenter device reflows a copy of the frame to its screen + size using constraints and auto layout, clears the previous screen's scroll and pan, and keeps + the file's frame geometry unchanged; No device restores the original size. Tablet and computer + presets show the screen at their resolution without a drawn hardware body. - **Evidence:** ROADMAP item 7 ("Left: tool by tool, panel by panel against the incumbent"). - **Impact:** Figma users notice the feel within minutes; it decides whether they stay. - **Estimate:** 40–60 h. Detail in [`ui-parity.md`](ui-parity.md). @@ -403,6 +407,7 @@ No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passe | Date | Change | Summary | |---|---|---| +| 2026-10-16 | minor | Gap 4: presenter device selection now uses responsive layout at the selected screen size and resets stale offsets; tablets and computers show bare screens, and the original frame is preserved. Estimates and ranking unchanged. | | 2026-10-15 | minor | Gap 4: presenter tab, thumbnail, device picker and scale controls. Estimates and ranking unchanged. | | 2026-10-15 | minor | Gap 7: bounded canvas overscan for smoother panning. Estimates and ranking unchanged. | | 2026-10-14 | minor | Russian catalog (M9), reviewed and approved by VanTan: all 2,165 current entries, Русский in Preferences and regional ru tags. Russian integer plurals use one/few/many; contributor display name VanTan added. Existing estimates unchanged. | From ac1a192a3aa6c4acdd3108956d2e7c4b1dc6076c Mon Sep 17 00:00:00 2001 From: Yarila Date: Fri, 16 Oct 2026 17:25:13 +0500 Subject: [PATCH 3/7] M7: keep mobile presenter fixed and confirm window close --- ROADMAP.md | 1 + crates/ui-egui/src/lib.rs | 5 ++ crates/ui-egui/src/present.rs | 90 ++++++++++++++++++++++++---- crates/ui-egui/src/tabs.rs | 10 +++- crates/ui-egui/src/titlebar_tests.rs | 19 +++++- crates/ui-egui/src/windows.rs | 9 ++- crates/ui-egui/src/windows_tests.rs | 19 ++++++ docs/gaps.md | 6 +- 8 files changed, 142 insertions(+), 17 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index b54a43ec..ce132520 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -313,6 +313,7 @@ Ranked; detail and milestones in [`docs/roadmap.md`](docs/roadmap.md). | Date | Change | Summary | |---|---|---| +| 2026-10-16 | minor | The full presenter now scrolls content beyond a responsive phone or tablet screen in both directions. A drag that starts inside the screen continues when the pointer leaves it; the device body stays fixed. Computer presets keep their ordinary scrolling rules. The unsaved-changes dialog appears over presentation when closing a window. The saved design is unchanged. Numbers unchanged. | | 2026-10-16 | minor | Choosing a device in the presenter now enables responsive layout at that device's screen size, clears offsets from the previous screen, and lets No device restore the design's frame size. Tablet and computer presets show a bare screen at their resolution; phones keep their device body. The saved frame geometry is unchanged. Numbers unchanged. | | 2026-10-15 | minor | Presenter has a separate tab, keeps its current screen when returning to design, and adds a frame thumbnail, device picker and scale controls. Numbers unchanged. | | 2026-10-16 | minor | Community fixes from #478 up (batches #591, #598, #602; 69 PRs) and a control-channel fix: a line that isn't JSON now ends a `--control` connection, so a web page can't drive the app through a browser request (#589). Highlights: page copies keep navigation, flows, prototype settings and guides; Find and Replace keeps line endings and case-insensitive matches; text hyperlinks survive import and export; recent colours record only what was picked; MCP screenshots respect `maxSize`; Swedish catalog (UI strings), Czech plurals; bounded canvas overscan while panning; Korean fallback at the run's weight; many vector-edit, guide, page and .fig round-trip fixes. Numbers unchanged | diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 91f7a56b..97b2be71 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -1312,9 +1312,14 @@ impl FigApp { self.end_pen_outside_design(); tabs::tab_bar(self, ui); if self.ui.present.is_some() { + // A close request can arrive while the presenter fills the window. Let its unsaved + // changes dialog take Escape and draw above the player just as it does in the editor. + dialogs::keys(self, &ctx); present::show(self, ui); + dialogs::show(self, &ctx); // What went wrong while presenting (a widget's plugin failing) shows over it. self.toast_ui(&ctx); + windows::requests(self, &ctx); return; } if !self.has_files() || self.ui.home { diff --git a/crates/ui-egui/src/present.rs b/crates/ui-egui/src/present.rs index 9fc85337..5a9d4bf3 100644 --- a/crates/ui-egui/src/present.rs +++ b/crates/ui-egui/src/present.rs @@ -541,7 +541,13 @@ impl Presenter { /// device's screen, other frames within themselves. fn range(&self, doc: &Document, frame: NodeId) -> (f64, f64) { let vp = if frame == self.current { viewport(doc, frame) } else { None }; - scroll_range_in(doc, frame, vp) + // In a responsive preview, make content outside the device reachable even if the source + // frame has no overflow mode. Its settings and geometry stay untouched in the file. + let mobile = frame == self.current && page_settings(doc, frame).device().is_some_and(|d| d.rotates); + let overflow = doc + .node(frame) + .map_or(Overflow::None, |n| if mobile && self.fit.is_some() && n.overflow == Overflow::None { Overflow::Both } else { n.overflow }); + scroll_range_with_overflow(doc, frame, vp, overflow) } /// What "Scroll to" `dest` moves: every scrolling frame around it, innermost first, brings the @@ -1171,8 +1177,13 @@ pub fn scroll_range(doc: &Document, frame: NodeId) -> (f64, f64) { /// frame taller than the screen scrolls through its whole height. Without a viewport the frame /// shows at its own size and what overflows it scrolls. Only the axes its overflow allows scroll. pub fn scroll_range_in(doc: &Document, frame: NodeId, viewport: Option<(f64, f64)>) -> (f64, f64) { + let overflow = doc.node(frame).map_or(Overflow::None, |n| n.overflow); + scroll_range_with_overflow(doc, frame, viewport, overflow) +} + +fn scroll_range_with_overflow(doc: &Document, frame: NodeId, viewport: Option<(f64, f64)>, overflow: Overflow) -> (f64, f64) { let Some(n) = doc.node(frame) else { return (0.0, 0.0) }; - if n.overflow == Overflow::None { + if overflow == Overflow::None { return (0.0, 0.0); } let (mut x1, mut y1) = (0.0f64, 0.0f64); @@ -1197,8 +1208,8 @@ pub fn scroll_range_in(doc: &Document, frame: NodeId, viewport: Option<(f64, f64 } None => (n.width, n.height), }; - let rx = if matches!(n.overflow, Overflow::Horizontal | Overflow::Both) { (x1 - vw).max(0.0) } else { 0.0 }; - let ry = if matches!(n.overflow, Overflow::Vertical | Overflow::Both) { (y1 - vh).max(0.0) } else { 0.0 }; + let rx = if matches!(overflow, Overflow::Horizontal | Overflow::Both) { (x1 - vw).max(0.0) } else { 0.0 }; + let ry = if matches!(overflow, Overflow::Vertical | Overflow::Both) { (y1 - vh).max(0.0) } else { 0.0 }; (if rx.is_finite() { rx } else { 0.0 }, if ry.is_finite() { ry } else { 0.0 }) } @@ -2367,7 +2378,7 @@ fn scrollers_at(p: &Presenter, base: &Document, disp: &Document, root: NodeId, p let mut out: Vec = disp .subtree(root) .into_iter() - .filter(|f| disp.node(*f).is_some_and(|n| n.visible && n.overflow != Overflow::None)) + .filter(|f| disp.node(*f).is_some_and(|n| n.visible)) .filter(|f| disp.world_bounds(*f).is_some_and(|b| place.rect(b).contains(q))) .filter(|f| p.range(base, *f) != (0.0, 0.0)) .collect(); @@ -2574,14 +2585,21 @@ fn input(p: &mut Presenter, ctx: &egui::Context, l: &Layout, over_area: bool, ke } return; } - // Otherwise the drag scrolls the innermost frame under it that scrolls, else pans a view - // bigger than the window. + // A drag begun inside a mobile screen moves its content, even if the pointer leaves the + // screen. The device body stays in place even when the drag begins outside its screen. + // Panning the whole view remains available only without a mobile device. if let Some(base) = p.doc.clone() { - let target = scrollers_at(p, &base, doc, root, &place, start) - .first() + let horizontal = d.x.abs() >= d.y.abs(); + let scrolls = scrollers_at(p, &base, doc, root, &place, start); + let on_axis = |range: (f64, f64)| if horizontal { range.0 > 0.0 } else { range.1 > 0.0 }; + let mobile = page_settings(&base, root).device().is_some_and(|device| device.rotates); + let target = scrolls + .iter() .copied() + .find(|f| on_axis(p.range(&base, *f))) + .or_else(|| scrolls.first().copied()) .map(Scroller::Frame) - .or((p.pan_range != (0.0, 0.0)).then_some(Scroller::View)); + .or((!mobile && p.pan_range != (0.0, 0.0)).then_some(Scroller::View)); if let Some(t) = target { p.fling = None; p.drag_scroll = Some((t, clamp_scroll(p.offset(t), p.limits(&base, t)))); @@ -2869,6 +2887,14 @@ mod tests { assert_eq!(ui.app.inspect()["presenter"]["scrollRange"], json!([0.0, 0.0])); assert_eq!(ui.app.session.doc().unwrap().node(frame).unwrap().width, 894.0, "the saved design keeps its geometry"); + let area = Rect::from_min_max(pos2(0.0, 40.0), pos2(1440.0, 900.0)); + let screen_before = layout(ui.app.ui.present.as_mut().unwrap(), area, FULL).unwrap().screen; + ui.button(pos2(720.0, 440.0), true); + ui.frame(vec![egui::Event::PointerMoved(pos2(300.0, 300.0))]); + ui.button(pos2(300.0, 300.0), false); + assert_eq!(ui.app.inspect()["presenter"]["scroll"], json!([0.0, 0.0]), "fitted content does not move"); + assert_eq!(layout(ui.app.ui.present.as_mut().unwrap(), area, FULL).unwrap().screen, screen_before); + let mut presenter = ui.app.ui.present.take().unwrap(); choose_device(&mut ui.app, &mut presenter, "None"); ui.app.ui.present = Some(presenter); @@ -2905,6 +2931,50 @@ mod tests { } } + #[test] + fn responsive_device_scrolls_content_in_both_directions_without_changing_saved_overflow() { + let mut session = figcraft_engine::Session::new(); + let frame = id(&session.execute("node.create", &json!({"type": "frame", "width": 894, "height": 844})).unwrap()); + session.execute("node.create", &json!({"type": "rectangle", "parent": frame, "x": 650, "y": 1050, "width": 80, "height": 80})).unwrap(); + let mut ui = Ui::new(session); + ui.run("proto.present", json!({"start": frame})); + let mut presenter = ui.app.ui.present.take().unwrap(); + choose_device(&mut ui.app, &mut presenter, "iPhone 17"); + ui.app.ui.present = Some(presenter); + ui.frame(vec![]); + + let range = &ui.app.inspect()["presenter"]["scrollRange"]; + assert!(range[0].as_f64().unwrap() > 0.0 && range[1].as_f64().unwrap() > 0.0, "{range}"); + let start = pos2(720.0, 440.0); + ui.button(start, true); + ui.frame(vec![egui::Event::PointerMoved(start - vec2(100.0, 120.0))]); + ui.button(start - vec2(100.0, 120.0), false); + let scroll = &ui.app.inspect()["presenter"]["scroll"]; + assert!(scroll[0].as_f64().unwrap() > 0.0 && scroll[1].as_f64().unwrap() > 0.0, "{scroll}"); + assert_eq!(ui.app.session.doc().unwrap().node(frame).unwrap().overflow, Overflow::None); + assert_eq!(ui.app.session.doc().unwrap().node(frame).unwrap().width, 894.0); + + // Like the phone preview, the content keeps following a drag after the pointer leaves + // the screen, while the device itself stays fixed on the stage. + ui.frames(60, Vec::new); + let area = Rect::from_min_max(pos2(0.0, 40.0), pos2(1440.0, 900.0)); + let screen_before = layout(ui.app.ui.present.as_mut().unwrap(), area, FULL).unwrap().screen; + ui.button(start, true); + ui.frame(vec![egui::Event::PointerMoved(pos2(300.0, 300.0))]); + let during = ui.app.inspect()["presenter"].clone(); + assert!(during["scroll"][0].as_f64().unwrap() > 0.0, "{during}"); + let screen_after = layout(ui.app.ui.present.as_mut().unwrap(), area, FULL).unwrap().screen; + assert_eq!(screen_after, screen_before); + ui.button(pos2(300.0, 300.0), false); + + let mut presenter = ui.app.ui.present.take().unwrap(); + choose_device(&mut ui.app, &mut presenter, "Desktop"); + ui.app.ui.present = Some(presenter); + ui.frame(vec![]); + let desktop = ui.app.inspect()["presenter"].clone(); + assert_eq!(desktop["scrollRange"], json!([0.0, 0.0])); + } + fn doc_with_two_frames() -> (Document, NodeId, NodeId) { let mut d = Document::new("t"); let page = d.add_page("Page 1"); diff --git a/crates/ui-egui/src/tabs.rs b/crates/ui-egui/src/tabs.rs index 534881fc..381b09dd 100644 --- a/crates/ui-egui/src/tabs.rs +++ b/crates/ui-egui/src/tabs.rs @@ -28,7 +28,7 @@ pub fn tab_bar(app: &mut FigApp, ui: &mut Ui) { ui.ctx().send_viewport_cmd(egui::ViewportCommand::Maximized(!max)); } } - let buttons_w = if app.ui.title_bar == TitleBar::Custom { window_buttons(ui, rect) } else { 0.0 }; + let buttons_w = if app.ui.title_bar == TitleBar::Custom { window_buttons(app, ui, rect) } else { 0.0 }; let mut x = rect.min.x + if app.ui.title_bar == TitleBar::Inset { 76.0 } else { 8.0 }; // Home. let hr = Rect::from_min_size(pos2(x, rect.min.y), vec2(44.0, HEIGHT)); @@ -256,7 +256,7 @@ pub fn live_mark(app: &FigApp, uid: u64) -> Option { } /// Minimise, maximise/restore and close at the right end of the title bar; returns their width. -fn window_buttons(ui: &mut Ui, bar: Rect) -> f32 { +fn window_buttons(app: &mut FigApp, ui: &mut Ui, bar: Rect) -> f32 { const W: f32 = 46.0; let t = Tokens::get(ui.ctx()); let max = ui.input(|i| i.viewport().maximized.unwrap_or(false)); @@ -284,7 +284,11 @@ fn window_buttons(ui: &mut Ui, bar: Rect) -> f32 { } icons::paint(ui.painter(), Rect::from_center_size(r.center(), vec2(14.0, 14.0)), icon, col); if resp.clicked() { - ui.ctx().send_viewport_cmd(cmd); + if close { + crate::windows::request_close(app, ui.ctx()); + } else { + ui.ctx().send_viewport_cmd(cmd); + } } } W * 3.0 diff --git a/crates/ui-egui/src/titlebar_tests.rs b/crates/ui-egui/src/titlebar_tests.rs index 796cb670..e9224404 100644 --- a/crates/ui-egui/src/titlebar_tests.rs +++ b/crates/ui-egui/src/titlebar_tests.rs @@ -4,6 +4,7 @@ use egui::{Event, PointerButton, Pos2, RawInput, Rect, ResizeDirection, ViewportCommand, ViewportId, pos2, vec2}; use figcraft_engine::Session; +use serde_json::json; use crate::{FigApp, NoServices, TitleBar}; @@ -76,7 +77,23 @@ fn window_buttons_minimise_maximise_and_close() { let mut u = Ui::new(TitleBar::Custom); assert!(u.click(window_button(0)).contains(&ViewportCommand::Minimized(true))); assert!(u.click(window_button(1)).contains(&ViewportCommand::Maximized(true))); - assert!(u.click(window_button(2)).contains(&ViewportCommand::Close)); + u.click(window_button(2)); + assert!(u.frame(vec![]).contains(&ViewportCommand::Close)); +} + +#[test] +fn titlebar_close_asks_over_the_presenter_when_a_file_is_unsaved() { + let mut u = Ui::new(TitleBar::Custom); + let frame = u.app.session.execute("node.create", &json!({"type": "frame", "width": 402, "height": 874})).unwrap()["id"].clone(); + u.app.session.execute("proto.present", &json!({"start": frame})).unwrap(); + u.app.handle_ui_requests(); + u.frame(vec![]); + assert!(u.app.ui.present.is_some()); + + let commands = u.click(window_button(2)); + assert!(!commands.contains(&ViewportCommand::Close)); + assert!(u.app.ui.confirm_close); + assert!(u.ctx.memory(|memory| memory.area_rect(egui::Id::new(Some(crate::i18n::tr("Unsaved changes")))).is_some())); } #[test] diff --git a/crates/ui-egui/src/windows.rs b/crates/ui-egui/src/windows.rs index 510c24f6..30b71f34 100644 --- a/crates/ui-egui/src/windows.rs +++ b/crates/ui-egui/src/windows.rs @@ -300,7 +300,12 @@ pub fn on_close_request(app: &mut FigApp, ctx: &Context) { if app.windows.current == 0 && (unsaved || !app.windows.list.is_empty()) { ctx.send_viewport_cmd(ViewportCommand::CancelClose); } - if unsaved { + request_close(app, ctx); +} + +/// The custom title bar's Close button uses the same unsaved-file check as a system close event. +pub(crate) fn request_close(app: &mut FigApp, ctx: &Context) { + if !app.unsaved().is_empty() { app.ui.confirm_close = true; ctx.request_repaint(); } else { @@ -325,7 +330,7 @@ pub(crate) fn confirm_close(app: &mut FigApp, ctx: &Context) { } let t = crate::theme::Tokens::get(ctx); let (mut open, mut discard, mut cancel) = (true, false, false); - crate::dialogs::window(tr("Unsaved changes"), ctx).open(&mut open).show(ctx, |ui| { + crate::dialogs::window(tr("Unsaved changes"), ctx).order(egui::Order::Foreground).open(&mut open).show(ctx, |ui| { ui.set_width(340.0); crate::widgets::label(ui, &trf("Unsaved changes in {names}. Close the window and lose them?", &[("names", &names.join(", "))]), t.text); ui.add_space(12.0); diff --git a/crates/ui-egui/src/windows_tests.rs b/crates/ui-egui/src/windows_tests.rs index 1a6e91bb..06e0a6a1 100644 --- a/crates/ui-egui/src/windows_tests.rs +++ b/crates/ui-egui/src/windows_tests.rs @@ -45,6 +45,25 @@ fn names(app: &FigApp) -> Vec { app.session.docs.iter().map(|d| d.doc.name.clone()).collect() } +#[test] +fn closing_a_window_in_the_presenter_shows_the_unsaved_changes_dialog() { + let mut session = Session::new(); + let frame_id = session.execute("node.create", &json!({"type": "frame", "width": 402, "height": 874})).unwrap()["id"].clone(); + let ctx = egui::Context::default(); + let mut app = FigApp::new(session, Box::new(NoServices)); + frame(&ctx, &mut app, false); + app.session.execute("proto.present", &json!({"start": frame_id})).unwrap(); + app.handle_ui_requests(); + frame(&ctx, &mut app, false); + assert!(app.ui.present.is_some()); + + frame(&ctx, &mut app, true); + assert!(app.ui.confirm_close); + assert!(ctx.memory(|memory| memory.area_rect(egui::Id::new(Some(crate::i18n::tr("Unsaved changes")))).is_some()), "dialog must be on screen"); + frame(&ctx, &mut app, false); + assert!(app.ui.present.is_some(), "asking to close does not dismiss the preview"); +} + #[test] fn windows_hold_tabs_and_close_with_their_files() { let mut s = Session::empty(); diff --git a/docs/gaps.md b/docs/gaps.md index 1e2cd114..94c387e5 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -144,7 +144,11 @@ No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passe - **Landed (2026-10-16):** choosing a presenter device reflows a copy of the frame to its screen size using constraints and auto layout, clears the previous screen's scroll and pan, and keeps the file's frame geometry unchanged; No device restores the original size. Tablet and computer - presets show the screen at their resolution without a drawn hardware body. + presets show the screen at their resolution without a drawn hardware body. In the full presenter, + dragging inside a phone or tablet scrolls content in either direction when it exceeds the screen, + even when the pointer moves outside the device. The device remains fixed; computer presets keep + their ordinary scrolling rules. These gestures do not alter the file. Closing a window from + presentation shows the unsaved-changes dialog over the presenter. - **Evidence:** ROADMAP item 7 ("Left: tool by tool, panel by panel against the incumbent"). - **Impact:** Figma users notice the feel within minutes; it decides whether they stay. - **Estimate:** 40–60 h. Detail in [`ui-parity.md`](ui-parity.md). From 88925c2f820eb176a03df2245c2a82502da41e09 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Sat, 17 Oct 2026 20:17:02 +0700 Subject: [PATCH 4/7] #537: drop the progress-doc edits --- ROADMAP.md | 5 +---- docs/gaps.md | 15 +-------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 82b6c4c0..2dcc2b9b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ **Stage: alpha** · next: beta, ~26 points and ~162–292 h away (one Opus 5.5 agent; ~33–67 h wall-clock with 5 agents) -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** minor (responsive presenter device sizing, bare tablet and computer screens; presenter tab, device picker and thumbnail; number variables in the text content picker (#629); frames and sections convert into each other (#719); bounded canvas pan overscan; community fixes from #478 up and a control-channel fix (#589); bounded canvas pan overscan; Typography spacing icons support scrubbing (#373); font scans skip named pipes; system theme on first run; recent files as cards with thumbnails on the home screen; community fixes: lost images reported on loading (#207), SVG import budgets (#190), Leptos code (#223), full screen (#227), server snapshots readable again (#188), owner-only preferences (#200), ruzstd 0.9.1 (#182), layer cycle repair (#205), batch rollback, Direct3D 12 on Windows, plugin metering (#192); vector edit mode regions: hover hatch, selection and drag; SVG/PDF exports refuse over-depth documents (#208); bounded MCP/control framing, connections and queues (#201); plugin log limits (#191); live-session revert guard (#198); attached MCP no longer replays after a lost reply (#194); repeat command recursion fix; the Layout panel's constrain-proportions link scales the other side, #220; core editor leftovers: component playground, auto gap handles, variables inside styles, inner shadows and background blur on groups, command-made text readable on dark pages, a one-step frame/group convert, delays on mouse triggers and manual overlay offsets, wrapped-line alignment; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; starter templates, a Templates tab and Getting started tips on the home screen; your online files; everyday editing partials: number fields, outline options, Hide when publishing, cursors, panel widths, dark pages; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; a public figcraft-server: open hosting, owner tokens, per-address limits, idle expiry, moderation, install.sh; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · **Target:** Figma Design (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** minor (community fixes from #524 up (55 PRs: `.fig` import fidelity, paste from other apps, the Actions palette, editor fixes, server limits) and a boolean-op crash guard; number variables in the text content picker (#629); frames and sections convert into each other (#719); bounded canvas pan overscan; community fixes from #478 up and a control-channel fix (#589); bounded canvas pan overscan; Typography spacing icons support scrubbing (#373); font scans skip named pipes; system theme on first run; recent files as cards with thumbnails on the home screen; community fixes: lost images reported on loading (#207), SVG import budgets (#190), Leptos code (#223), full screen (#227), server snapshots readable again (#188), owner-only preferences (#200), ruzstd 0.9.1 (#182), layer cycle repair (#205), batch rollback, Direct3D 12 on Windows, plugin metering (#192); vector edit mode regions: hover hatch, selection and drag; SVG/PDF exports refuse over-depth documents (#208); bounded MCP/control framing, connections and queues (#201); plugin log limits (#191); live-session revert guard (#198); attached MCP no longer replays after a lost reply (#194); repeat command recursion fix; the Layout panel's constrain-proportions link scales the other side, #220; core editor leftovers: component playground, auto gap handles, variables inside styles, inner shadows and background blur on groups, command-made text readable on dark pages, a one-step frame/group convert, delays on mouse triggers and manual overlay offsets, wrapped-line alignment; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; starter templates, a Templates tab and Getting started tips on the home screen; your online files; everyday editing partials: number fields, outline options, Hide when publishing, cursors, panel widths, dark pages; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; a public figcraft-server: open hosting, owner tokens, per-address limits, idle expiry, moderation, install.sh; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; `.fig` import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · **Target:** Figma Design (desktop app 126.10.7) FigCraft is a clean-room, open-source, pure-Rust reimplementation of the Figma design workflow, native on macOS, Windows, Linux and FreeBSD and in the browser, fully drivable by agents through @@ -318,9 +318,6 @@ Ranked; detail and milestones in [`docs/roadmap.md`](docs/roadmap.md). | 2026-10-17 | minor | Community fixes from #524 up (batches #727, #728, #733, #735, #736 and #729; 55 PRs) and a crash guard. `.fig` import: explicit instance identity, overrides by key, text style precedence, grid track sizes, slot content, connector labels, skip ink, paragraph options and hanging lists, list start numbers, vertical trim, per-point stroke joins, text on a path, image adjustments and embedded images; large files open within budgets from the file's own size; an import report after opening; imported bytes stay out of the command journal. Files and paste: save a copy as `.fig`; Cmd/Ctrl+V pastes images copied in other apps and layers copied from another design app (`edit.pasteDesignLayers`); paste over and paste properties; clipboard reads on Linux and the BSDs time out after 2 s. Editor: live font preview on hover; Shift+I and Resources open Assets; Shift-drag moves the selection; thin strokes take a nearby double-click; dropped points merge; Flatten keeps open paths; the Actions palette gets tabs, ranked search, a keyboard highlight and recents; the colour picker opens on a new fill or stroke; text strokes follow their alignment; selection highlights after line breaks; a draggable pages/layers divider; variant properties reorder by drag; submenus keep their hover with a safe triangle; menu actions that need a value ask for it; File ▸ Rename edits the name in place. Engine: bad paint indexes, non-finite geometry and pages in copy/cut are refused; a param naming a layer says so when it isn't one; a CLI script is one undo step and resolves `$step`. Server and collaboration: message limits follow `max_file_mb` (client capped at 1 GiB); a damaged generation field no longer drops flushed edits; the web build joins a session from a `#join=` link. Also Swedish command labels, Nix CI through the shared workflow, paint bounds once per render, and a guard that turns a panic inside the boolean-op library into bad input (the stroke draws unclipped). Numbers unchanged. | | 2026-10-17 | minor | Number variables on text content (M3, #629): the Typography section's variable picker also lists number variables for a text layer's content, as the engine already accepted (the text shows the number, e.g. 42.5, and follows the variable). Other text fields keep their own types. Numbers unchanged. | | 2026-10-17 | minor | Frames and sections convert into each other (M1, #719): `object.convertToSection` turns a frame on the page or in a section into a section in place (same box, name, fill and layers, which stay where they are; what only a frame has goes: auto layout, clipping, layout grids, guides, scrolling), and `object.convertToFrame` now also turns a section into a frame that keeps its fill and doesn't clip, so the look stays. Nested frames, instances, main components and sections holding sections are refused with the reason; one undo step each. Both are in the canvas context menu (Convert to section / Convert to frame) and in Spanish. Numbers unchanged. | -| 2026-10-16 | minor | The full presenter now scrolls content beyond a responsive phone or tablet screen in both directions. A drag that starts inside the screen continues when the pointer leaves it; the device body stays fixed. Computer presets keep their ordinary scrolling rules. The unsaved-changes dialog appears over presentation when closing a window. The saved design is unchanged. Numbers unchanged. | -| 2026-10-16 | minor | Choosing a device in the presenter now enables responsive layout at that device's screen size, clears offsets from the previous screen, and lets No device restore the design's frame size. Tablet and computer presets show a bare screen at their resolution; phones keep their device body. The saved frame geometry is unchanged. Numbers unchanged. | -| 2026-10-15 | minor | Presenter has a separate tab, keeps its current screen when returning to design, and adds a frame thumbnail, device picker and scale controls. Numbers unchanged. | | 2026-10-16 | minor | Community fixes from #478 up (batches #591, #598, #602; 69 PRs) and a control-channel fix: a line that isn't JSON now ends a `--control` connection, so a web page can't drive the app through a browser request (#589). Highlights: page copies keep navigation, flows, prototype settings and guides; Find and Replace keeps line endings and case-insensitive matches; text hyperlinks survive import and export; recent colours record only what was picked; MCP screenshots respect `maxSize`; Swedish catalog (UI strings), Czech plurals; bounded canvas overscan while panning; Korean fallback at the run's weight; many vector-edit, guide, page and .fig round-trip fixes. Numbers unchanged | | 2026-10-15 | minor | Drop files anywhere to open them (M7): dragging files over the window shows a "Drop to open" (home) or "Drop to import" (canvas) overlay. On the home screen each supported file opens as a document of its own and other files are turned away with a toast; on the canvas the files import at the drop point. Both wait behind a small card that is on screen before a large file blocks the window. A canvas import stays with the document and page that received the drop even if the tab or page changes meanwhile, and is cancelled with a message if that document or page is gone. Numbers unchanged. | | 2026-10-15 | minor | M7: system font discovery skips entries observed as non-regular files before opening them, avoiding the reproduced named-pipe stall. Regular-file symlinks remain supported; directory depth, font limits and priorities are unchanged. Numbers unchanged. | diff --git a/docs/gaps.md b/docs/gaps.md index 94c387e5..e8b111a8 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -1,6 +1,6 @@ # Where FigCraft falls short of Figma -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-16 · **Change:** minor (responsive presenter device sizing and bare tablet and computer screens; presenter navigation and device controls; bounded canvas pan overscan; reviewed Russian catalog and integer plurals; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; `.fig` import: editable vector networks, more layer kinds, variable prototype actions; `.fig` import, best effort: gap 1 down to its tail; Windows QA pass: everyday workflows on Windows 11, eight fixes incl. unsaved work kept after a crash or a forced quit; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings: gap 14 down to its tail) · **Target:** Figma Design (desktop app 126.10.7) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-15 · **Change:** minor (bounded canvas pan overscan; reviewed Russian catalog and integer plurals; `.fig` export: instance sizes, variables with modes, shared styles, variable-width strokes; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; `.fig` import: editable vector networks, more layer kinds, variable prototype actions; `.fig` import, best effort: gap 1 down to its tail; Windows QA pass: everyday workflows on Windows 11, eight fixes incl. unsaved work kept after a crash or a forced quit; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings: gap 14 down to its tail) · **Target:** Figma Design (desktop app 126.10.7) Every known shortfall against Figma, one entry each, ranked by how much it stops a Figma user from doing real work in FigCraft. Agents: pick work from the top unless the owner says otherwise. The @@ -138,17 +138,6 @@ No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passe cursor for every tool and modifier, panel widths, dark pages (`field_tests`, `cursor_tests`, `cursors_tests`, `outline_options_tests`, `hide_publishing_tests`, `panel_width_tests`, `theme_pages_tests`). -- **Landed (2026-10-15):** presentation keeps its own tab beside the design, preserves the - current screen when switching back to edit, shows a small current-screen preview and offers - screen, device and scale controls (`present_view_tests`). -- **Landed (2026-10-16):** choosing a presenter device reflows a copy of the frame to its screen - size using constraints and auto layout, clears the previous screen's scroll and pan, and keeps - the file's frame geometry unchanged; No device restores the original size. Tablet and computer - presets show the screen at their resolution without a drawn hardware body. In the full presenter, - dragging inside a phone or tablet scrolls content in either direction when it exceeds the screen, - even when the pointer moves outside the device. The device remains fixed; computer presets keep - their ordinary scrolling rules. These gestures do not alter the file. Closing a window from - presentation shows the unsaved-changes dialog over the presenter. - **Evidence:** ROADMAP item 7 ("Left: tool by tool, panel by panel against the incumbent"). - **Impact:** Figma users notice the feel within minutes; it decides whether they stay. - **Estimate:** 40–60 h. Detail in [`ui-parity.md`](ui-parity.md). @@ -411,8 +400,6 @@ No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passe | Date | Change | Summary | |---|---|---| -| 2026-10-16 | minor | Gap 4: presenter device selection now uses responsive layout at the selected screen size and resets stale offsets; tablets and computers show bare screens, and the original frame is preserved. Estimates and ranking unchanged. | -| 2026-10-15 | minor | Gap 4: presenter tab, thumbnail, device picker and scale controls. Estimates and ranking unchanged. | | 2026-10-15 | minor | Gap 7: bounded canvas overscan for smoother panning. Estimates and ranking unchanged. | | 2026-10-14 | minor | Russian catalog (M9), reviewed and approved by VanTan: all 2,165 current entries, Русский in Preferences and regional ru tags. Russian integer plurals use one/few/many; contributor display name VanTan added. Existing estimates unchanged. | | 2026-10-13 | minor | Gap 1: the experimental `.fig` export writes instance sizes (resized, filling an auto layout, scaled), variables with modes and bindings, shared styles and variable-width strokes, and the import reads them back. Checked by opening written files in other software: resized and scaled instances keep their size and lay their layers out for it, variables with their modes and colour bindings resolve there (a frame set to another mode shows that mode's colours, also inside instances), colour, text, effect and grid styles are listed, and variable-width strokes that are the same on both sides of the path draw with their width; number, string and boolean bindings and bindings on effects, layout guides and gradient stops come across as the values they give but did not show as bound there (their entries now also name the layer field they set, not yet checked there), and strokes wider on one side of the path are written as filled outlines, no longer editable strokes there (the stroke itself is kept as plugin data and our own import puts it back; not yet checked there). Hours and the ranking unchanged | From e77a02993ed4d2d89d90c72e945bf368d1d386f4 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Sat, 17 Oct 2026 20:17:04 +0700 Subject: [PATCH 5/7] #537: remove the two screenshots nothing references --- ATTRIBUTION.md | 2 -- docs/images/shot-8-presenter-tab.png | Bin 75341 -> 0 bytes docs/images/shot-9-device-picker.png | Bin 106019 -> 0 bytes 3 files changed, 2 deletions(-) delete mode 100644 docs/images/shot-8-presenter-tab.png delete mode 100644 docs/images/shot-9-device-picker.png diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index cf2e7e63..1f72aeb7 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -14,8 +14,6 @@ MIT OR Apache-2.0. No third-party icon sets are used. | `assets/app-icon/` (all files: `figcraft.svg`, `figcraft-small.svg`, `figcraft-*.png`, `figcraft.ico`, `hicolor/`) | The project owner (engraving-style drawing, vectorised) | Original work, see [`assets/app-icon/README.md`](assets/app-icon/README.md); derived files rendered by `cargo xtask icon` | MIT OR Apache-2.0, [`assets/app-icon/LICENSE.txt`](assets/app-icon/LICENSE.txt) | FigCraft app icon (chameleon) | | `docs/brand/artcraft-logo.svg`, `docs/brand/artcraft-logo.png`, `docs/brand/artcraft-logo-white.svg`, `docs/brand/artcraft-logo-white.png`, `docs/brand/artcraft-mark.svg`, `docs/brand/artcraft-mark.png`, `docs/brand/artcraft-mark-black.svg`, `docs/brand/artcraft-mark-black.png` | ArtCraft Team | storytold/craftrules `assets/brand/` | ArtCraft brand terms (`docs/brand/LICENSE-brand.txt`), not open source | Trademarks; unmodified use within FigCraft only | | `docs/images/` (all screenshots and exports: `shot-*.png`, `art-*.png`) | FigCraft contributors | Screenshots of FigCraft showing synthetic demo documents made in FigCraft, and PNG exports of those documents by FigCraft's renderer | MIT OR Apache-2.0 | No third-party artwork | -| `docs/images/shot-8-presenter-tab.png` | @YarilaFox | Original screenshot of FigCraft presenting a synthetic document made in FigCraft | MIT OR Apache-2.0 | Presenter tab and top bar; no third-party artwork | -| `docs/images/shot-9-device-picker.png` | @YarilaFox | Original screenshot of FigCraft presenting a synthetic document made in FigCraft | MIT OR Apache-2.0 | Device and scale controls; no third-party artwork | | `examples/*.figcraft` | FigCraft contributors | Synthetic demo documents built through FigCraft's command API; invented copy, shapes and vectors drawn from scratch, no images or embedded fonts | MIT OR Apache-2.0 | Text uses Inter (OFL, from craft-fonts or the system); no third-party artwork | ## Fonts (build input, not in this repository) diff --git a/docs/images/shot-8-presenter-tab.png b/docs/images/shot-8-presenter-tab.png deleted file mode 100644 index d5cee8e179bebf78e69afdb7311d460c4a5a072c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75341 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 E02Al^oB#j- diff --git a/docs/images/shot-9-device-picker.png b/docs/images/shot-9-device-picker.png deleted file mode 100644 index 2f4805154b9cef0c9e122acc1c8c7ed484c1d72e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106019 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 ILUZqjTh)0r*Z=?k From 725e2c6913aeeab509507de738b9156278cbc7b8 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Sat, 17 Oct 2026 20:17:14 +0700 Subject: [PATCH 6/7] #537: presenter strings in every catalog --- crates/ui-egui/locales/cs.toml | 4 ++++ crates/ui-egui/locales/de.toml | 4 ++++ crates/ui-egui/locales/fr.toml | 4 ++++ crates/ui-egui/locales/id.toml | 4 ++++ crates/ui-egui/locales/ja.toml | 4 ++++ crates/ui-egui/locales/ko.toml | 4 ++++ crates/ui-egui/locales/pt-BR.toml | 4 ++++ crates/ui-egui/locales/ru.toml | 4 ++++ crates/ui-egui/locales/sv.toml | 4 ++++ crates/ui-egui/locales/tr.toml | 4 ++++ crates/ui-egui/locales/zh-Hans.toml | 4 ++++ 11 files changed, 44 insertions(+) diff --git a/crates/ui-egui/locales/cs.toml b/crates/ui-egui/locales/cs.toml index 2459d104..24a1f8d5 100644 --- a/crates/ui-egui/locales/cs.toml +++ b/crates/ui-egui/locales/cs.toml @@ -333,6 +333,7 @@ status = "draft — needs native review" "Current version" = "Aktuální verze" "Cursor chat" = "Chat u kurzoru" "Custom" = "Vlastní" +"Custom size" = "Vlastní velikost" "Cut" = "Vyjmout" "Dark" = "Tmavý" "Darken" = "Ztmavit" @@ -795,6 +796,7 @@ status = "draft — needs native review" "Nested instance" = "Vnořená instance" "New design file" = "Nový soubor návrhu" "Newest first" = "Od nejnovějších" +"Next frame" = "Další rámec" "Next or previous control in the focused region" = "Další nebo předchozí ovládací prvek v zaměřené oblasti" "Next ready for dev" = "Další připravené pro vývoj" "Next size option" = "Další možnost velikosti" @@ -811,6 +813,7 @@ status = "draft — needs native review" "No components yet. Select layers and press {keys}." = "Zatím žádné komponenty. Vyberte vrstvy a stiskněte {keys}." "No conflicts." = "Žádné konflikty." "No contributor data was built into this copy." = "Toto sestavení neobsahuje údaje o přispěvatelích." +"No device" = "Bez zařízení" "No fonts match" = "Žádná odpovídající písma" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "Kód pro připojení není dostupný (server kódy nepodporuje nebo tuto adresu nelze do kódu vložit): sdílejte odkaz." "No layer changes to show." = "Žádné změny vrstev k zobrazení." @@ -994,6 +997,7 @@ status = "draft — needs native review" "Preview" = "Náhled" "Preview this flow" = "Náhled tohoto toku" "Preview this frame" = "Náhled tohoto rámce" +"Previous frame" = "Předchozí rámec" "Previous ready for dev" = "Předchozí připravené pro vývoj" "Progressive" = "Postupné" "Properties" = "Vlastnosti" diff --git a/crates/ui-egui/locales/de.toml b/crates/ui-egui/locales/de.toml index b679feb7..51a480d4 100644 --- a/crates/ui-egui/locales/de.toml +++ b/crates/ui-egui/locales/de.toml @@ -329,6 +329,7 @@ status = "draft — needs native review" "Current version" = "Aktuelle Version" "Cursor chat" = "Cursor-Chat" "Custom" = "Benutzerdefiniert" +"Custom size" = "Benutzerdefinierte Größe" "Cut" = "Ausschneiden" "Dark" = "Dunkel" "Darken" = "Abdunkeln" @@ -768,6 +769,7 @@ status = "draft — needs native review" "Navigate to" = "Navigieren zu" "Nested instance" = "Verschachtelte Instanz" "New design file" = "Neue Designdatei" +"Next frame" = "Nächster Rahmen" "Next or previous control in the focused region" = "Nächstes oder vorheriges Steuerelement im fokussierten Bereich" "Next ready for dev" = "Nächstes bereit für Entwicklung" "Next size option" = "Nächste Größenoption" @@ -784,6 +786,7 @@ status = "draft — needs native review" "No components yet. Select layers and press {keys}." = "Noch keine Komponenten. Wählen Sie Ebenen aus und drücken Sie {keys}." "No conflicts." = "Keine Konflikte." "No contributor data was built into this copy." = "Diese Kopie enthält keine Daten zu Mitwirkenden." +"No device" = "Kein Gerät" "No fonts match" = "Keine passenden Schriften" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "Hier gibt es keinen Beitrittscode (der Server ist älter als Beitrittscodes, oder diese Adresse passt in keinen): Teilen Sie stattdessen den Link." "No layer changes to show." = "Keine Ebenenänderungen vorhanden." @@ -960,6 +963,7 @@ status = "draft — needs native review" "Preview" = "Vorschau" "Preview this flow" = "Vorschau dieses Ablaufs" "Preview this frame" = "Vorschau dieses Rahmens" +"Previous frame" = "Vorheriger Rahmen" "Previous ready for dev" = "Vorheriges bereit für Entwicklung" "Progressive" = "Progressiv" "Properties" = "Eigenschaften" diff --git a/crates/ui-egui/locales/fr.toml b/crates/ui-egui/locales/fr.toml index 1c561f15..60985e5e 100644 --- a/crates/ui-egui/locales/fr.toml +++ b/crates/ui-egui/locales/fr.toml @@ -328,6 +328,7 @@ status = "draft — needs native review" "Current version" = "Version actuelle" "Cursor chat" = "Chat au curseur" "Custom" = "Personnalisé" +"Custom size" = "Taille personnalisée" "Cut" = "Couper" "Dark" = "Sombre" "Darken" = "Assombrir" @@ -764,6 +765,7 @@ status = "draft — needs native review" "Navigate to" = "Naviguer vers" "Nested instance" = "Instance imbriquée" "New design file" = "Nouveau fichier de design" +"Next frame" = "Cadre suivant" "Next or previous control in the focused region" = "Contrôle suivant ou précédent dans la région active" "Next ready for dev" = "Prêt pour le dev suivant" "Next size option" = "Option de taille suivante" @@ -780,6 +782,7 @@ status = "draft — needs native review" "No components yet. Select layers and press {keys}." = "Aucun composant pour l’instant. Sélectionnez des calques et appuyez sur {keys}." "No conflicts." = "Aucun conflit." "No contributor data was built into this copy." = "Cette copie ne contient aucune donnée de contributeurs." +"No device" = "Aucun appareil" "No fonts match" = "Aucune police ne correspond" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "Pas de code d’accès ici (le serveur est antérieur aux codes d’accès, ou cette adresse ne tient pas dans un code) : partagez plutôt le lien." "No layer changes to show." = "Aucune modification de calque à afficher." @@ -954,6 +957,7 @@ status = "draft — needs native review" "Preview" = "Aperçu" "Preview this flow" = "Prévisualiser ce flux" "Preview this frame" = "Prévisualiser ce cadre" +"Previous frame" = "Cadre précédent" "Previous ready for dev" = "Prêt pour le dev précédent" "Progressive" = "Progressif" "Properties" = "Propriétés" diff --git a/crates/ui-egui/locales/id.toml b/crates/ui-egui/locales/id.toml index 7a0a3c3c..52a2bda6 100644 --- a/crates/ui-egui/locales/id.toml +++ b/crates/ui-egui/locales/id.toml @@ -337,6 +337,7 @@ status = "draft — needs native review" "Current version" = "Versi saat ini" "Cursor chat" = "Chat kursor" "Custom" = "Kustom" +"Custom size" = "Ukuran kustom" "Cut" = "Potong" "Dark" = "Gelap" "Darken" = "Gelapkan" @@ -799,6 +800,7 @@ status = "draft — needs native review" "Nested instance" = "Instance bersarang" "New design file" = "File desain baru" "Newest first" = "Terbaru dulu" +"Next frame" = "Frame berikutnya" "Next or previous control in the focused region" = "Kontrol berikutnya atau sebelumnya di wilayah yang difokuskan" "Next ready for dev" = "Siap dev berikutnya" "Next size option" = "Opsi ukuran berikutnya" @@ -815,6 +817,7 @@ status = "draft — needs native review" "No components yet. Select layers and press {keys}." = "Belum ada component. Pilih layer lalu tekan {keys}." "No conflicts." = "Tidak ada konflik." "No contributor data was built into this copy." = "Tidak ada data kontributor yang disertakan dalam salinan ini." +"No device" = "Tanpa perangkat" "No fonts match" = "Tidak ada font yang cocok" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "Tidak ada kode gabung di sini (versi server lebih lama dari fitur kode gabung, atau alamat ini tidak dapat dimasukkan ke kode): bagikan link-nya saja." "No layer changes to show." = "Tidak ada perubahan layer untuk ditampilkan." @@ -998,6 +1001,7 @@ status = "draft — needs native review" "Preview" = "Pratinjau" "Preview this flow" = "Pratinjau alur ini" "Preview this frame" = "Pratinjau frame ini" +"Previous frame" = "Frame sebelumnya" "Previous ready for dev" = "Versi siap dev sebelumnya" "Progressive" = "Progresif" "Properties" = "Properti" diff --git a/crates/ui-egui/locales/ja.toml b/crates/ui-egui/locales/ja.toml index b09db3bd..4e6a532e 100644 --- a/crates/ui-egui/locales/ja.toml +++ b/crates/ui-egui/locales/ja.toml @@ -340,6 +340,7 @@ status = "draft — needs native review" "Current version" = "現在のバージョン" "Cursor chat" = "カーソルチャット" "Custom" = "カスタム" +"Custom size" = "カスタムサイズ" "Cut" = "カット" "Dark" = "ダーク" "Darken" = "比較(暗)" @@ -804,6 +805,7 @@ status = "draft — needs native review" "Nested instance" = "ネストされたインスタンス" "New design file" = "新規デザインファイル" "Newest first" = "新しい順" +"Next frame" = "次のフレーム" "Next or previous control in the focused region" = "フォーカス中の領域で次または前のコントロール" "Next ready for dev" = "次の開発準備完了" "Next size option" = "次のサイズオプション" @@ -820,6 +822,7 @@ status = "draft — needs native review" "No components yet. Select layers and press {keys}." = "コンポーネントはまだない。レイヤーを選択して {keys} を押す。" "No conflicts." = "競合なし。" "No contributor data was built into this copy." = "このコピーには貢献者データが含まれていない。" +"No device" = "デバイスなし" "No fonts match" = "一致するフォントなし" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "参加コードなし(サーバーが参加コードより古いか、このアドレスはコードにできない):代わりにリンクを共有すること。" "No layer changes to show." = "表示するレイヤーの変更なし。" @@ -1003,6 +1006,7 @@ status = "draft — needs native review" "Preview" = "プレビュー" "Preview this flow" = "このフローをプレビュー" "Preview this frame" = "このフレームをプレビュー" +"Previous frame" = "前のフレーム" "Previous ready for dev" = "前の開発準備完了" "Progressive" = "プログレッシブ" "Properties" = "プロパティ" diff --git a/crates/ui-egui/locales/ko.toml b/crates/ui-egui/locales/ko.toml index f2cfcfff..f999f9ad 100644 --- a/crates/ui-egui/locales/ko.toml +++ b/crates/ui-egui/locales/ko.toml @@ -328,6 +328,7 @@ status = "draft — needs native review" "Current version" = "현재 버전" "Cursor chat" = "커서 채팅" "Custom" = "사용자 지정" +"Custom size" = "사용자 지정 크기" "Cut" = "잘라내기" "Dark" = "다크" "Darken" = "어둡게 하기" @@ -764,6 +765,7 @@ status = "draft — needs native review" "Navigate to" = "이동 대상" "Nested instance" = "중첩된 인스턴스" "New design file" = "새 디자인 파일" +"Next frame" = "다음 프레임" "Next or previous control in the focused region" = "포커스된 영역의 다음 또는 이전 컨트롤" "Next ready for dev" = "다음 개발 준비 완료" "Next size option" = "다음 크기 옵션" @@ -780,6 +782,7 @@ status = "draft — needs native review" "No components yet. Select layers and press {keys}." = "아직 컴포넌트가 없음. 레이어를 선택하고 {keys}를 누르세요." "No conflicts." = "충돌 없음." "No contributor data was built into this copy." = "이 사본에는 기여자 데이터가 포함되지 않음." +"No device" = "기기 없음" "No fonts match" = "일치하는 글꼴 없음" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "참여 코드 없음(서버가 참여 코드 이전 버전이거나 이 주소를 코드에 담을 수 없음): 대신 링크를 공유하세요." "No layer changes to show." = "표시할 레이어 변경 사항 없음." @@ -954,6 +957,7 @@ status = "draft — needs native review" "Preview" = "미리 보기" "Preview this flow" = "이 플로우 미리 보기" "Preview this frame" = "이 프레임 미리 보기" +"Previous frame" = "이전 프레임" "Previous ready for dev" = "이전 개발 준비 완료" "Progressive" = "점진적" "Properties" = "속성" diff --git a/crates/ui-egui/locales/pt-BR.toml b/crates/ui-egui/locales/pt-BR.toml index e9e1300c..ea443327 100644 --- a/crates/ui-egui/locales/pt-BR.toml +++ b/crates/ui-egui/locales/pt-BR.toml @@ -327,6 +327,7 @@ status = "draft — needs native review" "Current version" = "Versão atual" "Cursor chat" = "Chat do cursor" "Custom" = "Personalizado" +"Custom size" = "Tamanho personalizado" "Cut" = "Recortar" "Dark" = "Escuro" "Darken" = "Escurecer" @@ -763,6 +764,7 @@ status = "draft — needs native review" "Navigate to" = "Navegar para" "Nested instance" = "Instância aninhada" "New design file" = "Novo arquivo de design" +"Next frame" = "Próximo quadro" "Next or previous control in the focused region" = "Controle seguinte ou anterior na região em foco" "Next ready for dev" = "Próximo pronto para dev" "Next size option" = "Próxima opção de tamanho" @@ -779,6 +781,7 @@ status = "draft — needs native review" "No components yet. Select layers and press {keys}." = "Ainda não há componentes. Selecione camadas e pressione {keys}." "No conflicts." = "Nenhum conflito." "No contributor data was built into this copy." = "Esta cópia não inclui dados de colaboradores." +"No device" = "Nenhum dispositivo" "No fonts match" = "Nenhuma fonte corresponde" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "Não há código de acesso aqui (o servidor é anterior aos códigos de acesso, ou este endereço não cabe em um): compartilhe o link." "No layer changes to show." = "Nenhuma alteração de camada para mostrar." @@ -953,6 +956,7 @@ status = "draft — needs native review" "Preview" = "Visualização" "Preview this flow" = "Visualizar este fluxo" "Preview this frame" = "Visualizar este quadro" +"Previous frame" = "Quadro anterior" "Previous ready for dev" = "Anterior pronto para dev" "Progressive" = "Progressivo" "Properties" = "Propriedades" diff --git a/crates/ui-egui/locales/ru.toml b/crates/ui-egui/locales/ru.toml index 2023b692..e02e12a1 100644 --- a/crates/ui-egui/locales/ru.toml +++ b/crates/ui-egui/locales/ru.toml @@ -334,6 +334,7 @@ name = "Русский" "Current version" = "Текущая версия" "Cursor chat" = "Чат у курсора" "Custom" = "Пользовательский" +"Custom size" = "Пользовательский размер" "Cut" = "Вырезать" "Dark" = "Тёмная" "Darken" = "Затемнение" @@ -796,6 +797,7 @@ name = "Русский" "Nested instance" = "Вложенный экземпляр" "New design file" = "Новый файл дизайна" "Newest first" = "Сначала новые" +"Next frame" = "Следующий Frame" "Next or previous control in the focused region" = "Следующий или предыдущий элемент в активной области" "Next ready for dev" = "Следующий готовый к разработке" "Next size option" = "Следующий вариант размера" @@ -812,6 +814,7 @@ name = "Русский" "No components yet. Select layers and press {keys}." = "Компонентов пока нет. Выделите слои и нажмите {keys}." "No conflicts." = "Конфликтов нет." "No contributor data was built into this copy." = "В этой сборке нет данных об участниках." +"No device" = "Без устройства" "No fonts match" = "Подходящих шрифтов нет" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "Код подключения недоступен (сервер не поддерживает коды или адрес нельзя включить в код): поделитесь ссылкой." "No layer changes to show." = "Нет изменений слоёв для показа." @@ -996,6 +999,7 @@ name = "Русский" "Preview" = "Предпросмотр" "Preview this flow" = "Предпросмотр этого сценария" "Preview this frame" = "Предпросмотр этого Frame" +"Previous frame" = "Предыдущий Frame" "Previous ready for dev" = "Предыдущий готовый к разработке" "Progressive" = "Прогрессивный" "Properties" = "Свойства" diff --git a/crates/ui-egui/locales/sv.toml b/crates/ui-egui/locales/sv.toml index 51f16508..472b83b1 100644 --- a/crates/ui-egui/locales/sv.toml +++ b/crates/ui-egui/locales/sv.toml @@ -339,6 +339,7 @@ name = "Svenska" "Current version" = "Aktuell version" "Cursor chat" = "Markörchatt" "Custom" = "Anpassad" +"Custom size" = "Anpassad storlek" "Cut" = "Klipp ut" "Dark" = "Mörk" "Darken" = "Mörkare" @@ -806,6 +807,7 @@ name = "Svenska" "Nested instance" = "Kapslad instans" "New design file" = "Ny designfil" "Newest first" = "Nyaste först" +"Next frame" = "Nästa ram" "Next or previous control in the focused region" = "Nästa eller föregående kontroll i den fokuserade regionen" "Next ready for dev" = "Nästa redo för utveckling" "Next size option" = "Nästa storleksalternativ" @@ -822,6 +824,7 @@ name = "Svenska" "No components yet. Select layers and press {keys}." = "Inga komponenter än. Markera lager och tryck på {keys}." "No conflicts." = "Inga konflikter." "No contributor data was built into this copy." = "Inga uppgifter om bidragsgivare finns inbyggda i den här kopian." +"No device" = "Ingen enhet" "No fonts match" = "Inga typsnitt matchar" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "Ingen anslutningskod här (servern är äldre än anslutningskoder, eller så kan den här adressen inte göras om till en): dela länken i stället." "No layer changes to show." = "Inga lagerändringar att visa." @@ -1007,6 +1010,7 @@ name = "Svenska" "Preview" = "Förhandsgranskning" "Preview this flow" = "Förhandsgranska det här flödet" "Preview this frame" = "Förhandsgranska den här ramen" +"Previous frame" = "Föregående ram" "Previous ready for dev" = "Föregående redo för utveckling" "Progressive" = "Progressiv" "Properties" = "Egenskaper" diff --git a/crates/ui-egui/locales/tr.toml b/crates/ui-egui/locales/tr.toml index cc002654..4de75c8a 100644 --- a/crates/ui-egui/locales/tr.toml +++ b/crates/ui-egui/locales/tr.toml @@ -337,6 +337,7 @@ name = "Türkçe" "Current version" = "Geçerli sürüm" "Cursor chat" = "İmleç sohbeti" "Custom" = "Özel" +"Custom size" = "Özel boyut" "Cut" = "Kes" "Dark" = "Koyu" "Darken" = "Koyulaştır" @@ -799,6 +800,7 @@ name = "Türkçe" "Nested instance" = "İç içe örnek" "New design file" = "Yeni tasarım dosyası" "Newest first" = "Önce en yeni" +"Next frame" = "Sonraki çerçeve" "Next or previous control in the focused region" = "Odaklanılan bölgedeki sonraki veya önceki denetim" "Next ready for dev" = "Sonraki geliştirmeye hazır" "Next size option" = "Sonraki boyut seçeneği" @@ -815,6 +817,7 @@ name = "Türkçe" "No components yet. Select layers and press {keys}." = "Henüz bileşen yok. Katmanları seçip {keys} tuşlarına basın." "No conflicts." = "Çakışma yok." "No contributor data was built into this copy." = "Bu kopyaya katkıda bulunan verisi eklenmemiş." +"No device" = "Cihaz yok" "No fonts match" = "Eşleşen yazı tipi yok" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "Burada katılma kodu yok (sunucu katılma kodlarından eski veya bu adres bir koda sığmıyor): bunun yerine bağlantıyı paylaşın." "No layer changes to show." = "Gösterilecek katman değişikliği yok." @@ -998,6 +1001,7 @@ name = "Türkçe" "Preview" = "Önizleme" "Preview this flow" = "Bu akışı önizle" "Preview this frame" = "Bu çerçeveyi önizle" +"Previous frame" = "Önceki çerçeve" "Previous ready for dev" = "Önceki geliştirmeye hazır" "Progressive" = "Aşamalı" "Properties" = "Özellikler" diff --git a/crates/ui-egui/locales/zh-Hans.toml b/crates/ui-egui/locales/zh-Hans.toml index 702cae7b..8ea0d6a9 100644 --- a/crates/ui-egui/locales/zh-Hans.toml +++ b/crates/ui-egui/locales/zh-Hans.toml @@ -329,6 +329,7 @@ status = "draft — needs native review" "Current version" = "当前版本" "Cursor chat" = "光标聊天" "Custom" = "自定义" +"Custom size" = "自定义大小" "Cut" = "剪切" "Dark" = "深色" "Darken" = "变暗" @@ -765,6 +766,7 @@ status = "draft — needs native review" "Navigate to" = "导航到" "Nested instance" = "嵌套实例" "New design file" = "新建设计文件" +"Next frame" = "下一个画框" "Next or previous control in the focused region" = "聚焦区域中的下一个或上一个控件" "Next ready for dev" = "下一个可供开发" "Next size option" = "下一个尺寸选项" @@ -781,6 +783,7 @@ status = "draft — needs native review" "No components yet. Select layers and press {keys}." = "还没有组件。选择图层并按 {keys}。" "No conflicts." = "没有冲突。" "No contributor data was built into this copy." = "此副本未内置贡献者数据。" +"No device" = "无设备" "No fonts match" = "没有匹配的字体" "No join code here (the server is older than join codes, or this address can't be put in one): share the link instead." = "此处没有加入代码(服务器版本早于加入代码,或此地址无法写入代码):请改为分享链接。" "No layer changes to show." = "没有可显示的图层更改。" @@ -955,6 +958,7 @@ status = "draft — needs native review" "Preview" = "预览" "Preview this flow" = "预览此流程" "Preview this frame" = "预览此画框" +"Previous frame" = "上一个画框" "Previous ready for dev" = "上一个可供开发" "Progressive" = "渐进" "Properties" = "属性" From acfc0352c3fde75f2c717a39863a60a2993986fc Mon Sep 17 00:00:00 2001 From: bflatastic Date: Sat, 17 Oct 2026 20:22:44 +0700 Subject: [PATCH 7/7] #537: frames scroll on phones only as their overflow allows; tablets and laptops keep their device body --- crates/ui-egui/src/present.rs | 109 +++++++++++++++------------------- 1 file changed, 48 insertions(+), 61 deletions(-) diff --git a/crates/ui-egui/src/present.rs b/crates/ui-egui/src/present.rs index 5a9d4bf3..863b540f 100644 --- a/crates/ui-egui/src/present.rs +++ b/crates/ui-egui/src/present.rs @@ -541,13 +541,7 @@ impl Presenter { /// device's screen, other frames within themselves. fn range(&self, doc: &Document, frame: NodeId) -> (f64, f64) { let vp = if frame == self.current { viewport(doc, frame) } else { None }; - // In a responsive preview, make content outside the device reachable even if the source - // frame has no overflow mode. Its settings and geometry stay untouched in the file. - let mobile = frame == self.current && page_settings(doc, frame).device().is_some_and(|d| d.rotates); - let overflow = doc - .node(frame) - .map_or(Overflow::None, |n| if mobile && self.fit.is_some() && n.overflow == Overflow::None { Overflow::Both } else { n.overflow }); - scroll_range_with_overflow(doc, frame, vp, overflow) + scroll_range_in(doc, frame, vp) } /// What "Scroll to" `dest` moves: every scrolling frame around it, innermost first, brings the @@ -1177,13 +1171,8 @@ pub fn scroll_range(doc: &Document, frame: NodeId) -> (f64, f64) { /// frame taller than the screen scrolls through its whole height. Without a viewport the frame /// shows at its own size and what overflows it scrolls. Only the axes its overflow allows scroll. pub fn scroll_range_in(doc: &Document, frame: NodeId, viewport: Option<(f64, f64)>) -> (f64, f64) { - let overflow = doc.node(frame).map_or(Overflow::None, |n| n.overflow); - scroll_range_with_overflow(doc, frame, viewport, overflow) -} - -fn scroll_range_with_overflow(doc: &Document, frame: NodeId, viewport: Option<(f64, f64)>, overflow: Overflow) -> (f64, f64) { let Some(n) = doc.node(frame) else { return (0.0, 0.0) }; - if overflow == Overflow::None { + if n.overflow == Overflow::None { return (0.0, 0.0); } let (mut x1, mut y1) = (0.0f64, 0.0f64); @@ -1208,8 +1197,8 @@ fn scroll_range_with_overflow(doc: &Document, frame: NodeId, viewport: Option<(f } None => (n.width, n.height), }; - let rx = if matches!(overflow, Overflow::Horizontal | Overflow::Both) { (x1 - vw).max(0.0) } else { 0.0 }; - let ry = if matches!(overflow, Overflow::Vertical | Overflow::Both) { (y1 - vh).max(0.0) } else { 0.0 }; + let rx = if matches!(n.overflow, Overflow::Horizontal | Overflow::Both) { (x1 - vw).max(0.0) } else { 0.0 }; + let ry = if matches!(n.overflow, Overflow::Vertical | Overflow::Both) { (y1 - vh).max(0.0) } else { 0.0 }; (if rx.is_finite() { rx } else { 0.0 }, if ry.is_finite() { ry } else { 0.0 }) } @@ -1546,11 +1535,6 @@ fn body_outset(device: &str, size: Vec2, landscape: bool) -> (f32, f32, f32) { } } -/// Tablet and computer presets size the screen without drawing a hardware shell around it. -fn has_device_body(device: Device) -> bool { - !device.name.starts_with("iPad") && !matches!(device.name, "MacBook Air" | "Desktop") -} - /// Place the presented frame in `area`: on its device's screen (the whole device sized by the /// view's scale option), else the frame itself. Fit and 100% keep the chrome's padding from the /// edges; Fit never goes above 100%. What doesn't fit the window pans (`Presenter::pan`). The @@ -1566,7 +1550,7 @@ fn layout(p: &mut Presenter, area: Rect, chrome: Chrome) -> Option { let fb = disp.world_bounds(p.current)?; let view = if chrome.pane { PresentView::default() } else { p.view }; // Custom sizes are just a screen: no body. - let body = device.filter(|d| view.device_frame && has_device_body(*d) && !d.colors.is_empty()); + let body = device.filter(|d| view.device_frame && !d.colors.is_empty()); let pad = if !fills && matches!(view.scale, PresentScale::Fit | PresentScale::Actual) { chrome.pad } else { 0.0 }; let avail = area.shrink(pad); let (sw, sh) = device.map_or((fb.width(), fb.height()), |d| (d.width, d.height)); @@ -2357,7 +2341,7 @@ fn options_menu(p: &mut Presenter, ui: &mut Ui, device: Option, responsi } ui.separator(); } - if device.is_some_and(|d| has_device_body(d) && !d.colors.is_empty()) && menu_check(ui, p.view.device_frame, tr("Show device frame"), "") { + if device.is_some_and(|d| !d.colors.is_empty()) && menu_check(ui, p.view.device_frame, tr("Show device frame"), "") { p.view.device_frame = !p.view.device_frame; ui.close(); } @@ -2378,7 +2362,7 @@ fn scrollers_at(p: &Presenter, base: &Document, disp: &Document, root: NodeId, p let mut out: Vec = disp .subtree(root) .into_iter() - .filter(|f| disp.node(*f).is_some_and(|n| n.visible)) + .filter(|f| disp.node(*f).is_some_and(|n| n.visible && n.overflow != Overflow::None)) .filter(|f| disp.world_bounds(*f).is_some_and(|b| place.rect(b).contains(q))) .filter(|f| p.range(base, *f) != (0.0, 0.0)) .collect(); @@ -2904,19 +2888,16 @@ mod tests { } #[test] - fn tablet_and_computer_presets_show_only_their_screen_at_the_real_resolution() { + fn device_presets_show_their_screen_at_the_real_resolution_in_their_body() { let mut session = figcraft_engine::Session::new(); let frame = id(&session.execute("node.create", &json!({"type": "frame", "width": 894, "height": 844})).unwrap()); let mut ui = Ui::new(session); ui.run("proto.present", json!({"start": frame})); let area = Rect::from_min_max(pos2(0.0, 40.0), pos2(1440.0, 860.0)); - for (name, width, height, body) in [ - ("iPad mini", 744.0, 1133.0, false), - ("MacBook Air", 1280.0, 832.0, false), - ("Desktop", 1440.0, 1024.0, false), - ("iPhone 17", 402.0, 874.0, true), - ] { + for (name, width, height) in + [("iPad mini", 744.0, 1133.0), ("MacBook Air", 1280.0, 832.0), ("Desktop", 1440.0, 1024.0), ("iPhone 17", 402.0, 874.0)] + { let mut presenter = ui.app.ui.present.take().unwrap(); choose_device(&mut ui.app, &mut presenter, name); ui.app.ui.present = Some(presenter); @@ -2924,38 +2905,52 @@ mod tests { let presenter = ui.app.ui.present.as_mut().unwrap(); let laid = layout(presenter, area, FULL).unwrap(); - assert_eq!(laid.color.is_some(), body, "{name}: body visibility"); + assert!(laid.color.is_some(), "{name}: drawn in its body"); assert!((f64::from(laid.screen.width()) / laid.scale - width).abs() < 0.1, "{name}: width"); assert!((f64::from(laid.screen.height()) / laid.scale - height).abs() < 0.1, "{name}: height"); assert_eq!(ui.app.session.doc().unwrap().node(frame).unwrap().width, 894.0); } } + /// A phone shows a frame's content past its screen only as far as the frame's overflow lets it + /// scroll: with "No scrolling" it's clipped, like on every other device. #[test] - fn responsive_device_scrolls_content_in_both_directions_without_changing_saved_overflow() { - let mut session = figcraft_engine::Session::new(); - let frame = id(&session.execute("node.create", &json!({"type": "frame", "width": 894, "height": 844})).unwrap()); - session.execute("node.create", &json!({"type": "rectangle", "parent": frame, "x": 650, "y": 1050, "width": 80, "height": 80})).unwrap(); - let mut ui = Ui::new(session); - ui.run("proto.present", json!({"start": frame})); - let mut presenter = ui.app.ui.present.take().unwrap(); - choose_device(&mut ui.app, &mut presenter, "iPhone 17"); - ui.app.ui.present = Some(presenter); - ui.frame(vec![]); - - let range = &ui.app.inspect()["presenter"]["scrollRange"]; - assert!(range[0].as_f64().unwrap() > 0.0 && range[1].as_f64().unwrap() > 0.0, "{range}"); + fn a_phone_scrolls_only_what_the_frames_overflow_allows() { + let on_phone = |overflow: &str| { + let mut session = figcraft_engine::Session::new(); + let frame = id(&session.execute("node.create", &json!({"type": "frame", "width": 894, "height": 844})).unwrap()); + session.execute("node.create", &json!({"type": "rectangle", "parent": frame, "x": 650, "y": 1050, "width": 80, "height": 80})).unwrap(); + session.execute("node.set", &json!({"id": frame, "props": {"overflow": overflow}})).unwrap(); + let mut ui = Ui::new(session); + ui.run("proto.present", json!({"start": frame})); + let mut presenter = ui.app.ui.present.take().unwrap(); + choose_device(&mut ui.app, &mut presenter, "iPhone 17"); + ui.app.ui.present = Some(presenter); + ui.frame(vec![]); + (ui, frame) + }; let start = pos2(720.0, 440.0); - ui.button(start, true); - ui.frame(vec![egui::Event::PointerMoved(start - vec2(100.0, 120.0))]); - ui.button(start - vec2(100.0, 120.0), false); - let scroll = &ui.app.inspect()["presenter"]["scroll"]; - assert!(scroll[0].as_f64().unwrap() > 0.0 && scroll[1].as_f64().unwrap() > 0.0, "{scroll}"); - assert_eq!(ui.app.session.doc().unwrap().node(frame).unwrap().overflow, Overflow::None); + let drag = |ui: &mut Ui, to: Pos2| { + ui.button(start, true); + ui.frame(vec![egui::Event::PointerMoved(to)]); + ui.button(to, false); + ui.app.inspect()["presenter"].clone() + }; + + let (mut ui, frame) = on_phone("none"); + assert_eq!(ui.app.inspect()["presenter"]["scrollRange"], json!([0.0, 0.0])); + assert_eq!(drag(&mut ui, start - vec2(100.0, 120.0))["scroll"], json!([0.0, 0.0]), "no scrolling stays clipped"); assert_eq!(ui.app.session.doc().unwrap().node(frame).unwrap().width, 894.0); - // Like the phone preview, the content keeps following a drag after the pointer leaves - // the screen, while the device itself stays fixed on the stage. + let (mut ui, frame) = on_phone("both"); + let range = &ui.app.inspect()["presenter"]["scrollRange"]; + assert!(range[0].as_f64().unwrap() > 0.0 && range[1].as_f64().unwrap() > 0.0, "{range}"); + let scroll = drag(&mut ui, start - vec2(100.0, 120.0))["scroll"].clone(); + assert!(scroll[0].as_f64().unwrap() > 0.0 && scroll[1].as_f64().unwrap() > 0.0, "{scroll}"); + assert_eq!(ui.app.session.doc().unwrap().node(frame).unwrap().width, 894.0); + + // The content keeps following a drag after the pointer leaves the screen, while the + // device itself stays fixed on the stage. ui.frames(60, Vec::new); let area = Rect::from_min_max(pos2(0.0, 40.0), pos2(1440.0, 900.0)); let screen_before = layout(ui.app.ui.present.as_mut().unwrap(), area, FULL).unwrap().screen; @@ -2963,16 +2958,8 @@ mod tests { ui.frame(vec![egui::Event::PointerMoved(pos2(300.0, 300.0))]); let during = ui.app.inspect()["presenter"].clone(); assert!(during["scroll"][0].as_f64().unwrap() > 0.0, "{during}"); - let screen_after = layout(ui.app.ui.present.as_mut().unwrap(), area, FULL).unwrap().screen; - assert_eq!(screen_after, screen_before); + assert_eq!(layout(ui.app.ui.present.as_mut().unwrap(), area, FULL).unwrap().screen, screen_before); ui.button(pos2(300.0, 300.0), false); - - let mut presenter = ui.app.ui.present.take().unwrap(); - choose_device(&mut ui.app, &mut presenter, "Desktop"); - ui.app.ui.present = Some(presenter); - ui.frame(vec![]); - let desktop = ui.app.inspect()["presenter"].clone(); - assert_eq!(desktop["scrollRange"], json!([0.0, 0.0])); } fn doc_with_two_frames() -> (Document, NodeId, NodeId) {