Univis UI Docs
This unified documentation book contains both language editions:
Use the language switcher shown at the top of each page to jump to the mirrored chapter in the other language.
Structure
ar/contains the Arabic documentation treeen/contains the English documentation tree- both trees share the same chapter map and live in one mdBook
- hosted docs URL:
https://univiseditor.github.io/univis_ui/
Fast Links
- Plugin Setup and First Examples
- إعداد الإضافات وأولى الأمثلة
- English Example Gallery
- معرض الأمثلة
- Migration and Limitations
- الترحيل والقيود
Guides vs API Docs
- Use the guide chapters for mental models, migration notes, and example-driven learning.
- Use generated
rustdocfor exact type paths, field lists, and signatures.
Generate API docs with:
cargo doc --no-deps -p univis_ui
Build
mdbook build docs
Serve
mdbook serve docs -n 127.0.0.1 -p 3000
المقدمة
univis_ui هو إطار UI مبني فوق Bevy، ويعتمد على رندر SDF لإخراج عناصر واجهة حادة وواضحة في 2D و3D.
هذا الكتاب هو المرجع التشغيلي الكامل للمشروع، ويغطي:
- بنية المشروع ووحداته الأساسية
- كيفية تشغيل النظام عبر
UnivisUiPlugin - مكونات التخطيط (
UNode,ULayout,USelf) وكل الامتدادات المتقدمة - نظام الالتقاط والتفاعل (
UInteraction) - الوحدات الجاهزة وسلوكها والأحداث التي تصدرها
- الرندر والقص (
UClip) والأداء وقياس الزمن - التاريخ العملي للأمثلة والمراجع الثابتة ومسارات التشغيل الحية الحالية
نطاق هذا الكتاب
- هذا الكتاب يشرح الحالة الفعلية للكود داخل المستودع
- تشير الفصول إلى المسارات المصدرية داخل
crates/*/src/وإلى حزمة عرض Android الحالية وإلى فهرس الأمثلة الثنائي اللغة - إذا اختلف الكود مستقبلًا، اعتبر المصدر (الكود) هو الحقيقة الأساسية
متطلبات أساسية
- Rust (stable حديث)
- Bevy
0.18.1(مضمنة عبرCargo.toml) - المعرفة الأساسية بـ ECS مفيدة لفهم التصميم
كيف تبني هذا الكتاب
cargo install mdbook
mdbook build docs
للمعاينة الحية:
mdbook serve docs -n 127.0.0.1 -p 3000
رابط الوثائق المنشورة:
https://univiseditor.github.io/univis_ui/
الشرح مقابل API Docs
- استخدم هذا الكتاب للمفاهيم ومسارات الترحيل وإرشادات العمل
- استخدم
rustdocالمولد عندما تحتاج المسارات الدقيقة والحقول والتواقيع
ولّد وثائق API بالأمر:
cargo doc --no-deps -p univis_ui
إلى أين بعد ذلك؟
- خريطة توفر الأمثلة: فهرس الأمثلة
- العرض المنسق للحالة الحالية: معرض الأمثلة
- فهرس
API: مرجع الواجهة العامة - صفحة الترحيل: الترحيل والقيود
البدء السريع
1) إضافة الحزمة
[dependencies]
univis_ui = "0.3.0"
2) تطبيق بسيط
use bevy::prelude::*;
use univis_ui::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(UnivisUiPlugin)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands
.spawn((
URootUi::screen(),
UNode {
width: UVal::Percent(1.0),
height: UVal::Percent(1.0),
background_color: Color::srgb(0.08, 0.1, 0.14),
..default()
},
ULayout {
display: UDisplay::Flex,
justify_content: UJustifyContent::Center,
align_items: UAlignItems::Center,
..default()
},
))
.with_children(|root| {
root.spawn(UTextLabel::new("Hello Univis UI"));
});
}
3) اختيارات الجذر
URootUi::screen()لمسار الواجهة الثابتة على الشاشة والعناصر المرتبطة بها.URootUi::world_2d(size)لواجهة في فضاء العالم ثنائية الأبعاد.URootUi::world_3d(size)لواجهة في فضاء العالم تستخدم مسار المواد ثلاثي الأبعاد.URootUi::world_2d_fit_content()وURootUi::world_3d_fit_content()لقياس حجم الجذر العالمي من المحتوى الداخلي.UVal::Pxيعني وحدات UI منطقية، لا pixels فعلية للشاشة.UiCanvasSize::Viewportيتبع مساحة رؤية الكاميرا المحلولة.UiCanvasSize::FitContent { min, max }يقيس مساحة الرسم المنطقية من المحتوى ثم يطبّق الحدود عند الحاجة.- الحجم الفيزيائي في فضاء العالم يُشتق بالعلاقة:
world_size = canvas_size * meters_per_unit
4) ماذا يضيف UnivisUiPlugin؟
- التفاعل:
UnivisInteractionPlugin - المحرك:
UnivisEnginePlugin - النمط والخطوط والأيقونات:
UnivisUiStylePlugin - الوحدات الجاهزة:
UnivisWidgetPlugin
5) ملاحظات مهمة مباشرة
UnivisWidgetPluginيضيف الآن أنظمة Runtime المدمجة الخاصة بـUTextFieldوUBadgeتلقائيًا.UnivisScrollViewPluginمضاف تلقائيًا داخلUnivisWidgetPlugin.- التفاعل يحسم الكاميرا من كل
URootUi. - في المشاهد متعددة الكاميرات يُفضّل ربط الجذر صراحة عبر
UiCameraRef::Entity. UScreenRootوUWorldRootموجودان فقط كطبقات توافق مهجورة على مسارات صريحة مثلunivis_ui::layout::layout_system::{UScreenRoot, UWorldRoot}.- اضبط
meters_per_unitصراحة عندما تحتاج حجمًا فيزيائيًا محددًا لجذور العالم. - إذا أردت قائمة إعداد موجزة ومسار أمثلة بحسب المهمة، فانتقل إلى إعداد الإضافات وأولى الأمثلة.
إذا كنت تركّب سطح widgets ضيقًا من دون UnivisWidgetPlugin، فما يزال بإمكانك إضافة UnivisTextFieldPlugin أو UnivisBadgePlugin يدويًا.
6) وضع الحزم المباشرة (متقدم)
use bevy::prelude::*;
use univis_ui_engine::prelude::*;
use univis_ui_engine::UnivisEnginePlugin;
use univis_ui_interaction::interaction::UnivisInteractionPlugin;
use univis_ui_style::style::UnivisUiStylePlugin;
use univis_ui_widgets::widget::UnivisWidgetPlugin;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(UnivisUiStylePlugin)
.add_plugins(UnivisEnginePlugin)
.add_plugins(UnivisInteractionPlugin)
.add_plugins(UnivisWidgetPlugin)
.run();
}
أمثلة مرتبطة
صفحات ترحيل مرتبطة
نقاط الدخول الرسمية في API
univis_ui::UnivisUiPluginunivis_ui::preludeunivis_ui::layout::layout_system::{UScreenRoot, UWorldRoot}لمسار التوافق القديم فقطunivis_ui_engine::layout::layout_system::URootUiunivis_ui_engine::layout::univis_node::{UNode, ULayout}
إلى أين بعد ذلك؟
- المثال المرتبط:
responsive_layout_test - صفحة الإعداد: إعداد الإضافات وأولى الأمثلة
- فهرس
API: مرجع الواجهة العامة - صفحة الترحيل: ترحيل الجذور إلى
URootUi
إعداد الإضافات وأولى المسارات
هذه الصفحة هي أقصر مسار موجّه بحسب المهمة بعد البدء السريع.
استخدمها عندما تريد صفحة واحدة تجيب عن سؤالين:
- ما هي الإضافات التي أحصل عليها فعليًا بشكل افتراضي؟
- ما الذي يجب أن أفتحه أو أشغّله أولًا بحسب المهمة التي تهمني؟
ملاحظة تخص هذا الفرع
يعرض فهرس الأمثلة فقط ملفات المصدر الموجودة في هذا الفرع. الحزمة المستقلة ذات الطابع Android
داخل android/android_phone_app هي أفضل عرض كامل للشاشة.
إعداد الواجهة المجمعة
إذا أضفت UnivisUiPlugin فأنت تحصل مسبقًا على:
UnivisUiStylePluginUnivisEnginePluginUnivisInteractionPluginUnivisWidgetPlugin
وهذا هو المسار الموصى به لمعظم التطبيقات.
تغطية Runtime للوحدات الجاهزة
يتضمن UnivisUiPlugin إضافة UnivisWidgetPlugin، وهذا السطح الافتراضي يضم الآن أيضًا:
UnivisTextFieldPluginلسلوك وأحداثUTextFieldUnivisBadgePluginللتحديثات الديناميكية لـUBadge/UTag
إذا ركّبت الإضافات يدويًا حول UnivisWidgetPlugin، فلست بحاجة إلى إضافات runtime إضافية:
use bevy::prelude::*;
use univis_ui_engine::UnivisEnginePlugin;
use univis_ui_interaction::interaction::UnivisInteractionPlugin;
use univis_ui_style::style::UnivisUiStylePlugin;
use univis_ui_widgets::widget::UnivisWidgetPlugin;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(UnivisUiStylePlugin)
.add_plugins(UnivisEnginePlugin)
.add_plugins(UnivisInteractionPlugin)
.add_plugins(UnivisWidgetPlugin)
.run();
}
واستخدم الإضافات المخصصة مباشرة فقط عندما تريد سطح widgets أضيق من UnivisWidgetPlugin.
إعداد الكاميرا
- التفاعل وتغيير حجم اللوحات يحسمان الكاميرا من كل
URootUi - تكفي
Camera2dبسيطة لأصغر مشاهد الواجهة الثابتة على الشاشة - في المشاهد متعددة الكاميرات يُفضّل
UiCameraRef::Entity(camera_entity)
مسارات البدء الأفضل
واجهة شاشة أساسية
ابدأ من:
ما الذي يجب التركيز عليه:
- أصغر مسار تشغيل على مستوى الواجهة المجمعة
- ثبات واجهة HUD على الشاشة أثناء حركة الكاميرا
شاشة تطبيق بطابع Android
شغّل هذا العرض:
cargo run --manifest-path android/android_phone_app/Cargo.toml
ما الذي يجب التركيز عليه:
- تركيب سطح تطبيق نظيف بطابع Android داخل
URootUi::screen() - دمج
UTextFieldوUToggleوUSeekBarوUButtonداخل شاشة واحدة ضيقة - التأكد من أن كثافة العناصر ما تزال مقروءة من دون رسم جسم الهاتف نفسه
لوحة داخل العالم
ابدأ من:
ما الذي يجب التركيز عليه:
- الفرق بين مساحة الرسم المنطقية والحجم الفيزيائي في العالم
- اللوحات العالمية التي يتحدد حجمها من المحتوى والجذور الشبيهة بلوحات الأدوات
إدخال نصي
ابدأ من:
ما الذي يجب التركيز عليه:
- الإدخال القابل للتحرير
- سلوك التغيير والإرسال
- تغطية
UTextFieldالافتراضية عبرUnivisWidgetPlugin
عناصر الاختيار
ابدأ من:
ما الذي يجب التركيز عليه:
- كيف تنسجم عناصر الاختيار مع بقية سطح الوحدات الجاهزة
- كيف تعكس الأمثلة الحالية واجهات الـ API للوحدات الجاهزة
صفحات مرتبطة
نظام التخطيط
نظام التخطيط في univis_ui يعتمد على فكرة:
- Pass صاعد (قياس intrinsic)
- Pass هابط (حل القيود + التموضع)
ويعمل فوق مكونات أساسية:
UNode: خصائص الصندوق والمرئيات الأساسية.ULayout: خصائص الحاوية (container behavior).USelf: خصائص العنصر الطفل (item behavior).
الملفات المهمة
crates/univis_ui_engine/src/layout/univis_node.rscrates/univis_ui_engine/src/layout/core/pass_up.rscrates/univis_ui_engine/src/layout/core/pass_down.rscrates/univis_ui_engine/src/layout/core/solver.rscrates/univis_ui_engine/src/layout/core/layout_cache.rs
مبادئ أساسية
- تبدأ الجذور من
URootUi. LayoutDepthيُحسب تلقائيًا عبر traversal.IntrinsicSizeيُستخدم لتقدير المقاسات المعتمدة على المحتوى.ComputedSizeهو الناتج النهائي المعتمد للرندر.
الجذور والمساحات
URootUi هو المدخل العام الوحيد للجذر في الواجهة.
ويحسم كل شجرة UI إلى واحد من ثلاثة فضاءات:
UiSpace::ScreenUiSpace::World2dUiSpace::World3d
شكل الجذر
#![allow(unused)]
fn main() {
#[derive(Component, Clone, Reflect)]
pub struct URootUi {
pub space: UiSpace,
pub canvas: UiCanvasSize,
pub camera: UiCameraRef,
pub meters_per_unit: f32,
pub resolution_scale: f32,
}
}
الشاشة
الاستخدام:
#![allow(unused)]
fn main() {
URootUi::screen()
}
الدلالة:
- يُحسم انطلاقًا من مساحة رؤية الكاميرا المستهدفة، لا من
Window.width()/height()مباشرة. - يتصرف كـ الواجهة الثابتة حقيقي.
- حركة الكاميرا والـ zoom والدوران لا يجب أن تحرك واجهة الشاشة بصريًا.
- يشكّل كبسولة تراكب مغلقة: الترتيب المحلي لا يخرج فوق جذر آخر.
- مناسب للقوائم، والعناصر العائمة، وعناصر الواجهة الثابتة الثابتة على الشاشة.
العالم ثنائي الأبعاد
الاستخدام:
#![allow(unused)]
fn main() {
URootUi::world_2d(Vec2::new(1280.0, 720.0))
}
أو:
#![allow(unused)]
fn main() {
URootUi::world_2d_fit_content()
}
الدلالة:
- يدعم مساحة رسم منطقية ثابتة أو مساحة رسم تُقاس من المحتوى.
- يعيش داخل العالم.
- يُرسم عبر مسار المواد ثنائي الأبعاد.
- يشكّل كبسولة تراكب مغلقة: الأبناء يبقون داخل الطبقة البصرية للجذر.
- مناسب للوحات والشاشات الداخلية والعناصر المربوطة بالمشهد.
العالم ثلاثي الأبعاد
الاستخدام:
#![allow(unused)]
fn main() {
URootUi::world_3d(Vec2::new(1280.0, 720.0))
}
أو:
#![allow(unused)]
fn main() {
URootUi::world_3d_fit_content()
}
الدلالة:
- يستخدم نفس نموذج مساحة الرسم المنطقية الموجود في
World2d، بما فيه القياس من المحتوى. - يعيش داخل العالم.
- يُرسم عبر المسار ثلاثي الأبعاد.
- يشكّل كبسولة تراكب مغلقة بالنسبة إلى جذور UI الأخرى.
- هنا تصبح إعدادات
UPbrذات معنى.
مساحة الرسم المنطقية ووحدات القياس
يبقى UVal نوعًا خاصًا بوحدات التخطيط داخل شجرة الواجهة.
UVal::Px(f32)يعني وحدات UI منطقية.UiCanvasSize::Viewportتعني اتباع مساحة رؤية الكاميرا المحلولة.UiCanvasSize::Fixed(Vec2)تعني مساحة رسم منطقية ثابتة الحجم.UiCanvasSize::FitContent { min, max }تعني قياس مساحة الرسم المنطقية من المحتوى ثم تطبيق حدودmin/maxعند الحاجة.
في جذور العالم، الحجم الفيزيائي يُشتق صراحةً:
world_size = canvas_size * meters_per_unit
وهذا يعني:
- التخطيط يبقى بوحدات UI منطقية
meters_per_unitيتحكم فقط في الحجم الفيزيائي داخل العالمresolution_scaleيتحكم في الجودة البصرية بشكل مستقل عن حجم العالم- الجذور المعتمدة على المحتوى تعمل أفضل عندما يكون المحتوى الداخلي intrinsic أو fixed؛ الاعتماد الكبير على
%أو flex المرتبط بحجم الجذر قد يخلق دورة توقعات
حسم الكاميرا
UiCameraRef::Auto مناسب للمشاهد البسيطة التي تحتوي كاميرا متوافقة واحدة فقط.
أما في المشاهد متعددة الكاميرات فالأفضل استخدام:
#![allow(unused)]
fn main() {
UiCameraRef::Entity(camera_entity)
}
حتى يبقى حسم مساحة الرؤية والتفاعل وتثبيت جذور الشاشة واضحًا وغير ملتبس.
ملاحظة التوافق مع السلوك القديم
UScreenRoot وUWorldRoot موجودان فقط كطبقات توافق مهجورة.
وهما الآن مساران صريحان للترحيل فقط، وهدف الإزالة الحالي هو أول alpha بعد
0.3.0 لا يعود يحتاج دعم الترحيل المبني على هذه الطبقات.
قواعد الترحيل:
UScreenRoot->URootUi::screen()UWorldRoot { size, is_3d: false }->URootUi::world_2d(size)UWorldRoot { size, is_3d: true }->URootUi::world_3d(size)
إذا احتجت حجمًا فيزيائيًا محددًا داخل العالم، فاستخدم:
#![allow(unused)]
fn main() {
URootUi {
meters_per_unit: 1.0,
..URootUi::world_2d(size)
}
}
أو:
#![allow(unused)]
fn main() {
URootUi {
meters_per_unit: 1.0,
..URootUi::world_3d(size)
}
}
أمثلة مرتبطة
صفحات ترحيل مرتبطة
نقاط الدخول الرسمية في API
univis_ui_engine::layout::layout_system::URootUiunivis_ui_engine::layout::layout_system::UiSpaceunivis_ui_engine::layout::layout_system::UiCanvasSizeunivis_ui_engine::layout::layout_system::UiCameraRefunivis_ui_engine::layout::pbr::UPbr
إلى أين بعد ذلك؟
- المثال المرتبط:
responsive_layout_test - فهرس
API: مرجع الواجهة العامة - صفحة الترحيل: ترحيل الجذور إلى
URootUi
UNode وقياسات الصندوق
UNode هو اللبنة الأساسية لأي عنصر واجهة.
الحقول الأساسية
width: UValheight: UValmin_width: f32max_width: f32min_height: f32max_height: f32padding: USidesmargin: USidesbackground_color: Colorborder_radius: UCornerRadiusshape_mode: UShapeMode
UVal
الوحدات المدعومة:
Px(f32)Percent(f32)MinContentMaxContentContentAutoFlex(f32)
ملاحظات الأحجام
widthوheightيمثلان طلب الحجم المفضل.min_widthوmax_widthوmin_heightوmax_heightتطبقclampعلى الناتج النهائي.paddingيدخل في القياس الجوهري، بينماmarginيؤثر على التموضع ومساحة الالتفاف ولا يغير المحتوى الداخلي المقاس للعقدة.UVal::Contentيبقى الاسم القديم الموافق لـUVal::MaxContent.UVal::Autoصار نمطًا سياقيًا وليس مرادفًا مباشرًا لـContent.- استخدم
MaxContentأوMinContentعندما تريد حجمًا جوهريًا صريحًا من دون سلوك التمدد الضمني الخاص بـAuto. border_radiusوshape_modeيظلان خصائص بصرية فقط، ولا يغيران قياس التخطيط بحد ذاتهما.
راجع دلالات الأحجام للتفاصيل الحالية الكاملة.
ComputedSize
بعد الحل النهائي يحصل كل عنصر على:
widthheightlocal_pos
وهذا هو القياس الذي يستخدمه الرندر.
UBorder
حدود مرئية مستقلة عن خلفية UNode:
colorwidthradiusoffset
Shape Modes
Round: زوايا مستديرة SDF.Cut: قص زوايا بنمط beveled/cut.
دلالات الأحجام
تثبت هذه الصفحة مفردات الأحجام المقصودة في خط alpha الحالي.
المصطلحات الأساسية
- الحجم المفضل: الحجم المطلوب عبر
widthوheight. - الحجم الأدنى: الحد الأدنى الذي تفرضه
min_widthوmin_height. - الحجم الأقصى: الحد الأعلى الذي تفرضه
max_widthوmax_height. - الحجم الجوهري: الحجم المقاس من المحتوى قبل تعديلات التخطيط القادمة من الأب.
أنماط UVal
Px: حجم ثابت بالوحدات المنطقية.Percent: نسبة من حجم الأب على ذلك المحور.Flex: يدخل في توزيع المساحة الحرة على المحور الرئيسي.MinContent: أصغر حجم جوهري ما زال يحتضن المحتوى.MaxContent: الحجم الجوهري الكامل من دون تمدد سياقي.Content: اسم عام قديم يبقى كمرادف عام لـMaxContent.Auto: حجم سياقي. يعتمد على القياس الجوهري كحل احتياطي، لكن خوارزمية التخطيط قد تمدده أو تعيد تفسيره عندما يطلب سياق التخطيط ذلك.
القواعد الحالية
- قيود
min_*وmax_*الصريحة تطبق دائمًا على الحجم النهائي، بما في ذلك إعادة توزيعflex growوflex shrink. - لم يعد
Autoيعامل كنفس نمطContent. - داخل
gridيمكن لعناصرAutoأن تتمدد إلى الخلية افتراضيًا. أماMinContentوMaxContentفيحتفظان بالحجم الجوهري إلا إذا طلبت المحاذاة التمدد صراحة. - في سلوك التمدد على المحور العرضي داخل
flexيشاركAutoفي التمدد الضمني. أما المحاذاة الصريحة فما تزال قادرة على فرض التمدد على الأنماط غير الثابتة وغير النسبية. - يتعامل
UImageمعAutoوContentوMinContentوMaxContentكأنماط قياس من الحجم الأصلي للصورة. ولأن للصورة حجمًا جوهريًا واحدًا فإن هذه الأنماط كلها تتحول إلى حجم الـ texture عندما تصبح الـ asset جاهزة.
إرشادات عملية
- استخدم
Autoعندما تريد أن يتكيف الحجم مع سياق التخطيط. - استخدم
MaxContentأوContentعندما تريد أن يحتضن العنصر محتواه المقاس ويتجنب التمدد الضمني الخاص بـAuto. - استخدم
MinContentعندما تريد أضيق احتواء جوهري ممكن. - أضف
min_width/max_widthأوmin_height/max_heightعندما تحتاج حدودًا صريحة حول أي من الأنماط السابقة.
ULayout وUSelf (واجهة هجينة)
التصميم الحالي يعتمد واجهة هجينة:
- حقول أساسية flat وسهلة الاستخدام.
- حقول متقدمة داخل nested ext structs.
ULayout للحاوية
الحقول الأساسية:
displayflex_directionjustify_contentalign_itemsgapgrid_columns
الحقول المتقدمة:
container_ext: ULayoutContainerExtbox_align: ULayoutBoxAlignContainerflex: ULayoutFlexContainergrid: ULayoutGridContainer
محاذاة الحاوية
justify_items: Option<UAlignItemsExt>align_content: Option<UContentAlignExt>row_gap: Option<f32>column_gap: Option<f32>
إعدادات الحاوية المرنة
wrap: UFlexWrapalign_content: Option<UContentAlignExt>
إعدادات الحاوية الشبكية
template_columns: Vec<UTrackSize>template_rows: Vec<UTrackSize>auto_flow: UGridAutoFlowauto_rows: UTrackSizeauto_columns: UTrackSize
USelf للعنصر
الحقول الأساسية:
align_selfleft/right/top/bottomorderposition_type
الحقول المتقدمة:
item_ext: ULayoutItemExtbox_align: ULayoutBoxAlignSelfflex: ULayoutFlexItemgrid: ULayoutGridItem
محاذاة العنصر
justify_self: Option<UAlignSelfExt>align_self: Option<UAlignSelfExt>justify_overflow: UOverflowPositionalign_overflow: UOverflowPosition
إعدادات العنصر المرن
flex_grow: Option<f32>flex_shrink: Option<f32>flex_basis: Option<UVal>
إعدادات العنصر الشبكي
column_start: Option<u32>column_span: u32row_start: Option<u32>row_span: u32
أنماط العرض
UDisplay يدعم الأنماط التالية:
FlexGridMasonryStackRadialNone
التدفق المرن
- يعتمد
flex_directionوjustify_contentوalign_items. - يدعم
wrapعبرcontainer_ext.flex.wrap. - يدعم
flex_grow/shrink/basisعلى مستوى العنصر.
الشبكة
- يمكن التشغيل بنمط بسيط عبر
grid_columns. - أو بنمط متقدم عبر
template_rows/template_columns. - التموضع التلقائي عبر
auto_flow+auto_rows/auto_columns.
البناء الحجري
- توزيع عنصر في أقصر عمود (شبيه بلوحات التثبيت).
- يتأثر بعدد الأعمدة والفواصل.
التكديس
- تراكب العناصر (شبيه بالطبقات).
الشعاعي
- توزيع العناصر حول دائرة، مناسب لقوائم خيال علمي.
تعطيل التخطيط
- تعطيل وضع التخطيط لتلك الحاوية.
UClip وUPbr
UClip
UClip { enabled: bool } يفرض قصًا على الأبناء.
الاستخدام الشائع:
#![allow(unused)]
fn main() {
commands.spawn((
UNode { ..default() },
UClip { enabled: true },
));
}
أين يُستخدم القص؟
- في
interaction/picking: لمنع hit-test خارج منطقة القص. - في
render/system: تمرير بيانات القص إلى مادةUNodeMaterial. - في النص: القص المحلي يتم داخل
sync_text_label_meshes، وبيانات قص الأسلاف تنتقل إلى مادة النص عبرsync_text_clipper_materials.
UPbr
عند العمل في 3D UI (UI3d):
UPbrيسمح بتخصيص:metallicroughnessemissive
هذا يؤثر على مسار المادة ثلاثية الأبعاد (UNodeMaterial3d).
المرور الصاعد والهابط والحال
المرور الصاعد: upward_measure_pass_الذاكرة المؤقتةd
- يتحرك من أعمق مستوى إلى الجذر.
- يحسب
IntrinsicSizeللحاويات اعتمادًا على الأبناء. - يتجاهل العناصر
Absoluteخارج التدفق. - يستخدم الذاكرة المؤقتة لتخطي الحساب عند عدم الاتساخ.
المرور الهابط: downward_solve_pass_safe
- يتحرك من الجذر إلى العمق الأقصى.
- يبني
SolverConfigوSolverSpecلكل عنصر. - يستدعي
solve_flex_layout(المحرك الأساسي لكل الأنماط عبر طبقة الربط). - يكتب النتائج إلى:
ComputedSizeTransform.translation
الحال
في src/layout/core/solver.rs:
- يفصل العناصر:
- in-flow
- absolute
- يحل main/cross sizes
- يطبق flex grow/shrink
- يطبق قواعد align/stretch
- يحل absolute box في نهاية الدورة
translate_spec / translate_config
translate_config: يقرأ container-level data منULayout.translate_spec: يقرأ item-level data منUSelf.
وهذا الفصل هو القلب الحسابي للمشروع.
الذاكرة المؤقتة وإبطالها
LayoutCache يقلل إعادة الحساب المتكرر.
ماذا يخزن؟
- المقاسات الجوهرية لكل كيان.
- العقد المتسخة.
- الكيانات المجمعة حسب العمق.
متى تصبح العقدة dirty؟
عند تغيّر واحد من:
UNodeULayoutUSelfChildrenIntrinsicSize
مع استثناء مهم:
- إذا كان التغيير الوحيد
IntrinsicSizeعلى عقدة لديها أبناء، يمكن تجاهله لتقليل الضوضاء.
دورة العمل
track_layout_changesيحدد العقد المتسخة.update_depth_cacheيعيد بناء خريطة العمق عند تغييرات هيكلية.upward_measure_pass_cachedيقرأ الذاكرة المؤقتة ويمسح أعلام الاتساخ في النهاية.
تشخيص الأداء
- راقب
dirty_count/dirty_ratio. - فعّل طبقة مراقبة الأداء عند الحاجة.
الوحدات الجاهزة
كل وحدة جاهزة في Univis عبارة عن مكوّن ECS مع إضافة صغيرة تدير:
- تهيئة الشكل/الأبناء.
- منطق التفاعل.
- تحديث المرئيات.
- إطلاق الرسائل عند الحاجة.
ترتيب ذهني سريع
- عرض/نص:
UTextLabel,UImage,UBadge,UTag,UProgressBar
- أفعال:
UButton,UIconButton,UToggle,UCheckbox,URadioButton
- Inputs:
USeekBar,UDragValue,USelect,UTextField
- Containers:
UPanel,UPanelWindow,UScrollContainer,UDivider
الإضافات المهمة
- مضافة تلقائيًا عبر
UnivisUiPlugin->UnivisWidgetPlugin: السطح القياسي للوحدات الجاهزة مع التمرير واللوحات وRuntime الخاص بـUTextFieldوUBadge. - وتبقى الإضافات المخصصة نفسها متاحة عندما تريد سطح widgets أضيق من
UnivisWidgetPlugin.
أمثلة مرتبطة
- حي الآن:
widgets_controls - حي الآن:
widgets_inputs - حي الآن:
widgets_display - حي الآن:
widgets_containers
نقاط الدخول الرسمية في API
univis_ui_widgets::widget::text_label::UTextLabelunivis_ui_widgets::widget::button::UButtonunivis_ui_widgets::widget::text_field::UTextFieldunivis_ui_widgets::widget::panel::{UPanel, UPanelWindow}univis_ui_widgets::widget::scroll_view::UScrollContainer
إلى أين بعد ذلك؟
- المثال المرتبط:
widgets_controls - صفحة الإعداد: إعداد الإضافات وأولى الأمثلة
- فهرس
API: مرجع الواجهة العامة - صفحة الترحيل: ترحيل مسارات الأمثلة
Text و Image و Badge
UTextLabel
الملف: src/widget/text_label.rs
الحقول الأساسية:
textfont_sizecolorfontjustifylinebreakautosizeoverflowافتراضيًا هوEllipsis، ويمكن التحويل إلىClipأوVisibleعند الحاجةtruncate_sideيتحكم في القص معEllipsis: من البداية أو النهاية أو الوسط
الأنظمة:
measure_text_label_layoutfit_node_to_text_sizesync_text_label_meshessync_text_clipper_materials
القص المحلي يتم على مستوى محارف النص، بينما ينتقل قص الأسلاف
UClipإلى مادة النص كي يطبقه الشيدر.
UImage
الملف: src/widget/image.rs
- يربط صورة بخلفية/texture مسار material.
sync_image_geometryيزامن أبعاد العرض.AutoوContentوMinContentوMaxContentتتحول إلى الحجم الأصلي للصورة عندما تصبح الـ asset متاحة.- تبقى قيود
UNodeمثلmin/maxمطبقة على الحجم النهائي بعد القياس الأصلي.
UBadge و UTag
الملف: src/widget/badge.rs
- أنماط badge (style/size presets).
UnivisBadgePluginمسؤول عن أنظمة التحديث الديناميكي للأنماط.- هذا الـ runtime مضاف افتراضيًا عبر
UnivisWidgetPlugin. - وتبقى الإضافة المخصصة نفسها متاحة عندما تريد سطح widgets أضيق.
مثال حي
- استخدم
cargo run --example widgets_displayلرؤيةUBadgeوUDividerوUProgressBarوUPanel
الوحدات التنفيذية
UButton
- الملف:
src/widget/button.rs - يطبق نمط زر عبر
UNode+UInteractionColors. - الأنماط الجاهزة:
primary,secondary,danger,success.
UIconButton
- الملف:
src/widget/icon_btn.rs - نفس فكرة الزر مع دعم خط الأيقونات.
UToggle
- الملف:
src/widget/toggle.rs - مفتاح تبديل مع تحريك للمقبض.
- الحدث:
ToggleChangedEvent
UCheckbox
- الملف:
src/widget/checkbox.rs - منطق بسيط يعتمد نقرة المؤشر.
URadioButton وURadioGroup
- الملف:
src/widget/radio.rs - إدارة مجموعة اختيار واحد.
- الحدث:
RadioButtonChangedEvent
مثال حي
- استخدم
cargo run --example widgets_controlsلرؤيةUButtonوUCheckboxوUToggleوURadioGroupوURadioButtonفي شاشة واحدة
وحدات الإدخال
USeekBar
- الملف:
src/widget/seekbar.rs - يدعم نطاقات وقيم وإظهار قيمة.
- الحدث:
SeekBarChangedEvent
UDragValue
- الملف:
src/widget/drag_value.rs - سحب أفقي لتغيير قيمة عددية.
- supports:
- min/max
- step
- decimals
- sensitivity
- events:
DragValueChangedEventDragValueCommitEvent
USelect
- الملف:
src/widget/select.rs - dropdown select مع خيارات معطلة ودعم keyboard أساسي.
- events:
SelectChangedEventSelectOpenStateChangedEvent
UTextField
- الملف:
src/widget/text_field.rs - text input مع cursor blink وfocus logic.
- Runtime مضاف افتراضيًا عبر
UnivisWidgetPlugin. - الإضافة المخصصة:
UnivisTextFieldPluginعند تركيب سطح widgets أضيق. - events:
TextFieldChangedEventTextFieldSubmitEvent
مثال حي
- استخدم
cargo run --example widgets_inputsلرؤيةUTextFieldوUSelectوUDragValueوUSeekBar
اللوحة ونافذة اللوحة
UPanel
الملف: src/widget/panel.rs
خصائص أساسية:
backgroundborder_colorborder_widthborder_radiuspaddinggapdirection
وظيفته: تقديم container جاهز بواجهة panel.
UPanelWindow الاختيارية
UPanelWindow يضيف سلوك resize من الحدود والزوايا إلى UPanel.
الحقول:
border_hit_thicknessmin_widthmin_height
builders:
with_min_size(width, height)with_border_hit_thickness(thickness)
السلوك الحالي
- 8 مناطق resize:
N,S,E,W,NE,NW,SE,SW. - resize فقط (بدون move).
- cursor icon يتغير عند hover/press على handles فقط.
- عند أول resize يتم تثبيت panel إلى
Absolute + Pxلضمان سلوك متوقع.
مثال حي
- استخدم
cargo run --example widgets_containersلرؤيةUPanelWindowالقابل لتغيير الحجم مع منفذ تمرير مرافق
مثال حي
شغّل cargo run --example widgets_containers لرؤية UPanelWindow القابل لتغيير الحجم مع منفذ تمرير مرافق.
حاوية التمرير
الملف: src/widget/scroll_view.rs
المكوّن
UScrollContainer:
scroll_speedverticalhorizontaloffset
الإضافة
UnivisScrollViewPlugin- يسجّل
UScrollContainerضمن الانعكاس. - يضيف
scroll_interaction_systemإلىUpdate.
منطق التمرير
- يعتمد على
MouseWheel. - يطبّق التمرير فقط عندما container في حالة
UInteraction::Hovered. - يتوقع أن أول ابن للحاوية هو content القابل للتحريك.
- يطبّق clamp بالاعتماد على overflow:
- المدى:
[-overflow, 0]
- المدى:
ملاحظات عملية
- يلزم
UInteractionعلى الحاوية لاكتشاف hover. - عادةً يدمج مع
UClip { enabled: true }لإخفاء المحتوى الخارج عن الإطار.
مثال حي
- استخدم
cargo run --example widgets_containersلرؤية منفذ تمرير حي موصول معUClipوUInteractionوUScrollContainer
نظام التفاعل
طبقة التفاعل في Univis مبنية على:
- خلفية التقاط مخصصة (
univis_picking_backend). - نداءات مراقبة لحالات المؤشر.
- حالة المكوّن (
UInteraction).
المكونات الأساسية
-
UInteraction:NormalHoveredPressedReleasedClicked
-
UInteractionColors:normalhoveredpressed
فكرة العمل
- خلفية الالتقاط تحسب الضربات.
- نظام الالتقاط في Bevy يطلق أحداث المؤشر.
- مراقبو الأحداث في
interaction/feedback.rsتحدّثUInteractionواللون.
ملاحظة
التفاعل يعتمد على وجود UInteraction على الكيان الهدف.
مراجع مرتبطة
أمثلة مرتبطة
نقاط الدخول الرسمية في API
univis_ui_interaction::interaction::feedback::UInteractionunivis_ui_interaction::interaction::feedback::UInteractionColorsunivis_ui_interaction::interaction::picking::univis_picking_backend
إلى أين بعد ذلك؟
- المثال المرتبط:
widgets_controls - فهرس
API: مرجع الواجهة العامة - صفحة مرجعية إضافية: القيود الحالية
خلفية الالتقاط
الملف: src/interaction/picking.rs
ماذا يفعل؟
- يقرأ مواضع المؤشر.
- يحول المؤشر من viewport إلى world.
- يختبر كل عنصر مرشح عبر SDF rounded box.
- يستبعد الضربات المقصوصة بواسطة الآباء (
UClip). - يحذف hit الأب إذا يوجد hit ابن أعمق في نفس المسار.
تفاصيل مهمة
- الاستعلام الأساسي يستهدف الكيانات التي تحمل
UInteraction. - العمق النهائي يجمع:
- عمق الشجرة
- ترجمة Z
دقة القص
is_clipped_by_ancestors:
- يصعد في شجرة الآباء.
- يحول نقطة المؤشر إلى الإحداثيات المحلية لكل سلف قاص.
- يطبق
sd_rounded_boxعلى حدود clip.
هذا يجعل الالتقاط متسقًا مع منطق القص المرئي.
حالات UInteraction
الملف: src/interaction/feedback.rs
transitions الأساسية
Pointer<Over>=>HoveredPointer<Out>=>NormalPointer<Press>=>PressedPointer<Release>=>ReleasedPointer<Click>=>Clicked
ألوان UInteraction
إذا كان الكيان يحمل UInteractionColors، فإن مراقب التفاعل يحدّث UNode.background_color تلقائيًا حسب الحالة.
ممارسات موصى بها
- استخدم
Pickable::IGNOREعلى النصوص/الأبناء غير التفاعليين داخل زر. - اجعل منطق الحالة النهائي داخل نظام الوحدة الجاهزة عند الحاجة، مثل السحب أو الاختيار، ولا تعتمد فقط على اللون.
مصفوفة دعم التفاعل (Screen / World2d / World3d)
المعاني:
Supported: مدعوم في المسار الموثق.جزئي: مدعوم جزئيًا مع قيود.N/A: غير مقصود لهذا النمط.
| القدرة | Screen UI (URootUi::screen()) | World UI (URootUi::world_2d(...)) | 3D UI (URootUi::world_3d(...)) | الشروط / الملاحظات |
|---|---|---|---|---|
| الرندر الأساسي | Supported | Supported | Supported | Screen وWorld2d يستخدمان مسار 2D، بينما World3d يستخدم مسار المواد ثلاثي الأبعاد. |
| الالتقاط + أحداث المؤشر | Supported | Supported | Supported | التفاعل يحسم الكاميرا من كل root عبر ResolvedRootUi. وفي المشاهد متعددة الكاميرات يُفضّل استخدام UiCameraRef::Entity. |
| hit testing مع القص | Supported | Supported | Supported | فحص قص الأسلاف يعمل في كل الفضاءات. وجذور العالم ما تزال تُفحص على مستوى plane الواجهة نفسها. |
مقابض تغيير حجم UPanelWindow | Supported | Supported | Supported | منطق تغيير الحجم يحسب حركة المؤشر عبر كاميرا الجذر ومستوى اللوحة. |
إدخال/أحداث UTextField | Supported | Supported | Supported | مضمّن افتراضيًا عبر UnivisWidgetPlugin؛ أضف UnivisTextFieldPlugin مباشرة فقط عند تركيب widgets يدويًا بشكل أضيق. |
تفاعل UScrollContainer | Supported | Supported | Supported | التمرير يتبع مسار الكاميرا المحلولة من الجذر. |
خصائص UPbr (metallic, roughness, emissive) | N/A | N/A | Supported | مخصصة فقط لمسار World3d. |
ملاحظات
URootUi::screen()هو مسار HUD حقيقي مربوط بالـ viewport المحلول.URootUi::world_2d(...)وURootUi::world_3d(...)يعتمدان canvas منطقيًا ثابتًا مع world scaling صريح.meters_per_unitيغيّر الحجم الفيزيائي في العالم من دون تغيير حجم التخطيط المنطقي.
مصادر التحقق
crates/univis_ui_interaction/src/interaction/picking.rscrates/univis_ui_widgets/src/widget/panel.rscrates/univis_ui_engine/src/layout/layout_system.rscrates/univis_ui_engine/src/layout/render/system.rs
فهرس الأمثلة
تعرض هذه الصفحة فقط ملفات الأمثلة الموجودة فعليًا في المستودع الحالي.
تشغيل العرض الحالي
cargo run --manifest-path android/android_phone_app/Cargo.toml
حزمة Android المستقلة
| المثال | المصدر | الغرض | الأمر |
|---|---|---|---|
android_phone | android/android_phone_app/examples/android_phone.rs | شاشة تطبيق بطابع Android مع بحث وتبديلات ومنزلقات ومحتوى قابل للتمرير وتنقل سفلي. | cargo run --manifest-path android/android_phone_app/Cargo.toml --example android_phone |
وتملك الحزمة نقطة دخول سطح مكتب مباشرة:
cargo run --manifest-path android/android_phone_app/Cargo.toml
أمثلة مساحة العمل
| المثال | المصدر | الغرض | الأمر |
|---|---|---|---|
responsive_layout_test | examples/responsive_layout_test.rs | مشهد ضغط لتركيب واجهة شاشة متجاوبة. | cargo run --example responsive_layout_test |
toggle_seekbar | examples/toggle_seekbar.rs | مشهد تحكم صغير لسلوك toggle وseek-bar. | cargo run --example toggle_seekbar |
z_order_hierarchy | examples/z_order_hierarchy.rs | فحص الترتيب البصري وسلوك تراكب الهرمية. | cargo run --example z_order_hierarchy |
تخطيط Grid
| المثال | المصدر | الغرض | الأمر |
|---|---|---|---|
grid_columns | examples/grid/columns.rs | أحجام أعمدة grid وسلوك التخطيط. | cargo run --example grid_columns |
grid_tracks | examples/grid/tracks.rs | سلوك أحجام مسارات grid. | cargo run --example grid_tracks |
grid_auto_flow | examples/grid/auto_flow.rs | سلوك التموضع التلقائي داخل grid. | cargo run --example grid_auto_flow |
grid_item_placement | examples/grid/item_placement.rs | التموضع الصريح لعناصر grid. | cargo run --example grid_item_placement |
أنماط التخطيط
| المثال | المصدر | الغرض | الأمر |
|---|---|---|---|
layout_flex | examples/layout/flex.rs | تركيب flex layout. | cargo run --example layout_flex |
layout_masonry | examples/layout/masonry.rs | تركيب masonry layout. | cargo run --example layout_masonry |
layout_stack | examples/layout/stack.rs | تركيب stack layout. | cargo run --example layout_stack |
layout_radial | examples/layout/radial.rs | تركيب radial layout. | cargo run --example layout_radial |
الوحدات الجاهزة
| المثال | المصدر | الغرض | الأمر |
|---|---|---|---|
widgets_controls | examples/widgets/controls.rs | أزرار وتبديلات وcheckbox وradio controls. | cargo run --example widgets_controls |
widgets_inputs | examples/widgets/inputs.rs | Text field وselect وdrag-value وseek-bar inputs. | cargo run --example widgets_inputs |
widgets_display | examples/widgets/display.rs | نصوص وbadges ومقسمات ولوحات وprogress display. | cargo run --example widgets_display |
widgets_containers | examples/widgets/containers.rs | سلوك panel window وscroll-container. | cargo run --example widgets_containers |
التحقق
افحص كل أمثلة مساحة العمل التي يعرفها Cargo حاليًا:
cargo check --workspace --examples
وافحص حزمة Android:
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
صفحات مرتبطة
معرض الأمثلة
تعرض هذه الصفحة الأمثلة الموجودة في المستودع الحالي فقط.
أفضل مسارات البدء
- البدء السريع
android_phonewidgets_controlswidgets_inputsresponsive_layout_test
واجهات الشاشة
| المثال | استخدمه من أجل | الأمر |
|---|---|---|
android_phone | شاشة كاملة بطابع تطبيق هاتف. | cargo run --manifest-path android/android_phone_app/Cargo.toml |
responsive_layout_test | تركيب واجهة شاشة متجاوبة. | cargo run --example responsive_layout_test |
z_order_hierarchy | فحص الترتيب البصري والتراكب. | cargo run --example z_order_hierarchy |
التخطيط
| المثال | استخدمه من أجل | الأمر |
|---|---|---|
layout_flex | تخطيط flex. | cargo run --example layout_flex |
layout_masonry | تخطيط masonry. | cargo run --example layout_masonry |
layout_stack | تخطيط stack. | cargo run --example layout_stack |
layout_radial | تخطيط radial. | cargo run --example layout_radial |
grid_columns | أعمدة grid. | cargo run --example grid_columns |
grid_tracks | مسارات grid. | cargo run --example grid_tracks |
grid_auto_flow | التموضع التلقائي في grid. | cargo run --example grid_auto_flow |
grid_item_placement | التموضع الصريح لعناصر grid. | cargo run --example grid_item_placement |
الوحدات الجاهزة
| المثال | استخدمه من أجل | الأمر |
|---|---|---|
widgets_controls | الأزرار والتبديلات وcheckbox وradio controls. | cargo run --example widgets_controls |
widgets_inputs | Text fields وselect وdrag-value وseek-bar inputs. | cargo run --example widgets_inputs |
widgets_display | النصوص وbadges والمقسمات واللوحات وprogress display. | cargo run --example widgets_display |
widgets_containers | Panel windows وscroll containers. | cargo run --example widgets_containers |
toggle_seekbar | مشهد صغير لـ toggle وseek-bar. | cargo run --example toggle_seekbar |
صفحات مرتبطة
شاشة تطبيق Android
توثق هذه الصفحة العرض الحي الحالي android_phone.
شغّله بالأمر:
cargo run --manifest-path android/android_phone_app/Cargo.toml
وتحتفظ الحزمة أيضًا بهدف مثال محلي باسم android_phone لاستخدامات Android الخاصة، لكن نقطة
الدخول أعلاه هي أسرع طريقة لمعاينة المشهد على سطح المكتب داخل هذا الفرع.
ماذا يوضح؟
- سطح تطبيق Android كامل الارتفاع لكنه مقيّد بعرض ضيق مناسب للهاتف
- بطاقة علوية مع
UTextFieldحي للبحث - feed قابلًا للتمرير مبنيًا بواسطة
UClipوUScrollContainerوUInteraction - عناصر تحكم مدمجة للهاتف باستخدام
UToggleوUSeekBarوUBadgeوUButton - صف تنقل سفلي يبقى ظاهرًا بينما يكبر المحتوى الوسطي
متى تشغله؟
- عندما تريد مرجع تخطيط محمول فعلي بدل عروض widgets المعزولة
- عندما تريد معايرة كثافة العناصر لشاشات الهاتف
- عندما تريد مشهدًا واحدًا يجمع التخطيط والتمرير وعناصر التحكم اللمسية
ملاحظات عملية
- يستخدم المشهد
URootUi::screen()، لذلك يبقى سطح التطبيق ثابتًا على مساحة الرؤية مثل HUD - يستخدم الغلاف الخارجي
max_widthبدل إطار جهاز مزيف، لذلك يظل المشهد مناسبًا لسطح المكتب وAndroid معًا - الجزء القابل للتمرير هو feed الوسطي فقط، بينما تبقى البطاقة العلوية والتنقل السفلي ظاهرين
- وللتركيز على سلوك وحدات بعينها، قارنه مع
widgets_controlsوwidgets_inputsوwidgets_containers
صفحات مرتبطة
مرجع الواجهة العامة
هذا القسم يقدّم فهرسًا عمليًا لسطح الـ API العام في univis_ui.
أين تجد المرجع الآلي الكامل؟
لتوليد rustdoc:
cargo doc --no-deps
ثم افتح:
cargo doc --no-deps --open
كيف تستخدم هذا القسم؟
- ابدأ بـ الأحداث والرسائل إذا كنت تربط الواجهة بمنطق اللعبة أو التطبيق.
- استخدم خريطة الحزم عندما تريد الاختيار بين الواجهة المجمعة والحزم الأدنى مستوى.
- راجع جدول الأنواع العامة للوصول السريع لكل بنية أو تعداد أو إضافة.
نقاط الدخول الأعلى أهمية
univis_ui::UnivisUiPluginلمسار الواجهة المجمعةunivis_ui_engine::layout::layout_system::URootUiللجذورunivis_ui_engine::layout::univis_node::UNodeلنموذج الصندوقunivis_ui_interaction::interaction::feedback::UInteractionلحالة التفاعلunivis_ui_widgets::widget::text_label::UTextLabelللنصوصunivis_ui_style::style::Themeللخطوط والأيقونات المشتركة
الأحداث والرسائل
تعتمد الأحداث في Univis على رسائل Bevy (#[derive(Message)]).
Toggle
ToggleChangedEvent
Radio
RadioButtonChangedEvent
SeekBar
SeekBarChangedEvent
DragValue
DragValueChangedEventDragValueCommitEvent
Select
SelectChangedEventSelectOpenStateChangedEvent
TextField
TextFieldChangedEventTextFieldSubmitEvent
نمط استهلاك الأحداث
#![allow(unused)]
fn main() {
use bevy::prelude::*;
use univis_ui::prelude::*;
fn consume(mut events: MessageReader<ToggleChangedEvent>) {
for ev in events.read() {
// handle
}
}
}
جدول الأنواع العامة
يجمع هذا الجدول أهم الأنواع العامة بحسب الـ crate وبحسب دورها العملي.
نقطة الدخول المجمعة
univis_ui::UnivisUiPluginunivis_ui::prelude
أنواع الجذور والتخطيط
univis_ui_engine::layout::layout_system::URootUiunivis_ui_engine::layout::layout_system::UiSpaceunivis_ui_engine::layout::layout_system::UiCanvasSizeunivis_ui_engine::layout::layout_system::UiCameraRefunivis_ui_engine::layout::univis_node::UNodeunivis_ui_engine::layout::univis_node::ULayoutunivis_ui_engine::layout::univis_node::USelfunivis_ui_engine::layout::univis_node::UBorderunivis_ui_engine::layout::univis_node::UClipunivis_ui_engine::layout::pbr::UPbrunivis_ui_engine::layout::geometry::UValunivis_ui_engine::layout::geometry::USidesunivis_ui_engine::layout::geometry::UCornerRadius
تم حذف UScreenRoot وUWorldRoot عمدًا من السطح الموصى به.
استعمل مسارهما الصريح فقط عند ترحيل الشيفرات الأقدم:
univis_ui::layout::layout_system::{UScreenRoot, UWorldRoot} أو
univis_ui_engine::layout::layout_system::{UScreenRoot, UWorldRoot}.
أنواع التفاعل
univis_ui_interaction::interaction::feedback::UInteractionunivis_ui_interaction::interaction::feedback::UInteractionColorsunivis_ui_interaction::interaction::UnivisInteractionPlugin
أنواع النمط
univis_ui_style::style::Themeunivis_ui_style::style::TextStylesunivis_ui_style::style::IconStylesunivis_ui_style::style::Fontsunivis_ui_style::style::UnivisUiStylePlugin
الوحدات الجاهزة
univis_ui_widgets::widget::text_label::UTextLabelunivis_ui_widgets::widget::button::UButtonunivis_ui_widgets::widget::checkbox::UCheckboxunivis_ui_widgets::widget::toggle::UToggleunivis_ui_widgets::widget::radio::{URadioButton, URadioGroup}univis_ui_widgets::widget::seekbar::USeekBarunivis_ui_widgets::widget::drag_value::UDragValueunivis_ui_widgets::widget::select::{USelect, USelectOption}univis_ui_widgets::widget::text_field::UTextFieldunivis_ui_widgets::widget::scroll_view::UScrollContainerunivis_ui_widgets::widget::panel::{UPanel, UPanelWindow}univis_ui_widgets::widget::progress::UProgressBarunivis_ui_widgets::widget::badge::{UBadge, UTag}
أنواع التشخيص والرندر
univis_ui_engine::layout::render::UnivisRenderPluginunivis_ui_engine::layout::profiling::{LayoutProfiler, UnivisLayoutProfilingPlugin}univis_ui_engine::layout::core::layout_cache::{LayoutCache, UnivisLayoutCachePlugin}
للحصول على التواقيع والتفاصيل الدقيقة لكل نوع أو حقل، استخدم
cargo doc --no-deps.
خريطة الحزم
استعمل أصغر سطح عام يطابق المهمة التي تعمل عليها.
نقطة البداية الموصى بها
univis_uiهي الاعتمادية الافتراضية لمعظم التطبيقات.univis_ui::preludeهو سطح الاستيراد اليومي الموصى به.- يجمع
preludeالخاص بالواجهة المجمعة أنواع الجذور والتخطيط والتفاعل والنمط والوحدات الجاهزة الرسمية. - يتم استبعاد طبقات التوافق المهجورة عمدًا من
prelude. استعمل المسارات الصريحة مثلunivis_ui::layout::layout_system::{UScreenRoot, UWorldRoot}فقط عند ترحيل الشيفرات الأقدم.
متى تعتمد على كل حزمة؟
univis_ui: استعملها عندما تريد إضافة واحدة وقصة استيراد واحدة لكامل الطبقة.univis_ui_engine: استعملها عندما تحتاج الجذور أو التخطيط أو مزامنة الرندر أو بناء widgets/runtime مخصص من دون الواجهة المجمعة الكاملة.univis_ui_interaction: استعملها عندما تحتاج الالتقاط وحالةUInteractionفوق جذور المحرك.univis_ui_widgets: استعملها عندما تريد الوحدات الجاهزة لكنك ما تزال تدير تركيب الإضافات بنفسك.univis_ui_style: استعملها عندما تحتاج فقط موارد النمط المشتركة أو الخطوط أو الأيقونات أو أنماط النص.
سياسة prelude
- يعني
preludeسطح الاستيراد اليومي المستقر والموصى به. - تبقى الوحدات المسماة مثل
layoutوrenderوinteractionوwidgetعامة، لكنها موجهة للتكاملات المتقدمة. - تبقى طبقات التوافق المهجورة على مسارات صريحة بدل أن تدخل في قصة الاستيراد الافتراضية.
التطوير والمساهمة
قواعد عملية قبل أي تعديل
- افهم ترتيب الأنظمة قبل التعديل، خصوصًا في التخطيط والرندر والتفاعل.
- لا تكسر
Reflectionللأنواع العامة بلا سبب واضح. - اختبر التعديل على الحزمة الحية الحالية أو على فحوص مصدرية مكافئة، وليس على اختبارات الوحدة فقط.
- عند إضافة وحدة جاهزة جديدة، وفّر:
- واجهة مكوّن واضحة
- إضافة مستقلة
- رسائل أحداث عند الحاجة
- عرضًا قابلًا للتشغيل عندما يحمل الفرع أمثلة تشغيلية فعلية
- توثيقًا في README وهذا الكتاب
مكان التوثيق والأمثلة
- أضف أي صفحة شرح جديدة في
docs/src/enوdocs/src/arمعًا. - ضع مثال التشغيل الجديد داخل الـ crate التي تملك الميزة.
- اترك الجذر
examples/فقط للعروض المجمعة المتكاملة عندما تكون موجودة فعلًا في الفرع. - اتبع القواعد المذكورة في قواعد تحرير التوثيق.
- اتبع اصطلاحات التسمية عند تقسيم الوحدات الداخلية أو إعادة تسميتها.
- راجع خريطة الصيانة وقواعد المعمارية قبل نقل حدود الملكية أو التبعيات.
- راجع اتفاقيات بنية الوحدات الجاهزة وحدود محرك التخطيط قبل تقسيم subsystem كبيرة.
- راجع مسار تأليف التوثيق للخطوات الدقيقة المتعلقة باللغتين و
rustdoc. - استخدم قائمة مراجعة التوثيق قبل الدمج.
أسلوب الكود داخل المشروع
- فضّل المكونات الصغيرة والأنظمة الواضحة
- اجعل السلوك البصري مدفوعًا عبر
UNodeوUBorderوUInteractionColors - تجنب الآثار الجانبية المفاجئة خارج الجدولة المقصودة
فروع العمل المقترحة
feat/<name>للميزاتfix/<name>للإصلاحاتdocs/<name>للتوثيق
المعمارية
بنية univis_ui مقسمة إلى أربع وحدات رئيسية:
layout/: محرك التخطيط والحساب المكاني.interaction/: الالتقاط بالمؤشر وحالات التفاعل.widget/: الوحدات الجاهزة المضمنة، مثل الأزرار والإدخال والقوائم.style/: خطوط وأيقونات وثيم أساسي.
الفكرة الأساسية
كل شيء في Univis مبني من كيانات ومكوّنات ضمن ECS:
- لا توجد شجرة واجهة محتفظ بها خارجيًا.
- كل عنصر واجهة هو كيان يحمل
UNodeومعه مكونات إضافية. - التخطيط والحساب يتمان عبر أنظمة ضمن جداول Bevy.
المسار القياسي للإطار
PreUpdate:
- تشغيل خلفية الالتقاط لاكتشاف الكيانات المصابة.
Update:
- أنظمة الوحدات الجاهزة والتفاعل وتحديث المرئيات المنطقية.
PostUpdate:
- خط معالجة التخطيط:
update_layout_hierarchyupward_measure_pass_cacheddownward_solve_pass_safe
- أنظمة الرندر/المواد (حسب التغييرات).
أهداف التصميم
- دقة بصرية عالية عبر SDF.
- مرونة عالية في التخطيط، مثل التدفق المرن والشبكة والبناء الحجري والتكديس والشعاعي.
- قابلية التوسيع عبر مكونات ECS والإضافات.
- قابلية تتبع الأداء عبر طبقة المراقبة والذاكرة المؤقتة.
خريطة الإضافات
الإضافة الجذرية
في src/lib.rs:
UnivisUiPluginيضيف بالترتيب:UnivisUiStylePluginUnivisEnginePluginUnivisInteractionPluginUnivisWidgetPlugin
التخطيط
UnivisEnginePlugin:UnivisNodePluginUnivisLayoutPluginUnivisRenderPlugin- وتوفر معًا بدائيات العقدة وحسم الجذور وحل التخطيط ومزامنة الرندر.
التفاعل
UnivisInteractionPlugin:univis_picking_backendفيPreUpdate.- مراقبو الأحداث:
on_pointer_overon_pointer_outon_pointer_presson_pointer_releaseon_pointer_click
النمط
UnivisUiStylePlugin:- تحميل خطوط مضمّنة.
- تحميل خط أيقونات Lucide.
- إنشاء المورد
Theme.
الوحدات الجاهزة
UnivisWidgetPlugin يضيف مجموعة الوحدات الجاهزة الأساسية. الحالة الحالية:
- مضاف تلقائيًا:
UnivisTextPluginUnivisProgressPluginUnivisButtonPluginUnivisRadioPluginUnivisIconButtonPluginUnivisTogglePluginUnivisCheckboxPluginUnivisSeekBarPluginUnivisScrollViewPluginUnivisDividerPluginUnivisPanelPluginUnivisBadgePluginUnivisDragValuePluginUnivisSelectPluginUnivisTextFieldPlugin
وتبقى الإضافات المخصصة نفسها متاحة عندما تريد تركيب سطح widgets أضيق من UnivisWidgetPlugin.
مرجع سريع
- راجع أيضًا: جدول حقيقة الإضافات
جدول حقيقة الإضافات
هذه الصفحة هي مرجع الحقيقة الرسمي لحالة تسجيل الإضافات في المستودع الحالي.
تركيب الجذر (UnivisUiPlugin)
| الإضافة | تُضاف عبر UnivisUiPlugin | ملاحظات |
|---|---|---|
UnivisUiStylePlugin | نعم | الخطوط/الأيقونات المضمنة + Theme. |
UnivisEnginePlugin | نعم | يضيف UnivisNodePlugin وUnivisLayoutPlugin وUnivisRenderPlugin. |
UnivisInteractionPlugin | نعم | يضيف خلفية الالتقاط ومراقبي المؤشر. |
UnivisWidgetPlugin | نعم | يسجّل مجموعة الإضافات الأساسية للوحدات الجاهزة. |
UnivisLayoutProfilingPlugin | لا | إضافة اختيارية للتشخيص وتُضاف يدويًا. |
تركيب الوحدات الجاهزة (UnivisWidgetPlugin)
| إضافة الوحدة الجاهزة | تُسجّل تلقائيًا عبر UnivisUiPlugin | ملاحظات |
|---|---|---|
UnivisTextPlugin | نعم | UTextLabel وأنظمة text clipping. |
UnivisProgressPlugin | نعم | UProgressBar. |
UnivisButtonPlugin | نعم | UButton. |
UnivisRadioPlugin | نعم | URadioButton, URadioGroup. |
UnivisIconButtonPlugin | نعم | UIconButton. |
UnivisTogglePlugin | نعم | UToggle. |
UnivisCheckboxPlugin | نعم | UCheckbox. |
UnivisSeekBarPlugin | نعم | USeekBar. |
UnivisScrollViewPlugin | نعم | UScrollContainer. |
UnivisDividerPlugin | نعم | UDivider. |
UnivisPanelPlugin | نعم | UPanel وسلوك UPanelWindow. |
UnivisBadgePlugin | نعم | UBadge مع تحديثات المرئيات الديناميكية للـ badge/tag. |
UnivisDragValuePlugin | نعم | UDragValue. |
UnivisSelectPlugin | نعم | USelect. |
UnivisTextFieldPlugin | نعم | سلوك/أحداث UTextField. |
وتبقى الإضافات المخصصة نفسها متاحة عندما تريد بناء سطح widgets أضيق من UnivisWidgetPlugin.
مصادر التحقق
src/lib.rscrates/univis_ui_engine/src/lib.rscrates/univis_ui_widgets/src/widget/mod.rs
دورة الإطار
هذا الفصل يربط بين الأنظمة في الزمن داخل إطار Bevy واحد.
ما قبل التحديث
- النظام
univis_picking_backend:- يحول موقع المؤشر إلى فضاء العالم.
- يفحص تقاطع SDF مع كل عنصر تفاعلي.
- يحترم القص من الآباء (
UClip). - ينشر
PointerHitsلاستخدامها بواسطة أحداث المراقبة.
التحديث
- أنظمة الوحدات الجاهزة (تحديث الحالة، مزامنة المرئيات، وإطلاق الرسائل).
- أنظمة التمرير وتغيير حجم اللوحة وغيرها.
- أنظمة النص وتحديث حجمه.
ما بعد التحديث
-
خط معالجة التخطيط بالترتيب الحرج:
update_layout_hierarchyupward_measure_pass_cacheddownward_solve_pass_safe
-
مزامنة الرندر:
update_materials_optimizedيزامنUNode/ComputedSize/UBorder/...إلى المواد.
لماذا هذا الترتيب مهم؟
- أي تعديل في
Update، مثل تغيير حجم اللوحة أو قيمة الإدخال، يجب أن ينعكس في التخطيط النهائي قبل الرسم. - الذاكرة المؤقتة وآلية الإبطال تعملان قبل القياس لتقليل الحساب غير الضروري.
الرندر
الرندر في Univis يعتمد على مواد SDF مخصصة:
UNodeMaterialلمسار 2D.UNodeMaterial3dلمسار 3D.
الملفات الأساسية:
src/layout/render/system.rssrc/layout/render/material.rssrc/layout/render/material_3d.rssrc/layout/render/shaders/unode.wgslsrc/layout/render/shaders/unode_3d.wgsl
مسار التحديث
update_materials_optimized:
- يقرأ
UNode,ComputedSize,UBorder,UImage,UI3d,UPbr. - يقرر 2D أو 3D حسب وجود
UI3d. - يعيد استخدام handles في
MaterialHandlesلتقليل التخصيص. - يمرر بيانات القص إلى مادة ثنائية الأبعاد.
لماذا SDF؟
- حواف نظيفة تحت التكبير.
- دعم border radius وقص وتنعيم جيد.
- مرونة لشكل
RoundوCut.
أمثلة مرتبطة
المواد والشيدر
UNodeMaterial (2D)
أهم الحقول:
colorborder_colorradiussizeborder_widthborder_offsetsoftnessshape_modeuse_texturetextureclip_centerclip_sizeclip_radiususe_clip
UNodeMaterial3d
مسار 3D يضيف خصائص PBR:
metallicroughnessemissive
الشيدر 2D
في unode.wgsl:
- يحسب SDF للشكل الأساسي.
- يحسب mask للحدود والجسم الداخلي.
- إن كان
use_clip = 1يطبق قناع القص قبل إخراج اللون.
الشيدر 3D
في unode_3d.wgsl:
- نفس فكرة SDF للشكل.
- يدمج مع خط المعالجة ثلاثي الأبعاد.
قص النصوص
النموذج الحالي
UTextLabel يستخدم مرحلتين منفصلتين للقص:
- قص محلي داخل الـ label نفسه
- قص اختياري من الأسلاف عبر
UClip
القص المحلي داخل UTextLabel
القص المحلي يتم داخل sync_text_label_meshes.
- النظام يبني quads للمحارف انطلاقًا من النص المقاس
- عندما يكون
overflowهوClipأوEllipsisيتم قص كل quad على حدود محتوى الـ label قبل بناء الـ mesh - عندما يكون
overflowهوVisibleيتم تعطيل هذا القص المحلي
إذا كان Ellipsis مفعّلًا، فالنظام يقيس النص أولًا، ثم يختصره عند الحاجة، ثم يقص المحارف المتبقية داخل حدود الـ label.
الـ labels التي تعمل بـ autosize ما زالت تحترم قيود الأب إذا كان للأب أبعاد صريحة، لذلك يتوقف الفيض عند حد الأب بدل أن يستمر في التمدد بلا نهاية.
القص عبر الأسلاف UClip
قص الأسلاف يتم داخل sync_text_clipper_materials.
- النظام يصعد من كل mesh نصي مولد
- يبحث عن أقرب ancestor يحمل
UClipمفعّلًا - ينسخ مركز القص وحجمه ونصف قطر الزوايا إلى مادة النص SDF
- الشيدر يقص النص داخل ذلك المستطيل ذي الزوايا المستديرة
بهذا صار قص النص مرتبطًا بمسار المادة/الشيدر، وليس بإخفاء كيان النص بالكامل.
ما الذي تغيّر؟
كانت الوثائق القديمة تصف حلًا يعتمد على الإظهار أو الإخفاء الكامل عندما يخرج النص خارج ancestor قاص.
هذا لم يعد هو السلوك الحالي:
- القص المحلي يتم على مستوى quads الخاصة بالمحارف
- بيانات
UClipتنتقل إلى المادة/الشيدر - يمكن أن يبقى جزء من النص ظاهرًا بدل سلوك الإخفاء الكامل
قيد معروف
حاليًا مادة النص تستخدم أقرب ancestor يحمل UClip مفعّلًا فقط. إذا كانت هناك عدة أسلاف قاصين متداخلين، فهي لا تُدمج بعد في تقاطع قص واحد للنص.
الأداء والتشخيص
المشروع يحتوي ثلاث أدوات أساسية للأداء:
LayoutCacheلتقليل الحسابات.UnivisLayoutProfilingPluginلقياس الزمن وعرض طبقة المراقبة../scripts/run_perf_baselines.shلتشغيل قياسات معيارية قابلة للتكرار من سطر الأوامر.
أين تراقب الأداء؟
- نسبة الاتساخ وعدد العقد المعاد حسابها.
- زمن المرور الصاعد والهابط.
- زمن تحديث المواد.
- عدد المواد الجديدة مقابل المعاد استخدامها.
- تغيّر خطوط الأساس في سيناريوهات المحلل وسيناريوهات التشغيل.
ذاكرة التخطيط المؤقتة
الملف: src/layout/core/layout_cache.rs
المورد LayoutCache
يحفظ:
- المقاسات الجوهرية
- العقد المتسخة
- الكيانات بحسب العمق
- عدادات الإطارات
أفضل ممارسات
- لا تعدّل
UNode/ULayout/USelfفي كل إطار بدون سبب. - فضّل التحديث عند تغيّر حالة فعلية.
- قلّل الاضطراب في البنية الهرمية، مثل الإضافة والحذف العشوائي المستمر.
متى تفكر بالتوسعة؟
- إذا زاد عدد العقد كبيرًا جدًا.
- إذا أصبحت قيمة
dirty_ratioمرتفعة أغلب الوقت.
تحقق مرتبط
cargo test -p univis_ui_engine --lib layout::core::layout_cache
طبقة مراقبة الأداء
الملف: src/layout/profiling.rs
الإضافة
UnivisLayoutProfilingPlugin
بيانات يعرضها
- زمن المرور الصاعد
- زمن المرور الهابط
- زمن تحديث المواد
- إحصائيات الذاكرة المؤقتة
- السجل والمخطط
اختصارات لوحة المفاتيح
F10: إظهار أو إخفاء المراقبF11: تبديل طبقة المراقبةF9: تبديل المخططF12: تغيير موضع طبقة المراقبة
متى تستخدمه؟
- عند ملاحظة قفزات الإطارات.
- عند مقارنة تأثير تعديل تخطيط كبير.
- عند تقييم فعالية الذاكرة المؤقتة.
حزمة القياس
التقارير الملتزم بها هي المرجع الحالي لمقارنات الأداء.
الملفات المرجعية الحالية
perf_baselines/current_max/2026-04-05/solver_benchmarks.txtperf_baselines/current_max/2026-04-05/runtime_benchmarks.txtperf_baselines/current_max/2026-04-05/manifest.jsonperf_baselines/current_max/2026-04-05/README.md
نطاق التغطية الحالي
ما تزال موجة القياسات الملتزم بها تغطي المسارات الثقيلة حسابيًا والمسارات الثقيلة وقت التشغيل:
- سيناريوهات المحلل مثل الصفوف الكثيفة والبطاقات الملتفة ولوحات grid
- سيناريوهات وقت التشغيل مثل root capsules والاستقرار بعد settlement وتغيرات الرندر فقط وقياس النص والتقاط الإشارات واللوحات الثقيلة و
World3d
كيف تستخدمها الآن
- اقرأ ملفات
.txtالملتزم بها للمخرجات الخام لكل سيناريو - استخدم
manifest.jsonللبيانات المنظمة - استخدم
scripts/render_benchmark_report.pyإذا أردت تقريرًا مرئيًا مبنيًا على البيانات المخزنة
حالة run_perf_baselines.sh
يوجّه ./scripts/run_perf_baselines.sh المشرفين حاليًا إلى بيانات الخطوط الأساسية الملتزم بها في هذا الفرع.
قواعد تحرير التوثيق
تهدف هذه القواعد إلى إبقاء الشجرتين العربية والإنجليزية متوازيتين، وقابلتين للبحث، وسهلتي الصيانة.
الفصل اللغوي
- لغة واحدة في كل ملف.
- الصفحات الإنجليزية تستخدم نثرًا إنجليزيًا فقط.
- الصفحات العربية تستخدم نثرًا عربيًا فقط.
- تبقى أسماء
APIالمشتركة داخل backticks فقط، مثلURootUiوUTextLabel.
شكل الصفحة
يُفضَّل اتباع بنية قصيرة ومتكررة:
- لماذا توجد هذه الصفحة.
- الحد الأدنى من النموذج الذهني المطلوب.
- القواعد العملية أو الأمثلة.
- الأمثلة المرتبطة.
- أنواع
APIالمرتبطة عند الحاجة.
قواعد التسمية
- استخدم الاسم العام الرسمي كما يظهر في Rust.
- لا تبتكر أسماء بديلة للأنواع العامة.
- عند ذكر مثال، اذكر اسمه واسم الـ package المالكة له معًا.
قواعد ربط الأمثلة
عند الإشارة إلى مثال من داخل صفحة شرح:
- اربط دائمًا إلى المدخل المرجعي داخل
docs/src/ar/examples/index.md - اذكر الـ package المالكة
- لا تستخدم أمرًا من الشكل
cargo run -p <package> --example <name>إلا إذا كان مصدر المثال موجودًا فعلًا في هذا الفرع؛ وإلا فاربط إلى فهرس التوفر أو إلى الحزمة الحية الحالية
قواعد API Docs
- يجب أن يشرح
rustdocالنية والمعنى، لا أن يعيد أسماء الحقول فقط. - تُفضَّل أمثلة
no_runالقصيرة على الفقرات الطويلة. - المساعدات الداخلية التي لا تدخل في القصة العامة للمكتبة يجب إخفاؤها أو تقليل بروزها.
قواعد التناظر بين اللغتين
- إذا أُضيفت صفحة إنجليزية، فأضف الصفحة العربية النظيرة في نفس التغيير.
- حافظ على نفس هيكلة المعلومات حتى لو اختلفت الصياغة.
- إذا عُدلت شجرة واحدة فقط، فوثّق السبب قبل الدمج.
اصطلاحات التسمية
تحدد هذه الصفحة قواعد التسمية الداخلية التي تجعل مساحة العمل قابلة للتوقع للمساهمين.
الأهداف
- تسهيل توقع مكان الشيفرة قبل فتح الملفات
- توحيد أسماء الإضافات والمجموعات والحالات والمكوّنات بين الحزم
- حجز ألفاظ التوافق للحالات التي تحافظ فعلًا على سلوك قديم
أسماء الوحدات
- استخدم
modelلتمثيل نموذج البيانات المعرّف من طرف المستخدم أو الدوال النقية التي تتحقق منه وتطبّعه - استخدم
runtimeلعلاماتECSالداخلية، وتتبع الأبناء المُولّدين، والأنظمة التي تملك الشجرة الحية للوحدة - استخدم
stateللحالة طويلة العمر التي تقرؤها وتحدّثها عدة أنظمة - استخدم
eventsللرسائل الصادرة وللشيفرة التي تترجم تغيّر الحالة إلى إشعارات خارجية - استخدم
translationلمنطق تحويل البيانات المعرّفة إلى إعدادات runtime أو solver - استخدم
placementلمنطق تموضع الأبناء بعد معرفة الأحجام - تجنب الأسماء العامة مثل
typesأوhelpersأوdisplayعندما يتوفر اسم أكثر دقة
أسماء الأنواع
- يجب أن تتبع الإضافات النمط
Univis<Name>Plugin - يجب أن تتبع مجموعات الجدولة النمط
Univis<Domain>SetأوUnivis<Stage>Set - يجب أن تحتفظ مكوّنات الواجهة العامة بالبادئة
U* - يجب أن تستعمل علامات runtime الداخلية أسماء صريحة مثل
SelectTriggerأوPanelResizeHandleأوUiWorkState - يجب أن تنتهي الموارد التي تضبط السلوك باللاحقة
Settings - يجب أن تنتهي الموارد أو المكوّنات التي تتتبع التقدّم الحي باللاحقة
State
التعليقات
- اجعل تعليقات التنفيذ باللغة الإنجليزية
- فضّل التعليقات التي تشرح القيود أو الثوابت أو سبب وجود فرع معين
- احذف التعليقات التي تعيد فقط ما تقوله السطر التالية حرفيًا
أسماء التوافق والأنماط القديمة
- استخدم
legacy_*فقط عندما تحافظ الشيفرة عمدًا على دلالة قديمة - أبقِ طبقات التوافق المهجورة واضحة في التسمية والتوثيق
- تجنب إضافة أسماء انتقالية جديدة إلا إذا كانت تحمي مسار ترحيل عام حقيقي
قائمة تحقق قبل إعادة التسمية
قبل إنشاء وحدة جديدة أو إعادة تسميتها، تأكد من:
- هل يصف اسم الملف المسؤولية بدلًا من التفصيل التنفيذي؟
- هل يستطيع مساهم جديد أن يعرف هل تنتمي الشيفرة إلى
modelأوruntimeأوstateأوeventsأوtranslationأوplacement؟ - هل يطابق الاسم الجديد أنماط الإضافات والمكوّنات والحالات الموجودة في الوحدات الشقيقة؟
خريطة الصيانة
هذه الصفحة هي الخريطة المختصرة الموجهة للمحافظين على المشروع: من يملك ماذا، وأين توجد الحدود الكبيرة بين الوحدات، وما هي النقاط الحساسة التي تحتاج مراجعة دقيقة.
خريطة الحزم في مساحة العمل
univis_ui: حزمة الواجهة الجامعة وقصة الاستيراد الموصى بها للتطبيقاتunivis_ui_style: موارد الثيم والخطوط والأيقونات المشتركةunivis_ui_engine: نموذج الجذور، solver التخطيط، وجدولة settlement، ومزامنة الرندرunivis_ui_interaction: الالتقاط وحالة التفاعل والتحقق المبني على المؤشرunivis_ui_widgets: الوحدات الجاهزة عالية المستوى المبنية فوق المحرك والتفاعل
خريطة وحدات المحرك
layout::layout_system: حل الجذور، وكبسولات ترتيب الجذور، وتحويلات الشاشة، وحالة settlement لكل rootlayout::univis_node: المكوّنات التي يكتبها المستخدم للعقدة والتخطيط والتموضع المحليlayout::geometry: وحدات الواجهة المنطقية والهوامش والقيود ومساعدات المحاورlayout::core: تتبع البنية والذاكرة المؤقتة والقياس والحل ومساعدات solverlayout::render: مزامنة الـ mesh والمواد بعد استقرار التخطيطlayout::profiling: أدوات التشخيص والطبقة البصرية الاختياريةlayout::registrationوlayout::settlement_loop: ربط pipeline وتنفيذPostUpdateالمحدود
خريطة وحدات الوحدات الجاهزة
- الوحدات البسيطة تبقى في ملف واحد عندما تكون runtime صغيرة
- الوحدات ذات الحالة تقسم حسب المسؤولية:
modelruntimeinteractionvisualsevents
text_labelهو الاستثناء الأكبر لأنه يملك شجرتيmeasure/وrender/
ملكية المناطق الحساسة
- المناطق الحساسة في المحرك والتخطيط:
crates/univis_ui_engine/src/layout/** - المناطق الحساسة في التفاعل:
crates/univis_ui_interaction/src/interaction/** - المناطق الحساسة في الوحدات الجاهزة:
crates/univis_ui_widgets/src/widget/** - قصة الواجهة الجامعة والتوثيق: الجذر
src/وREADME*وdocs/src/**
مناطق المراجعة ذات الأولوية
- تغييرات حل الجذور وترتيب الجذور قد تؤثر في التخطيط والرندر والالتقاط معًا
- تغييرات الكاش و settlement loop قد تصنع regressions واسعة حتى إذا مرت الاختبارات المحلية
- تغييرات قياس النص أو رندره تحتاج تحققًا من التخطيط والرندر معًا
- إعادة هيكلة runtime للوحدات الجاهزة يجب أن تحافظ على قصة الجدولة
Build -> Logic -> Visual -> Events
قواعد المعمارية
تحدد هذه القواعد ما الذي يعد سطحًا عامًا مستقرًا، وما الذي يعد داخليًا، ومتى ينبغي توسيع مساحة العمل بحزمة أو مجلد جديد.
السطح العام
preludeهو قصة الاستيراد المستقرة الموصى بها- الوحدات المسماة مثل
layoutوrenderوinteractionوwidgetعامة لكنها موجهة للتكاملات المتقدمة - الأنواع العامة التي يكتبها المستخدم يجب أن تبقى موثقة عند موضع تعريفها
- طبقات التوافق تبقى على مسارات صريحة ولا تدخل في الـ preludes الموصى بها
السطح الداخلي
internalوinternal_preludeأدوات تنفيذ داخلية لمساحة العمل وليستا عقدًا عامًا مع التطبيقات- الوحدات المخفية مثل
layout::coreوlayout::algorithmsوlayout::componentsوlayout::pipelineيمكن أن تتغير لدعم إعادة هيكلة المحرك - علامات runtime والكاشات وتتبع الأبناء المولدين يجب أن تبقى خاصة بالحزمة أو
pub(super)ما لم تحتجها حزمة أخرى فعلًا - سياسة الحدود الفورية داخل مساحة العمل موثقة في الملف الجذري
ENGINE_BOUNDARY_RULES.md - يمنع
./scripts/check_engine_boundary_guardrails.shظهور imports جديدة من engine internals خارج المحرك أثناء تنظيف الاستثناءات الحالية
متى تضيف حزمة جديدة
أضف حزمة جديدة فقط إذا تحقق واحد على الأقل مما يلي:
- الشيفرة تقدم حدًا reusable يمكن للتطبيقات اختياره بشكل مستقل
- الميزة تحتاج سطح استيراد عامًا منفصلًا أو lifecycle مستقلة للإضافة
- رسم الاعتماديات يصبح أنظف بعزل subsystem واضح
لا تضف حزمة فقط لتقسيم الملفات. ابدأ بالمجلدات والوحدات أولًا.
متى تضيف مجلدًا أو وحدة
- أضف مجلدًا عندما تصبح مسؤولية واحدة مكوّنة من عدة ملفات متعاونة بأدوار واضحة
- أضف وحدة عندما تجعل الملكية أو الاكتشاف أوضح من ملف طويل واحد
- فضّل أسماء المسؤوليات مثل
rootsأوstateأوruntimeأوeventsأوplacement - تجنب الأسماء العامة عندما يتوفر اسم domain أدق
قواعد الاعتماديات
- الوحدات الجاهزة تعتمد على المحرك والتفاعل والستايل، لكن المحرك لا يعتمد على الوحدات الجاهزة
- التفاعل يعتمد على حالة المحرك للجذور والهندسة، لكن المحرك لا يعتمد على التفاعل
- حزم الواجهة الجامعة تعيد تصدير سطوح عامة منتقاة، ويجب ألا تسرّب المساعدات الداخلية بالخطأ
نموذج الأخطاء والتشخيص
تفضّل مساحة العمل التشخيصات القابلة للاسترداد والمحددة النوع بدل الفشل الصامت أو المسارات المعتمة من نوع Result<_, ()>.
القواعد الأساسية
- المشاكل القابلة للاسترداد في runtime يجب أن تفضّل fallback مع تحذير منظّم
- أنواع الخطأ أو المشكلة المعرّفة يجب أن تعرض على الأقل
reasonوactionعندما يكون ذلك مفيدًا - عدم التطابق المخصص للتحقق فقط يجب أن يبقى خلف أوضاع rollout أو shadow validation
- الفحوصات التي تنتهي بـ panic مكانها الاختبارات والأمثلة والثوابت الحقيقية، لا المسارات الساخنة في runtime
شكل التحذير
معظم التحذيرات تتبع هذا الشكل:
- وسم subsystem مثل
[layout/root_resolution]أو[widget/text_label_measure] - سياق entity أو generation عندما يكون متاحًا
reason=...action=...عندما توجد خطوة واضحة يمكن اتخاذها
أمثلة معيارية حالية
- حل الجذور يستعمل
RootResolutionIssueللتمييز بين الكاميرا المفقودة أو الملتبسة أو غير النشطة - قياس النص يستعمل
TextMeasureErrorKindوTextMeasureErrorعندما يفشل إنشاء قياس النص في Bevy - runtime الخاصة بـ select تستعمل
SelectRuntimeErrorعندما تكون شجرة الأبناء المولدة ناقصة - settlement loop وpicking validation يسجلان تحذيرات مرتبطة بالجيل عندما تفشل فحوصات rollout أو عند استهلاك ميزانية التكرار
متى تضيف نوع خطأ جديد
- أضف enum محددًا عندما تتشارك عدة أسباب فشل في موضع استدعاء واحد
- أضف تحذيرًا منظّمًا عندما يستطيع النظام المتابعة لكن المحافظين يحتاجون أثرًا واضحًا
- أبقِ النوع محليًا إذا كان يخدم subsystem واحدة فقط
- رقِّ النوع إلى مستوى أوسع فقط عندما تحتاج وحدة أخرى أن تتفرع على أساسه
اتفاقيات بنية الوحدات الجاهزة
تحدد هذه الصفحة كيف ينبغي تنظيم الوحدات ذات الحالة داخل crates/univis_ui_widgets/src/widget/.
السطح العام
- كل وحدة تعرض مكوّنًا عامًا يكتبه المستخدم مثل
USelectأوUTextFieldأوUPanel - كل وحدة تعرض إضافة باسم
Univis<Name>Plugin - الرسائل الخارجة توضع في
eventsعندما تكون الوحدة تبعثها
التقسيم الداخلي
استعمل هذه المسؤوليات عندما تكبر الوحدة على ملف واحد بسيط:
model: بيانات المستخدم، ومساعدات التطبيع، وأنواع الإعداد العامةruntime: علامات شجرة الأبناء المولدة، والموارد الداخلية، ومساعدات البناءinteraction: معالجة الإدخال وانتقالات الحالةvisuals: مزامنة الألوان والنصوص والهندسة وباقي المخرجات المرئيةevents: الرسائل الخارجة بعد استقرار الحالة
قواعد الجدولة
Build: إنشاء شجرة runtime أو إصلاحهاLogic: الاستجابة للإدخال وتحديث الحالةVisual: مزامنة الشجرة المرئية من أحدث حالةEvents: إرسال الرسائل للخارج بعد استقرار المنطق والمرئيات
أنماط شائعة
select/يستعملmodelوruntimeوinteractionوvisualsوeventspanel/يفصل بين حسابات resize ومنطق cursor وحالة runtime والمرئياتtext_label/يستعملmeasure/وrender/لأنه subsystem يجمع بين التخطيط والرندر
قواعد الإتاحة
- المكوّنات العامة التي يكتبها المستخدم تبقى عامة وموثقة
- علامات runtime وأنواع التتبع الداخلي يجب غالبًا أن تبقى
pub(super) - الاختبارات تبقى قرب الوحدة التي تتحقق منها حتى تظل إعادة الهيكلة محلية
حدود محرك التخطيط
هذه الصفحة هي المرجع الداخلي الذي يحدد أين تبدأ وتنتهي مسؤوليات التخطيط داخل univis_ui_engine.
السطح الذي يكتبه المستخدم
layout::layout_system: نموذج الجذور العام وحالة الجذر المحلولةlayout::univis_node: مكوّنات العقدة والتخطيط والتموضع المحلي العامةlayout::geometry: بدائيات الأحجام والمسافات العامةlayout::imageوlayout::pbr: مساعدين عامين مرتبطين بمدخلات الرندر
pipeline الداخلية للتخطيط
layout::core::hierarchy: تتبع العمق وتحديث الأنساب المخزنةlayout::core::layout_cache: تتبع dirty ومرحلات stage وfrontier queueslayout::core::pass_up: القياس الداخلي ونشر أحجام المحتوىlayout::core::pass_down: مخرجات الحل النهائي وتموضع الأبناءlayout::core::solver: حل الأحجام وربط placementlayout::algorithms: منطق placement الخاص بكل algorithm
حد الرندر
- التخطيط يحل الحجم والموضع المنطقيين
- مزامنة الرندر تستهلك النتائج المحلولة وتحدث الـ mesh والمواد
- رندر النص هو الحالة الرئيسية العابرة للحدود، لذلك تملك
text_labelمنطق القياس والرندر معًا من جهة الوحدات الجاهزة
حد الجدولة
layout::registrationيربط settlement schedule وترتيب المراحلlayout::settlement_loopيملك التنفيذ المحدود وتتبع الأجيال والتحقق من الوصول إلى fixed point- الوحدات الأخرى يجب أن تصف العمل، لا أن تعيد تعريف سياسة settlement العامة
اتجاه الاعتماديات
- حل الجذور قد يغذي hierarchy وsolve وrender sync وpicking
- hierarchy والكاش قد يبطلان المراحل اللاحقة
- render sync يجب ألا يعيد إدخال measure أو solve إلا إذا تغير مُدخل تخطيط حقيقي كتبه المستخدم
- التشخيص والتحقق يمكنهما مراقبة pipeline لكن لا ينبغي أن يعيدا تعريف معناها بصمت
مسار تأليف التوثيق
توضح هذه الصفحة مكان إضافة التوثيق وأمثلة التشغيل الجديدة.
أين تذهب صفحات التوثيق الجديدة
- أضف صفحات الشرح الموجهة للمستخدم إلى
docs/src/enوdocs/src/ar - حافظ على نفس هيكلة المعلومات في الشجرتين
- ضع مواد الترحيل داخل
docs/src/*/migration - اترك التفاصيل الدقيقة للتواقيع والحقول إلى
rustdocبدل تضخيم صفحات الشرح
أين تذهب أمثلة التشغيل الجديدة
- إذا أضفت مثالًا قابلًا للتشغيل أو أعدت مثالًا قديمًا، فضعه داخل الـ crate المالكة للميزة
- إذا عاد عرض متكامل على مستوى الواجهة المجمعة، يبقى الجذر
examples/موطنه المقصود - حدّث فهرس الأمثلة في اللغتين عندما تتغير حالة التوفر
- أضف تعليقًا قصيرًا داخل المثال يشير إلى صفحة الشرح المرتبطة عندما يكون المثال مرجعيًا
كيفية إضافة صفحات متقابلة بين اللغتين
- أنشئ الصفحة الإنجليزية
- أنشئ الصفحة العربية النظيرة في المسار المقابل
- أضف الصفحتين إلى
docs/src/SUMMARY.md - حدّث هدف مبدّل اللغة إذا كانت الصفحة امتدادًا لفصل موجود
كيفية إضافة rustdoc عام
عند إضافة سطح API عام جديد:
- أضف أو وسّع توثيق crate أو الوحدة إذا كان السطح الجديد يغير مسار الاكتشاف
- وثّق النوع العام أو الإضافة عند موضع تعريفها
- فضّل أمثلة
no_runالقصيرة - أخفِ المساعدات الداخلية إذا كانت ستلوّث القصة العامة في الوثائق المولدة
متى تحدّث README وchangelog
- حدّث
README.mdوREADME_AR.mdإذا تغيّرت قصة الدخول من GitHub - حدّث
changelog.mdعند وجود تغيير ملحوظ في التوثيق أو الأمثلة أو السطح العام - استخدم اصطلاحات التسمية عند إضافة وحدات داخلية جديدة أو إعادة تسميتها
نشر الوثائق
تشرح هذه الصفحة كيف يتم توليد النسخة المنشورة من الوثائق انطلاقًا من المستودع.
الرابط العام
- رابط الوثائق المنشورة:
https://univiseditor.github.io/univis_ui/
ما هو المصدر المرجعي
- مصدر الكتاب موجود داخل
docs/ - يعرّف
docs/book.tomlإعداداتmdBook - تعيش الشجرتان العربية والإنجليزية داخل
docs/src/arوdocs/src/en - يولّد
mdbook build docsالموقع الثابت داخلtarget/book/docs
نموذج النشر
- يبقى التحقق ضمن
.github/workflows/docs_examples_api.yml - يتولى
.github/workflows/docs_publish.ymlوحده مهمة النشر - تُبنى النسخة المنشورة من نفس شجرة
docs/التي يستخدمها المساهم محليًا - الوجهة العامة المقصودة للنشر هي صفحات GitHub
مسار العمل المحلي للمساهم
mdbook build docs
mdbook serve docs -n 127.0.0.1 -p 3000
يجب أن يبقى هذا المسار المحلي هو الطريقة المرجعية لمعاينة التغييرات قبل رفعها.
ما الذي يجب التحقق منه في النسخة المنشورة
- أن صفحة الوثائق الرئيسية تعمل بشكل صحيح
- أن الشجرة الإنجليزية قابلة للوصول في النسخة المنشورة
- أن الشجرة العربية قابلة للوصول في النسخة المنشورة
- أن مبدّل اللغة يعمل بين الصفحات النظيرة
- أن روابط معرض الأمثلة وصفحات الترحيل ما زالت صحيحة
صفحات مرتبطة
قائمة مراجعة التوثيق
استخدم هذه القائمة عند مراجعة طلبات الدمج المعتمدة على التوثيق.
- اكتمل
./scripts/check_quality.shقبل الدمج - اكتمل
./scripts/check_representative_examples.shقبل الدمج - اكتمل
mdbook build docsعندما يتغير التوثيق أو الأمثلة أو نصوص الجذر - تم تحديث الصفحتين العربية والإنجليزية معًا عندما يكون التغيير موجّهًا للمستخدم
- أضيفت الصفحة إلى
docs/src/SUMMARY.md - وُضع المثال داخل الـ crate المالكة
- تم تحديث فهرس الأمثلة عند إضافة مثال جديد
- أضيفت روابط عكسية من الأمثلة المرجعية إلى صفحات الشرح عند الحاجة
- أضيف
rustdocللسطح العام الجديد عند موضع تعريفه - لم تُرفع المساعدات الداخلية إلى واجهة الوثائق المولدة دون قصد
- تستخدم الأوامر في التوثيق استدعاءات الأمثلة المرتبطة بالـ package عند الحاجة
- تم تحديث ملاحظات التحقق البصري عندما يتغير سلوك الأمثلة المرجعية أو سلوك الرندر
- تم تحديث
READMEوREADME_ARإذا تغيّرت قصة الدخول - تم تحديث
changelog.mdإذا كان التغيير ملحوظًا
جودة هندسية
- اكتمل
./scripts/check_public_api_surface.shعندما يتغير سطح الاستيراد أو تركيب الإضافات أو تعريض المسارات المهجورة - اكتمل
./scripts/check_engine_boundary_guardrails.shعند نقل المنطق بينengineوinteractionوwidgets - لم يضف التغيير hotspot كبيرة في ملفات المصدر دون سبب واضح
- لم يوسّع التغيير السطح العام أو الاقتران بلا حاجة موجّهة للمستخدم
- لم يضف التغيير اعتمادًا جديدًا على
univis_ui_engine::internalأو وحدات المحرك المخفية خارج crate المحرك - بقيت التسمية منسجمة مع صفحات التسمية والمعمارية الخاصة بالمحافظين
التحقق البصري
تحدد هذه الصفحة فحوص التحقق البصري اليدوية الخفيفة التي ما تزال مهمة حتى بعد نجاح الوثائق وAPI Docs.
الهدف
- التقاط الانحدارات التي تُبنى بنجاح لكن تبدو خاطئة
- الحفاظ على الثقة البصرية في العرض الحي الحالي
- إبقاء التحقق البصري مركزًا على الأمثلة والحزم الموجودة في هذا الفرع
السياسة الحالية
- تبقى لقطات الشاشة مواد تحضير يدوية قبل الإصدار، وليست خرجًا إجباريًا في CI
- يعرض معرض الأمثلة المصادر القابلة للتشغيل حاليًا فقط
- ما يزال التحقق البصري وقت التشغيل مهمًا لكثافة التخطيط ومظهر النص وإدراك الوحدات الجاهزة وصقل الواجهة
الهدف الحي للتحقق
شغّل الحزمة الحية الحالية عندما يكون التغيير بصريًا أو تفاعليًا بدرجة واضحة:
cargo run --manifest-path android/android_phone_app/Cargo.toml
ما الذي يجب ملاحظته
حزمة Android الحالية
- بقاء سطح التطبيق المتمركز متوازنًا داخل عرض ضيق
- بقاء
UTextFieldوUToggleوUSeekBarوUButtonواضحة بصريًا وسهلة الاستهداف - قراءة المسافات والكثافة جيدًا من دون إطار هاتف مصطنع
ما المتوقع قبل الإصدار
- نفّذ مرورًا بصريًا يدويًا واحدًا على الأقل عندما يمس التغيير الرندر أو دلالات التخطيط أو تقديم الواجهة الأساسية
- التقط لقطات شاشة فقط عندما تساعد فعلاً في التواصل مع الإصدار أو جودة المعرض
- لا تجعل توليد لقطات الشاشة عائقًا أمام تدفق المساهمات اليومية
صفحات مرتبطة
جاهزية الإصدار
هذه الصفحة هي قائمة التحقق النهائية قبل قطع alpha التالية.
أدلة التحضير المحلية الحالية لـ 0.3.0 مسجلة في ملف الجذر RELEASE_PREP_0.3.0.md.
الفحوص التي يجب إعادة تشغيلها
أعد فحص هذه الخطوات بالتسلسل:
cargo check --workspace --all-targets
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
./scripts/check_representative_examples.sh
ويبقى التحقق اليدوي وقت التشغيل مستحسنًا لمرور واحد على الأقل عبر الحزمة الحية الحالية.
اتساق الوثائق والترحيل والإصدار
تأكد من أن هذه الملفات تصف الواقع الحالي نفسه:
README.mdREADME_AR.mdMIGRATION.mdMIGRATION_AR.mdRELEASE_NOTES.mdchangelog.md
القائمة المحلية الحالية
-
mdbook build docs -
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps -
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targetsعبر./scripts/check_representative_examples.sh -
./scripts/check_representative_examples.sh -
./scripts/verify_alpha_release.sh - أن تذكر ملاحظات الإصدار وصفحات الترحيل القصة الحالية نفسها لتوفر الأمثلة
- مرور بصري يدوي واحد على الحزمة ذات الطابع Android وعلى الأمثلة الحالية المرتبطة من التحقق البصري
- تأكيد GitHub Actions للبوابات نفسها
- فرز وإغلاق ملاحظات RC
قرار إزالة الطبقات المتوافقة
في alpha التالية يكون القرار:
- لا تزل
UScreenRootأوUWorldRootتلقائيًا ضمن القطع الحالي - أبقهما كطبقتي توافق مهجورتين حتى تنتهي مراجعة استقرار أخرى
- أعد النظر في الإزالة فقط بعد شحن alpha التالية ووصول التغذية الراجعة
أدوار ملفات الجذر
README.md: قصة الدخول وأسرع نقطة بدايةREADME_AR.md: صفحة الدخول العربيةMIGRATION.md: مسار الترقية من الوثائق والأمثلة والافتراضات الأقدمMIGRATION_AR.md: مسار الترحيل العربيRELEASE_NOTES.md: الملخص الحالي على مستوى الإصدار alphaRELEASE_PREP_0.3.0.md: أدلة التحقق المحلية قبل قطع0.3.0changelog.md: السجل الزمني المرتب حسب التواريخ
صفحات مرتبطة
الاختبارات والتحقق
اختبارات الوحدة
لتخفيف الضغط على الأجهزة الأضعف، شغّل الاختبارات هدفًا واحدًا في كل مرة:
cargo test --release <test_name> --lib
التحقق من الجودة
./scripts/check_quality.sh
./scripts/check_representative_examples.sh
./scripts/check_examples_serial_release.sh
يشغّل ./scripts/check_quality.sh ما يلي:
cargo fmt --all --checkcargo clippy --workspace --all-targetsمع قائمة السماح الحالية للديون المعروفة المرتبطة بـ Bevycargo check --workspace --all-targets./scripts/check_public_api_surface.sh./scripts/check_structure_guardrails.sh./scripts/check_engine_boundary_guardrails.shcargo test --workspace --lib
أما ./scripts/check_representative_examples.sh فأصبح يترجم حزمة Android الحالية ثم يفحص أي أدلة أمثلة ما تزال موجودة في مساحة العمل.
ويظل ./scripts/check_examples_serial_release.sh مفيدًا عندما يحتوي الفرع فعليًا على أهداف examples/*.rs؛ أما في هذا الفرع فقد يكتفي بالإبلاغ عن عدم وجود أمثلة تشغيلية داخل مساحة العمل.
التحقق من الوثائق
cargo doc --no-deps
mdbook build docs
خطوط الأداء الأساسية
استخدم هذه الملفات الملتزم بها:
perf_baselines/current_max/2026-04-05/solver_benchmarks.txtperf_baselines/current_max/2026-04-05/runtime_benchmarks.txtperf_baselines/current_max/2026-04-05/manifest.json
التحقق داخل CI
ما تزال GitHub Actions تتحقق من الجودة والوثائق وAPI Docs وفحوص الأمثلة الحالية عبر سير العمل الحالية.
التحقق التسلسلي على الأجهزة الضعيفة
# كل اختبارات lib واحدة تلو الأخرى
./scripts/test_lib_serial_release.sh
# كل أمثلة مساحة العمل الحالية التي يعرفها السكربت
./scripts/check_examples_serial_release.sh
# حزمة Android الحالية مع فحص أمثلة مساحة العمل
./scripts/check_representative_examples.sh
# التحقق الكامل: اختبارات lib + الأمثلة الحالية
./scripts/verify_serial_release.sh
# التحقق التسلسلي لحزمة مساحة عمل محددة
./scripts/test_lib_serial_release.sh -p univis_ui_engine
./scripts/check_examples_serial_release.sh -p univis_ui_engine
./scripts/verify_serial_release.sh -p univis_ui_engine
# حزمة Android مباشرة
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
# تحقق alpha قبل الإصدار
./scripts/verify_alpha_release.sh
# بناءات alpha فقط من دون تحقق
./scripts/package_alpha_serial.sh --no-verify
إستراتيجية عملية قبل الدمج
- شغّل اختبارات الوحدة المرتبطة بالتغيير
- شغّل
./scripts/check_quality.sh - شغّل
./scripts/check_representative_examples.sh - شغّل
cargo check --workspace --examples - شغّل حزمة Android عندما يمس التغيير السطح الحي الحالي
- استخدم التحقق البصري عندما يكون التغيير ثقيلًا في الرندر أو التخطيط أو التفاعل
المطلوب قبل قطع alpha التالية
./scripts/check_quality.shmdbook build docscargo doc -p univis_ui_style --no-depscargo doc -p univis_ui_engine --no-depscargo doc -p univis_ui_interaction --no-depscargo doc -p univis_ui_widgets --no-depscargo doc -p univis_ui --no-depscargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets./scripts/check_representative_examples.sh- مرور يدوي واحد عبر حزمة Android والأمثلة الحالية المرتبطة
- مرور واحد عبر جاهزية الإصدار
سياسة لقطات الشاشة
- تبقى لقطات الشاشة مواد تحضير يدوية قبل الإصدار
- يمكن لمعرض الأمثلة أن يربط إلى مراجع بصرية ثابتة
- توليد لقطات الشاشة ليس بوابة CI إلزامية في خط alpha الحالي
تقرير التحقق من الأمثلة
نطاق التحقق الحالي
يتحقق هذا الفرع فقط من ملفات الأمثلة الموجودة فعليًا في المستودع.
الأوامر
افحص أمثلة مساحة العمل:
cargo check --workspace --examples
افحص حزمة Android المستقلة:
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
شغّل مسار التحقق التمثيلي في وضع release:
./scripts/check_representative_examples.sh
مصادر الأمثلة الحالية
android/android_phone_app/examples/android_phone.rsexamples/responsive_layout_test.rsexamples/toggle_seekbar.rsexamples/z_order_hierarchy.rsexamples/grid/auto_flow.rsexamples/grid/columns.rsexamples/grid/item_placement.rsexamples/grid/tracks.rsexamples/layout/flex.rsexamples/layout/masonry.rsexamples/layout/radial.rsexamples/layout/stack.rsexamples/widgets/containers.rsexamples/widgets/controls.rsexamples/widgets/display.rsexamples/widgets/inputs.rs
ما يزال سلوك Runtime يحتاج فحوص smoke يدوية بنافذة فعلية للتفاعل والدقة البصرية.
مصفوفة التوافق
تاريخ خط الأساس للتحقق: 3 أبريل 2026.
المعاني:
نعم: مدعوم ومتحقق منه في خط الأساس الحالي.جزئي: مدعوم جزئيًا مع قيود معروفة.لا: غير مدعوم في خط الأساس الحالي.مؤجل: تحقق مخطط له لكنه أُجِّل عمدًا في هذه الدورة.
| القدرة | واجهة الشاشة | واجهة العالم (ثنائي الأبعاد) | واجهة العالم (ثلاثي الأبعاد) | مصدر التحقق |
|---|---|---|---|---|
| التشغيل اليدوي السريع في هذا الفرع | نعم | مؤجل | مؤجل | الهدف الحي الحالي هو android/android_phone_app، انظر خطة اختبارات Smoke |
| التحقق البنيوي في هذا الفرع | نعم | جزئي | جزئي | cargo check --workspace --all-targets وفحص حزمة Android وسكربتات الأمثلة فقط عندما تكون المصادر التشغيلية موجودة |
| مسار الرندر الأساسي | نعم | نعم | نعم | تحقق على مستوى المصدر مع الأمثلة الحالية القابلة للتشغيل عندما تكون متاحة |
| تفاعل المؤشر | نعم | نعم | نعم | تُحسم الكاميرا من كل root عبر ResolvedRootUi، ويُفضّل UiCameraRef::Entity في المشاهد متعددة الكاميرات |
| الالتقاط مع مراعاة القص | نعم | نعم | نعم | فحص قص الأسلاف داخل خلفية الالتقاط |
تغيير حجم UPanelWindow | نعم | نعم | نعم | منطق تغيير الحجم يحسب حركة المؤشر عبر كاميرا الجذر ومستوى اللوحة |
سلوك/أحداث UTextField | نعم | نعم | نعم | مضمّن افتراضيًا عبر UnivisWidgetPlugin |
التحديثات الديناميكية لـ UBadge | نعم | نعم | نعم | مضمّنة افتراضيًا عبر UnivisWidgetPlugin |
سلوك UScrollContainer | نعم | نعم | نعم | التفاعل يتبع مسار كاميرا الجذر المحلولة |
خصائص UPbr | لا | لا | نعم | مخصصة لمسار UI3d |
مرتبط
خطة اختبارات Smoke
الهدف
تقديم قائمة تشغيل يدوية خفيفة بعد اجتياز التحقق البنيوي.
الفحص المسبق
ابدأ بالتحقق البنيوي أولًا:
./scripts/check_representative_examples.sh
./scripts/verify_serial_release.sh
سيناريوهات التشغيل اليدوي
- سلامة حزمة الشاشة الضيقة بطابع Android
- فحص أمثلة مساحة العمل المرتبطة بمناطق التخطيط أو الوحدات المتأثرة
- مرور سريع على وضوح النصوص وعناصر التحكم
الأوامر
cargo run --manifest-path android/android_phone_app/Cargo.toml
لأمثلة مساحة العمل، استخدم cargo run --example <name> مع مدخل من فهرس الأمثلة.
معايير النجاح
- عدم حدوث panic عند البداية
- فتح الحزمة بطابع Android مع بقاء سطح التطبيق المقروء داخل العرض الضيق
- بقاء
UTextFieldوUToggleوUSeekBarوUButtonمتماسكة بصريًا وتفاعليًا - فتح أمثلة مساحة العمل المرتبطة وبقاؤها متماسكة بصريًا
تشخيص الإخفاق
- سجّل السطح الذي فشل والعرض الظاهر للمشكلة
- أعد تشغيل حزمة Android مع
RUST_BACKTRACE=1إذا كان الإخفاق وقت التشغيل - صنّف المشكلة: compile أو runtime أو widget أو rendering
- أضف ملاحظة في issue مع أمر إعادة الإنتاج وبيانات البيئة
راجع أيضًا: التحقق البصري وجاهزية الإصدار.
استكشاف الأخطاء
1) العناصر لا تظهر
تحقق من:
- وجود كاميرا متوافقة مع الجذر الحالي.
- وجود جذر مبني على
URootUi. - أن
ComputedSizeليس صفرًا. - أن
VisibilityليستHidden.
2) التفاعل لا يعمل
تحقق من:
- وجود
UInteractionعلى الكيان التفاعلي. - عدم اعتراض ابن/أب الالتقاط بشكل غير مقصود.
- عدم وجود قص ancestor يلغي hit.
3) النص يخرج خارج container مقصوص
- تأكد من
UClip { enabled: true }على ancestor الصحيح. - تأكد أن
UnivisTextPluginيعمل حتى يطبّقsync_text_label_meshesالقص المحلي وsync_text_clipper_materialsقص الأسلاف.
4) التمرير لا يعمل
- الكيان الحاوي يحمل
UScrollContainer+UInteraction. - الماوس في حالة hover على الحاوية.
- المحتوى أطول/أعرض من النافذة (overflow > 0).
5) panel resize لا يعمل
- تأكد من إضافة
UPanelWindowمعUPanel. - افحص
min_width/min_heightوborder_hit_thickness. - تأكد أن الواجهة ضمن مساحة قابلة للالتقاط من الكاميرا الحالية.
مراجع مرتبطة
الترحيل والقيود
يتتبع هذا القسم خطوات الترحيل المرتبطة بالتوثيق حول السطح العام الحالي للمشروع.
ما الذي تغيّر مؤخرًا
- توحّد سطح الجذور العامة حول
URootUi - أصبح فهرس الأمثلة يعرض فقط المصادر الموجودة في هذا الفرع
- أصبحت الوثائق موجودة داخل كتاب ثنائي اللغة واحد في
docs/
ابدأ من هنا
- ترحيل سطح التوثيق والأمثلة
- ترحيل الجذور إلى
URootUi - حالة التوافق القديم
- ترحيل مسارات الأمثلة
- القيود الحالية
ما الذي يغطيه هذا القسم
- كيفية تحديث كود الجذور الأقدم
- كيفية الانتقال من نمط الاكتشاف القديم في التوثيق
- أين توجد مصادر الأمثلة الحالية
- ما الذي يعتبر رسميًا الآن وما الذي بقي فقط للتوافق مع القديم
- ما هي القيود التي ما زالت موجودة فعلًا في المرحلة alpha الحالية
ترحيل سطح الوثائق والأمثلة
تشرح هذه الصفحة شكل الوثائق والأمثلة الحالي.
ما الذي تغيّر
- الوثائق موجودة في
mdBookثنائي اللغة واحد داخلdocs/ - الفصول العربية والإنجليزية متقابلة تحت
SUMMARY.mdواحد - فهرس الأمثلة يعرض فقط ملفات المصدر الموجودة في هذا الفرع
- حزمة العرض المستقلة هي
android/android_phone_app - قصة الجذور تدور حول
URootUi
مسار الاكتشاف الحالي
README.mdأوREADME_AR.mddocs/src/index.md- فصل الشرح المناسب
- قائمة الأمثلة الحالية داخل
docs/src/*/examples/index.md rustdocالمولد للمسارات والتواقيع الدقيقة
أوامر الأمثلة في هذا الفرع
استخدم هذه الأوامر مع شجرة العمل الحالية:
cargo run --manifest-path android/android_phone_app/Cargo.tomlcargo check --workspace --examplescargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
وللعرض بحسب المهمة، راجع:
ترحيل وثائق الجذور
إذا كنت قد تعلّمت نموذج الجذور عبر UScreenRoot أو UWorldRoot، فابدأ الآن من:
المصادر المرجعية الحالية
- قصة الدخول:
README.md/README_AR.md - صفحات الشرح:
docs/src/en/*وdocs/src/ar/* - الأمثلة الحالية:
docs/src/en/examples/index.mdوdocs/src/ar/examples/index.md - مرجع
API: ناتجcargo doc --no-deps -p univis_ui
ترحيل الجذور إلى URootUi
أصبح URootUi هو الواجهة العامة الرسمية للجذور.
التحويل من القديم إلى الجديد
UScreenRoot->URootUi::screen()UWorldRoot { size, is_3d: false }->URootUi::world_2d(size)UWorldRoot { size, is_3d: true }->URootUi::world_3d(size)
أهم التغييرات الدلالية
URootUi::screen()أصبح جذر واجهة ثابتة على الشاشة وحقيقيًا وثابتًا على منفذ العرض.- كل
URootUiيعمل ككبسولة تراكب مغلقة. UVal::Pxيعني وحدات UI منطقية، لا pixels شاشة فعلية.- الحجم الفيزيائي في فضاء العالم يُحسم عبر
meters_per_unit.
ملاحظات التوافق المرحلي
- يبقى
UScreenRootوUWorldRootطبقتي توافق مهجورتين. - وهما الآن مساران صريحان للترحيل فقط، ولم يعودا جزءًا من قصة
preludeالموصى بها. - هدف الإزالة الحالي هو أول alpha بعد
0.3.0لا يعود يحتاج دعم الترحيل المبني على هذه الطبقات. - اضبط
meters_per_unitصراحة عندما تحتاج حجمًا فيزيائيًا محددًا لجذر العالم.
صفحات مرتبطة
حالة التوافق القديم
تشرح هذه الصفحة مسارات التوافق الخاصة بالترحيل التي ما تزال متاحة عمدًا، وما الذي تم تخفيف التركيز عليه بالفعل، وما الذي يُتوقع أن يبقى على المدى الطويل.
التصنيف العام
| العنصر | الحالة الحالية | المسار الموصى به | الاتجاه المخطط |
|---|---|---|---|
URootUi وURootUi::screen() وURootUi::world_2d(...) وURootUi::world_3d(...) | الواجهة العامة الرسمية | استعملها مباشرة | تبقى على المدى الطويل |
UiSpace وUiCameraRef وUiCanvasSize | أنواع دعم رسمية | استعملها مباشرة | تبقى على المدى الطويل |
UScreenRoot | طبقة مهجورة على مسار صريح فقط | URootUi::screen() | يتم تقليل التركيز عليها الآن؛ وهدف الإزالة الحالي هو أول alpha بعد 0.3.0 لا يعود يحتاج دعم الترحيل المبني على هذه الطبقة |
UWorldRoot | طبقة مهجورة على مسار صريح فقط | URootUi::world_2d(size) أو URootUi::world_3d(size) | يتم تقليل التركيز عليها الآن؛ وهدف الإزالة الحالي هو أول alpha بعد 0.3.0 لا يعود يحتاج دعم الترحيل المبني على هذه الطبقة |
meters_per_unit = 1.0 على URootUi | مفتاح توافق صريح داخل الواجهة الرسمية | استعمله فقط عندما تحتاج الحجم الفيزيائي التاريخي نفسه لجذور العالم القديمة | يبقى على المدى الطويل كمفتاح اختياري صريح، لا كقصة افتراضية |
ترجمة التوافق داخليًا
هذه العناصر ليست القصة العامة الموصى بها، لكنها ما تزال موجودة داخليًا بينما يستقر سطح alpha:
- طبقات الجذور القديمة تتحول أولًا إلى مدخلات الجذر الرسمية قبل بدء حسم الكاميرا وحجم الـ canvas
- طبقة المحاذاة scalar القديمة تتحول نحو نموذج المحاذاة الممتد قبل قرارات التمركز
- مسار flex الرئيسي القديم ما يزال موجودًا داخليًا كتوافق، بينما تبقى حقول grow/shrink الرسمية هي المفضلة
قواعد الصيانة
- لا تضف
UScreenRootأوUWorldRootإلىpreludeالموصى بها - لا تضف أمثلة جديدة تعتمد على طبقات الجذور المهجورة
- أبقِ نصوص README ووثائق الترحيل متطابقة مع هذه الصفحة قبل كل قطع alpha
نافذة الإزالة المخططة
- الهدف الحالي: إزالة
UScreenRootوUWorldRootفي أول alpha بعد0.3.0إذا بقيت ملاحظات الترحيل نظيفة - أعد تقييم هذا الهدف قبل القطع إذا بقيت أمثلة منشورة أو أدلة ترحيل أو تقارير مستخدمين تعتمد على هذه الطبقات
مرتبط
ترحيل مسارات الأمثلة
تسجل هذه الصفحة مواقع الأمثلة الحالية.
المسارات الحالية
- عرض حزمة Android:
android/android_phone_app - أمثلة جذر مساحة العمل:
examples/*.rs - أمثلة grid:
examples/grid/*.rs - أمثلة layout:
examples/layout/*.rs - أمثلة widgets:
examples/widgets/*.rs
الأوامر الحالية
شغّل التطبيق ذي الطابع Android:
cargo run --manifest-path android/android_phone_app/Cargo.toml
افحص كل أمثلة مساحة العمل المسجلة في Cargo:
cargo check --workspace --examples
افحص حزمة Android المستقلة:
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
صفحات مرتبطة
القيود الحالية
هذه الصفحة تجمع القيود الحالية المؤكدة من الكود، حتى تبقى إعدادات الاستخدام واضحة ومتوقعة.
اعتماد التفاعل على الكاميرا
univis_picking_backendيحسم الكاميرا من كلURootUiعبرResolvedRootUi، ولا يعتمد علىCamera2dبشكل صلب.- تغيير حجم
UPanelWindowيتبع المسار نفسه المبني على كاميرا الجذر المحلولة. - النتيجة العملية: يبقى التفاعل الموثوق مشروطًا بقدرة كل root نشط على حل كاميرا تملك viewport صالحًا.
- في المشاهد متعددة الكاميرات، يُفضّل استخدام
UiCameraRef::Entity(...)بدل الاعتماد على الحل التلقائي.
ملاحظات Runtime للوحدات الجاهزة
UnivisUiPluginيضيفUnivisWidgetPluginتلقائيًا.UnivisWidgetPluginيضم الآن Runtime المدمج الخاص بـUTextFieldوUBadgeافتراضيًا.- تبقى الإضافات المخصصة نفسها متاحة عندما تريد سطح widgets أضيق.
- ما تزال أنظمة Runtime الخاصة بـ
UTagمحدودة، لذا اختبر المشاهد الثقيلة بالوسوم يدويًا.
مصادر التحقق
crates/univis_ui_interaction/src/interaction/picking.rscrates/univis_ui_widgets/src/widget/panel.rscrates/univis_ui_widgets/src/widget/mod.rscrates/univis_ui_widgets/src/widget/text_field.rscrates/univis_ui_widgets/src/widget/badge.rscrates/univis_ui_engine/src/layout/layout_system.rs
سجل التغييرات
Changelog
All notable changes to this project will be documented in this file.
[Unreleased]
Added
- 3D Text Rendering: Added full support for rendering
UTextLabelin 3D using standard PBR lighting. Text now accurately reacts to scene lighting and shadows just like standard 3D meshes. - 3D Text Example: Added
examples/text_3d.rsto demonstrate PBR-lit 3D text labels alongside normal widgets and scene lights. - 2D Picking Example: Added
examples/picking_2d.rsto demonstrate 2D UI picking interactions.
Fixed
- 3D Text Scaling: Fixed an issue where text meshes ignored the root UI scale (
ui_to_world_scale) in 3D. 3D text now correctly and automatically scales to match the physical node dimensions (default0.001scale) without requiring manual Transform scaling. - Shader Pipeline Panics: Resolved
Validation Error: Pipeline layout mismatchpanics occurring when using the wrong material bind group in 3D UI nodes. PBR widgets and text SDF shaders now correctly bind to@group(3). - UI Picking Math: Fixed UI picking math scaling and interaction detection for 3D elements, specifically ensuring hit tests work accurately under scaled projections and when nodes are nested.
- Widget Behaviors: Addressed issues with widgets like
seekbarnot responding interactively unless properly configured within panels.
Introduction
univis_ui is a UI framework built on top of Bevy, using SDF-based rendering for crisp 2D and 3D interfaces.
This book is the full operational reference for the project. It covers:
- project architecture and core modules
- runtime composition through
UnivisUiPlugin - layout components (
UNode,ULayout,USelf) and advanced extensions - picking and interaction (
UInteraction) - built-in widgets, behavior, and emitted events
- rendering, clipping (
UClip), performance, and profiling - practical example history, static references, and current runnable paths
Scope
- This book documents the actual repository state.
- Chapters reference concrete paths in
crates/*/src/, the current Android demo package, and the bilingual examples catalog. - If code and docs diverge, treat the source code as the ground truth.
Requirements
- Rust (recent stable toolchain)
- Bevy
0.18.1(viaCargo.toml) - Basic ECS knowledge is recommended
Build Books
cargo install mdbook
mdbook build docs
Serve locally:
mdbook serve docs -n 127.0.0.1 -p 3000
Hosted docs URL:
https://univiseditor.github.io/univis_ui/
Guides vs API Docs
- Use this book for concepts, migration notes, and workflow guidance.
- Use generated
rustdocfor exact type paths, fields, and signatures.
Generate the API docs with:
cargo doc --no-deps -p univis_ui
Where To Look Next
- example availability map: Examples
- curated availability view: Example Gallery
- related API index: API Reference
- related migration notes: Migration and Limitations
Quick Start
1) Add Dependency
[dependencies]
univis_ui = "0.3.0"
2) Minimal App
use bevy::prelude::*;
use univis_ui::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(UnivisUiPlugin)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands
.spawn((
URootUi::screen(),
UNode {
width: UVal::Percent(1.0),
height: UVal::Percent(1.0),
background_color: Color::srgb(0.08, 0.1, 0.14),
..default()
},
ULayout {
display: UDisplay::Flex,
justify_content: UJustifyContent::Center,
align_items: UAlignItems::Center,
..default()
},
))
.with_children(|root| {
root.spawn(UTextLabel::new("Hello Univis UI"));
});
}
3) Root Choices
URootUi::screen()for real HUD and screen-fixed overlays.URootUi::world_2d(size)for flat world-space UI.URootUi::world_3d(size)for world-space UI that uses the 3D material path.URootUi::world_2d_fit_content()andURootUi::world_3d_fit_content()size world roots from measured content.UVal::Pxmeans logical UI units, not literal display pixels.UiCanvasSize::Viewportfollows the resolved camera viewport.UiCanvasSize::FitContent { min, max }measures logical canvas size from content and clamps it when needed.- World-space physical size is derived as:
world_size = canvas_size * meters_per_unit
4) What UnivisUiPlugin Adds
- Interaction:
UnivisInteractionPlugin - Engine:
UnivisEnginePlugin - Style/fonts/icons:
UnivisUiStylePlugin - Widgets:
UnivisWidgetPlugin
5) Important Notes
UnivisWidgetPluginnow auto-registers the built-inUTextFieldandUBadgeruntime systems.UnivisScrollViewPluginis included by default inUnivisWidgetPlugin.- Interaction resolves the camera from each
URootUi. - In multi-camera scenes, prefer binding the root explicitly with
UiCameraRef::Entity. UScreenRootandUWorldRootremain available only as deprecated compatibility wrappers on explicit paths such asunivis_ui::layout::layout_system::{UScreenRoot, UWorldRoot}.- Set
meters_per_unitexplicitly when you need a specific physical size for world-space roots. - For a task-oriented setup checklist and recommended first runs, continue with Plugin Setup and First Examples.
If you compose widgets narrowly without UnivisWidgetPlugin, you can still add UnivisTextFieldPlugin or UnivisBadgePlugin directly.
6) Direct Crate Mode (Advanced)
use bevy::prelude::*;
use univis_ui_engine::prelude::*;
use univis_ui_engine::UnivisEnginePlugin;
use univis_ui_interaction::interaction::UnivisInteractionPlugin;
use univis_ui_style::style::UnivisUiStylePlugin;
use univis_ui_widgets::widget::UnivisWidgetPlugin;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(UnivisUiStylePlugin)
.add_plugins(UnivisEnginePlugin)
.add_plugins(UnivisInteractionPlugin)
.add_plugins(UnivisWidgetPlugin)
.run();
}
Related Examples
Related Migration Notes
API Entry Points
univis_ui::UnivisUiPluginunivis_ui::preludeunivis_ui::layout::layout_system::{UScreenRoot, UWorldRoot}for explicit legacy compatibility onlyunivis_ui_engine::layout::layout_system::URootUiunivis_ui_engine::layout::univis_node::{UNode, ULayout}
Where To Look Next
- related example:
responsive_layout_test - related setup page: Plugin Setup and First Examples
- related API index: API Reference
- related migration page: Root API Migration to
URootUi
Plugin Setup and First Paths
This page is the shortest task-oriented path after Quick Start.
Use it when you want one page that answers two questions:
- which plugins do I really get by default?
- what should I open or run first for the task I care about?
Current Branch Note
The examples catalog lists only source files that are present in this branch.
The standalone Android-style package under android/android_phone_app is the best full-screen demo.
Facade Setup
If you add UnivisUiPlugin, you already get:
UnivisUiStylePluginUnivisEnginePluginUnivisInteractionPluginUnivisWidgetPlugin
This is the recommended path for most applications.
Widget Runtime Coverage
UnivisUiPlugin includes UnivisWidgetPlugin, and that default widget surface now includes:
UnivisTextFieldPluginforUTextFieldbehavior and eventsUnivisBadgePluginfor dynamicUBadge/UTagupdates
If you compose plugins manually around UnivisWidgetPlugin, you do not need extra widget runtime plugins anymore:
use bevy::prelude::*;
use univis_ui_engine::UnivisEnginePlugin;
use univis_ui_interaction::interaction::UnivisInteractionPlugin;
use univis_ui_style::style::UnivisUiStylePlugin;
use univis_ui_widgets::widget::UnivisWidgetPlugin;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(UnivisUiStylePlugin)
.add_plugins(UnivisEnginePlugin)
.add_plugins(UnivisInteractionPlugin)
.add_plugins(UnivisWidgetPlugin)
.run();
}
Use the dedicated widget plugins directly only when you intentionally want a narrower widget surface than UnivisWidgetPlugin.
Camera Setup
- interaction and panel resizing resolve the camera from each
URootUi - a simple
Camera2dis enough for the smallest screen-space scenes - in multi-camera scenes, prefer
UiCameraRef::Entity(camera_entity)
Best-First Paths
Basic Screen HUD
Start with:
Focus on:
- the smallest facade-level boot path
- viewport-fixed HUD and screen-root behavior
Android App Screen
Run this:
cargo run --manifest-path android/android_phone_app/Cargo.toml
Focus on:
- composing a clean Android-style application surface inside
URootUi::screen() - combining
UTextField,UToggle,USeekBar, andUButtonin one narrow screen - checking whether your mobile-like spacing still reads well without drawing device hardware
World-Space Panel
Start with:
Focus on:
- logical canvas size versus physical world size
- content-sized world panels and inspector-like roots
Text Input
Start with:
Focus on:
- editable input
- change and submit behavior
- default text-field runtime coverage through
UnivisWidgetPlugin
Selection Controls
Start with:
Focus on:
- how selection-oriented controls fit into the broader built-in widget surface
- how the current widget examples map to the built-in widget APIs
Related Pages
Layout System
The layout system in univis_ui is built around two passes:
- an upward pass for intrinsic measurement
- a downward pass for constraint solving and placement
It operates on three core components:
UNode: box metrics and basic visualsULayout: container behaviorUSelf: per-child item behavior
Important Files
crates/univis_ui_engine/src/layout/univis_node.rscrates/univis_ui_engine/src/layout/core/pass_up.rscrates/univis_ui_engine/src/layout/core/pass_down.rscrates/univis_ui_engine/src/layout/core/solver.rscrates/univis_ui_engine/src/layout/core/layout_cache.rs
Core Principles
- roots start from
URootUi LayoutDepthis derived automatically from hierarchy traversalIntrinsicSizeestimates content-driven sizingComputedSizeis the final size consumed by rendering
Roots And Spaces
URootUi is the single public root API.
It resolves each UI tree into one of three spaces:
UiSpace::ScreenUiSpace::World2dUiSpace::World3d
Root Shape
#![allow(unused)]
fn main() {
#[derive(Component, Clone, Reflect)]
pub struct URootUi {
pub space: UiSpace,
pub canvas: UiCanvasSize,
pub camera: UiCameraRef,
pub meters_per_unit: f32,
pub resolution_scale: f32,
}
}
Screen
Use:
#![allow(unused)]
fn main() {
URootUi::screen()
}
Semantics:
- Resolves against the target camera viewport, not raw
Window.width()/height(). - Behaves as a real HUD.
- Camera translation, zoom, and rotation should not visually move screen UI.
- Forms a closed stacking capsule: local ordering never escapes above another root.
- Best for menus, overlays, HUDs, and cursor-fixed elements.
World2d
Use:
#![allow(unused)]
fn main() {
URootUi::world_2d(Vec2::new(1280.0, 720.0))
}
or:
#![allow(unused)]
fn main() {
URootUi::world_2d_fit_content()
}
Semantics:
- Supports either a fixed logical canvas or a content-driven one.
- Lives in world space.
- Renders through the flat 2D material path.
- Forms a closed stacking capsule: descendants stay inside the root’s visual layer.
- Best for panels, diegetic monitors, and boards attached to the scene.
World3d
Use:
#![allow(unused)]
fn main() {
URootUi::world_3d(Vec2::new(1280.0, 720.0))
}
or:
#![allow(unused)]
fn main() {
URootUi::world_3d_fit_content()
}
Semantics:
- Uses the same logical canvas model as
World2d, including fit-content sizing. - Lives in world space.
- Renders through the 3D material path.
- Forms a closed stacking capsule relative to other UI roots.
UPbrsettings apply here.
Logical Canvas And Units
UVal remains a layout-unit type for the UI tree.
UVal::Px(f32)means logical UI units.UiCanvasSize::Viewportmeans “follow the resolved camera viewport”.UiCanvasSize::Fixed(Vec2)means a fixed logical canvas for layout.UiCanvasSize::FitContent { min, max }means “measure the logical canvas from content, then clamp it”.
For world roots, physical size is derived explicitly:
world_size = canvas_size * meters_per_unit
This means:
- layout stays in logical UI units
meters_per_unitcontrols only physical world sizeresolution_scalecontrols visual quality independently from world size- fit-content roots work best when their direct content has intrinsic or fixed sizing; heavy
%or root-relative flex can introduce circular expectations
Camera Resolution
UiCameraRef::Auto is convenient for simple scenes with exactly one compatible camera.
For multi-camera scenes, prefer:
#![allow(unused)]
fn main() {
UiCameraRef::Entity(camera_entity)
}
That keeps viewport resolution, interaction, and screen-root anchoring deterministic.
Legacy Compatibility Note
UScreenRoot and UWorldRoot are deprecated compatibility wrappers.
They are explicit-only migration paths, and the current removal target is the
first alpha after 0.3.0 that no longer needs wrapper-based migration
support.
Migration rules:
UScreenRoot->URootUi::screen()UWorldRoot { size, is_3d: false }->URootUi::world_2d(size)UWorldRoot { size, is_3d: true }->URootUi::world_3d(size)
If you need a specific world-space physical size, set:
#![allow(unused)]
fn main() {
URootUi {
meters_per_unit: 1.0,
..URootUi::world_2d(size)
}
}
or:
#![allow(unused)]
fn main() {
URootUi {
meters_per_unit: 1.0,
..URootUi::world_3d(size)
}
}
Related Examples
Related Migration Notes
API Entry Points
univis_ui_engine::layout::layout_system::URootUiunivis_ui_engine::layout::layout_system::UiSpaceunivis_ui_engine::layout::layout_system::UiCanvasSizeunivis_ui_engine::layout::layout_system::UiCameraRefunivis_ui_engine::layout::pbr::UPbr
Where To Look Next
- related example:
responsive_layout_test - related API index: API Reference
- related migration page: Root API Migration to
URootUi
UNode and Box Metrics
UNode is the fundamental building block of every UI element.
Main Fields
widthheightmin_widthmax_widthmin_heightmax_heightpaddingmarginbackground_colorborder_radiusshape_mode
Supported units:
UVal::PxUVal::PercentUVal::MinContentUVal::MaxContentUVal::ContentUVal::AutoUVal::Flex
Sizing Notes
widthandheightare the preferred size request.min_width,max_width,min_height, andmax_heightclamp the solved result.paddingparticipates in intrinsic measurement, whilemarginaffects placement and wrap span rather than the node’s inner measured content.UVal::Contentis the legacy alias forUVal::MaxContent.UVal::Autois contextual rather than identical toContent.- Use
MaxContentorMinContentwhen you want explicit intrinsic sizing without implicit auto-stretch behavior. border_radiusandshape_modestay visual-only; they do not change the measured layout size by themselves.
See Sizing Semantics for the current detailed rules.
Final Size
After layout solving, every entity receives:
ComputedSize
That final size is what rendering uses.
UBorder
Borders are visually separate from the UNode background and support:
- width
- color
- rounded corners
Shape Modes
Round: rounded SDF cornersCut: beveled or cut corners
Sizing Semantics
This page freezes the intended sizing vocabulary for the current alpha line.
Core Terms
- Preferred size: the size requested by
widthandheight. - Minimum size: the floor applied by
min_widthandmin_height. - Maximum size: the ceiling applied by
max_widthandmax_height. - Intrinsic size: the size measured from content before parent-driven layout adjustments.
UVal Modes
Px: fixed logical size.Percent: percentage of the parent size on that axis.Flex: participates in main-axis free-space distribution.MinContent: smallest intrinsic size that still fits the content.MaxContent: full intrinsic size without contextual stretch.Content: legacy public alias forMaxContent.Auto: contextual size. It falls back to intrinsic measurement, but the layout algorithm may stretch or reinterpret it when the surrounding layout calls for that behavior.
Current Rules
- Explicit
min_*andmax_*always clamp the solved size, including flex grow and flex shrink redistribution. Autois no longer treated as the same mode asContent.- In grid placement,
Autoitems can stretch to the cell by default.MinContentandMaxContentkeep their intrinsic size unless alignment explicitly asks for stretch. - In flex cross-axis stretch behavior,
Autoparticipates in implicit stretch. Explicit alignment can still force stretch for non-fixed, non-percent modes. UImagetreatsAuto,Content,MinContent, andMaxContentas native-image measurement modes. Images have one intrinsic size, so these modes all resolve to the texture size once the asset is ready.
Practical Guidance
- Use
Autowhen the size should adapt to layout context. - Use
MaxContentorContentwhen the element should hug its measured content and avoid implicit auto-stretch behavior. - Use
MinContentwhen you want the tightest intrinsic fit. - Add
min_width/max_widthormin_height/max_heightwhen you need hard bounds around any of the modes above.
ULayout and USelf (Hybrid API)
The current design follows a hybrid API:
- flat fields for common use
- nested extension structs for advanced behavior
ULayout (Container)
Common fields:
displayflex_directionjustify_contentalign_itemsgapgrid_columns
Advanced groups:
container_ext.box_aligncontainer_ext.flexcontainer_ext.grid
Box Align Container
Holds advanced alignment controls such as:
justify_itemsalign_contentrow_gapcolumn_gap
Flex Container
Holds advanced flex controls such as:
wrapalign_content
Grid Container
Holds advanced grid controls such as:
template_columnstemplate_rowsauto_flowauto_rowsauto_columns
USelf (Item)
Common fields:
position_typeleft,right,top,bottomalign_selforder
Advanced groups:
item_ext.box_alignitem_ext.flexitem_ext.grid
Box Align Item
Includes:
justify_selfalign_self
Flex Item
Includes:
flex_growflex_shrinkflex_basis
Grid Item
Includes:
grid_column_startgrid_column_spangrid_row_startgrid_row_span
Display Modes
UDisplay currently supports:
FlexGridMasonryStackRadialNone
Flex
- uses
flex_direction,justify_content, andalign_items - supports wrapping through
container_ext.flex.wrap - supports
flex_grow,flex_shrink, andflex_basison items
Grid
- can run in a simple mode through
grid_columns - or in an advanced mode through
template_rowsandtemplate_columns - supports auto-placement through
auto_flow,auto_rows, andauto_columns
Masonry
- places each item in the shortest column
- useful for Pinterest-like layouts
Stack
- overlays children in the same space
Radial
- distributes items around a circle
- useful for sci-fi or menu-like layouts
None
- disables layout behavior for the container
UClip and UPbr
UClip
UClip { enabled: bool } clips descendants.
Typical usage:
#![allow(unused)]
fn main() {
UClip { enabled: true }
}
Where Clipping Is Used
- in
interaction/pickingto reject hits outside clip bounds - in
render/systemto pass clip data intoUNodeMaterial - in text through local glyph clipping in
sync_text_label_meshesand ancestor material clipping insync_text_clipper_materials
UPbr
For 3D UI roots:
UPbrconfigures metallic, roughness, and emissive properties- the settings affect the
UNodeMaterial3dpath
Upward / Downward Passes and Solver
Upward Pass: upward_measure_pass_cached
- walks from the deepest level back to the root
- computes
IntrinsicSizefor containers from their children - ignores
Absoluteitems that are out of flow - uses the cache to skip clean nodes
Downward Pass: downward_solve_pass_safe
- walks from the root toward deeper levels
- builds
SolverConfigandSolverSpecfor each node - calls
solve_flex_layout - writes results into:
ComputedSizeTransform
Solver
In src/layout/core/solver.rs, the solver:
- separates in-flow and absolute items
- resolves main and cross sizes
- applies flex grow and shrink
- applies align and stretch rules
- resolves the absolute box at the end
translate_spec / translate_config
translate_configreads container-level data fromULayouttranslate_specreads item-level data fromUSelf
This translation layer is the bridge between public layout components and the internal solver.
Cache and Invalidation
LayoutCache reduces repeated layout work.
What It Stores
- intrinsic sizes per entity
- dirty flags
- per-depth entity lists
When A Node Becomes Dirty
Whenever one of these changes:
UNodeULayoutUSelf- hierarchy structure
Important exception:
- if the only change is
IntrinsicSizeon a node with children, the cache may ignore it to reduce noise
Lifecycle
track_layout_changesmarks dirty nodesupdate_depth_cacherebuilds the depth map on structural changesupward_measure_pass_cachedreads the cache and clears dirty flags afterward
Performance Diagnostics
- watch
dirty_countanddirty_ratio - enable the profiler overlay when needed
Widgets
Each Univis widget is an ECS component plus a small plugin that manages:
- shape or child initialization
- interaction logic
- visual synchronization
- message emission when needed
Quick Mental Model
- Display and text:
UTextLabel,UImage,UBadge,UTag,UProgressBar
- Actions:
UButton,UIconButton,UToggle,UCheckbox,URadioButton
- Inputs:
USeekBar,UDragValue,USelect,UTextField
- Containers:
UPanel,UPanelWindow,UScrollContainer,UDivider
Important Plugins
- included by default through
UnivisUiPlugin->UnivisWidgetPlugin: the standard widget set, scrolling, panel support,UTextFieldruntime, andUBadgeruntime - dedicated widget plugins still remain available when you intentionally want a narrower surface than
UnivisWidgetPlugin
Related Examples
- live now:
widgets_controls - live now:
widgets_inputs - live now:
widgets_display - live now:
widgets_containers
API Entry Points
univis_ui_widgets::widget::text_label::UTextLabelunivis_ui_widgets::widget::button::UButtonunivis_ui_widgets::widget::text_field::UTextFieldunivis_ui_widgets::widget::panel::{UPanel, UPanelWindow}univis_ui_widgets::widget::scroll_view::UScrollContainer
Where To Look Next
- related example:
widgets_controls - related setup page: Plugin Setup and First Examples
- related API index: API Reference
- related migration page: Example Path Migration
Text, Image, and Badge
UTextLabel
File: src/widget/text_label.rs
Core fields:
textfont_sizecolorjustifylinebreakoverflowdefaults toEllipsis; useCliporVisiblewhen neededtruncate_sidecontrols whether ellipsis trims the start, end, or middle
Systems:
measure_text_label_layoutfit_node_to_text_sizesync_text_label_meshessync_text_clipper_materials
Local overflow is clipped per glyph quad, while ancestor UClip data is pushed into the text material for shader-side clipping.
UImage
File: src/widget/image.rs
- binds an image into the material path
sync_image_geometrykeeps rendered size aligned with layoutAuto,Content,MinContent, andMaxContentresolve to the native texture size once the image asset is availableUNodemin/maxconstraints still clamp the final solved image size after native measurement
UBadge and UTag
File: src/widget/badge.rs
- badge style presets
- dynamic badge styling lives in
UnivisBadgePlugin - this runtime is included by default through
UnivisWidgetPlugin - the dedicated plugin still remains available when you intentionally compose a narrower widget surface
Live Example
- use
cargo run --example widgets_displayforUBadge,UDivider,UProgressBar, andUPanel
Action Widgets
UButton
- file:
src/widget/button.rs - applies button styling through
UNodeandUInteractionColors
UIconButton
- file:
src/widget/icon_btn.rs - follows the same button model with icon font support
UToggle
- file:
src/widget/toggle.rs - implements a switch with knob animation
UCheckbox
- file:
src/widget/checkbox.rs - simple click-driven check state
URadioButton
- file:
src/widget/radio.rs - supports single-choice group behavior
Live Example
- use
cargo run --example widgets_controlsforUButton,UCheckbox,UToggle,URadioGroup, andURadioButtonin one screen
Input Widgets
USeekBar
- file:
src/widget/seekbar.rs - supports ranges, values, and optional value display
UDragValue
- file:
src/widget/drag_value.rs - horizontal dragging changes a numeric value
USelect
- file:
src/widget/select.rs - dropdown selection with disabled options and basic keyboard handling
UTextField
- file:
src/widget/text_field.rs - text input with cursor blink and focus logic
- runtime coverage: included by default through
UnivisWidgetPlugin - dedicated plugin:
UnivisTextFieldPluginwhen composing a narrower widget surface
Live Example
- use
cargo run --example widgets_inputsforUTextField,USelect,UDragValue, andUSeekBar
UPanel and UPanelWindow
UPanel
File: src/widget/panel.rs
Basic fields:
- width and height limits
- background styling
- panel frame behavior
Its role is to provide a ready-to-use panel container.
UPanelWindow
UPanelWindow adds border and corner resize behavior on top of UPanel.
Fields:
min_widthmin_heightborder_hit_thickness
Current Behavior
- eight resize handles:
N,S,E,W,NE,NW,SE,SW - resize only, no drag-to-move behavior yet
- cursor icons only change on active resize handles
- the panel is converted to
Absolute + Pxon the first resize for predictable behavior
Live Example
- use
cargo run --example widgets_containersfor a resizableUPanelWindowand a scrollable companion viewport
Historical Example
For a current panel-window scene, run cargo run --example widgets_containers.
UScrollContainer
File: src/widget/scroll_view.rs
Component
UScrollContainer stores:
- scroll offset
- orientation
- scroll speed
Plugin
UnivisScrollViewPlugin
Scroll Logic
- driven by
MouseWheel - scrolling only applies while the container is in
UInteraction::Hovered - the first child is expected to be the scrollable content
- the offset is clamped to
[-overflow, 0]
Practical Notes
- the container needs
UInteractionto detect hover - it is usually paired with
UClip { enabled: true }
Historical Example
- use
cargo run --example widgets_containersfor a live scroll viewport wired withUClip,UInteraction, andUScrollContainer
For a current scroll-container scene, run cargo run --example widgets_containers.
Interaction System
The interaction layer is built on:
- a custom picking backend:
univis_picking_backend - observer callbacks for pointer events
- component state through
UInteraction
Core Components
UInteraction- stores the current interaction state
UInteractionColors- maps state changes to background colors
How It Works
- the backend computes hits
- Bevy picking emits pointer events
- observers in
interaction/feedback.rsupdateUInteractionand visuals
Note
Interaction depends on UInteraction being present on the target entity.
Related References
Related Examples
API Entry Points
univis_ui_interaction::interaction::feedback::UInteractionunivis_ui_interaction::interaction::feedback::UInteractionColorsunivis_ui_interaction::interaction::picking::univis_picking_backend
Where To Look Next
- related example:
widgets_controls - related API index: API Reference
- related migration page: Current Limitations
Picking Backend
File: src/interaction/picking.rs
What It Does
- reads pointer locations
- converts pointer coordinates from viewport space into world space
- evaluates candidate nodes with an SDF rounded-box test
- rejects hits clipped by ancestors through
UClip - removes an ancestor hit if a deeper child wins in the same path
Important Details
- the main query targets entities that carry
UInteraction - final ordering combines:
- tree depth
- root capsule precedence
- local depth inside the same root
Clip Accuracy
The backend walks clip ancestors, converts the pointer into local space for each one, and evaluates sd_rounded_box against clip bounds. This keeps picking aligned with visible clipping.
UInteraction States
Core transitions:
NoneHoveredPressedDisabled
UInteractionColors
When an entity carries UInteractionColors, the feedback observer updates UNode.background_color automatically from the current state.
Recommended Practice
- use
Pickable::IGNOREon decorative text or child entities inside a button - keep final state logic inside widget systems when needed, rather than relying only on color
Interaction Support Matrix (Screen / World2d / World3d)
Legend:
Supported: works in the documented path.Partial: works with constraints.N/A: capability is not intended for that mode.
| Capability | Screen UI (URootUi::screen()) | World UI (URootUi::world_2d(...)) | 3D UI (URootUi::world_3d(...)) | Conditions / Notes |
|---|---|---|---|---|
| Base rendering | Supported | Supported | Supported | Screen and World2d use the 2D path. World3d uses the 3D material path. |
| Picking + pointer events | Supported | Supported | Supported | Interaction resolves the camera from each root through ResolvedRootUi. For multi-camera scenes, prefer UiCameraRef::Entity. |
| Clipping-aware hit testing | Supported | Supported | Supported | Ancestor clipping checks apply across all spaces. World roots are still hit-tested against their UI plane. |
UPanelWindow resize handles | Supported | Supported | Supported | Resize logic resolves cursor movement through the root camera and panel plane. |
UTextField input/events | Supported | Supported | Supported | Included by default through UnivisWidgetPlugin; add UnivisTextFieldPlugin directly only for narrower manual widget composition. |
UScrollContainer interaction | Supported | Supported | Supported | Scroll interaction follows the resolved root camera path. |
UPbr controls (metallic, roughness, emissive) | N/A | N/A | Supported | Intended only for the World3d render path. |
Notes
URootUi::screen()is a real HUD path tied to the resolved viewport.URootUi::world_2d(...)andURootUi::world_3d(...)use a fixed logical canvas plus explicit world scaling.meters_per_unitchanges physical world size without changing logical layout size.
Verification Sources
crates/univis_ui_interaction/src/interaction/picking.rscrates/univis_ui_widgets/src/widget/panel.rscrates/univis_ui_engine/src/layout/layout_system.rscrates/univis_ui_engine/src/layout/render/system.rs
Examples
This page lists only example source files that exist in the current repository.
Run The Current Demo
cargo run --manifest-path android/android_phone_app/Cargo.toml
Standalone Android Package
| Example | Source | Purpose | Command |
|---|---|---|---|
android_phone | android/android_phone_app/examples/android_phone.rs | Android-style app screen with search, toggles, sliders, scroll content, and bottom navigation. | cargo run --manifest-path android/android_phone_app/Cargo.toml --example android_phone |
The package also has a native desktop entry point:
cargo run --manifest-path android/android_phone_app/Cargo.toml
Workspace Examples
| Example | Source | Purpose | Command |
|---|---|---|---|
responsive_layout_test | examples/responsive_layout_test.rs | Stress scene for responsive screen composition. | cargo run --example responsive_layout_test |
toggle_seekbar | examples/toggle_seekbar.rs | Compact control scene for toggle and seek-bar behavior. | cargo run --example toggle_seekbar |
z_order_hierarchy | examples/z_order_hierarchy.rs | Checks visual ordering and hierarchy stacking behavior. | cargo run --example z_order_hierarchy |
Grid Layout
| Example | Source | Purpose | Command |
|---|---|---|---|
grid_columns | examples/grid/columns.rs | Grid column sizing and layout behavior. | cargo run --example grid_columns |
grid_tracks | examples/grid/tracks.rs | Grid track sizing behavior. | cargo run --example grid_tracks |
grid_auto_flow | examples/grid/auto_flow.rs | Grid auto-flow placement behavior. | cargo run --example grid_auto_flow |
grid_item_placement | examples/grid/item_placement.rs | Explicit grid item placement. | cargo run --example grid_item_placement |
Layout Modes
| Example | Source | Purpose | Command |
|---|---|---|---|
layout_flex | examples/layout/flex.rs | Flex layout composition. | cargo run --example layout_flex |
layout_masonry | examples/layout/masonry.rs | Masonry layout composition. | cargo run --example layout_masonry |
layout_stack | examples/layout/stack.rs | Stack layout composition. | cargo run --example layout_stack |
layout_radial | examples/layout/radial.rs | Radial layout composition. | cargo run --example layout_radial |
Widgets
| Example | Source | Purpose | Command |
|---|---|---|---|
widgets_controls | examples/widgets/controls.rs | Buttons, toggles, checkboxes, and radio controls. | cargo run --example widgets_controls |
widgets_inputs | examples/widgets/inputs.rs | Text field, select, drag-value, and seek-bar inputs. | cargo run --example widgets_inputs |
widgets_display | examples/widgets/display.rs | Text, badges, dividers, panels, and progress display. | cargo run --example widgets_display |
widgets_containers | examples/widgets/containers.rs | Panel window and scroll-container behavior. | cargo run --example widgets_containers |
Validation
Check every workspace example currently known to Cargo:
cargo check --workspace --examples
Check the Android package:
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
Related Pages
Example Gallery
This page highlights the examples that exist in the current repository.
Best First Paths
- Quick Start
android_phonewidgets_controlswidgets_inputsresponsive_layout_test
Screen UI
| Example | Use this for | Command |
|---|---|---|
android_phone | A complete mobile-style screen. | cargo run --manifest-path android/android_phone_app/Cargo.toml |
responsive_layout_test | Responsive screen composition. | cargo run --example responsive_layout_test |
z_order_hierarchy | Visual ordering and stacking checks. | cargo run --example z_order_hierarchy |
Layout
| Example | Use this for | Command |
|---|---|---|
layout_flex | Flex layout. | cargo run --example layout_flex |
layout_masonry | Masonry layout. | cargo run --example layout_masonry |
layout_stack | Stack layout. | cargo run --example layout_stack |
layout_radial | Radial layout. | cargo run --example layout_radial |
grid_columns | Grid columns. | cargo run --example grid_columns |
grid_tracks | Grid tracks. | cargo run --example grid_tracks |
grid_auto_flow | Grid auto-flow. | cargo run --example grid_auto_flow |
grid_item_placement | Explicit grid item placement. | cargo run --example grid_item_placement |
Widgets
| Example | Use this for | Command |
|---|---|---|
widgets_controls | Buttons, toggles, checkboxes, and radio controls. | cargo run --example widgets_controls |
widgets_inputs | Text fields, select, drag-value, and seek-bar inputs. | cargo run --example widgets_inputs |
widgets_display | Text, badges, dividers, panels, and progress display. | cargo run --example widgets_display |
widgets_containers | Panel windows and scroll containers. | cargo run --example widgets_containers |
toggle_seekbar | A compact toggle and seek-bar scene. | cargo run --example toggle_seekbar |
Related Pages
Android App Screen
This page documents the current live android_phone demo package.
Run it with:
cargo run --manifest-path android/android_phone_app/Cargo.toml
The package also keeps an android_phone example target locally for Android-oriented packaging,
but the desktop-friendly entry point above is the fastest way to inspect the scene in this branch.
What It Demonstrates
- a full-height Android-style app surface capped to a narrow mobile width
- a top summary card plus a live
UTextFieldsearch input - a scrollable feed using
UClip,UScrollContainer, andUInteraction - compact mobile controls built from
UToggle,USeekBar,UBadge, andUButton - a bottom navigation row that stays visible while the middle feed grows
When To Run It
- when you want a concrete mobile layout reference instead of isolated widget demos
- when you want to verify spacing density for phone-sized screens
- when you want one scene that mixes layout, scrolling, and touch-friendly controls
Practical Notes
- the scene uses
URootUi::screen(), so the app surface stays viewport-fixed like a HUD - the outer shell uses
max_widthinstead of a fake device frame, so the same scene reads well on desktop and Android - the center feed is the part meant to scroll; the top summary and bottom navigation remain visible
- for focused widget behavior, compare it with
widgets_controls,widgets_inputs, andwidgets_containers
Related Pages
API Reference
This section is a practical index for the public univis_ui API surface.
Where To Find The Generated Reference
To generate rustdoc:
cargo doc --no-deps
Then open:
target/doc/univis_ui/index.html
How To Use This Section
- start with Events and Messages if you connect UI to gameplay or app logic
- use Crate Map when deciding between the facade crate and the lower-level crates
- use Public Types Table for a fast map of the main structs, enums, and plugins
High-Value Entry Points
univis_ui::UnivisUiPluginfor the facade pathunivis_ui_engine::layout::layout_system::URootUifor rootsunivis_ui_engine::layout::univis_node::UNodefor the box modelunivis_ui_interaction::interaction::feedback::UInteractionfor runtime stateunivis_ui_widgets::widget::text_label::UTextLabelfor textunivis_ui_style::style::Themefor shared fonts and icon handles
Events and Messages
Univis events use Bevy messages via #[derive(Message)].
Common examples include:
ButtonClickedToggleChangedSelectChangedSeekBarChangedTextFieldSubmitted
Consumption Pattern
Typical message handling looks like this:
#![allow(unused)]
fn main() {
fn read_messages(mut events: MessageReader<ButtonClicked>) {
for event in events.read() {
// react to the click
}
}
}
Practical Guidance
- use messages for app-level reactions
- keep local visual state inside widget systems
- avoid duplicating the same state in both widget components and external resources unless needed
Public Types Table
This page groups the highest-value public types by crate and by job.
Facade Entry
univis_ui::UnivisUiPluginunivis_ui::prelude
Root And Layout Types
univis_ui_engine::layout::layout_system::URootUiunivis_ui_engine::layout::layout_system::UiSpaceunivis_ui_engine::layout::layout_system::UiCanvasSizeunivis_ui_engine::layout::layout_system::UiCameraRefunivis_ui_engine::layout::univis_node::UNodeunivis_ui_engine::layout::univis_node::ULayoutunivis_ui_engine::layout::univis_node::USelfunivis_ui_engine::layout::univis_node::UBorderunivis_ui_engine::layout::univis_node::UClipunivis_ui_engine::layout::pbr::UPbrunivis_ui_engine::layout::geometry::UValunivis_ui_engine::layout::geometry::USidesunivis_ui_engine::layout::geometry::UCornerRadius
UScreenRoot and UWorldRoot are intentionally omitted from the recommended surface.
Use their explicit compatibility path only when migrating older code:
univis_ui::layout::layout_system::{UScreenRoot, UWorldRoot} or
univis_ui_engine::layout::layout_system::{UScreenRoot, UWorldRoot}.
Interaction Types
univis_ui_interaction::interaction::feedback::UInteractionunivis_ui_interaction::interaction::feedback::UInteractionColorsunivis_ui_interaction::interaction::UnivisInteractionPlugin
Style Types
univis_ui_style::style::Themeunivis_ui_style::style::TextStylesunivis_ui_style::style::IconStylesunivis_ui_style::style::Fontsunivis_ui_style::style::UnivisUiStylePlugin
Widget Types
univis_ui_widgets::widget::text_label::UTextLabelunivis_ui_widgets::widget::button::UButtonunivis_ui_widgets::widget::checkbox::UCheckboxunivis_ui_widgets::widget::toggle::UToggleunivis_ui_widgets::widget::radio::{URadioButton, URadioGroup}univis_ui_widgets::widget::seekbar::USeekBarunivis_ui_widgets::widget::drag_value::UDragValueunivis_ui_widgets::widget::select::{USelect, USelectOption}univis_ui_widgets::widget::text_field::UTextFieldunivis_ui_widgets::widget::scroll_view::UScrollContainerunivis_ui_widgets::widget::panel::{UPanel, UPanelWindow}univis_ui_widgets::widget::progress::UProgressBarunivis_ui_widgets::widget::badge::{UBadge, UTag}
Diagnostics And Rendering Types
univis_ui_engine::layout::render::UnivisRenderPluginunivis_ui_engine::layout::profiling::{LayoutProfiler, UnivisLayoutProfilingPlugin}univis_ui_engine::layout::core::layout_cache::{LayoutCache, UnivisLayoutCachePlugin}
For exact signatures and field-level detail, use cargo doc --no-deps.
Crate Map
Use the smallest public surface that matches your job.
Recommended Starting Point
univis_uiis the default dependency for most applications.univis_ui::preludeis the recommended day-to-day import surface.- The facade prelude includes the canonical root, layout, interaction, style, and built-in widget APIs.
- Deprecated compatibility wrappers are intentionally excluded from the prelude. Use explicit paths such as
univis_ui::layout::layout_system::{UScreenRoot, UWorldRoot}only when migrating older code.
When To Depend On Each Crate
univis_ui: use this when you want one plugin and one import story for the full stack.univis_ui_engine: use this when you need roots, layout, rendering sync, or custom widget/runtime work without the full facade.univis_ui_interaction: use this when you need picking andUInteraction-driven feedback on top of engine roots.univis_ui_widgets: use this when you want the built-in controls but still manage plugin composition yourself.univis_ui_style: use this when you only need shared theme resources, fonts, icons, or text styles.
Prelude Policy
preludemeans the stable recommended import surface for everyday use.- Named modules such as
layout,render,interaction, andwidgetare advanced but still public. - Deprecated compatibility wrappers stay on explicit paths instead of the default import story.
Contributing
Practical Rules Before Any Change
- Understand system order before editing layout, rendering, or interaction.
- Do not break reflection on public types without a clear reason.
- Validate changes against the current live package or equivalent source-level checks, not only unit tests.
- When adding a new widget, ship:
- a clear component API
- a dedicated plugin
- messages when needed
- a runnable demo when the branch currently carries example sources
- documentation in the README and this book
Docs and Example Placement
- Add new guide pages in both
docs/src/enanddocs/src/ar. - Put a new runnable example inside the crate that owns the feature.
- Keep root
examples/only for facade-level integrated demos when such demos are present in the branch. - Follow the conventions in Editorial Rules.
- Follow Naming Conventions when splitting or renaming internal modules.
- Use Maintainer Map and Architecture Rules before moving ownership boundaries.
- Use Widget Structure Conventions and Layout Engine Boundaries before splitting large subsystems.
- Use Docs Authoring Workflow for the exact bilingual and
rustdocsteps. - Use Docs Review Checklist before merging docs-heavy work.
Code Style Inside The Project
- favor small components and clear systems
- keep visual behavior driven by
UNode,UBorder, andUInteractionColors - avoid surprising side effects outside the intended schedule
Suggested Branch Names
feat/<name>for featuresfix/<name>for fixesdocs/<name>for documentation work
Architecture
univis_ui is organized around four main subsystems:
layout/: layout solving and spatial computationinteraction/: picking and interaction statewidget/: ready-made UI widgetsstyle/: fonts, icons, and shared theme resources
Core Idea
Everything in Univis is built from ECS entities and components:
- there is no external retained UI tree
- every UI element is an entity with
UNodeplus optional companion components - layout, interaction, and rendering all run through Bevy systems
Standard Frame Flow
PreUpdate- the picking backend resolves hit entities
Update- widget logic, interaction logic, and visual state changes run here
PostUpdate- the layout pipeline runs:
update_layout_hierarchyupward_measure_pass_cacheddownward_solve_pass_safe
- render and material sync systems apply visual output
- the layout pipeline runs:
Design Goals
- crisp visuals through SDF rendering
- flexible layout through
Flex,Grid,Masonry,Stack, andRadial - easy extension through ECS components and plugins
- debuggable performance through profiling and cache-aware systems
Plugin Map
Root Plugin
In src/lib.rs, UnivisUiPlugin adds the stack in this order:
UnivisUiStylePluginUnivisEnginePluginUnivisInteractionPluginUnivisWidgetPlugin
What Each Layer Adds
UnivisEnginePluginUnivisNodePluginUnivisLayoutPluginUnivisRenderPlugin- together these provide node primitives, root resolution, layout solving, and render synchronization
Interaction
UnivisInteractionPlugin adds:
univis_picking_backendinPreUpdate- pointer feedback observers
- interaction state transitions
Style
UnivisUiStylePlugin adds:
- bundled fonts
- Lucide icon font loading
- the shared
Themeresource
Widgets
UnivisWidgetPlugin registers the standard widget set.
Automatically included today:
UnivisTextPluginUnivisProgressPluginUnivisButtonPluginUnivisRadioPluginUnivisIconButtonPluginUnivisTogglePluginUnivisCheckboxPluginUnivisSeekBarPluginUnivisScrollViewPluginUnivisDividerPluginUnivisPanelPluginUnivisBadgePluginUnivisDragValuePluginUnivisSelectPluginUnivisTextFieldPlugin
Dedicated widget plugins still remain available when you intentionally compose a narrower surface than UnivisWidgetPlugin.
Quick Reference
See also: Plugin Truth Table
Plugin Truth Table
This page is the canonical plugin registration truth for the current repository state.
Root Composition (UnivisUiPlugin)
| Plugin | Added by UnivisUiPlugin | Notes |
|---|---|---|
UnivisUiStylePlugin | Yes | Embedded fonts/icons + Theme resource. |
UnivisEnginePlugin | Yes | Adds UnivisNodePlugin, UnivisLayoutPlugin, and UnivisRenderPlugin. |
UnivisInteractionPlugin | Yes | Registers picking backend and pointer observers. |
UnivisWidgetPlugin | Yes | Registers built-in widget plugin set. |
UnivisLayoutProfilingPlugin | No | Optional diagnostics plugin; add manually when needed. |
Widget Composition (UnivisWidgetPlugin)
| Widget Plugin | Auto-registered via UnivisUiPlugin | Notes |
|---|---|---|
UnivisTextPlugin | Yes | Text label and text clipping systems. |
UnivisProgressPlugin | Yes | UProgressBar. |
UnivisButtonPlugin | Yes | UButton. |
UnivisRadioPlugin | Yes | URadioButton, URadioGroup. |
UnivisIconButtonPlugin | Yes | UIconButton. |
UnivisTogglePlugin | Yes | UToggle. |
UnivisCheckboxPlugin | Yes | UCheckbox. |
UnivisSeekBarPlugin | Yes | USeekBar. |
UnivisScrollViewPlugin | Yes | UScrollContainer. |
UnivisDividerPlugin | Yes | UDivider. |
UnivisPanelPlugin | Yes | UPanel, UPanelWindow behavior. |
UnivisBadgePlugin | Yes | UBadge, plus dynamic badge/tag visual updates. |
UnivisDragValuePlugin | Yes | UDragValue. |
UnivisSelectPlugin | Yes | USelect. |
UnivisTextFieldPlugin | Yes | UTextField behavior/events. |
Dedicated widget plugins still remain available when you intentionally build a narrower widget surface than UnivisWidgetPlugin.
Verification Sources
src/lib.rscrates/univis_ui_engine/src/lib.rscrates/univis_ui_widgets/src/widget/mod.rs
Frame Lifecycle
This chapter connects the main systems across a single Bevy frame.
PreUpdate
univis_picking_backend- converts pointer position into world space
- evaluates SDF intersection against interactive entities
- respects ancestor clipping through
UClip - emits
PointerHitsfor Bevy picking observers
Update
- widget systems update state, sync visuals, and emit messages
- scroll behavior, panel resize, and similar interaction systems run here
- text systems refresh text layout inputs
PostUpdate
Critical layout order:
update_layout_hierarchyupward_measure_pass_cacheddownward_solve_pass_safe
After layout:
update_materials_optimizedsyncsUNode,ComputedSize,UBorder, and related data into materials
Why The Order Matters
- any
Updatechange, such as panel resize or input state, must be reflected before the frame is rendered - cache and invalidation run before measurement to avoid unnecessary work
- rendering depends on final
ComputedSizeand resolved transforms
Rendering
Univis rendering is built on custom SDF materials:
UNodeMaterialfor the 2D pathUNodeMaterial3dfor the 3D path
Main files:
src/layout/render/system.rssrc/layout/render/material.rssrc/layout/render/material_3d.rssrc/layout/render/shaders/unode.wgslsrc/layout/render/shaders/unode_3d.wgsl
Update Path
The render sync system:
- reads
UNode,ComputedSize,UBorder,UImage,UI3d, andUPbr - chooses the 2D or 3D path from the resolved root context
- reuses
MaterialHandlesto reduce allocations - passes clipping data to the 2D material path
Why SDF?
- clean edges under zoom
- good support for border radius, clipping, and antialiasing
- flexibility for both
RoundandCutshapes
Related Examples
Materials and Shaders
UNodeMaterial (2D)
Important fields include:
- fill color
- border color
- size
- corner radius
- clip rectangle data
UNodeMaterial3d
The 3D path adds PBR-related properties:
- metallic
- roughness
- emissive
2D Shader
In unode.wgsl:
- the base shape is evaluated as an SDF
- body and border masks are computed
- if
use_clip = 1, the clip mask is applied before final color output
3D Shader
In unode_3d.wgsl:
- the same SDF shape logic is used
- the result is integrated into the 3D pipeline
Text Clipping Behavior
Current Model
UTextLabel uses two separate clipping stages:
- local overflow handling inside the label itself
- optional ancestor clipping through
UClip
Local Label Clipping
Local clipping happens in sync_text_label_meshes.
- the system generates glyph quads from the measured text
- when
overflowisCliporEllipsis, each quad is clipped against the label content rect before the mesh is built - when
overflowisVisible, this local clip is disabled
If Ellipsis is active, text is measured first, shortened if needed, then the remaining glyph quads are clipped to the label bounds.
Autosized labels still respect parent constraints when the parent has explicit bounds, so overflow handling can stop at the parent edge instead of growing forever.
Ancestor UClip
Ancestor clipping happens in sync_text_clipper_materials.
- the system walks upward from each generated text mesh
- it finds the nearest enabled
UClip - it copies that clip center, size, and corner radius into the text SDF material
- the shader clips the text against that rounded rect
This means text clipping now matches the material-based clip path used by normal nodes instead of hiding the entire text entity.
What Changed
Older docs described a visibility-only fallback that hid text when it escaped a clipped ancestor.
That is no longer the current behavior:
- text is clipped at the glyph-quad level locally
- ancestor clip data is applied in the material/shader path
- partial text visibility is supported instead of all-or-nothing hiding
Known Limitation
Today the text material uses the nearest enabled UClip ancestor. Nested clip ancestors are not combined into a single intersection for text.
Performance and Diagnostics
The project currently centers around three main performance tools:
LayoutCacheto reduce unnecessary recalculationUnivisLayoutProfilingPluginto measure runtime cost and display the overlay./scripts/run_perf_baselines.shfor repeatable CLI baseline runs
What To Watch
- dirty ratio and recalculated node count
pass_upandpass_downtiming- material sync timing
- newly allocated versus reused materials
- baseline drift in the solver and runtime benchmark scenarios
Layout Cache
File: src/layout/core/layout_cache.rs
LayoutCache stores:
- cached intrinsic sizes
- dirty flags
- per-depth entity lists
Best Practices
- avoid mutating
UNode,ULayout, orUSelfevery frame without a real reason - prefer state-driven updates
- avoid unnecessary hierarchy churn
When To Extend It
- when node counts grow much larger
- when dirty ratios stay high most of the time
Related Validation
cargo test -p univis_ui_engine --lib layout::core::layout_cache
Profiler Overlay
File: src/layout/profiling.rs
What It Shows
- upward pass time
- downward pass time
- material update time
- cache statistics
Keyboard Shortcuts
F10: toggle the overlayF11: toggle compact modeF12: move the overlay
When To Use It
- when tracking frame spikes
- when comparing the impact of a large layout change
- when evaluating cache effectiveness
Benchmark Harness
The committed benchmark reports are the current reference for performance comparisons.
Current Reference Artifacts
perf_baselines/current_max/2026-04-05/solver_benchmarks.txtperf_baselines/current_max/2026-04-05/runtime_benchmarks.txtperf_baselines/current_max/2026-04-05/manifest.jsonperf_baselines/current_max/2026-04-05/README.md
Current Coverage
The committed baseline wave still covers both algorithm-heavy and runtime-heavy paths:
- solver scenarios such as dense rows, wrapped cards, and grid dashboards
- runtime scenarios such as root capsules, idle-after-settle, render-only churn, text measurement, picking traversal, widget-heavy panels, and
World3dpanels
How To Use It Now
- read the committed
.txtreports for the raw scenario output - read
manifest.jsonfor the structured metadata - use
scripts/render_benchmark_report.pyif you want a rendered report from the stored data
Status Of run_perf_baselines.sh
./scripts/run_perf_baselines.sh currently points maintainers to the committed baseline data used by this branch.
Editorial Rules
These rules keep the English and Arabic documentation trees mirrored, searchable, and easy to maintain.
Language Separation
- One language per file.
- English pages use English prose only.
- Arabic pages use Arabic prose only.
- Shared API identifiers stay inside backticks, for example
URootUiorUTextLabel.
Page Structure
Prefer a short and repeatable shape:
- What this page is for.
- The minimum mental model.
- Practical rules or examples.
- Related examples.
- Related API types when useful.
Naming Rules
- Use the public API name exactly as it appears in Rust.
- Do not invent alternative nicknames for public types.
- When an example is mentioned, include both the example name and its owning package.
Example-Link Rules
When a guide references an example:
- point to the canonical entry in
docs/src/en/examples/index.md - mention the owning package
- only use
cargo run -p <package> --example <name>when that example source is actually shipped in the current branch; otherwise point to the availability catalog or the current live package
API Doc Rules
rustdocshould explain intent, not repeat field names.- Short
no_runexamples are preferred over long walls of prose. - Internal helpers that are not part of the intended public story should be hidden or de-emphasized.
Mirror Rules
- If an English page is added, add the Arabic counterpart in the same change.
- Keep the same information architecture even when wording differs.
- If only one tree is edited, note why before merging.
Naming Conventions
This page defines the internal naming rules that keep the workspace predictable for contributors.
Goals
- make it easy to guess where code should live before opening files
- keep plugin, set, state, and component names aligned across crates
- reserve compatibility wording for real compatibility behavior only
Module Names
- use
modelfor the authored data model or pure helpers that validate and normalize it - use
runtimefor ECS-only runtime markers, spawned child-entity bookkeeping, and systems that own the live widget tree - use
statefor long-lived mutable engine or widget state that multiple systems read and update - use
eventsfor emitted messages and the code that translates state transitions into outward-facing notifications - use
translationfor authored-to-runtime or authored-to-solver conversion logic - use
placementfor child placement after sizes are known - avoid vague buckets such as
types,helpers, ordisplaywhen a more specific domain name is available
Type Names
- plugins should follow
Univis<Name>Plugin - schedule sets should follow
Univis<Domain>SetorUnivis<Stage>Set - public authored UI components should keep the
U*prefix - internal runtime markers should use explicit nouns such as
SelectTrigger,PanelResizeHandle, orUiWorkState - resources that tune behavior should end in
Settings - resources or components that track live progress should end in
State
Comments
- keep implementation comments in English
- prefer comments that explain constraints, invariants, or why a branch exists
- remove comments that only restate what the next line already says
Legacy And Compatibility Names
- use
legacy_*only when code preserves old semantics on purpose - keep deprecated compatibility wrappers explicit in naming and documentation
- avoid introducing new transitional aliases unless they protect a real public migration path
Rename Checklist
Before creating or renaming a module, check:
- does the filename describe responsibility rather than implementation detail?
- would a new contributor know whether the code belongs in
model,runtime,state,events,translation, orplacement? - does the new name match existing plugin, component, and state patterns in sibling modules?
Maintainer Map
This page is the short maintainer-facing map for the workspace: which crate owns what, where major module boundaries live, and which hotspots need careful review.
Workspace Crate Map
univis_ui: facade crate for the recommended application-facing import story and the full stack pluginunivis_ui_style: shared theme, font, and icon resourcesunivis_ui_engine: root model, layout solver, settlement schedule, and render syncunivis_ui_interaction: picking, interaction state, and pointer-driven validationunivis_ui_widgets: higher-level controls built on top of engine and interaction crates
Engine Module Map
layout::layout_system: root resolution, root stacking capsules, screen transforms, and per-root settlement statelayout::univis_node: authored node, layout, and local-positioning componentslayout::geometry: logical UI units, sides, constraints, and axis helperslayout::core: hierarchy tracking, cache invalidation, measurement, solving, and solver helperslayout::render: mesh/material synchronization after layout settleslayout::profiling: optional runtime diagnostics and overlay helperslayout::registrationandlayout::settlement_loop: pipeline wiring and boundedPostUpdateexecution
Widget Module Map
- single-file widgets stay flat when their runtime is small
- stateful widgets split by responsibility:
modelruntimeinteractionvisualsevents
text_labelis the main exception because it owns bothmeasure/andrender/subtrees
Hotspot Ownership
- engine layout hotspots:
crates/univis_ui_engine/src/layout/** - interaction hotspots:
crates/univis_ui_interaction/src/interaction/** - widget hotspots:
crates/univis_ui_widgets/src/widget/** - facade/docs/import story: root
src/,README*, anddocs/src/**
Review Priority Areas
- root resolution and root stacking changes can affect layout, rendering, and picking at once
- cache and settlement loop changes can create broad regressions even when local tests pass
- text-label measurement/render changes need both layout and rendering validation
- widget runtime refactors should preserve the
Build -> Logic -> Visual -> Eventsschedule story
Architecture Rules
These rules define which APIs are considered stable, which ones are internal, and when the workspace should grow new crates or folders.
Public API
preludeis the recommended stable import story- named modules such as
layout,render,interaction, andwidgetare advanced but public - public authored components keep their declaration-site
rustdoc - compatibility wrappers stay on explicit paths and do not belong in recommended preludes
Internal API
internalandinternal_preludeare workspace implementation tools, not application-facing contractslayout::core,layout::algorithms,layout::components,layout::pipeline, and similar hidden modules may change to support engine refactors- runtime marker components, caches, and generated child-tree bookkeeping should stay crate-private or
pub(super)unless another crate truly needs them - the immediate workspace boundary policy is tracked in the root file
ENGINE_BOUNDARY_RULES.md ./scripts/check_engine_boundary_guardrails.shprevents new external imports from engine internals while current legacy exceptions are being removed
When To Add A Crate
Add a new crate only when at least one of these is true:
- the code introduces a reusable dependency boundary that applications may choose independently
- the feature needs a separate public import story or plugin lifecycle
- the dependency graph becomes cleaner by isolating a subsystem
Do not add a crate just to split files. Prefer folders and modules first.
When To Add A Folder Or Module
- add a folder when one responsibility has multiple collaborating files with clear roles
- add a module when it makes ownership or discovery more explicit than one long file
- prefer responsibility names such as
roots,state,runtime,events, orplacement - avoid generic buckets when a domain-specific name is available
Dependency Rules
- widgets depend on engine, interaction, and style; engine must not depend on widgets
- interaction depends on engine state for roots and geometry; engine must not depend on interaction
- facade crates re-export curated public surfaces but should not leak internal helpers accidentally
Error Model And Diagnostics
The workspace favors typed, recoverable diagnostics over silent failure or opaque Result<_, ()> paths.
Core Rules
- recoverable runtime problems should prefer fallback behavior plus a structured warning
- typed error or issue enums should expose at least a
reasonand, when useful, anaction - validation-only mismatches should stay behind rollout or shadow-validation modes
- panic-oriented checks belong in tests, examples, or true invariants, not hot runtime paths
Warning Shape
Most runtime warnings follow this structure:
- subsystem tag such as
[layout/root_resolution]or[widget/text_label_measure] - entity or generation context when available
reason=...action=...when the caller can do something concrete
Current Canonical Examples
- root resolution uses
RootResolutionIssueto distinguish missing, ambiguous, or inactive cameras - text measurement uses
TextMeasureErrorKindandTextMeasureErrorwhen Bevy text measurement cannot be created - select runtime uses
SelectRuntimeErrorwhen the generated child tree is incomplete - settlement loop and picking validation log generation-aware warnings when rollout checks fail or the bounded loop exhausts its budget
When To Add A New Error Type
- add a typed enum when multiple failure reasons share one call site
- add a structured warning when the system can continue but maintainers need a breadcrumb
- keep the type local if it only supports one subsystem
- promote the type only when another module genuinely needs to branch on it
Widget Structure Conventions
This page defines how stateful widgets should be organized inside crates/univis_ui_widgets/src/widget/.
Public Surface
- each widget exposes one public authored component such as
USelect,UTextField, orUPanel - each widget exposes one plugin named
Univis<Name>Plugin - outward-facing messages live in
eventswhen the widget emits them
Internal Split
Use these responsibilities when a widget grows beyond a small single-file implementation:
model: authored data, normalization helpers, and public configuration typesruntime: generated child-tree markers, runtime resources, and setup helpersinteraction: input handling and state transitionsvisuals: syncing colors, labels, geometry, and other rendered outputevents: emitted messages after state settles
Schedule Rules
Build: spawn or repair runtime child treesLogic: respond to input and mutate widget stateVisual: synchronize the live visual tree from the latest stateEvents: emit outward-facing messages after logic and visuals settle
Typical Patterns
select/usesmodel,runtime,interaction,visuals, andeventspanel/splits resize math, cursor logic, runtime resize state, and visualstext_label/usesmeasure/andrender/because text is both a layout and rendering subsystem
Visibility Rules
- public authored components stay public and documented
- runtime markers and bookkeeping types should usually remain
pub(super) - tests should sit next to the widget they validate so structural refactors stay local
Layout Engine Boundaries
This page is the maintainer reference for where layout responsibilities start and stop inside univis_ui_engine.
Authored Surface
layout::layout_system: public root model and resolved root statelayout::univis_node: public node, layout, and local-position componentslayout::geometry: public sizing and spacing primitiveslayout::imageandlayout::pbr: public authored helpers tied to rendering inputs
Internal Layout Pipeline
layout::core::hierarchy: depth tracking and cached ancestry refreshlayout::core::layout_cache: dirty tracking, stage generations, and frontier queueslayout::core::pass_up: intrinsic measurement and content-size propagationlayout::core::pass_down: final solve output and child transform placementlayout::core::solver: size solving and placement bridge integrationlayout::algorithms: algorithm-specific placement logic
Render Boundary
- layout solves logical size and position
- render sync consumes solved results and updates meshes/materials
- text rendering is the main cross-boundary case, so
text_labelowns both measurement and render-facing logic on the widget side
Scheduling Boundary
layout::registrationwires the settlement schedule and stage orderinglayout::settlement_loopowns bounded execution, generation tracking, and per-frame fixed-point checks- other modules should describe work, not decide global settlement policy
Dependency Direction
- root resolution may feed hierarchy, solve, render sync, and picking
- hierarchy and cache may invalidate later stages
- render sync must not reintroduce measure/solve work unless a real authored layout input changed
- diagnostics and validation can observe the pipeline but should not silently redefine its semantics
Docs Authoring Workflow
This page defines where new docs and new runnable examples should live.
Where New Docs Go
- add end-user guides to
docs/src/enanddocs/src/ar - keep the same information architecture in both trees
- put migration material under
docs/src/*/migration - keep API-signature detail in
rustdoc, not in long guide prose
Where New Runnable Examples Go
- if you add or restore a runnable example, put it in the crate that owns the feature
- if a facade-level integrated demo returns, root
examples/is still the intended home - update the examples index in both languages when availability changes
- add a short source comment back-link to the related guide when the example is canonical
Adding Mirrored Pages
- create the English page
- create the Arabic counterpart in the matching path
- add both to
docs/src/SUMMARY.md - add or update the language switch target if the page is mirrored from an existing chapter
Adding Public rustdoc
When a new public API surface is added:
- add or extend crate-level/module-level docs if the new surface changes discovery
- document the public type or plugin at the declaration site
- prefer short
no_runexamples - hide internal helpers if they would pollute the generated docs story
When To Update README And Changelog
- update
README.mdandREADME_AR.mdwhen the landing story changes - update
changelog.mdfor notable docs/example/API surface changes - use Naming Conventions when adding or renaming maintainer-facing modules
Docs Publishing
This page explains how the hosted documentation build is produced from the repository.
Public URL
- Hosted docs URL:
https://univiseditor.github.io/univis_ui/
Source Of Truth
- the book source lives under
docs/ docs/book.tomldefines the mdBook configuration- the bilingual chapter trees live under
docs/src/enanddocs/src/ar mdbook build docsproduces the static site undertarget/book/docs
Publishing Model
- validation remains in
.github/workflows/docs_examples_api.yml - publishing is handled only by
.github/workflows/docs_publish.yml - the hosted site is built from the same
docs/source tree used locally - the intended public deployment target is GitHub Pages
Local Contributor Workflow
mdbook build docs
mdbook serve docs -n 127.0.0.1 -p 3000
Keep this local path as the canonical way to preview changes before pushing.
What To Verify In The Hosted Build
- the docs home page loads correctly
- the English tree is reachable under the hosted book
- the Arabic tree is reachable under the hosted book
- the language switcher works across mirrored pages
- example gallery links and migration links remain valid
Related Pages
Docs Review Checklist
Use this checklist for docs-heavy pull requests.
-
./scripts/check_quality.shcompleted before merge -
./scripts/check_representative_examples.shcompleted before merge -
mdbook build docscompleted when docs, examples, or root copy changed - English and Arabic pages were updated together when the change is user-facing
- the page was added to
docs/src/SUMMARY.md - the example lives in the owning crate
- the examples index was updated when a new example was added
- canonical examples link back to the related guide when useful
- new public API has
rustdocat the declaration site - internal-only helpers were not promoted accidentally in generated docs
- commands in docs use package-aware example invocations where needed
- visual validation notes were updated when representative examples or rendering behavior changed
-
README/README_ARwere updated if the landing story changed -
changelog.mdwas updated if the change is notable
Engineering Quality
-
./scripts/check_public_api_surface.shcompleted when facade imports, plugin wiring, or deprecated path exposure changed -
./scripts/check_engine_boundary_guardrails.shcompleted when moving logic acrossengine,interaction, orwidgets - the change did not introduce a new large source hotspot without a clear reason
- the change did not widen public API or coupling without a user-facing need
- the change did not add a new dependency on
univis_ui_engine::internalor hidden engine modules outside the engine crate - naming stayed consistent with the maintainer naming and architecture pages
Visual Validation
This page defines the lightweight manual visual checks that still matter even after docs and API docs pass.
Purpose
- catch regressions that compile cleanly but look wrong
- keep the current live demo visually trustworthy
- keep runtime visual checks focused on examples and packages that exist in this branch
Current Policy
- screenshots remain manual release-prep artifacts, not a required CI output
- the example gallery lists only current runnable sources
- runtime visual checks still matter for layout density, text appearance, widget affordances, and overall polish
Live Validation Target
Run the current live package when the affected area is visual or interaction-heavy:
cargo run --manifest-path android/android_phone_app/Cargo.toml
What To Look For
Android Phone Package
- the centered app surface remains balanced in a narrow viewport
UTextField,UToggle,USeekBar, andUButtonremain visually legible and easy to target- spacing and density still read well without a fake hardware frame
Release-Prep Expectation
- do at least one manual visual pass when the change affects rendering, layout semantics, or flagship UI presentation
- capture screenshots only when they materially help release communication or gallery quality
- do not block everyday contributor flow on screenshot generation
Related Pages
Release Readiness
This page is the final pre-release checklist for the next alpha cut.
Current local 0.3.0 prep evidence is recorded at the repository root in RELEASE_PREP_0.3.0.md.
Compile Checks To Re-run
Compile-check these sequentially:
cargo check --workspace --all-targets
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
./scripts/check_representative_examples.sh
Manual runtime validation is still recommended for at least one pass through the current live package.
Docs, Migration, And Release Alignment
Confirm that these files describe the same current reality:
README.mdREADME_AR.mdMIGRATION.mdMIGRATION_AR.mdRELEASE_NOTES.mdchangelog.md
Current Local Checklist
-
mdbook build docs -
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps -
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targetsthrough./scripts/check_representative_examples.sh -
./scripts/check_representative_examples.sh -
./scripts/verify_alpha_release.sh - release notes and migration pages mention the same current example-availability story
- one manual visual pass over the Android package and relevant current examples from Visual Validation
- GitHub Actions confirmation for the same gates
- RC feedback triage and closure
Wrapper Removal Decision
For the next alpha cut, the decision is:
- do not remove
UScreenRootorUWorldRootautomatically as part of the cut - keep them as deprecated compatibility wrappers until another stabilization review is complete
- reconsider removal only after the next alpha cut has shipped and feedback is in
Root-Level File Roles
README.md: landing story and fastest entry pointREADME_AR.md: Arabic landing storyMIGRATION.md: upgrade path from older docs and assumptionsMIGRATION_AR.md: Arabic migration pathRELEASE_NOTES.md: current alpha release-scale summaryRELEASE_PREP_0.3.0.md: local evidence for the next0.3.0cutchangelog.md: chronological dated history
Related Pages
Testing and Validation
Unit Tests
To reduce load on weaker machines, run tests one target at a time:
cargo test --release <test_name> --lib
Quality Validation
./scripts/check_quality.sh
./scripts/check_representative_examples.sh
./scripts/check_examples_serial_release.sh
./scripts/check_quality.sh runs:
cargo fmt --all --checkcargo clippy --workspace --all-targetswith the current CI allowlist for known Bevy-heavy lint debtcargo check --workspace --all-targets./scripts/check_public_api_surface.sh./scripts/check_structure_guardrails.sh./scripts/check_engine_boundary_guardrails.shcargo test --workspace --lib
./scripts/check_representative_examples.sh now compiles the standalone Android phone package and then scans any currently shipped workspace example directories.
./scripts/check_examples_serial_release.sh remains useful when a branch actually ships examples/*.rs targets; in the current branch it may simply report that no workspace examples are present.
Documentation Validation
cargo doc --no-deps
mdbook build docs
Performance Baselines
Use these committed artifacts:
perf_baselines/current_max/2026-04-05/solver_benchmarks.txtperf_baselines/current_max/2026-04-05/runtime_benchmarks.txtperf_baselines/current_max/2026-04-05/manifest.json
CI Validation
GitHub Actions still validates quality, docs, API docs, and current example checks through the existing workflows.
Sequential Validation On Low-End Machines
# all lib tests one by one
./scripts/test_lib_serial_release.sh
# all current workspace examples known to the script
./scripts/check_examples_serial_release.sh
# Android package plus workspace example scan
./scripts/check_representative_examples.sh
# full validation: lib tests + current examples
./scripts/verify_serial_release.sh
# sequential validation for a specific workspace package
./scripts/test_lib_serial_release.sh -p univis_ui_engine
./scripts/check_examples_serial_release.sh -p univis_ui_engine
./scripts/verify_serial_release.sh -p univis_ui_engine
# Android package directly
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
# alpha validation before release
./scripts/verify_alpha_release.sh
# package alpha builds only, without validation
./scripts/package_alpha_serial.sh --no-verify
Practical Pre-Merge Strategy
- run the unit tests related to the change
- run
./scripts/check_quality.sh - run
./scripts/check_representative_examples.sh - run
cargo check --workspace --examples - launch the Android package when the change affects the live demo surface
- use Visual Validation when the change is rendering-, layout-, or interaction-heavy
Required Before The Next Alpha Cut
./scripts/check_quality.shmdbook build docscargo doc -p univis_ui_style --no-depscargo doc -p univis_ui_engine --no-depscargo doc -p univis_ui_interaction --no-depscargo doc -p univis_ui_widgets --no-depscargo doc -p univis_ui --no-depscargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets./scripts/check_representative_examples.sh- one manual pass through the Android package and relevant current examples
- one pass through Release Readiness
Screenshot Policy
- screenshots remain manual release-prep material
- the example gallery can link to static visual references
- screenshot generation is not a required CI gate in the current alpha line
Example Validation Report
Current Validation Scope
The current branch validates only example sources that exist in the repository.
Commands
Check workspace examples:
cargo check --workspace --examples
Check the standalone Android package:
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
Run the release-mode representative pass:
./scripts/check_representative_examples.sh
Current Example Sources
android/android_phone_app/examples/android_phone.rsexamples/responsive_layout_test.rsexamples/toggle_seekbar.rsexamples/z_order_hierarchy.rsexamples/grid/auto_flow.rsexamples/grid/columns.rsexamples/grid/item_placement.rsexamples/grid/tracks.rsexamples/layout/flex.rsexamples/layout/masonry.rsexamples/layout/radial.rsexamples/layout/stack.rsexamples/widgets/containers.rsexamples/widgets/controls.rsexamples/widgets/display.rsexamples/widgets/inputs.rs
Runtime behavior still requires manual windowed smoke checks for interaction and visual correctness.
Compatibility Matrix
Validation baseline date: April 3, 2026.
Legend:
Yes: supported and validated in current baseline.Partial: supported with known constraints.No: not supported in the current baseline.Deferred: planned validation was intentionally skipped in this cycle.
| Capability | Screen UI | World UI (2D) | World UI (3D) | Validation Source |
|---|---|---|---|---|
| Manual runtime smoke in current branch | Yes | Deferred | Deferred | current live target is android/android_phone_app; see Smoke Test Plan |
| Compile validation in current branch | Yes | Partial | Partial | cargo check --workspace --all-targets, Android package checks, and example scripts only when runnable example sources are present |
| Base rendering path | Yes | Yes | Yes | source-level validation plus current runnable examples where available |
| Pointer interaction | Yes | Yes | Yes | camera resolves from each root through ResolvedRootUi; prefer UiCameraRef::Entity in multi-camera scenes |
| Clipping-aware picking | Yes | Yes | Yes | ancestor clipping checks in the picking backend |
UPanelWindow resize | Yes | Yes | Yes | resize logic resolves cursor movement through the root camera and panel plane |
UTextField behavior/events | Yes | Yes | Yes | included by default through UnivisWidgetPlugin |
UBadge dynamic visual updates | Yes | Yes | Yes | included by default through UnivisWidgetPlugin |
UScrollContainer behavior | Yes | Yes | Yes | interaction follows the resolved root-camera path |
UPbr controls | No | No | Yes | intended for UI3d path |
Related
Smoke Test Plan
Goal
Provide a lightweight manual runtime checklist after passing compile validation.
Pre-check
Run compile validation first:
./scripts/check_representative_examples.sh
./scripts/verify_serial_release.sh
Manual Runtime Scenarios
- Android-style narrow-screen package sanity
- Workspace example sanity for affected layout or widget areas
- Text and control readability pass
Commands
cargo run --manifest-path android/android_phone_app/Cargo.toml
For workspace examples, use cargo run --example <name> with an entry from Examples.
Pass Criteria
- No startup panics.
- The Android-style package opens and keeps the centered app surface readable in a narrow viewport.
UTextField,UToggle,USeekBar, andUButtonremain visually coherent and interactive.- Relevant workspace examples still open and remain visually coherent.
Failure Triage
- Capture the failing surface and the symptom.
- Re-run the Android package with
RUST_BACKTRACE=1if the failure is runtime-related. - Classify as compile/runtime/widget/rendering regression.
- Add an issue note with the repro command and environment details.
See also: Visual Validation and Release Readiness.
Troubleshooting
1) Elements Do Not Appear
Check:
- that a compatible camera exists
- that a root entity built from
URootUiexists - that
ComputedSizeis not zero - that
Visibilityis notHidden
2) Interaction Does Not Work
Check:
- that
UInteractionexists on the interactive entity - that no unintended child or parent is intercepting picking
- that no ancestor clip removes the hit
3) Text Escapes A Clipped Container
- confirm
UClip { enabled: true }is present on the correct ancestor - confirm
UnivisTextPluginis active sosync_text_label_meshesandsync_text_clipper_materialscan apply local and ancestor clipping
4) Scrolling Does Not Work
- the container must carry
UScrollContainerandUInteraction - the mouse must actually hover the container
- the content must overflow the visible area
5) Panel Resize Does Not Work
- make sure
UPanelWindowis present withUPanel - inspect
min_width,min_height, andborder_hit_thickness - make sure the UI is reachable from the currently resolved root camera
Related References
Migration and Limitations
This section tracks the documentation-facing migration steps around the current public surface.
What Changed Recently
- public roots converged on
URootUi - the example catalog now lists only sources that exist in this branch
- the docs now live in one bilingual
docs/book
Start Here
- Docs and Examples Surface Migration
- Root API Migration to
URootUi - Legacy Compatibility Status
- Example Path Migration
- Current Limitations
What This Section Covers
- how to update older root code
- how to move from older docs discovery habits
- where the current example sources live
- what is considered canonical versus legacy compatibility
- which limitations are still real in the current alpha line
Docs and Examples Surface Migration
This page explains the current documentation and example layout.
What Changed
- the docs live in one bilingual mdBook under
docs/ - English and Arabic chapters are mirrored under one shared
SUMMARY.md - the examples catalog lists only source files that exist in this branch
- the standalone demo package is
android/android_phone_app - root guidance centers on
URootUi
Current Discovery Path
README.mdorREADME_AR.mddocs/src/index.md- the relevant guide chapter
- the current example list in
docs/src/*/examples/index.md - generated
rustdocfor exact type paths and signatures
Example Commands In This Branch
Use these commands for the current working tree:
cargo run --manifest-path android/android_phone_app/Cargo.tomlcargo check --workspace --examplescargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
For a task-oriented view, see:
Root Docs Migration
If you previously learned the root model through UScreenRoot or UWorldRoot, use these pages now:
Canonical Sources Now
- landing story:
README.md/README_AR.md - guides:
docs/src/en/*anddocs/src/ar/* - current examples:
docs/src/en/examples/index.mdanddocs/src/ar/examples/index.md - API reference: generated
cargo doc --no-deps -p univis_ui
Root API Migration to URootUi
URootUi is now the canonical public root API.
Old to New Mapping
UScreenRoot->URootUi::screen()UWorldRoot { size, is_3d: false }->URootUi::world_2d(size)UWorldRoot { size, is_3d: true }->URootUi::world_3d(size)
Important Semantic Changes
URootUi::screen()is a real viewport-fixed HUD root.URootUiroots are closed stacking capsules.UVal::Pxmeans logical UI units, not literal monitor pixels.- world-space physical size is controlled by
meters_per_unit.
Legacy Compatibility Notes
UScreenRootandUWorldRootremain deprecated compatibility wrappers.- They are explicit-only migration paths and are no longer part of the recommended prelude story.
- The current removal target is the first alpha after
0.3.0that no longer needs wrapper-based migration support. - Set
meters_per_unitexplicitly when you need a specific physical world-root size.
Related Guides
Legacy Compatibility Status
This page explains which migration-era compatibility paths are still intentionally available, which ones are already de-emphasized, and which ones are expected to stay long-term.
Public Classification
| Item | Current Status | Recommended Path | Planned Direction |
|---|---|---|---|
URootUi, URootUi::screen(), URootUi::world_2d(...), URootUi::world_3d(...) | Canonical public API | keep using them directly | keep long-term |
UiSpace, UiCameraRef, UiCanvasSize | Canonical support types | keep using them directly | keep long-term |
UScreenRoot | Deprecated explicit-only wrapper | URootUi::screen() | de-emphasize now; planned removal target is the first alpha after 0.3.0 that no longer needs wrapper-based migration support |
UWorldRoot | Deprecated explicit-only wrapper | URootUi::world_2d(size) or URootUi::world_3d(size) | de-emphasize now; planned removal target is the first alpha after 0.3.0 that no longer needs wrapper-based migration support |
meters_per_unit = 1.0 on URootUi | Explicit compatibility knob on the canonical root API | keep it only when you need the historical world-root physical size | keep long-term as an opt-in control, not as the default story |
Internal Compatibility Translation
These items are not the recommended public story, but they still exist internally while the alpha surface settles:
- legacy root wrappers are translated into the canonical root-resolution input before camera and canvas resolution run
- legacy scalar alignment fallback is translated toward the ext alignment model before placement decisions
- legacy main-axis flex fallback remains an internal compatibility path while canonical grow/shrink fields stay preferred
Maintainer Rules
- do not add
UScreenRootorUWorldRootto recommended preludes - do not add new examples that depend on deprecated root wrappers
- keep migration docs and README wording aligned with this page before each alpha cut
Planned Removal Window
- current target: remove
UScreenRootandUWorldRootin the first alpha after0.3.0if migration feedback stays clean - reevaluate that target before the cut if published examples, migration guides, or user reports still depend on the wrappers
Related
Example Path Migration
This page records the current example locations.
Current Paths
- Android package demo:
android/android_phone_app - root workspace examples:
examples/*.rs - grid examples:
examples/grid/*.rs - layout examples:
examples/layout/*.rs - widget examples:
examples/widgets/*.rs
Current Commands
Run the Android-style app:
cargo run --manifest-path android/android_phone_app/Cargo.toml
Check every workspace example registered with Cargo:
cargo check --workspace --examples
Check the standalone Android package:
cargo check --manifest-path android/android_phone_app/Cargo.toml --all-targets
Related Guides
Current Limitations
This page lists current, code-verified constraints so setup guidance remains explicit and predictable.
Interaction Camera Dependency
univis_picking_backendresolves the camera from eachURootUithroughResolvedRootUi; it does not hardcodeCamera2d.UPanelWindowresize interaction follows the same resolved-root camera path.- Practical consequence: reliable interaction still requires each active root to resolve to a camera with a valid viewport.
- In multi-camera scenes, prefer
UiCameraRef::Entity(...)instead of relying on automatic camera resolution.
Widget Runtime Notes
UnivisUiPluginaddsUnivisWidgetPluginautomatically.UnivisWidgetPluginnow includes the built-inUTextFieldandUBadgeruntime systems by default.- Dedicated widget plugins remain available when you intentionally compose a narrower widget surface.
UTagruntime systems are still limited; validate tag-heavy scenes manually.
Verification Sources
crates/univis_ui_interaction/src/interaction/picking.rscrates/univis_ui_widgets/src/widget/panel.rscrates/univis_ui_widgets/src/widget/mod.rscrates/univis_ui_widgets/src/widget/text_field.rscrates/univis_ui_widgets/src/widget/badge.rscrates/univis_ui_engine/src/layout/layout_system.rs
Changelog
Changelog
All notable changes to this project will be documented in this file.
[Unreleased]
Added
- 3D Text Rendering: Added full support for rendering
UTextLabelin 3D using standard PBR lighting. Text now accurately reacts to scene lighting and shadows just like standard 3D meshes. - 3D Text Example: Added
examples/text_3d.rsto demonstrate PBR-lit 3D text labels alongside normal widgets and scene lights. - 2D Picking Example: Added
examples/picking_2d.rsto demonstrate 2D UI picking interactions.
Fixed
- 3D Text Scaling: Fixed an issue where text meshes ignored the root UI scale (
ui_to_world_scale) in 3D. 3D text now correctly and automatically scales to match the physical node dimensions (default0.001scale) without requiring manual Transform scaling. - Shader Pipeline Panics: Resolved
Validation Error: Pipeline layout mismatchpanics occurring when using the wrong material bind group in 3D UI nodes. PBR widgets and text SDF shaders now correctly bind to@group(3). - UI Picking Math: Fixed UI picking math scaling and interaction detection for 3D elements, specifically ensuring hit tests work accurately under scaled projections and when nodes are nested.
- Widget Behaviors: Addressed issues with widgets like
seekbarnot responding interactively unless properly configured within panels.