diff --git a/crates/op-editor-core/assets/scene_templates/cityguide-film-carousel.op b/crates/op-editor-core/assets/scene_templates/cityguide-film-carousel.op index 755ebfffb..3b397e96e 100644 --- a/crates/op-editor-core/assets/scene_templates/cityguide-film-carousel.op +++ b/crates/op-editor-core/assets/scene_templates/cityguide-film-carousel.op @@ -60,6 +60,7 @@ "height": 1440, "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -1844,6 +1845,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -1929,6 +1931,7 @@ "height": 1440, "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -3726,6 +3729,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -3811,6 +3815,7 @@ "height": 1440, "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -5935,6 +5940,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -6020,6 +6026,7 @@ "height": 1440, "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -7817,6 +7824,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -7875,8 +7883,8 @@ ] } ], - "x": 3600, - "y": 0 + "x": 0, + "y": 1800 }, { "type": "frame", @@ -7902,6 +7910,7 @@ "height": 1440, "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -9881,6 +9890,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -9939,8 +9949,8 @@ ] } ], - "x": 4800, - "y": 0 + "x": 1200, + "y": 1800 }, { "type": "frame", @@ -9966,6 +9976,7 @@ "height": 1440, "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -11626,6 +11637,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -11684,8 +11696,8 @@ ] } ], - "x": 6000, - "y": 0 + "x": 2400, + "y": 1800 }, { "type": "frame", @@ -11711,6 +11723,7 @@ "height": 1440, "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -13612,6 +13625,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "rectangle", @@ -13670,8 +13684,8 @@ ] } ], - "x": 7200, - "y": 0 + "x": 0, + "y": 3600 } ] } diff --git a/crates/op-editor-core/assets/scene_templates/tutorial-journal-carousel.op b/crates/op-editor-core/assets/scene_templates/tutorial-journal-carousel.op index 1dd1100bf..119d5b2e9 100644 --- a/crates/op-editor-core/assets/scene_templates/tutorial-journal-carousel.op +++ b/crates/op-editor-core/assets/scene_templates/tutorial-journal-carousel.op @@ -59,6 +59,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "path", @@ -480,6 +481,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "ellipse", @@ -654,6 +656,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "path", @@ -1310,6 +1313,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "ellipse", @@ -1484,6 +1488,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "path", @@ -2019,6 +2024,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "ellipse", @@ -2193,6 +2199,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "path", @@ -2874,6 +2881,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "ellipse", @@ -3022,8 +3030,8 @@ ] } ], - "x": 3600, - "y": 0 + "x": 0, + "y": 1800 }, { "type": "frame", @@ -3048,6 +3056,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "path", @@ -3474,6 +3483,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "ellipse", @@ -3622,8 +3632,8 @@ ] } ], - "x": 4800, - "y": 0 + "x": 1200, + "y": 1800 }, { "type": "frame", @@ -3648,6 +3658,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "path", @@ -4258,6 +4269,7 @@ "height": "fill_container", "layout": "none", "fill": [], + "locked": true, "children": [ { "type": "ellipse", @@ -4406,8 +4418,8 @@ ] } ], - "x": 6000, - "y": 0 + "x": 2400, + "y": 1800 } ] } diff --git a/templates/step0/_generators/tpl_cityguide_carousel.py b/templates/step0/_generators/tpl_cityguide_carousel.py index 11c476ae2..ef2c7d18e 100644 --- a/templates/step0/_generators/tpl_cityguide_carousel.py +++ b/templates/step0/_generators/tpl_cityguide_carousel.py @@ -111,6 +111,13 @@ CJK = "Noto Sans SC" NUM = "DM Mono" W, H, GAP = 1080, 1440, 120 + +# 3 板一行 —— 与 deck 体系(deckkit.BOARDS_PER_ROW)同一约定:多板模板在画布上 +# 分行铺开,而不是拖成一长排。行间距比列间距多 240 不是手滑:画布在帧上方以 +# **屏幕空间**固定偏移画帧名,缩到能整屏看时 120 文档像素只剩十几个屏幕像素, +# 第二行的帧名会压到上一行的板上。 +BOARDS_PER_ROW = 3 +ROW_GAP = GAP + 240 BORDER = 24 # 相纸白边 EDGE = 80 - BORDER # 片窗内的左右内边距,合计仍是 80 TOP, BOT = 96 - BORDER, 128 - BORDER @@ -241,7 +248,13 @@ def footer(edge_code): def board(page, name, main, edge_code): - """一板。外壳是相纸白,白边之内才是片基 —— 白边是本套的第一识别信号。""" + """一板。外壳是相纸白,白边之内才是片基 —— 白边是本套的第一识别信号。 + + 齿孔层与色偏层都上 `locked`:两者都是铺满整板的壳子,自己一寸不画(墨 + 在里面那 24 个孔 / 两条色带上)。齿孔层还压在正文之上,不锁的话它自身 + 就是一块盖住全板的透明板。locked 让壳子不可选而壳内的孔照常可选 + (hit_test_walk 的 locked 判定在子节点遍历之后)。 + """ content = frame(ids, f"{name} · 内容", width="fill_container", height="fill_container", layout="vertical", padding=[TOP, EDGE, BOT, EDGE], gap=0, @@ -253,19 +266,20 @@ def board(page, name, main, edge_code): fill=solid("$c-bg"), clipContent=True) # 装饰(色偏)最后 —— jian 里 index 0 最上,写反了会盖住正文。 cast = frame(ids, f"{name} · 色偏", width="fill_container", - height="fill_container", layout="none", fill=[]) + height="fill_container", layout="none", fill=[], + locked=True) cast["children"] = colour_cast() gate["children"] = [content, cast] shell = frame(ids, f"{page:02d} {name}", width=W, height=H, layout="none", fill=solid("$c-print"), padding=BORDER, clipContent=True) holes = frame(ids, f"{name} · 齿孔", width=W, height=H, layout="none", - fill=[]) + fill=[], locked=True) holes["children"] = sprockets() holes["x"], holes["y"] = -BORDER, -BORDER shell["children"] = [holes, gate] - shell["x"] = (page - 1) * (W + GAP) - shell["y"] = 0 + shell["x"] = ((page - 1) % BOARDS_PER_ROW) * (W + GAP) + shell["y"] = ((page - 1) // BOARDS_PER_ROW) * (H + ROW_GAP) return shell diff --git a/templates/step0/_generators/tpl_tutorial_carousel.py b/templates/step0/_generators/tpl_tutorial_carousel.py index edaf21a23..312f50d82 100644 --- a/templates/step0/_generators/tpl_tutorial_carousel.py +++ b/templates/step0/_generators/tpl_tutorial_carousel.py @@ -102,6 +102,13 @@ CJK = "Noto Sans SC" NUM = "Inter" W, H, GAP = 1080, 1440, 120 + +# 3 板一行 —— 与 deck 体系(deckkit.BOARDS_PER_ROW)同一约定:多板模板在画布上 +# 分行铺开,而不是拖成一长排。行间距比列间距多 240 不是手滑:画布在帧上方以 +# **屏幕空间**固定偏移画帧名,缩到能整屏看时 120 文档像素只剩十几个屏幕像素, +# 第二行的帧名会压到上一行的板上。 +BOARDS_PER_ROW = 3 +ROW_GAP = GAP + 240 EDGE = 80 RING_GUTTER = 56 # 活页孔占掉的左侧宽度 TEXT_EDGE = EDGE + RING_GUTTER @@ -265,6 +272,11 @@ def board(page, name, main, tapes): jian 的兄弟顺序是 index 0 最上(canvas_viewport_paint_mask 反着遍历)。 胶带层用 group:group 不是图片投放目标(image_drop.rs 不匹配 Group), 所以它盖在整板上也不会截走用户拖进来的图。 + + 两个装饰层都上 `locked`:它们是 fill_container 的满幅壳子,压在正文之 + 上,但自己一寸也不画(真正的墨在里面那几条胶带 / 六个孔上)。locked 让 + 壳子自身不可选,壳内的胶带和孔照常可选(hit_test_walk 的 locked 判定在 + 子节点遍历之后),于是拖动装饰不会拽走整层,框选也不会一网兜住整板。 """ content = frame(ids, f"{name} · 内容", width="fill_container", height="fill_container", layout="vertical", @@ -273,18 +285,20 @@ def board(page, name, main, tapes): content["children"] = [header(page), main, footer()] tape_layer = group(ids, f"{name} · 胶带", width="fill_container", - height="fill_container", layout="none", fill=[]) + height="fill_container", layout="none", fill=[], + locked=True) tape_layer["children"] = tapes holes = frame(ids, f"{name} · 活页孔", width="fill_container", - height="fill_container", layout="none", fill=[]) + height="fill_container", layout="none", fill=[], + locked=True) holes["children"] = ring_holes() shell = frame(ids, f"{page:02d} {name}", width=W, height=H, layout="none", fill=solid("$c-bg"), clipContent=True) shell["children"] = [tape_layer, content, holes] - shell["x"] = (page - 1) * (W + GAP) - shell["y"] = 0 + shell["x"] = ((page - 1) % BOARDS_PER_ROW) * (W + GAP) + shell["y"] = ((page - 1) // BOARDS_PER_ROW) * (H + ROW_GAP) return shell diff --git a/vendor/jian b/vendor/jian index 453bd70b6..18691c421 160000 --- a/vendor/jian +++ b/vendor/jian @@ -1 +1 @@ -Subproject commit 453bd70b646417e58f0d5c9a51594e27d399d849 +Subproject commit 18691c42169f59374d58d13065fc606fa6c39c24