Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 tree
  • en/ 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/

Guides vs API Docs

  • Use the guide chapters for mental models, migration notes, and example-driven learning.
  • Use generated rustdoc for 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

إلى أين بعد ذلك؟

البدء السريع

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::UnivisUiPlugin
  • univis_ui::prelude
  • univis_ui::layout::layout_system::{UScreenRoot, UWorldRoot} لمسار التوافق القديم فقط
  • univis_ui_engine::layout::layout_system::URootUi
  • univis_ui_engine::layout::univis_node::{UNode, ULayout}

إلى أين بعد ذلك؟

إعداد الإضافات وأولى المسارات

هذه الصفحة هي أقصر مسار موجّه بحسب المهمة بعد البدء السريع.

استخدمها عندما تريد صفحة واحدة تجيب عن سؤالين:

  • ما هي الإضافات التي أحصل عليها فعليًا بشكل افتراضي؟
  • ما الذي يجب أن أفتحه أو أشغّله أولًا بحسب المهمة التي تهمني؟

ملاحظة تخص هذا الفرع

يعرض فهرس الأمثلة فقط ملفات المصدر الموجودة في هذا الفرع. الحزمة المستقلة ذات الطابع Android داخل android/android_phone_app هي أفضل عرض كامل للشاشة.

إعداد الواجهة المجمعة

إذا أضفت UnivisUiPlugin فأنت تحصل مسبقًا على:

  • UnivisUiStylePlugin
  • UnivisEnginePlugin
  • UnivisInteractionPlugin
  • UnivisWidgetPlugin

وهذا هو المسار الموصى به لمعظم التطبيقات.

تغطية Runtime للوحدات الجاهزة

يتضمن UnivisUiPlugin إضافة UnivisWidgetPlugin، وهذا السطح الافتراضي يضم الآن أيضًا:

  • UnivisTextFieldPlugin لسلوك وأحداث UTextField
  • UnivisBadgePlugin للتحديثات الديناميكية لـ 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.rs
  • crates/univis_ui_engine/src/layout/core/pass_up.rs
  • crates/univis_ui_engine/src/layout/core/pass_down.rs
  • crates/univis_ui_engine/src/layout/core/solver.rs
  • crates/univis_ui_engine/src/layout/core/layout_cache.rs

مبادئ أساسية

  • تبدأ الجذور من URootUi.
  • LayoutDepth يُحسب تلقائيًا عبر traversal.
  • IntrinsicSize يُستخدم لتقدير المقاسات المعتمدة على المحتوى.
  • ComputedSize هو الناتج النهائي المعتمد للرندر.

الجذور والمساحات

URootUi هو المدخل العام الوحيد للجذر في الواجهة. ويحسم كل شجرة UI إلى واحد من ثلاثة فضاءات:

  • UiSpace::Screen
  • UiSpace::World2d
  • UiSpace::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::URootUi
  • univis_ui_engine::layout::layout_system::UiSpace
  • univis_ui_engine::layout::layout_system::UiCanvasSize
  • univis_ui_engine::layout::layout_system::UiCameraRef
  • univis_ui_engine::layout::pbr::UPbr

إلى أين بعد ذلك؟

UNode وقياسات الصندوق

UNode هو اللبنة الأساسية لأي عنصر واجهة.

الحقول الأساسية

  • width: UVal
  • height: UVal
  • min_width: f32
  • max_width: f32
  • min_height: f32
  • max_height: f32
  • padding: USides
  • margin: USides
  • background_color: Color
  • border_radius: UCornerRadius
  • shape_mode: UShapeMode

UVal

الوحدات المدعومة:

  • Px(f32)
  • Percent(f32)
  • MinContent
  • MaxContent
  • Content
  • Auto
  • Flex(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

بعد الحل النهائي يحصل كل عنصر على:

  • width
  • height
  • local_pos

وهذا هو القياس الذي يستخدمه الرندر.

UBorder

حدود مرئية مستقلة عن خلفية UNode:

  • color
  • width
  • radius
  • offset

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 للحاوية

الحقول الأساسية:

  • display
  • flex_direction
  • justify_content
  • align_items
  • gap
  • grid_columns

الحقول المتقدمة:

  • container_ext: ULayoutContainerExt
    • box_align: ULayoutBoxAlignContainer
    • flex: ULayoutFlexContainer
    • grid: ULayoutGridContainer

محاذاة الحاوية

  • justify_items: Option<UAlignItemsExt>
  • align_content: Option<UContentAlignExt>
  • row_gap: Option<f32>
  • column_gap: Option<f32>

إعدادات الحاوية المرنة

  • wrap: UFlexWrap
  • align_content: Option<UContentAlignExt>

إعدادات الحاوية الشبكية

  • template_columns: Vec<UTrackSize>
  • template_rows: Vec<UTrackSize>
  • auto_flow: UGridAutoFlow
  • auto_rows: UTrackSize
  • auto_columns: UTrackSize

USelf للعنصر

الحقول الأساسية:

  • align_self
  • left/right/top/bottom
  • order
  • position_type

الحقول المتقدمة:

  • item_ext: ULayoutItemExt
    • box_align: ULayoutBoxAlignSelf
    • flex: ULayoutFlexItem
    • grid: ULayoutGridItem

محاذاة العنصر

  • justify_self: Option<UAlignSelfExt>
  • align_self: Option<UAlignSelfExt>
  • justify_overflow: UOverflowPosition
  • align_overflow: UOverflowPosition

إعدادات العنصر المرن

  • flex_grow: Option<f32>
  • flex_shrink: Option<f32>
  • flex_basis: Option<UVal>

إعدادات العنصر الشبكي

  • column_start: Option<u32>
  • column_span: u32
  • row_start: Option<u32>
  • row_span: u32

أنماط العرض

UDisplay يدعم الأنماط التالية:

  • Flex
  • Grid
  • Masonry
  • Stack
  • Radial
  • None

التدفق المرن

  • يعتمد 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 يسمح بتخصيص:
    • metallic
    • roughness
    • emissive

هذا يؤثر على مسار المادة ثلاثية الأبعاد (UNodeMaterial3d).

المرور الصاعد والهابط والحال

المرور الصاعد: upward_measure_pass_الذاكرة المؤقتةd

  • يتحرك من أعمق مستوى إلى الجذر.
  • يحسب IntrinsicSize للحاويات اعتمادًا على الأبناء.
  • يتجاهل العناصر Absolute خارج التدفق.
  • يستخدم الذاكرة المؤقتة لتخطي الحساب عند عدم الاتساخ.

المرور الهابط: downward_solve_pass_safe

  • يتحرك من الجذر إلى العمق الأقصى.
  • يبني SolverConfig وSolverSpec لكل عنصر.
  • يستدعي solve_flex_layout (المحرك الأساسي لكل الأنماط عبر طبقة الربط).
  • يكتب النتائج إلى:
    • ComputedSize
    • Transform.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؟

عند تغيّر واحد من:

  • UNode
  • ULayout
  • USelf
  • Children
  • IntrinsicSize

مع استثناء مهم:

  • إذا كان التغيير الوحيد 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.

أمثلة مرتبطة

نقاط الدخول الرسمية في API

  • univis_ui_widgets::widget::text_label::UTextLabel
  • univis_ui_widgets::widget::button::UButton
  • univis_ui_widgets::widget::text_field::UTextField
  • univis_ui_widgets::widget::panel::{UPanel, UPanelWindow}
  • univis_ui_widgets::widget::scroll_view::UScrollContainer

إلى أين بعد ذلك؟

Text و Image و Badge

UTextLabel

الملف: src/widget/text_label.rs

الحقول الأساسية:

  • text
  • font_size
  • color
  • font
  • justify
  • linebreak
  • autosize
  • overflow افتراضيًا هو Ellipsis، ويمكن التحويل إلى Clip أو Visible عند الحاجة
  • truncate_side يتحكم في القص مع Ellipsis: من البداية أو النهاية أو الوسط

الأنظمة:

  • measure_text_label_layout
  • fit_node_to_text_size
  • sync_text_label_meshes
  • sync_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:
    • DragValueChangedEvent
    • DragValueCommitEvent

USelect

  • الملف: src/widget/select.rs
  • dropdown select مع خيارات معطلة ودعم keyboard أساسي.
  • events:
    • SelectChangedEvent
    • SelectOpenStateChangedEvent

UTextField

  • الملف: src/widget/text_field.rs
  • text input مع cursor blink وfocus logic.
  • Runtime مضاف افتراضيًا عبر UnivisWidgetPlugin.
  • الإضافة المخصصة: UnivisTextFieldPlugin عند تركيب سطح widgets أضيق.
  • events:
    • TextFieldChangedEvent
    • TextFieldSubmitEvent

مثال حي

  • استخدم cargo run --example widgets_inputs لرؤية UTextField وUSelect وUDragValue وUSeekBar

اللوحة ونافذة اللوحة

UPanel

الملف: src/widget/panel.rs

خصائص أساسية:

  • background
  • border_color
  • border_width
  • border_radius
  • padding
  • gap
  • direction

وظيفته: تقديم container جاهز بواجهة panel.

UPanelWindow الاختيارية

UPanelWindow يضيف سلوك resize من الحدود والزوايا إلى UPanel.

الحقول:

  • border_hit_thickness
  • min_width
  • min_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_speed
  • vertical
  • horizontal
  • offset

الإضافة

  • 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:

    • Normal
    • Hovered
    • Pressed
    • Released
    • Clicked
  • UInteractionColors:

    • normal
    • hovered
    • pressed

فكرة العمل

  1. خلفية الالتقاط تحسب الضربات.
  2. نظام الالتقاط في Bevy يطلق أحداث المؤشر.
  3. مراقبو الأحداث في interaction/feedback.rs تحدّث UInteraction واللون.

ملاحظة

التفاعل يعتمد على وجود UInteraction على الكيان الهدف.

مراجع مرتبطة

أمثلة مرتبطة

نقاط الدخول الرسمية في API

  • univis_ui_interaction::interaction::feedback::UInteraction
  • univis_ui_interaction::interaction::feedback::UInteractionColors
  • univis_ui_interaction::interaction::picking::univis_picking_backend

إلى أين بعد ذلك؟

خلفية الالتقاط

الملف: 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> => Hovered
  • Pointer<Out> => Normal
  • Pointer<Press> => Pressed
  • Pointer<Release> => Released
  • Pointer<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(...))الشروط / الملاحظات
الرندر الأساسيSupportedSupportedSupportedScreen وWorld2d يستخدمان مسار 2D، بينما World3d يستخدم مسار المواد ثلاثي الأبعاد.
الالتقاط + أحداث المؤشرSupportedSupportedSupportedالتفاعل يحسم الكاميرا من كل root عبر ResolvedRootUi. وفي المشاهد متعددة الكاميرات يُفضّل استخدام UiCameraRef::Entity.
hit testing مع القصSupportedSupportedSupportedفحص قص الأسلاف يعمل في كل الفضاءات. وجذور العالم ما تزال تُفحص على مستوى plane الواجهة نفسها.
مقابض تغيير حجم UPanelWindowSupportedSupportedSupportedمنطق تغيير الحجم يحسب حركة المؤشر عبر كاميرا الجذر ومستوى اللوحة.
إدخال/أحداث UTextFieldSupportedSupportedSupportedمضمّن افتراضيًا عبر UnivisWidgetPlugin؛ أضف UnivisTextFieldPlugin مباشرة فقط عند تركيب widgets يدويًا بشكل أضيق.
تفاعل UScrollContainerSupportedSupportedSupportedالتمرير يتبع مسار الكاميرا المحلولة من الجذر.
خصائص UPbr (metallic, roughness, emissive)N/AN/ASupportedمخصصة فقط لمسار World3d.

ملاحظات

  • URootUi::screen() هو مسار HUD حقيقي مربوط بالـ viewport المحلول.
  • URootUi::world_2d(...) وURootUi::world_3d(...) يعتمدان canvas منطقيًا ثابتًا مع world scaling صريح.
  • meters_per_unit يغيّر الحجم الفيزيائي في العالم من دون تغيير حجم التخطيط المنطقي.

مصادر التحقق

  • crates/univis_ui_interaction/src/interaction/picking.rs
  • crates/univis_ui_widgets/src/widget/panel.rs
  • crates/univis_ui_engine/src/layout/layout_system.rs
  • crates/univis_ui_engine/src/layout/render/system.rs

فهرس الأمثلة

تعرض هذه الصفحة فقط ملفات الأمثلة الموجودة فعليًا في المستودع الحالي.

تشغيل العرض الحالي

cargo run --manifest-path android/android_phone_app/Cargo.toml

حزمة Android المستقلة

المثالالمصدرالغرضالأمر
android_phoneandroid/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_testexamples/responsive_layout_test.rsمشهد ضغط لتركيب واجهة شاشة متجاوبة.cargo run --example responsive_layout_test
toggle_seekbarexamples/toggle_seekbar.rsمشهد تحكم صغير لسلوك toggle وseek-bar.cargo run --example toggle_seekbar
z_order_hierarchyexamples/z_order_hierarchy.rsفحص الترتيب البصري وسلوك تراكب الهرمية.cargo run --example z_order_hierarchy

تخطيط Grid

المثالالمصدرالغرضالأمر
grid_columnsexamples/grid/columns.rsأحجام أعمدة grid وسلوك التخطيط.cargo run --example grid_columns
grid_tracksexamples/grid/tracks.rsسلوك أحجام مسارات grid.cargo run --example grid_tracks
grid_auto_flowexamples/grid/auto_flow.rsسلوك التموضع التلقائي داخل grid.cargo run --example grid_auto_flow
grid_item_placementexamples/grid/item_placement.rsالتموضع الصريح لعناصر grid.cargo run --example grid_item_placement

أنماط التخطيط

المثالالمصدرالغرضالأمر
layout_flexexamples/layout/flex.rsتركيب flex layout.cargo run --example layout_flex
layout_masonryexamples/layout/masonry.rsتركيب masonry layout.cargo run --example layout_masonry
layout_stackexamples/layout/stack.rsتركيب stack layout.cargo run --example layout_stack
layout_radialexamples/layout/radial.rsتركيب radial layout.cargo run --example layout_radial

الوحدات الجاهزة

المثالالمصدرالغرضالأمر
widgets_controlsexamples/widgets/controls.rsأزرار وتبديلات وcheckbox وradio controls.cargo run --example widgets_controls
widgets_inputsexamples/widgets/inputs.rsText field وselect وdrag-value وseek-bar inputs.cargo run --example widgets_inputs
widgets_displayexamples/widgets/display.rsنصوص وbadges ومقسمات ولوحات وprogress display.cargo run --example widgets_display
widgets_containersexamples/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

صفحات مرتبطة

معرض الأمثلة

تعرض هذه الصفحة الأمثلة الموجودة في المستودع الحالي فقط.

أفضل مسارات البدء

  1. البدء السريع
  2. android_phone
  3. widgets_controls
  4. widgets_inputs
  5. responsive_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_inputsText fields وselect وdrag-value وseek-bar inputs.cargo run --example widgets_inputs
widgets_displayالنصوص وbadges والمقسمات واللوحات وprogress display.cargo run --example widgets_display
widgets_containersPanel 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

  • DragValueChangedEvent
  • DragValueCommitEvent

Select

  • SelectChangedEvent
  • SelectOpenStateChangedEvent

TextField

  • TextFieldChangedEvent
  • TextFieldSubmitEvent

نمط استهلاك الأحداث

#![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::UnivisUiPlugin
  • univis_ui::prelude

أنواع الجذور والتخطيط

  • univis_ui_engine::layout::layout_system::URootUi
  • univis_ui_engine::layout::layout_system::UiSpace
  • univis_ui_engine::layout::layout_system::UiCanvasSize
  • univis_ui_engine::layout::layout_system::UiCameraRef
  • univis_ui_engine::layout::univis_node::UNode
  • univis_ui_engine::layout::univis_node::ULayout
  • univis_ui_engine::layout::univis_node::USelf
  • univis_ui_engine::layout::univis_node::UBorder
  • univis_ui_engine::layout::univis_node::UClip
  • univis_ui_engine::layout::pbr::UPbr
  • univis_ui_engine::layout::geometry::UVal
  • univis_ui_engine::layout::geometry::USides
  • univis_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::UInteraction
  • univis_ui_interaction::interaction::feedback::UInteractionColors
  • univis_ui_interaction::interaction::UnivisInteractionPlugin

أنواع النمط

  • univis_ui_style::style::Theme
  • univis_ui_style::style::TextStyles
  • univis_ui_style::style::IconStyles
  • univis_ui_style::style::Fonts
  • univis_ui_style::style::UnivisUiStylePlugin

الوحدات الجاهزة

  • univis_ui_widgets::widget::text_label::UTextLabel
  • univis_ui_widgets::widget::button::UButton
  • univis_ui_widgets::widget::checkbox::UCheckbox
  • univis_ui_widgets::widget::toggle::UToggle
  • univis_ui_widgets::widget::radio::{URadioButton, URadioGroup}
  • univis_ui_widgets::widget::seekbar::USeekBar
  • univis_ui_widgets::widget::drag_value::UDragValue
  • univis_ui_widgets::widget::select::{USelect, USelectOption}
  • univis_ui_widgets::widget::text_field::UTextField
  • univis_ui_widgets::widget::scroll_view::UScrollContainer
  • univis_ui_widgets::widget::panel::{UPanel, UPanelWindow}
  • univis_ui_widgets::widget::progress::UProgressBar
  • univis_ui_widgets::widget::badge::{UBadge, UTag}

أنواع التشخيص والرندر

  • univis_ui_engine::layout::render::UnivisRenderPlugin
  • univis_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 عامة، لكنها موجهة للتكاملات المتقدمة.
  • تبقى طبقات التوافق المهجورة على مسارات صريحة بدل أن تدخل في قصة الاستيراد الافتراضية.

التطوير والمساهمة

قواعد عملية قبل أي تعديل

  1. افهم ترتيب الأنظمة قبل التعديل، خصوصًا في التخطيط والرندر والتفاعل.
  2. لا تكسر Reflection للأنواع العامة بلا سبب واضح.
  3. اختبر التعديل على الحزمة الحية الحالية أو على فحوص مصدرية مكافئة، وليس على اختبارات الوحدة فقط.
  4. عند إضافة وحدة جاهزة جديدة، وفّر:
    • واجهة مكوّن واضحة
    • إضافة مستقلة
    • رسائل أحداث عند الحاجة
    • عرضًا قابلًا للتشغيل عندما يحمل الفرع أمثلة تشغيلية فعلية
    • توثيقًا في README وهذا الكتاب

مكان التوثيق والأمثلة

أسلوب الكود داخل المشروع

  • فضّل المكونات الصغيرة والأنظمة الواضحة
  • اجعل السلوك البصري مدفوعًا عبر UNode وUBorder وUInteractionColors
  • تجنب الآثار الجانبية المفاجئة خارج الجدولة المقصودة

فروع العمل المقترحة

  • feat/<name> للميزات
  • fix/<name> للإصلاحات
  • docs/<name> للتوثيق

المعمارية

بنية univis_ui مقسمة إلى أربع وحدات رئيسية:

  • layout/: محرك التخطيط والحساب المكاني.
  • interaction/: الالتقاط بالمؤشر وحالات التفاعل.
  • widget/: الوحدات الجاهزة المضمنة، مثل الأزرار والإدخال والقوائم.
  • style/: خطوط وأيقونات وثيم أساسي.

الفكرة الأساسية

كل شيء في Univis مبني من كيانات ومكوّنات ضمن ECS:

  • لا توجد شجرة واجهة محتفظ بها خارجيًا.
  • كل عنصر واجهة هو كيان يحمل UNode ومعه مكونات إضافية.
  • التخطيط والحساب يتمان عبر أنظمة ضمن جداول Bevy.

المسار القياسي للإطار

  1. PreUpdate:
  • تشغيل خلفية الالتقاط لاكتشاف الكيانات المصابة.
  1. Update:
  • أنظمة الوحدات الجاهزة والتفاعل وتحديث المرئيات المنطقية.
  1. PostUpdate:
  • خط معالجة التخطيط:
    • update_layout_hierarchy
    • upward_measure_pass_cached
    • downward_solve_pass_safe
  • أنظمة الرندر/المواد (حسب التغييرات).

أهداف التصميم

  • دقة بصرية عالية عبر SDF.
  • مرونة عالية في التخطيط، مثل التدفق المرن والشبكة والبناء الحجري والتكديس والشعاعي.
  • قابلية التوسيع عبر مكونات ECS والإضافات.
  • قابلية تتبع الأداء عبر طبقة المراقبة والذاكرة المؤقتة.

خريطة الإضافات

الإضافة الجذرية

في src/lib.rs:

  • UnivisUiPlugin يضيف بالترتيب:
    1. UnivisUiStylePlugin
    2. UnivisEnginePlugin
    3. UnivisInteractionPlugin
    4. UnivisWidgetPlugin

التخطيط

  • UnivisEnginePlugin:
    • UnivisNodePlugin
    • UnivisLayoutPlugin
    • UnivisRenderPlugin
    • وتوفر معًا بدائيات العقدة وحسم الجذور وحل التخطيط ومزامنة الرندر.

التفاعل

  • UnivisInteractionPlugin:
    • univis_picking_backend في PreUpdate.
    • مراقبو الأحداث:
      • on_pointer_over
      • on_pointer_out
      • on_pointer_press
      • on_pointer_release
      • on_pointer_click

النمط

  • UnivisUiStylePlugin:
    • تحميل خطوط مضمّنة.
    • تحميل خط أيقونات Lucide.
    • إنشاء المورد Theme.

الوحدات الجاهزة

UnivisWidgetPlugin يضيف مجموعة الوحدات الجاهزة الأساسية. الحالة الحالية:

  • مضاف تلقائيًا:
    • UnivisTextPlugin
    • UnivisProgressPlugin
    • UnivisButtonPlugin
    • UnivisRadioPlugin
    • UnivisIconButtonPlugin
    • UnivisTogglePlugin
    • UnivisCheckboxPlugin
    • UnivisSeekBarPlugin
    • UnivisScrollViewPlugin
    • UnivisDividerPlugin
    • UnivisPanelPlugin
    • UnivisBadgePlugin
    • UnivisDragValuePlugin
    • UnivisSelectPlugin
    • UnivisTextFieldPlugin

وتبقى الإضافات المخصصة نفسها متاحة عندما تريد تركيب سطح 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.rs
  • crates/univis_ui_engine/src/lib.rs
  • crates/univis_ui_widgets/src/widget/mod.rs

دورة الإطار

هذا الفصل يربط بين الأنظمة في الزمن داخل إطار Bevy واحد.

ما قبل التحديث

  • النظام univis_picking_backend:
    • يحول موقع المؤشر إلى فضاء العالم.
    • يفحص تقاطع SDF مع كل عنصر تفاعلي.
    • يحترم القص من الآباء (UClip).
    • ينشر PointerHits لاستخدامها بواسطة أحداث المراقبة.

التحديث

  • أنظمة الوحدات الجاهزة (تحديث الحالة، مزامنة المرئيات، وإطلاق الرسائل).
  • أنظمة التمرير وتغيير حجم اللوحة وغيرها.
  • أنظمة النص وتحديث حجمه.

ما بعد التحديث

  • خط معالجة التخطيط بالترتيب الحرج:

    1. update_layout_hierarchy
    2. upward_measure_pass_cached
    3. downward_solve_pass_safe
  • مزامنة الرندر:

    • update_materials_optimized يزامن UNode/ComputedSize/UBorder/... إلى المواد.

لماذا هذا الترتيب مهم؟

  • أي تعديل في Update، مثل تغيير حجم اللوحة أو قيمة الإدخال، يجب أن ينعكس في التخطيط النهائي قبل الرسم.
  • الذاكرة المؤقتة وآلية الإبطال تعملان قبل القياس لتقليل الحساب غير الضروري.

الرندر

الرندر في Univis يعتمد على مواد SDF مخصصة:

  • UNodeMaterial لمسار 2D.
  • UNodeMaterial3d لمسار 3D.

الملفات الأساسية:

  • src/layout/render/system.rs
  • src/layout/render/material.rs
  • src/layout/render/material_3d.rs
  • src/layout/render/shaders/unode.wgsl
  • src/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)

أهم الحقول:

  • color
  • border_color
  • radius
  • size
  • border_width
  • border_offset
  • softness
  • shape_mode
  • use_texture
  • texture
  • clip_center
  • clip_size
  • clip_radius
  • use_clip

UNodeMaterial3d

مسار 3D يضيف خصائص PBR:

  • metallic
  • roughness
  • emissive

الشيدر 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 مفعّلًا فقط. إذا كانت هناك عدة أسلاف قاصين متداخلين، فهي لا تُدمج بعد في تقاطع قص واحد للنص.

الأداء والتشخيص

المشروع يحتوي ثلاث أدوات أساسية للأداء:

  1. LayoutCache لتقليل الحسابات.
  2. UnivisLayoutProfilingPlugin لقياس الزمن وعرض طبقة المراقبة.
  3. ./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.txt
  • perf_baselines/current_max/2026-04-05/runtime_benchmarks.txt
  • perf_baselines/current_max/2026-04-05/manifest.json
  • perf_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.

شكل الصفحة

يُفضَّل اتباع بنية قصيرة ومتكررة:

  1. لماذا توجد هذه الصفحة.
  2. الحد الأدنى من النموذج الذهني المطلوب.
  3. القواعد العملية أو الأمثلة.
  4. الأمثلة المرتبطة.
  5. أنواع 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_* فقط عندما تحافظ الشيفرة عمدًا على دلالة قديمة
  • أبقِ طبقات التوافق المهجورة واضحة في التسمية والتوثيق
  • تجنب إضافة أسماء انتقالية جديدة إلا إذا كانت تحمي مسار ترحيل عام حقيقي

قائمة تحقق قبل إعادة التسمية

قبل إنشاء وحدة جديدة أو إعادة تسميتها، تأكد من:

  1. هل يصف اسم الملف المسؤولية بدلًا من التفصيل التنفيذي؟
  2. هل يستطيع مساهم جديد أن يعرف هل تنتمي الشيفرة إلى model أو runtime أو state أو events أو translation أو placement؟
  3. هل يطابق الاسم الجديد أنماط الإضافات والمكوّنات والحالات الموجودة في الوحدات الشقيقة؟

خريطة الصيانة

هذه الصفحة هي الخريطة المختصرة الموجهة للمحافظين على المشروع: من يملك ماذا، وأين توجد الحدود الكبيرة بين الوحدات، وما هي النقاط الحساسة التي تحتاج مراجعة دقيقة.

خريطة الحزم في مساحة العمل

  • univis_ui: حزمة الواجهة الجامعة وقصة الاستيراد الموصى بها للتطبيقات
  • univis_ui_style: موارد الثيم والخطوط والأيقونات المشتركة
  • univis_ui_engine: نموذج الجذور، solver التخطيط، وجدولة settlement، ومزامنة الرندر
  • univis_ui_interaction: الالتقاط وحالة التفاعل والتحقق المبني على المؤشر
  • univis_ui_widgets: الوحدات الجاهزة عالية المستوى المبنية فوق المحرك والتفاعل

خريطة وحدات المحرك

  • layout::layout_system: حل الجذور، وكبسولات ترتيب الجذور، وتحويلات الشاشة، وحالة settlement لكل root
  • layout::univis_node: المكوّنات التي يكتبها المستخدم للعقدة والتخطيط والتموضع المحلي
  • layout::geometry: وحدات الواجهة المنطقية والهوامش والقيود ومساعدات المحاور
  • layout::core: تتبع البنية والذاكرة المؤقتة والقياس والحل ومساعدات solver
  • layout::render: مزامنة الـ mesh والمواد بعد استقرار التخطيط
  • layout::profiling: أدوات التشخيص والطبقة البصرية الاختيارية
  • layout::registration وlayout::settlement_loop: ربط pipeline وتنفيذ PostUpdate المحدود

خريطة وحدات الوحدات الجاهزة

  • الوحدات البسيطة تبقى في ملف واحد عندما تكون runtime صغيرة
  • الوحدات ذات الحالة تقسم حسب المسؤولية:
    • model
    • runtime
    • interaction
    • visuals
    • events
  • 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 خارج المحرك أثناء تنظيف الاستثناءات الحالية

متى تضيف حزمة جديدة

أضف حزمة جديدة فقط إذا تحقق واحد على الأقل مما يلي:

  1. الشيفرة تقدم حدًا reusable يمكن للتطبيقات اختياره بشكل مستقل
  2. الميزة تحتاج سطح استيراد عامًا منفصلًا أو lifecycle مستقلة للإضافة
  3. رسم الاعتماديات يصبح أنظف بعزل 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 وevents
  • panel/ يفصل بين حسابات 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 queues
  • layout::core::pass_up: القياس الداخلي ونشر أحجام المحتوى
  • layout::core::pass_down: مخرجات الحل النهائي وتموضع الأبناء
  • layout::core::solver: حل الأحجام وربط placement
  • layout::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/ موطنه المقصود
  • حدّث فهرس الأمثلة في اللغتين عندما تتغير حالة التوفر
  • أضف تعليقًا قصيرًا داخل المثال يشير إلى صفحة الشرح المرتبطة عندما يكون المثال مرجعيًا

كيفية إضافة صفحات متقابلة بين اللغتين

  1. أنشئ الصفحة الإنجليزية
  2. أنشئ الصفحة العربية النظيرة في المسار المقابل
  3. أضف الصفحتين إلى docs/src/SUMMARY.md
  4. حدّث هدف مبدّل اللغة إذا كانت الصفحة امتدادًا لفصل موجود

كيفية إضافة 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.md
  • README_AR.md
  • MIGRATION.md
  • MIGRATION_AR.md
  • RELEASE_NOTES.md
  • changelog.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: الملخص الحالي على مستوى الإصدار alpha
  • RELEASE_PREP_0.3.0.md: أدلة التحقق المحلية قبل قطع 0.3.0
  • changelog.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 --check
  • cargo clippy --workspace --all-targets مع قائمة السماح الحالية للديون المعروفة المرتبطة بـ Bevy
  • cargo check --workspace --all-targets
  • ./scripts/check_public_api_surface.sh
  • ./scripts/check_structure_guardrails.sh
  • ./scripts/check_engine_boundary_guardrails.sh
  • cargo 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.txt
  • perf_baselines/current_max/2026-04-05/runtime_benchmarks.txt
  • perf_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

إستراتيجية عملية قبل الدمج

  1. شغّل اختبارات الوحدة المرتبطة بالتغيير
  2. شغّل ./scripts/check_quality.sh
  3. شغّل ./scripts/check_representative_examples.sh
  4. شغّل cargo check --workspace --examples
  5. شغّل حزمة Android عندما يمس التغيير السطح الحي الحالي
  6. استخدم التحقق البصري عندما يكون التغيير ثقيلًا في الرندر أو التخطيط أو التفاعل

المطلوب قبل قطع alpha التالية

  • ./scripts/check_quality.sh
  • mdbook build docs
  • cargo doc -p univis_ui_style --no-deps
  • cargo doc -p univis_ui_engine --no-deps
  • cargo doc -p univis_ui_interaction --no-deps
  • cargo doc -p univis_ui_widgets --no-deps
  • cargo doc -p univis_ui --no-deps
  • cargo 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.rs
  • examples/responsive_layout_test.rs
  • examples/toggle_seekbar.rs
  • examples/z_order_hierarchy.rs
  • examples/grid/auto_flow.rs
  • examples/grid/columns.rs
  • examples/grid/item_placement.rs
  • examples/grid/tracks.rs
  • examples/layout/flex.rs
  • examples/layout/masonry.rs
  • examples/layout/radial.rs
  • examples/layout/stack.rs
  • examples/widgets/containers.rs
  • examples/widgets/controls.rs
  • examples/widgets/display.rs
  • examples/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

سيناريوهات التشغيل اليدوي

  1. سلامة حزمة الشاشة الضيقة بطابع Android
  2. فحص أمثلة مساحة العمل المرتبطة بمناطق التخطيط أو الوحدات المتأثرة
  3. مرور سريع على وضوح النصوص وعناصر التحكم

الأوامر

cargo run --manifest-path android/android_phone_app/Cargo.toml

لأمثلة مساحة العمل، استخدم cargo run --example <name> مع مدخل من فهرس الأمثلة.

معايير النجاح

  • عدم حدوث panic عند البداية
  • فتح الحزمة بطابع Android مع بقاء سطح التطبيق المقروء داخل العرض الضيق
  • بقاء UTextField وUToggle وUSeekBar وUButton متماسكة بصريًا وتفاعليًا
  • فتح أمثلة مساحة العمل المرتبطة وبقاؤها متماسكة بصريًا

تشخيص الإخفاق

  1. سجّل السطح الذي فشل والعرض الظاهر للمشكلة
  2. أعد تشغيل حزمة Android مع RUST_BACKTRACE=1 إذا كان الإخفاق وقت التشغيل
  3. صنّف المشكلة: compile أو runtime أو widget أو rendering
  4. أضف ملاحظة في 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/

ابدأ من هنا

ما الذي يغطيه هذا القسم

  • كيفية تحديث كود الجذور الأقدم
  • كيفية الانتقال من نمط الاكتشاف القديم في التوثيق
  • أين توجد مصادر الأمثلة الحالية
  • ما الذي يعتبر رسميًا الآن وما الذي بقي فقط للتوافق مع القديم
  • ما هي القيود التي ما زالت موجودة فعلًا في المرحلة alpha الحالية

ترحيل سطح الوثائق والأمثلة

تشرح هذه الصفحة شكل الوثائق والأمثلة الحالي.

ما الذي تغيّر

  • الوثائق موجودة في mdBook ثنائي اللغة واحد داخل docs/
  • الفصول العربية والإنجليزية متقابلة تحت SUMMARY.md واحد
  • فهرس الأمثلة يعرض فقط ملفات المصدر الموجودة في هذا الفرع
  • حزمة العرض المستقلة هي android/android_phone_app
  • قصة الجذور تدور حول URootUi

مسار الاكتشاف الحالي

  1. README.md أو README_AR.md
  2. docs/src/index.md
  3. فصل الشرح المناسب
  4. قائمة الأمثلة الحالية داخل docs/src/*/examples/index.md
  5. rustdoc المولد للمسارات والتواقيع الدقيقة

أوامر الأمثلة في هذا الفرع

استخدم هذه الأوامر مع شجرة العمل الحالية:

  • cargo run --manifest-path android/android_phone_app/Cargo.toml
  • cargo check --workspace --examples
  • cargo 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.rs
  • crates/univis_ui_widgets/src/widget/panel.rs
  • crates/univis_ui_widgets/src/widget/mod.rs
  • crates/univis_ui_widgets/src/widget/text_field.rs
  • crates/univis_ui_widgets/src/widget/badge.rs
  • crates/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 UTextLabel in 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.rs to demonstrate PBR-lit 3D text labels alongside normal widgets and scene lights.
  • 2D Picking Example: Added examples/picking_2d.rs to 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 (default 0.001 scale) without requiring manual Transform scaling.
  • Shader Pipeline Panics: Resolved Validation Error: Pipeline layout mismatch panics 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 seekbar not 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 (via Cargo.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 rustdoc for exact type paths, fields, and signatures.

Generate the API docs with:

cargo doc --no-deps -p univis_ui

Where To Look Next

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() and URootUi::world_3d_fit_content() size world roots from measured content.
  • UVal::Px means logical UI units, not literal display pixels.
  • UiCanvasSize::Viewport follows 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

  • UnivisWidgetPlugin now auto-registers the built-in UTextField and UBadge runtime systems.
  • UnivisScrollViewPlugin is included by default in UnivisWidgetPlugin.
  • Interaction resolves the camera from each URootUi.
  • In multi-camera scenes, prefer binding the root explicitly with UiCameraRef::Entity.
  • UScreenRoot and UWorldRoot remain available only as deprecated compatibility wrappers on explicit paths such as univis_ui::layout::layout_system::{UScreenRoot, UWorldRoot}.
  • Set meters_per_unit explicitly 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();
}

API Entry Points

  • univis_ui::UnivisUiPlugin
  • univis_ui::prelude
  • univis_ui::layout::layout_system::{UScreenRoot, UWorldRoot} for explicit legacy compatibility only
  • univis_ui_engine::layout::layout_system::URootUi
  • univis_ui_engine::layout::univis_node::{UNode, ULayout}

Where To Look Next

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:

  • UnivisUiStylePlugin
  • UnivisEnginePlugin
  • UnivisInteractionPlugin
  • UnivisWidgetPlugin

This is the recommended path for most applications.

Widget Runtime Coverage

UnivisUiPlugin includes UnivisWidgetPlugin, and that default widget surface now includes:

  • UnivisTextFieldPlugin for UTextField behavior and events
  • UnivisBadgePlugin for dynamic UBadge / UTag updates

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 Camera2d is 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, and UButton in 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

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 visuals
  • ULayout: container behavior
  • USelf: per-child item behavior

Important Files

  • crates/univis_ui_engine/src/layout/univis_node.rs
  • crates/univis_ui_engine/src/layout/core/pass_up.rs
  • crates/univis_ui_engine/src/layout/core/pass_down.rs
  • crates/univis_ui_engine/src/layout/core/solver.rs
  • crates/univis_ui_engine/src/layout/core/layout_cache.rs

Core Principles

  • roots start from URootUi
  • LayoutDepth is derived automatically from hierarchy traversal
  • IntrinsicSize estimates content-driven sizing
  • ComputedSize is 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::Screen
  • UiSpace::World2d
  • UiSpace::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.
  • UPbr settings apply here.

Logical Canvas And Units

UVal remains a layout-unit type for the UI tree.

  • UVal::Px(f32) means logical UI units.
  • UiCanvasSize::Viewport means “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_unit controls only physical world size
  • resolution_scale controls 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)
}
}

API Entry Points

  • univis_ui_engine::layout::layout_system::URootUi
  • univis_ui_engine::layout::layout_system::UiSpace
  • univis_ui_engine::layout::layout_system::UiCanvasSize
  • univis_ui_engine::layout::layout_system::UiCameraRef
  • univis_ui_engine::layout::pbr::UPbr

Where To Look Next

UNode and Box Metrics

UNode is the fundamental building block of every UI element.

Main Fields

  • width
  • height
  • min_width
  • max_width
  • min_height
  • max_height
  • padding
  • margin
  • background_color
  • border_radius
  • shape_mode

Supported units:

  • UVal::Px
  • UVal::Percent
  • UVal::MinContent
  • UVal::MaxContent
  • UVal::Content
  • UVal::Auto
  • UVal::Flex

Sizing Notes

  • width and height are the preferred size request.
  • min_width, max_width, min_height, and max_height clamp the solved result.
  • padding participates in intrinsic measurement, while margin affects placement and wrap span rather than the node’s inner measured content.
  • UVal::Content is the legacy alias for UVal::MaxContent.
  • UVal::Auto is contextual rather than identical to Content.
  • Use MaxContent or MinContent when you want explicit intrinsic sizing without implicit auto-stretch behavior.
  • border_radius and shape_mode stay 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 corners
  • Cut: 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 width and height.
  • Minimum size: the floor applied by min_width and min_height.
  • Maximum size: the ceiling applied by max_width and max_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 for MaxContent.
  • 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_* and max_* always clamp the solved size, including flex grow and flex shrink redistribution.
  • Auto is no longer treated as the same mode as Content.
  • In grid placement, Auto items can stretch to the cell by default. MinContent and MaxContent keep their intrinsic size unless alignment explicitly asks for stretch.
  • In flex cross-axis stretch behavior, Auto participates in implicit stretch. Explicit alignment can still force stretch for non-fixed, non-percent modes.
  • UImage treats Auto, Content, MinContent, and MaxContent as 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 Auto when the size should adapt to layout context.
  • Use MaxContent or Content when the element should hug its measured content and avoid implicit auto-stretch behavior.
  • Use MinContent when you want the tightest intrinsic fit.
  • Add min_width / max_width or min_height / max_height when 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:

  • display
  • flex_direction
  • justify_content
  • align_items
  • gap
  • grid_columns

Advanced groups:

  • container_ext.box_align
  • container_ext.flex
  • container_ext.grid

Box Align Container

Holds advanced alignment controls such as:

  • justify_items
  • align_content
  • row_gap
  • column_gap

Flex Container

Holds advanced flex controls such as:

  • wrap
  • align_content

Grid Container

Holds advanced grid controls such as:

  • template_columns
  • template_rows
  • auto_flow
  • auto_rows
  • auto_columns

USelf (Item)

Common fields:

  • position_type
  • left, right, top, bottom
  • align_self
  • order

Advanced groups:

  • item_ext.box_align
  • item_ext.flex
  • item_ext.grid

Box Align Item

Includes:

  • justify_self
  • align_self

Flex Item

Includes:

  • flex_grow
  • flex_shrink
  • flex_basis

Grid Item

Includes:

  • grid_column_start
  • grid_column_span
  • grid_row_start
  • grid_row_span

Display Modes

UDisplay currently supports:

  • Flex
  • Grid
  • Masonry
  • Stack
  • Radial
  • None

Flex

  • uses flex_direction, justify_content, and align_items
  • supports wrapping through container_ext.flex.wrap
  • supports flex_grow, flex_shrink, and flex_basis on items

Grid

  • can run in a simple mode through grid_columns
  • or in an advanced mode through template_rows and template_columns
  • supports auto-placement through auto_flow, auto_rows, and auto_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/picking to reject hits outside clip bounds
  • in render/system to pass clip data into UNodeMaterial
  • in text through local glyph clipping in sync_text_label_meshes and ancestor material clipping in sync_text_clipper_materials

UPbr

For 3D UI roots:

  • UPbr configures metallic, roughness, and emissive properties
  • the settings affect the UNodeMaterial3d path

Upward / Downward Passes and Solver

Upward Pass: upward_measure_pass_cached

  • walks from the deepest level back to the root
  • computes IntrinsicSize for containers from their children
  • ignores Absolute items 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 SolverConfig and SolverSpec for each node
  • calls solve_flex_layout
  • writes results into:
    • ComputedSize
    • Transform

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_config reads container-level data from ULayout
  • translate_spec reads item-level data from USelf

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:

  • UNode
  • ULayout
  • USelf
  • hierarchy structure

Important exception:

  • if the only change is IntrinsicSize on a node with children, the cache may ignore it to reduce noise

Lifecycle

  • track_layout_changes marks dirty nodes
  • update_depth_cache rebuilds the depth map on structural changes
  • upward_measure_pass_cached reads the cache and clears dirty flags afterward

Performance Diagnostics

  • watch dirty_count and dirty_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, UTextField runtime, and UBadge runtime
  • dedicated widget plugins still remain available when you intentionally want a narrower surface than UnivisWidgetPlugin

API Entry Points

  • univis_ui_widgets::widget::text_label::UTextLabel
  • univis_ui_widgets::widget::button::UButton
  • univis_ui_widgets::widget::text_field::UTextField
  • univis_ui_widgets::widget::panel::{UPanel, UPanelWindow}
  • univis_ui_widgets::widget::scroll_view::UScrollContainer

Where To Look Next

Text, Image, and Badge

UTextLabel

File: src/widget/text_label.rs

Core fields:

  • text
  • font_size
  • color
  • justify
  • linebreak
  • overflow defaults to Ellipsis; use Clip or Visible when needed
  • truncate_side controls whether ellipsis trims the start, end, or middle

Systems:

  • measure_text_label_layout
  • fit_node_to_text_size
  • sync_text_label_meshes
  • sync_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_geometry keeps rendered size aligned with layout
  • Auto, Content, MinContent, and MaxContent resolve to the native texture size once the image asset is available
  • UNode min/max constraints 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_display for UBadge, UDivider, UProgressBar, and UPanel

Action Widgets

UButton

  • file: src/widget/button.rs
  • applies button styling through UNode and UInteractionColors

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_controls for UButton, UCheckbox, UToggle, URadioGroup, and URadioButton in 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: UnivisTextFieldPlugin when composing a narrower widget surface

Live Example

  • use cargo run --example widgets_inputs for UTextField, USelect, UDragValue, and USeekBar

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_width
  • min_height
  • border_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 + Px on the first resize for predictable behavior

Live Example

  • use cargo run --example widgets_containers for a resizable UPanelWindow and 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 UInteraction to detect hover
  • it is usually paired with UClip { enabled: true }

Historical Example

  • use cargo run --example widgets_containers for a live scroll viewport wired with UClip, UInteraction, and UScrollContainer

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

  1. the backend computes hits
  2. Bevy picking emits pointer events
  3. observers in interaction/feedback.rs update UInteraction and visuals

Note

Interaction depends on UInteraction being present on the target entity.

API Entry Points

  • univis_ui_interaction::interaction::feedback::UInteraction
  • univis_ui_interaction::interaction::feedback::UInteractionColors
  • univis_ui_interaction::interaction::picking::univis_picking_backend

Where To Look Next

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:

  • None
  • Hovered
  • Pressed
  • Disabled

UInteractionColors

When an entity carries UInteractionColors, the feedback observer updates UNode.background_color automatically from the current state.

  • use Pickable::IGNORE on 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.
CapabilityScreen UI (URootUi::screen())World UI (URootUi::world_2d(...))3D UI (URootUi::world_3d(...))Conditions / Notes
Base renderingSupportedSupportedSupportedScreen and World2d use the 2D path. World3d uses the 3D material path.
Picking + pointer eventsSupportedSupportedSupportedInteraction resolves the camera from each root through ResolvedRootUi. For multi-camera scenes, prefer UiCameraRef::Entity.
Clipping-aware hit testingSupportedSupportedSupportedAncestor clipping checks apply across all spaces. World roots are still hit-tested against their UI plane.
UPanelWindow resize handlesSupportedSupportedSupportedResize logic resolves cursor movement through the root camera and panel plane.
UTextField input/eventsSupportedSupportedSupportedIncluded by default through UnivisWidgetPlugin; add UnivisTextFieldPlugin directly only for narrower manual widget composition.
UScrollContainer interactionSupportedSupportedSupportedScroll interaction follows the resolved root camera path.
UPbr controls (metallic, roughness, emissive)N/AN/ASupportedIntended only for the World3d render path.

Notes

  • URootUi::screen() is a real HUD path tied to the resolved viewport.
  • URootUi::world_2d(...) and URootUi::world_3d(...) use a fixed logical canvas plus explicit world scaling.
  • meters_per_unit changes physical world size without changing logical layout size.

Verification Sources

  • crates/univis_ui_interaction/src/interaction/picking.rs
  • crates/univis_ui_widgets/src/widget/panel.rs
  • crates/univis_ui_engine/src/layout/layout_system.rs
  • crates/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

ExampleSourcePurposeCommand
android_phoneandroid/android_phone_app/examples/android_phone.rsAndroid-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

ExampleSourcePurposeCommand
responsive_layout_testexamples/responsive_layout_test.rsStress scene for responsive screen composition.cargo run --example responsive_layout_test
toggle_seekbarexamples/toggle_seekbar.rsCompact control scene for toggle and seek-bar behavior.cargo run --example toggle_seekbar
z_order_hierarchyexamples/z_order_hierarchy.rsChecks visual ordering and hierarchy stacking behavior.cargo run --example z_order_hierarchy

Grid Layout

ExampleSourcePurposeCommand
grid_columnsexamples/grid/columns.rsGrid column sizing and layout behavior.cargo run --example grid_columns
grid_tracksexamples/grid/tracks.rsGrid track sizing behavior.cargo run --example grid_tracks
grid_auto_flowexamples/grid/auto_flow.rsGrid auto-flow placement behavior.cargo run --example grid_auto_flow
grid_item_placementexamples/grid/item_placement.rsExplicit grid item placement.cargo run --example grid_item_placement

Layout Modes

ExampleSourcePurposeCommand
layout_flexexamples/layout/flex.rsFlex layout composition.cargo run --example layout_flex
layout_masonryexamples/layout/masonry.rsMasonry layout composition.cargo run --example layout_masonry
layout_stackexamples/layout/stack.rsStack layout composition.cargo run --example layout_stack
layout_radialexamples/layout/radial.rsRadial layout composition.cargo run --example layout_radial

Widgets

ExampleSourcePurposeCommand
widgets_controlsexamples/widgets/controls.rsButtons, toggles, checkboxes, and radio controls.cargo run --example widgets_controls
widgets_inputsexamples/widgets/inputs.rsText field, select, drag-value, and seek-bar inputs.cargo run --example widgets_inputs
widgets_displayexamples/widgets/display.rsText, badges, dividers, panels, and progress display.cargo run --example widgets_display
widgets_containersexamples/widgets/containers.rsPanel 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

Example Gallery

This page highlights the examples that exist in the current repository.

Best First Paths

  1. Quick Start
  2. android_phone
  3. widgets_controls
  4. widgets_inputs
  5. responsive_layout_test

Screen UI

ExampleUse this forCommand
android_phoneA complete mobile-style screen.cargo run --manifest-path android/android_phone_app/Cargo.toml
responsive_layout_testResponsive screen composition.cargo run --example responsive_layout_test
z_order_hierarchyVisual ordering and stacking checks.cargo run --example z_order_hierarchy

Layout

ExampleUse this forCommand
layout_flexFlex layout.cargo run --example layout_flex
layout_masonryMasonry layout.cargo run --example layout_masonry
layout_stackStack layout.cargo run --example layout_stack
layout_radialRadial layout.cargo run --example layout_radial
grid_columnsGrid columns.cargo run --example grid_columns
grid_tracksGrid tracks.cargo run --example grid_tracks
grid_auto_flowGrid auto-flow.cargo run --example grid_auto_flow
grid_item_placementExplicit grid item placement.cargo run --example grid_item_placement

Widgets

ExampleUse this forCommand
widgets_controlsButtons, toggles, checkboxes, and radio controls.cargo run --example widgets_controls
widgets_inputsText fields, select, drag-value, and seek-bar inputs.cargo run --example widgets_inputs
widgets_displayText, badges, dividers, panels, and progress display.cargo run --example widgets_display
widgets_containersPanel windows and scroll containers.cargo run --example widgets_containers
toggle_seekbarA compact toggle and seek-bar scene.cargo run --example toggle_seekbar

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 UTextField search input
  • a scrollable feed using UClip, UScrollContainer, and UInteraction
  • compact mobile controls built from UToggle, USeekBar, UBadge, and UButton
  • 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_width instead 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, and widgets_containers

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::UnivisUiPlugin for the facade path
  • univis_ui_engine::layout::layout_system::URootUi for roots
  • univis_ui_engine::layout::univis_node::UNode for the box model
  • univis_ui_interaction::interaction::feedback::UInteraction for runtime state
  • univis_ui_widgets::widget::text_label::UTextLabel for text
  • univis_ui_style::style::Theme for shared fonts and icon handles

Events and Messages

Univis events use Bevy messages via #[derive(Message)].

Common examples include:

  • ButtonClicked
  • ToggleChanged
  • SelectChanged
  • SeekBarChanged
  • TextFieldSubmitted

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::UnivisUiPlugin
  • univis_ui::prelude

Root And Layout Types

  • univis_ui_engine::layout::layout_system::URootUi
  • univis_ui_engine::layout::layout_system::UiSpace
  • univis_ui_engine::layout::layout_system::UiCanvasSize
  • univis_ui_engine::layout::layout_system::UiCameraRef
  • univis_ui_engine::layout::univis_node::UNode
  • univis_ui_engine::layout::univis_node::ULayout
  • univis_ui_engine::layout::univis_node::USelf
  • univis_ui_engine::layout::univis_node::UBorder
  • univis_ui_engine::layout::univis_node::UClip
  • univis_ui_engine::layout::pbr::UPbr
  • univis_ui_engine::layout::geometry::UVal
  • univis_ui_engine::layout::geometry::USides
  • univis_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::UInteraction
  • univis_ui_interaction::interaction::feedback::UInteractionColors
  • univis_ui_interaction::interaction::UnivisInteractionPlugin

Style Types

  • univis_ui_style::style::Theme
  • univis_ui_style::style::TextStyles
  • univis_ui_style::style::IconStyles
  • univis_ui_style::style::Fonts
  • univis_ui_style::style::UnivisUiStylePlugin

Widget Types

  • univis_ui_widgets::widget::text_label::UTextLabel
  • univis_ui_widgets::widget::button::UButton
  • univis_ui_widgets::widget::checkbox::UCheckbox
  • univis_ui_widgets::widget::toggle::UToggle
  • univis_ui_widgets::widget::radio::{URadioButton, URadioGroup}
  • univis_ui_widgets::widget::seekbar::USeekBar
  • univis_ui_widgets::widget::drag_value::UDragValue
  • univis_ui_widgets::widget::select::{USelect, USelectOption}
  • univis_ui_widgets::widget::text_field::UTextField
  • univis_ui_widgets::widget::scroll_view::UScrollContainer
  • univis_ui_widgets::widget::panel::{UPanel, UPanelWindow}
  • univis_ui_widgets::widget::progress::UProgressBar
  • univis_ui_widgets::widget::badge::{UBadge, UTag}

Diagnostics And Rendering Types

  • univis_ui_engine::layout::render::UnivisRenderPlugin
  • univis_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.

  • univis_ui is the default dependency for most applications.
  • univis_ui::prelude is 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 and UInteraction-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

  • prelude means the stable recommended import surface for everyday use.
  • Named modules such as layout, render, interaction, and widget are advanced but still public.
  • Deprecated compatibility wrappers stay on explicit paths instead of the default import story.

Contributing

Practical Rules Before Any Change

  1. Understand system order before editing layout, rendering, or interaction.
  2. Do not break reflection on public types without a clear reason.
  3. Validate changes against the current live package or equivalent source-level checks, not only unit tests.
  4. 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

Code Style Inside The Project

  • favor small components and clear systems
  • keep visual behavior driven by UNode, UBorder, and UInteractionColors
  • avoid surprising side effects outside the intended schedule

Suggested Branch Names

  • feat/<name> for features
  • fix/<name> for fixes
  • docs/<name> for documentation work

Architecture

univis_ui is organized around four main subsystems:

  • layout/: layout solving and spatial computation
  • interaction/: picking and interaction state
  • widget/: ready-made UI widgets
  • style/: 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 UNode plus optional companion components
  • layout, interaction, and rendering all run through Bevy systems

Standard Frame Flow

  1. PreUpdate
    • the picking backend resolves hit entities
  2. Update
    • widget logic, interaction logic, and visual state changes run here
  3. PostUpdate
    • the layout pipeline runs:
      • update_layout_hierarchy
      • upward_measure_pass_cached
      • downward_solve_pass_safe
    • render and material sync systems apply visual output

Design Goals

  • crisp visuals through SDF rendering
  • flexible layout through Flex, Grid, Masonry, Stack, and Radial
  • 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:

  1. UnivisUiStylePlugin
  2. UnivisEnginePlugin
  3. UnivisInteractionPlugin
  4. UnivisWidgetPlugin

What Each Layer Adds

  • UnivisEnginePlugin
    • UnivisNodePlugin
    • UnivisLayoutPlugin
    • UnivisRenderPlugin
    • together these provide node primitives, root resolution, layout solving, and render synchronization

Interaction

UnivisInteractionPlugin adds:

  • univis_picking_backend in PreUpdate
  • pointer feedback observers
  • interaction state transitions

Style

UnivisUiStylePlugin adds:

  • bundled fonts
  • Lucide icon font loading
  • the shared Theme resource

Widgets

UnivisWidgetPlugin registers the standard widget set.

Automatically included today:

  • UnivisTextPlugin
  • UnivisProgressPlugin
  • UnivisButtonPlugin
  • UnivisRadioPlugin
  • UnivisIconButtonPlugin
  • UnivisTogglePlugin
  • UnivisCheckboxPlugin
  • UnivisSeekBarPlugin
  • UnivisScrollViewPlugin
  • UnivisDividerPlugin
  • UnivisPanelPlugin
  • UnivisBadgePlugin
  • UnivisDragValuePlugin
  • UnivisSelectPlugin
  • UnivisTextFieldPlugin

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)

PluginAdded by UnivisUiPluginNotes
UnivisUiStylePluginYesEmbedded fonts/icons + Theme resource.
UnivisEnginePluginYesAdds UnivisNodePlugin, UnivisLayoutPlugin, and UnivisRenderPlugin.
UnivisInteractionPluginYesRegisters picking backend and pointer observers.
UnivisWidgetPluginYesRegisters built-in widget plugin set.
UnivisLayoutProfilingPluginNoOptional diagnostics plugin; add manually when needed.

Widget Composition (UnivisWidgetPlugin)

Widget PluginAuto-registered via UnivisUiPluginNotes
UnivisTextPluginYesText label and text clipping systems.
UnivisProgressPluginYesUProgressBar.
UnivisButtonPluginYesUButton.
UnivisRadioPluginYesURadioButton, URadioGroup.
UnivisIconButtonPluginYesUIconButton.
UnivisTogglePluginYesUToggle.
UnivisCheckboxPluginYesUCheckbox.
UnivisSeekBarPluginYesUSeekBar.
UnivisScrollViewPluginYesUScrollContainer.
UnivisDividerPluginYesUDivider.
UnivisPanelPluginYesUPanel, UPanelWindow behavior.
UnivisBadgePluginYesUBadge, plus dynamic badge/tag visual updates.
UnivisDragValuePluginYesUDragValue.
UnivisSelectPluginYesUSelect.
UnivisTextFieldPluginYesUTextField behavior/events.

Dedicated widget plugins still remain available when you intentionally build a narrower widget surface than UnivisWidgetPlugin.

Verification Sources

  • src/lib.rs
  • crates/univis_ui_engine/src/lib.rs
  • crates/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 PointerHits for 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:

  1. update_layout_hierarchy
  2. upward_measure_pass_cached
  3. downward_solve_pass_safe

After layout:

  • update_materials_optimized syncs UNode, ComputedSize, UBorder, and related data into materials

Why The Order Matters

  • any Update change, 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 ComputedSize and resolved transforms

Rendering

Univis rendering is built on custom SDF materials:

  • UNodeMaterial for the 2D path
  • UNodeMaterial3d for the 3D path

Main files:

  • src/layout/render/system.rs
  • src/layout/render/material.rs
  • src/layout/render/material_3d.rs
  • src/layout/render/shaders/unode.wgsl
  • src/layout/render/shaders/unode_3d.wgsl

Update Path

The render sync system:

  • reads UNode, ComputedSize, UBorder, UImage, UI3d, and UPbr
  • chooses the 2D or 3D path from the resolved root context
  • reuses MaterialHandles to 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 Round and Cut shapes

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 overflow is Clip or Ellipsis, each quad is clipped against the label content rect before the mesh is built
  • when overflow is Visible, 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:

  1. LayoutCache to reduce unnecessary recalculation
  2. UnivisLayoutProfilingPlugin to measure runtime cost and display the overlay
  3. ./scripts/run_perf_baselines.sh for repeatable CLI baseline runs

What To Watch

  • dirty ratio and recalculated node count
  • pass_up and pass_down timing
  • 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, or USelf every 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
  • 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 overlay
  • F11: toggle compact mode
  • F12: 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.txt
  • perf_baselines/current_max/2026-04-05/runtime_benchmarks.txt
  • perf_baselines/current_max/2026-04-05/manifest.json
  • perf_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 World3d panels

How To Use It Now

  • read the committed .txt reports for the raw scenario output
  • read manifest.json for the structured metadata
  • use scripts/render_benchmark_report.py if 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 URootUi or UTextLabel.

Page Structure

Prefer a short and repeatable shape:

  1. What this page is for.
  2. The minimum mental model.
  3. Practical rules or examples.
  4. Related examples.
  5. 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.

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

  • rustdoc should explain intent, not repeat field names.
  • Short no_run examples 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 model for the authored data model or pure helpers that validate and normalize it
  • use runtime for ECS-only runtime markers, spawned child-entity bookkeeping, and systems that own the live widget tree
  • use state for long-lived mutable engine or widget state that multiple systems read and update
  • use events for emitted messages and the code that translates state transitions into outward-facing notifications
  • use translation for authored-to-runtime or authored-to-solver conversion logic
  • use placement for child placement after sizes are known
  • avoid vague buckets such as types, helpers, or display when a more specific domain name is available

Type Names

  • plugins should follow Univis<Name>Plugin
  • schedule sets should follow Univis<Domain>Set or Univis<Stage>Set
  • public authored UI components should keep the U* prefix
  • internal runtime markers should use explicit nouns such as SelectTrigger, PanelResizeHandle, or UiWorkState
  • 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:

  1. does the filename describe responsibility rather than implementation detail?
  2. would a new contributor know whether the code belongs in model, runtime, state, events, translation, or placement?
  3. 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 plugin
  • univis_ui_style: shared theme, font, and icon resources
  • univis_ui_engine: root model, layout solver, settlement schedule, and render sync
  • univis_ui_interaction: picking, interaction state, and pointer-driven validation
  • univis_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 state
  • layout::univis_node: authored node, layout, and local-positioning components
  • layout::geometry: logical UI units, sides, constraints, and axis helpers
  • layout::core: hierarchy tracking, cache invalidation, measurement, solving, and solver helpers
  • layout::render: mesh/material synchronization after layout settles
  • layout::profiling: optional runtime diagnostics and overlay helpers
  • layout::registration and layout::settlement_loop: pipeline wiring and bounded PostUpdate execution

Widget Module Map

  • single-file widgets stay flat when their runtime is small
  • stateful widgets split by responsibility:
    • model
    • runtime
    • interaction
    • visuals
    • events
  • text_label is the main exception because it owns both measure/ and render/ 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*, and docs/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 -> Events schedule 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

  • prelude is the recommended stable import story
  • named modules such as layout, render, interaction, and widget are 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

  • internal and internal_prelude are workspace implementation tools, not application-facing contracts
  • layout::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.sh prevents 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:

  1. the code introduces a reusable dependency boundary that applications may choose independently
  2. the feature needs a separate public import story or plugin lifecycle
  3. 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, or placement
  • 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 reason and, when useful, an action
  • 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 RootResolutionIssue to distinguish missing, ambiguous, or inactive cameras
  • text measurement uses TextMeasureErrorKind and TextMeasureError when Bevy text measurement cannot be created
  • select runtime uses SelectRuntimeError when 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, or UPanel
  • each widget exposes one plugin named Univis<Name>Plugin
  • outward-facing messages live in events when 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 types
  • runtime: generated child-tree markers, runtime resources, and setup helpers
  • interaction: input handling and state transitions
  • visuals: syncing colors, labels, geometry, and other rendered output
  • events: emitted messages after state settles

Schedule Rules

  • Build: spawn or repair runtime child trees
  • Logic: respond to input and mutate widget state
  • Visual: synchronize the live visual tree from the latest state
  • Events: emit outward-facing messages after logic and visuals settle

Typical Patterns

  • select/ uses model, runtime, interaction, visuals, and events
  • panel/ splits resize math, cursor logic, runtime resize state, and visuals
  • text_label/ uses measure/ and render/ 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 state
  • layout::univis_node: public node, layout, and local-position components
  • layout::geometry: public sizing and spacing primitives
  • layout::image and layout::pbr: public authored helpers tied to rendering inputs

Internal Layout Pipeline

  • layout::core::hierarchy: depth tracking and cached ancestry refresh
  • layout::core::layout_cache: dirty tracking, stage generations, and frontier queues
  • layout::core::pass_up: intrinsic measurement and content-size propagation
  • layout::core::pass_down: final solve output and child transform placement
  • layout::core::solver: size solving and placement bridge integration
  • layout::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_label owns both measurement and render-facing logic on the widget side

Scheduling Boundary

  • layout::registration wires the settlement schedule and stage ordering
  • layout::settlement_loop owns 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/en and docs/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

  1. create the English page
  2. create the Arabic counterpart in the matching path
  3. add both to docs/src/SUMMARY.md
  4. 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_run examples
  • hide internal helpers if they would pollute the generated docs story

When To Update README And Changelog

  • update README.md and README_AR.md when the landing story changes
  • update changelog.md for 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.toml defines the mdBook configuration
  • the bilingual chapter trees live under docs/src/en and docs/src/ar
  • mdbook build docs produces the static site under target/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

Docs Review Checklist

Use this checklist for docs-heavy pull requests.

  • ./scripts/check_quality.sh completed before merge
  • ./scripts/check_representative_examples.sh completed before merge
  • mdbook build docs completed 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 rustdoc at 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_AR were updated if the landing story changed
  • changelog.md was updated if the change is notable

Engineering Quality

  • ./scripts/check_public_api_surface.sh completed when facade imports, plugin wiring, or deprecated path exposure changed
  • ./scripts/check_engine_boundary_guardrails.sh completed when moving logic across engine, interaction, or widgets
  • 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::internal or 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, and UButton remain 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

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.md
  • README_AR.md
  • MIGRATION.md
  • MIGRATION_AR.md
  • RELEASE_NOTES.md
  • changelog.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-targets through ./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 UScreenRoot or UWorldRoot automatically 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 point
  • README_AR.md: Arabic landing story
  • MIGRATION.md: upgrade path from older docs and assumptions
  • MIGRATION_AR.md: Arabic migration path
  • RELEASE_NOTES.md: current alpha release-scale summary
  • RELEASE_PREP_0.3.0.md: local evidence for the next 0.3.0 cut
  • changelog.md: chronological dated history

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 --check
  • cargo clippy --workspace --all-targets with the current CI allowlist for known Bevy-heavy lint debt
  • cargo check --workspace --all-targets
  • ./scripts/check_public_api_surface.sh
  • ./scripts/check_structure_guardrails.sh
  • ./scripts/check_engine_boundary_guardrails.sh
  • cargo 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.txt
  • perf_baselines/current_max/2026-04-05/runtime_benchmarks.txt
  • perf_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

  1. run the unit tests related to the change
  2. run ./scripts/check_quality.sh
  3. run ./scripts/check_representative_examples.sh
  4. run cargo check --workspace --examples
  5. launch the Android package when the change affects the live demo surface
  6. use Visual Validation when the change is rendering-, layout-, or interaction-heavy

Required Before The Next Alpha Cut

  • ./scripts/check_quality.sh
  • mdbook build docs
  • cargo doc -p univis_ui_style --no-deps
  • cargo doc -p univis_ui_engine --no-deps
  • cargo doc -p univis_ui_interaction --no-deps
  • cargo doc -p univis_ui_widgets --no-deps
  • cargo doc -p univis_ui --no-deps
  • cargo 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.rs
  • examples/responsive_layout_test.rs
  • examples/toggle_seekbar.rs
  • examples/z_order_hierarchy.rs
  • examples/grid/auto_flow.rs
  • examples/grid/columns.rs
  • examples/grid/item_placement.rs
  • examples/grid/tracks.rs
  • examples/layout/flex.rs
  • examples/layout/masonry.rs
  • examples/layout/radial.rs
  • examples/layout/stack.rs
  • examples/widgets/containers.rs
  • examples/widgets/controls.rs
  • examples/widgets/display.rs
  • examples/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.
CapabilityScreen UIWorld UI (2D)World UI (3D)Validation Source
Manual runtime smoke in current branchYesDeferredDeferredcurrent live target is android/android_phone_app; see Smoke Test Plan
Compile validation in current branchYesPartialPartialcargo check --workspace --all-targets, Android package checks, and example scripts only when runnable example sources are present
Base rendering pathYesYesYessource-level validation plus current runnable examples where available
Pointer interactionYesYesYescamera resolves from each root through ResolvedRootUi; prefer UiCameraRef::Entity in multi-camera scenes
Clipping-aware pickingYesYesYesancestor clipping checks in the picking backend
UPanelWindow resizeYesYesYesresize logic resolves cursor movement through the root camera and panel plane
UTextField behavior/eventsYesYesYesincluded by default through UnivisWidgetPlugin
UBadge dynamic visual updatesYesYesYesincluded by default through UnivisWidgetPlugin
UScrollContainer behaviorYesYesYesinteraction follows the resolved root-camera path
UPbr controlsNoNoYesintended for UI3d path

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

  1. Android-style narrow-screen package sanity
  2. Workspace example sanity for affected layout or widget areas
  3. 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, and UButton remain visually coherent and interactive.
  • Relevant workspace examples still open and remain visually coherent.

Failure Triage

  1. Capture the failing surface and the symptom.
  2. Re-run the Android package with RUST_BACKTRACE=1 if the failure is runtime-related.
  3. Classify as compile/runtime/widget/rendering regression.
  4. 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 URootUi exists
  • that ComputedSize is not zero
  • that Visibility is not Hidden

2) Interaction Does Not Work

Check:

  • that UInteraction exists 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 UnivisTextPlugin is active so sync_text_label_meshes and sync_text_clipper_materials can apply local and ancestor clipping

4) Scrolling Does Not Work

  • the container must carry UScrollContainer and UInteraction
  • the mouse must actually hover the container
  • the content must overflow the visible area

5) Panel Resize Does Not Work

  • make sure UPanelWindow is present with UPanel
  • inspect min_width, min_height, and border_hit_thickness
  • make sure the UI is reachable from the currently resolved root camera

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

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

  1. README.md or README_AR.md
  2. docs/src/index.md
  3. the relevant guide chapter
  4. the current example list in docs/src/*/examples/index.md
  5. generated rustdoc for 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.toml
  • cargo check --workspace --examples
  • cargo 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/* and docs/src/ar/*
  • current examples: docs/src/en/examples/index.md and docs/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.
  • URootUi roots are closed stacking capsules.
  • UVal::Px means logical UI units, not literal monitor pixels.
  • world-space physical size is controlled by meters_per_unit.

Legacy Compatibility Notes

  • UScreenRoot and UWorldRoot remain 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.0 that no longer needs wrapper-based migration support.
  • Set meters_per_unit explicitly when you need a specific physical world-root size.

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

ItemCurrent StatusRecommended PathPlanned Direction
URootUi, URootUi::screen(), URootUi::world_2d(...), URootUi::world_3d(...)Canonical public APIkeep using them directlykeep long-term
UiSpace, UiCameraRef, UiCanvasSizeCanonical support typeskeep using them directlykeep long-term
UScreenRootDeprecated explicit-only wrapperURootUi::screen()de-emphasize now; planned removal target is the first alpha after 0.3.0 that no longer needs wrapper-based migration support
UWorldRootDeprecated explicit-only wrapperURootUi::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 URootUiExplicit compatibility knob on the canonical root APIkeep it only when you need the historical world-root physical sizekeep 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 UScreenRoot or UWorldRoot to 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 UScreenRoot and UWorldRoot in the first alpha after 0.3.0 if migration feedback stays clean
  • reevaluate that target before the cut if published examples, migration guides, or user reports still depend on the wrappers

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

Current Limitations

This page lists current, code-verified constraints so setup guidance remains explicit and predictable.

Interaction Camera Dependency

  • univis_picking_backend resolves the camera from each URootUi through ResolvedRootUi; it does not hardcode Camera2d.
  • UPanelWindow resize 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

  • UnivisUiPlugin adds UnivisWidgetPlugin automatically.
  • UnivisWidgetPlugin now includes the built-in UTextField and UBadge runtime systems by default.
  • Dedicated widget plugins remain available when you intentionally compose a narrower widget surface.
  • UTag runtime systems are still limited; validate tag-heavy scenes manually.

Verification Sources

  • crates/univis_ui_interaction/src/interaction/picking.rs
  • crates/univis_ui_widgets/src/widget/panel.rs
  • crates/univis_ui_widgets/src/widget/mod.rs
  • crates/univis_ui_widgets/src/widget/text_field.rs
  • crates/univis_ui_widgets/src/widget/badge.rs
  • crates/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 UTextLabel in 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.rs to demonstrate PBR-lit 3D text labels alongside normal widgets and scene lights.
  • 2D Picking Example: Added examples/picking_2d.rs to 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 (default 0.001 scale) without requiring manual Transform scaling.
  • Shader Pipeline Panics: Resolved Validation Error: Pipeline layout mismatch panics 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 seekbar not responding interactively unless properly configured within panels.