diff --git a/apps/README.md b/apps/README.md index 003caeeb..65b10756 100644 --- a/apps/README.md +++ b/apps/README.md @@ -125,7 +125,7 @@ profiles. Phone-sized desktop captures are not physical-device verification. | --- | --- | --- | --- | --- | --- | | [News](news/bundle) | `os.news` | Hacker News, TechMeme and Google News feeds in tabs (Today, HN, TechMeme, Google, Saved), with a reader for stories | `storage`, `net`, `images`, `web`, `news`, `glance` | `hn.algolia.com`, `www.techmeme.com`, `news.google.com`, `api.gdeltproject.org`, `feeds.bbci.co.uk`, `feeds.npr.org`, `www.theguardian.com`, `feeds.arstechnica.com` | [`news`](news/host-service) | | [Photos](photos/bundle) | `os.photos` | A sample library with AI-curated Memories, optional story prompts, saved stories and slideshows; moments, albums, people, favorites, a grid with selection, a full-screen viewer | `storage`, `glance`, `model` | none (the host calls the model) | `model.complete`; its own `photos` service on the desktop: `photos.notify` through the shell's notice hook, `photos.info` on the photo engine; on the phone, which leaves that engine out, the shell notice service answers `photos.notify` and `photos.info` is unavailable (full-size photos use the asset mount) | -| [Maps](maps/bundle) | `os.maps` | `MapView` map of places that can always be dragged and zoomed: search near the visible area, place cards with OpenStreetMap details (hours, phone, website, cuisine), saved places as pins, a long press for "What's here", directions with a changeable start and up to two stops, and a drive mode with turn-by-turn and a 2D/3D view; starts at the device's GPS fix when there is one; the browse map draws makepad's pre-baked world map (`makepad.nl`), the drive maps and the place details read OpenStreetMap through Overpass | `storage`, `net`, `location`, `web`, `glance` | `photon.komoot.io`, `router.project-osrm.org`, `overpass-api.de`, `overpass.kumi.systems`, `maps.mail.ru`, `overpass.openstreetmap.fr`, `makepad.nl` | `maps.notify` via the shell notice service | +| [Maps](maps/bundle) | `os.maps` | `MapView` map of places that can always be dragged and zoomed: search near the visible area, place cards with OpenStreetMap details (hours, phone, website, cuisine), saved places as pins, a long press for "What's here", directions with a changeable start and up to two stops, and a drive mode with turn-by-turn and a 2D/3D view; starts at the device's GPS fix when there is one; every map draws makepad's pre-baked world map (`makepad.nl`), with buildings raised in the 3D drive view; the place details read OpenStreetMap through Overpass | `storage`, `net`, `location`, `web`, `glance` | `photon.komoot.io`, `router.project-osrm.org`, `overpass-api.de`, `overpass.kumi.systems`, `overpass.openstreetmap.fr`, `makepad.nl` | `maps.notify` via the shell notice service | | [Camera](camera/bundle) | `os.camera` (Home) | Photo and video over the runtime's `CameraPreview` widget, flash and zoom, a thumbnail of the last shot and a viewer | `storage`, `camera`, `microphone`, `library`, `glance` | none | `camera.notify` via the shell notice service | | [Mail](mail/bundle) | `os.mail` | Accounts, folders, message list, reader (HTML rebuilt by the service) and composer; its agent puts notice cards on the glance screen (`mail.notify`) | `storage`, `mail`, `glance` | none (the service connects, not the app) | [`mail`](mail/host-service) | | [AI providers](ai-providers/bundle) | `os.ai-providers` | The assistant's LLM providers: a primary and fallbacks, each with a model pull-down from octos's catalog and Test connection; an add wizard (family, model, route, key, test); Show QR for phone and import by camera, image or paste | `storage`, `llm` | none (the service connects, not the app) | [`llm`](ai-providers/host-service) | @@ -199,12 +199,24 @@ See [capabilities and execution boundaries](../docs/capabilities.md). Recent, a place card with OpenStreetMap details and its Website reader, Save and pins, a long press, Directions framed once and then left to the person, ‹ Back and Close removing the route, and the drive view with End. - The 3D drive view drew map tiles near the route, some still missing after - 30 seconds. Before the place map, on the OnePlus 6 (2026-09-27), search, + With the drive maps on the same pre-baked map, the 3D drive view filled + the screen within about 20 seconds and drew buildings with walls and + roofs; the 2D drive view was blank for about 5 seconds the first time it + opened, then drew. Before that, when the drive maps read Overpass, the 3D + drive view drew map tiles near the route, some still missing after 30 + seconds. Before the place map, on the OnePlus 6 (2026-09-27), search, place, route, adding and removing a stop, driving with turn-by-turn and the 2D view worked; the 3D drive view drew the route but no map tiles, on the phone and on the desktop, before and after the stops changed. The OnePlus 6T, iOS and OpenHarmony are **unverified**. + On macOS (2026-10-21, native Metal), the current runtime reproduced a + labels-only 3D drive view even after all visible tiles had loaded. The + driving maps now render in a texture with their own depth buffer, so host + backgrounds cannot hide tilted geometry. The same San Jose route then + showed roads, terrain and raised buildings beneath the navigation panels. + Switching 2D/3D, panning, resizing and ending navigation also worked. + The Pixel observations above predate this depth-buffer fix; the fix has + not been verified on a phone. - **News**: runs in `card-host` during development, but not exercised end to end in the shell PRs' test runs (the test phone had no network). - **Mail**: verified with the demo mailbox on desktop and on the OnePlus 6. diff --git a/apps/README.zh-CN.md b/apps/README.zh-CN.md index e28c1f9a..42a00932 100644 --- a/apps/README.zh-CN.md +++ b/apps/README.zh-CN.md @@ -102,7 +102,7 @@ OctoSense-System-Apps 仓库(已归档)。 | --- | --- | --- | --- | --- | --- | | [News](news/bundle) | `os.news` | Hacker News、TechMeme 和 Google News 的订阅源,分标签页(Today、HN、TechMeme、Google、Saved),带文章阅读器 | `storage`、`net`、`images`、`web`、`news`、`glance` | `hn.algolia.com`、`www.techmeme.com`、`news.google.com`、`api.gdeltproject.org`、`feeds.bbci.co.uk`、`feeds.npr.org`、`www.theguardian.com`、`feeds.arstechnica.com` | [`news`](news/host-service) | | [Photos](photos/bundle) | `os.photos` | 示例相册:AI 整理的回忆、可选主题提示、保存的故事和幻灯片;本地回忆、相簿、人物、收藏、可多选的网格、全屏查看器 | `storage`、`glance`、`model` | 无(宿主调用模型) | `model.complete`;桌面上用自己的 `photos` 服务:`photos.notify` 经 Shell 的通知回调、`photos.info` 在照片引擎上;手机不带该引擎,由 Shell 通知服务应答 `photos.notify`,`photos.info` 不可用(原图使用资源挂载) | -| [Maps](maps/bundle) | `os.maps` | 随时可拖动和缩放的 `MapView` 地点地图:按可见区域搜索、带 OpenStreetMap 详情(营业时间、电话、网站、菜系)的地点卡片、以图钉显示的收藏地点、长按查看“这里是什么”、可更改起点并最多添加两个途经点的路线,以及带逐向导航和 2D/3D 视图的驾驶模式;有 GPS 定位时从当前位置开始;浏览地图使用 makepad 预先烘焙的世界地图(`makepad.nl`),驾驶地图和地点详情通过 Overpass 读取 OpenStreetMap | `storage`、`net`、`location`、`web`、`glance` | `photon.komoot.io`、`router.project-osrm.org`、`overpass-api.de`、`overpass.kumi.systems`、`maps.mail.ru`、`overpass.openstreetmap.fr`、`makepad.nl` | Shell 通知服务的 `maps.notify` | +| [Maps](maps/bundle) | `os.maps` | 随时可拖动和缩放的 `MapView` 地点地图:按可见区域搜索、带 OpenStreetMap 详情(营业时间、电话、网站、菜系)的地点卡片、以图钉显示的收藏地点、长按查看“这里是什么”、可更改起点并最多添加两个途经点的路线,以及带逐向导航和 2D/3D 视图的驾驶模式;有 GPS 定位时从当前位置开始;所有地图都使用 makepad 预先烘焙的世界地图(`makepad.nl`),3D 驾驶视图中的建筑是立体的;地点详情通过 Overpass 读取 OpenStreetMap | `storage`、`net`、`location`、`web`、`glance` | `photon.komoot.io`、`router.project-osrm.org`、`overpass-api.de`、`overpass.kumi.systems`、`overpass.openstreetmap.fr`、`makepad.nl` | Shell 通知服务的 `maps.notify` | | [Camera](camera/bundle) | `os.camera`(Home) | 基于运行时 `CameraPreview` 控件的拍照和录像,闪光灯和变焦,最近一张的缩略图和查看器 | `storage`、`camera`、`microphone`、`library`、`glance` | 无 | Shell 通知服务的 `camera.notify` | | [Mail](mail/bundle) | `os.mail` | 账户、文件夹、邮件列表、阅读(HTML 由服务重建)和写信;它的 Agent 把通知卡片放到 glance 屏幕上(`mail.notify`) | `storage`、`mail`、`glance` | 无(由服务联网,而不是应用) | [`mail`](mail/host-service) | | [AI providers](ai-providers/bundle) | `os.ai-providers` | 助手的大模型服务商:一个主用与若干备用,每项都有来自 octos 模型目录的型号下拉菜单和“测试连接”;添加向导(系列、型号、线路、密钥、测试);“为手机显示二维码”,以及通过相机、图片或粘贴导入 | `storage`、`llm` | 无(由服务联网,而不是应用) | [`llm`](ai-providers/host-service) | @@ -155,11 +155,18 @@ WebView 页面、图库导出、邮件、新闻、Glance 或单次模型调用 - **Maps**:在 Pixel 7 Pro 上(2026-10-08,深色模式)地点地图运行正常:打开时位于 GPS 定位处,◎ 能飞回该处;地图可拖动,也可双指缩放;按可见地图搜索、收藏与最近、 带 OpenStreetMap 详情的地点卡片及其网站阅读器、收藏与图钉、长按、路线只取景一次 - 之后由使用者掌控、‹ Back 和 Close 移除路线,以及驾驶视图和 End 都正常。3D 驾驶 - 视图在路线附近画出了地图瓦片,30 秒后仍有部分缺失。改为地点地图之前,在 OnePlus 6 + 之后由使用者掌控、‹ Back 和 Close 移除路线,以及驾驶视图和 End 都正常。驾驶地图 + 改用同一份预先烘焙的地图后,3D 驾驶视图约 20 秒内铺满屏幕,并画出带墙面和屋顶的建筑; + 2D 驾驶视图第一次打开时约 5 秒是空白的,之后正常显示。此前驾驶地图通过 Overpass 读取时, + 3D 驾驶视图只在路线附近画出地图瓦片,30 秒后仍有部分缺失。改为地点地图之前,在 OnePlus 6 上(2026-09-27)搜索、地点详情、路线、添加和移除途经点、逐向导航驾驶以及 2D 视图 都正常;3D 驾驶视图会画出路线但没有地图瓦片,手机和桌面上都是如此,途经点改动前后 一样。OnePlus 6T、iOS 和 OpenHarmony **未验证**。 + 在 macOS 上(2026-10-21,原生 Metal)使用当前运行时复现了 3D 驾驶视图只有文字标签的 + 问题,此时所有可见瓦片均已加载。驾驶地图现使用独立深度缓冲区渲染到纹理,避免宿主背景 + 遮住倾斜的地图几何体。同一条圣何塞路线随后正常显示道路、地形和立体建筑,导航面板位于 + 地图上方。2D/3D 切换、平移、调整窗口大小和结束导航均正常。上述 Pixel 记录早于此深度 + 缓冲区修复;修复尚未在手机上验证。 - **News**:开发时在 `card-host` 中运行过,但在 Shell PR 的测试中没有 端到端验证(测试手机没有网络)。 - **Mail**:已在桌面和 OnePlus 6 上用演示邮箱验证。Mail 与 `llm` 两个宿主服务使用根目录 diff --git a/apps/maps/bundle/main.splash b/apps/maps/bundle/main.splash index ce204831..ee1b5be3 100644 --- a/apps/maps/bundle/main.splash +++ b/apps/maps/bundle/main.splash @@ -1061,13 +1061,15 @@ View{width: Fill height: Fill flow: Overlay show_bg: true draw_bg.color: #xe8eae on_viewport: |lat, lon, zoom| viewport_moved(lat, lon, zoom)} } drive_box := View{visible: false width: Fill height: Fill flow: Overlay - drive_3d := View{width: Fill height: Fill + // Tilted geometry needs depth testing within the map, isolated from + // the host window's background. Composite below the navigation UI. + drive_3d := CachedView{width: Fill height: Fill texture_depth: true drive_map := MapView{width: Fill height: Fill dark_theme: !ui_light nav_mode: "3d" nav_period: 100 nav_route_width: 14.0 zoom: 15.0 min_zoom: 3.0 max_zoom: 19.0 - center_lat: 37.3350 center_lon: -121.8850 use_network: true use_local_mbtiles: false debug_cam: false} + center_lat: 37.3350 center_lon: -121.8850 archive_url: "https://makepad.nl/maps/world-20260926.mkmap" buildings_3d: true debug_cam: false} } - drive_2d := View{visible: false width: Fill height: Fill + drive_2d := CachedView{visible: false width: Fill height: Fill texture_depth: true drive_map_2d := MapView{width: Fill height: Fill dark_theme: !ui_light nav_mode: "2d" nav_period: 100 nav_route_width: 11.0 zoom: 16.0 min_zoom: 3.0 max_zoom: 19.0 - center_lat: 37.3350 center_lon: -121.8850 use_network: true use_local_mbtiles: false debug_cam: false} + center_lat: 37.3350 center_lon: -121.8850 archive_url: "https://makepad.nl/maps/world-20260926.mkmap" debug_cam: false} } } View{width: Fill height: Fill flow: Down padding: Inset{left: 10 right: 10 top: 10 bottom: 16} diff --git a/apps/maps/bundle/manifest.json b/apps/maps/bundle/manifest.json index c5a96d16..1f1f9d4d 100644 --- a/apps/maps/bundle/manifest.json +++ b/apps/maps/bundle/manifest.json @@ -19,7 +19,6 @@ "router.project-osrm.org", "overpass-api.de", "overpass.kumi.systems", - "maps.mail.ru", "overpass.openstreetmap.fr", "makepad.nl" ] diff --git a/crates/shell/src/maps_model_tests.rs b/crates/shell/src/maps_model_tests.rs index bdc48274..64c61b0d 100644 --- a/crates/shell/src/maps_model_tests.rs +++ b/crates/shell/src/maps_model_tests.rs @@ -717,6 +717,58 @@ for lat in [0 37.335 -45 60 78] { } } +#[test] +fn maps_draws_every_map_from_the_world_archive_and_raises_buildings_in_3d() { + // The drive maps once built their tiles on the phone from Overpass, and + // the 3D one drew a flat, patchy map: every map now reads makepad's + // pre-baked world map, and the 3D drive map raises its buildings. + let maps: Vec<&str> = MAPS + .split("MapView{") + .skip(1) + .map(|rest| &rest[..rest.find('}').unwrap()]) + .collect(); + assert_eq!(maps.len(), 3); + for map in &maps { + assert!( + map.contains(r#"archive_url: "https://makepad.nl/maps/world-"#), + "{map}" + ); + } + let raised: Vec = maps + .iter() + .map(|map| map.contains("buildings_3d: true")) + .collect(); + let drive_3d: Vec = maps + .iter() + .map(|map| map.contains(r#"nav_mode: "3d""#)) + .collect(); + assert_eq!(raised, drive_3d); +} + +#[test] +fn maps_declares_only_the_hosts_it_asks() { + // Photon searches, OSRM routes (`sys.navroute`), Maps' own Overpass + // mirrors give a place's details and makepad.nl serves the maps. + let manifest: serde_json::Value = + serde_json::from_str(include_str!("../../../apps/maps/bundle/manifest.json")).unwrap(); + let mut declared: Vec = manifest["network"]["hosts"] + .as_array() + .unwrap() + .iter() + .map(|host| host.as_str().unwrap().to_string()) + .collect(); + let mut asked: Vec = maps_model("OVERPASS.to_json()") + .as_array() + .unwrap() + .iter() + .map(|host| host.as_str().unwrap().to_string()) + .collect(); + asked.extend(["photon.komoot.io", "router.project-osrm.org", "makepad.nl"].map(String::from)); + declared.sort(); + asked.sort(); + assert_eq!(declared, asked); +} + #[test] fn maps_keeps_the_way_back_above_the_list_while_choosing_a_start_or_a_stop() { // The list scrolls, and keeps its place when the screen changes: "◎ Your diff --git a/runtime-patches.lock.json b/runtime-patches.lock.json index e1940f67..d2a186a9 100644 --- a/runtime-patches.lock.json +++ b/runtime-patches.lock.json @@ -4,7 +4,7 @@ "base_revision": "d653bc4493619ab979ccff165cf48c0c63b77d19", "patch": "tools/runtime-patches/makepad-settings.patch", "sha256": "3a79cddddc89dc4d064a9f0bdd17dc8111dcab9c796a334d95f61ecb9d5011aa", - "tree": "90b364c1dea98fb385ae21aaeda88fc0e16ce099", + "tree": "e756018052209a8159ae5ba6d3a66dba8e04d4c0", "product_fixes": [ "Settings integration: Android IME synchronization, accessibility and reduced motion, GLES program-cache validation, obscured-gesture cancellation and scroll-position observation.", "Contained-app isolation and secret-input restrictions come from the pinned upstream runtime; the Settings overlay preserves those gates.", @@ -50,7 +50,8 @@ "Camera capture and recording use explicit per-call boolean audio/library options, defaulting to silent app-local output. Permission availability never opts into recording audio or exporting captures; async microphone checks retain capture intent and background provenance. Unsupported library export fails before capture.", "A hidden Android native composer remembers animated IME insets without requesting a root layout every frame; showing it applies the latest inset before its first visible frame.", "Launch-input hardening: the Studio connection and the OCTOS_PROXY app HTTP proxy, which Makepad itself acts on from an Android Intent extra, are honoured only when the build opts into launch-time development input (debuggable, or the manifest meta-data dev.makepad.LAUNCH_STUDIO). A shipped build ignores them and drops any Studio host a development build saved. The exported activity would otherwise let another installed app point it at a host or a proxy.", - "Apple UI typeface (OctoSense-org/makepad#129): on macOS and iOS every text role leads with PingFang SC, read from the system and never packaged (Regular for regular and italic, Semibold for bold), fitted to the theme's line box so layouts keep their size; the bundled IBM Plex, LXGW WenKai and emoji chain stays behind it, code and icon roles keep their faces, and MAKEPAD_SYSTEM_FONTS=0 or another platform keeps today's chains. A font member can name a face of a collection (PingFang.ttc's face 0 is PingFang HK)." + "Apple UI typeface (OctoSense-org/makepad#129): on macOS and iOS every text role leads with PingFang SC, read from the system and never packaged (Regular for regular and italic, Semibold for bold), fitted to the theme's line box so layouts keep their size; the bundled IBM Plex, LXGW WenKai and emoji chain stays behind it, code and icon roles keep their faces, and MAKEPAD_SYSTEM_FONTS=0 or another platform keeps today's chains. A font member can name a face of a collection (PingFang.ttc's face 0 is PingFang HK).", + "CachedView can opt into an isolated depth buffer. Maps driving views use it so tilted terrain, roads and buildings are not hidden by host UI backgrounds, while route and navigation overlays retain normal composition." ], "stacked": [ { @@ -200,6 +201,10 @@ { "patch": "tools/runtime-patches/makepad-apple-ui-font.patch", "sha256": "eb6773f9f44681a89e43ffee45f3e6975d842fa5b0423e094ed1503859c953c1" + }, + { + "patch": "tools/runtime-patches/makepad-map-texture-depth.patch", + "sha256": "bf54076f55d8c501b0dda378e2ed9121aca3f47bc243f1b72256aa9f0844b6d8" } ] } diff --git a/tools/runtime-patches/makepad-map-texture-depth.patch b/tools/runtime-patches/makepad-map-texture-depth.patch new file mode 100644 index 00000000..6f5d95e2 --- /dev/null +++ b/tools/runtime-patches/makepad-map-texture-depth.patch @@ -0,0 +1,57 @@ +diff --git a/widgets/src/view.rs b/widgets/src/view.rs +index 838f1e4cf..9740c07ab 100644 +--- a/widgets/src/view.rs ++++ b/widgets/src/view.rs +@@ -95,6 +95,10 @@ pub struct View { + #[live(false)] + pub texture_caching: bool, + ++ /// Give a texture-cached subtree its own depth buffer for 3D content. ++ #[live(false)] ++ pub texture_depth: bool, ++ + #[rust] + optimize: ViewOptimize, + #[live] +@@ -293,6 +297,15 @@ fn on_after_apply( + if self.optimize.needs_draw_list() && self.draw_list.is_none() { + self.draw_list = Some(DrawList2d::script_new(vm)); + } ++ if let Some(cache) = &self.texture_cache { ++ let cx = vm.cx_mut(); ++ if self.texture_depth != cx.passes[cache.pass.draw_pass_id()].depth_texture.is_some() { ++ self.texture_cache = None; ++ if let Some(draw_list) = &mut self.draw_list { ++ draw_list.redraw(cx); ++ } ++ } ++ } + if !self.scroll_bars.is_zero() { + if let Some(bars) = self.scroll_bars_obj.as_mut() { + if apply.is_reload() { +@@ -1181,11 +1194,23 @@ fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawSte + if self.texture_cache.is_none() { + self.texture_cache = Some(ViewTextureCache { + pass: DrawPass::new(cx), +- _depth_texture: Texture::new(cx), ++ _depth_texture: Texture::new_with_format( ++ cx, ++ TextureFormat::DepthD32 { ++ size: TextureSize::Auto, ++ initial: true, ++ }, ++ ), + color_texture: Texture::new(cx), + }); + let texture_cache = self.texture_cache.as_mut().unwrap(); +- //cache.pass.set_depth_texture(cx, &cache.depth_texture, PassClearDepth::ClearWith(1.0)); ++ if self.texture_depth { ++ texture_cache.pass.set_depth_texture( ++ cx, ++ &texture_cache._depth_texture, ++ DrawPassClearDepth::ClearWith(1.0), ++ ); ++ } + texture_cache.color_texture = Texture::new_with_format( + cx, + TextureFormat::RenderBGRAu8 {