mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-04 13:24:13 +08:00
Replace RoadScore panel with compact camera-edge ribbon
This commit is contained in:
+2
-2
@@ -6,7 +6,7 @@ The conductor receives only road messages already delivered by replay. It reques
|
||||
|
||||
## Reading the overlay
|
||||
|
||||
The lower-left panel is 94–112 logical pixels tall on the comma four's 536 × 240 canvas, with width limited to 55% of the screen. The existing camera, lane and path display stays in place. Its rows show RoadScore's activity, profile, section, compute backend and buffered music.
|
||||
A 34-pixel translucent ribbon sits at the lower-left edge of the comma four's 536 × 240 canvas, leaving the road visible. Its width follows the content, capped at 300 pixels. Profile and section lead, with a compact state indicator; the second line shows RoadScore, backend or a contextual event, and a quiet buffer time. Degraded explanations take priority over other detail.
|
||||
|
||||
| Display | Meaning |
|
||||
| --- | --- |
|
||||
@@ -40,6 +40,6 @@ python3 roadscore/tools/preview_overlay.py --output roadscore/results/ui-polish/
|
||||
|
||||
The preview renders six full 536 × 240 synthetic canvases with the repository's Inter bitmap font atlas: preparation, ready, generating, accepted-music hold, failed composer and stored score. It uses CPU image drawing and does not open a window, contact a device, start a worker, run replay or open an audio stream. It is a layout review, not a native-rendering or hardware-validation claim. The output stays in ignored `results/`.
|
||||
|
||||
Generation timing and road gestures have separate space in the footer, so an active job cannot hide the event. The startup label uses the selected Prism/Aurora profile; stored playback is labeled as such from preparation onward.
|
||||
Road gestures take priority over job timing in the detail row; degraded explanations take priority over both. The startup label uses the selected Prism/Aurora profile; stored playback is labeled as such from preparation onward.
|
||||
|
||||
The active native overlay is `prototype/overlay.py`; the pure presentation helper is `prototype/overlay_view.py`. `prototype/index.html` and `prototype/native_display.py` are older excerpt-specific bench interfaces, not the normal onroad demo. The historical style selector is not an ACE profile selector. Keep those older entrypoints distinct when presenting the current demo.
|
||||
|
||||
@@ -65,45 +65,48 @@ def fit_text(text, max_width, measure):
|
||||
|
||||
|
||||
def draw_panel(rl, font, state, screen_width, screen_height):
|
||||
"""A content-sized edge ribbon; leave the road and native right rail clear."""
|
||||
view = overlay_view(state)
|
||||
width = min(320, screen_width * .55, screen_width - 24)
|
||||
height = 112 if view['note'] or view['event'] else 94
|
||||
x, y = 12, max(12, screen_height - height - 12)
|
||||
color = {'READY': (123, 229, 193), 'GENERATING': (131, 192, 255),
|
||||
'DEGRADED': (255, 197, 112), 'PREPARING': (180, 190, 204)}[view['activity']]
|
||||
'DEGRADED': (255, 197, 112), 'PREPARING': (196, 204, 214)}[view['activity']]
|
||||
accent = rl.Color(*color, 255)
|
||||
muted = rl.Color(180, 190, 204, 255)
|
||||
rl.draw_rectangle_rounded(rl.Rectangle(x, y, width, height), .12, 8, rl.Color(15, 22, 31, 235))
|
||||
|
||||
def text(label, left, top, size=13, tint=rl.WHITE, available=None):
|
||||
available = width - left - 12 if available is None else available
|
||||
label = fit_text(label, available, lambda s: rl.measure_text_ex(font, s, size, 0).x)
|
||||
rl.draw_text_ex(font, label, rl.Vector2(x + left, y + top), size, 0, tint)
|
||||
|
||||
badge_width = rl.measure_text_ex(font, view['activity'], 11, 0).x + 16
|
||||
rl.draw_rectangle_rounded(rl.Rectangle(x + width - badge_width - 10, y + 10, badge_width, 22), .4, 8, rl.Color(*color, 28))
|
||||
text(view['activity'], width - badge_width - 2, 15, 11, accent)
|
||||
text('RoadScore', 12, 12, 17, available=width - badge_width - 34)
|
||||
text(view['profile'].upper(), 12, 35, 15)
|
||||
text(view['section'], 12, 55, 11, muted)
|
||||
muted = rl.Color(210, 218, 225, 255)
|
||||
measure = lambda label, size: rl.measure_text_ex(font, label, size, 0).x
|
||||
section = view['section'].removeprefix('INTENT: ')
|
||||
if section in ('ARCHIVED SCORE', 'WAITING FOR SCORE'):
|
||||
section = ''
|
||||
elif state.get('form_labels_are_intent'):
|
||||
section = 'intent ' + section.title()
|
||||
else:
|
||||
section = section.title()
|
||||
primary = view['profile'] + (' / ' + section if section else '')
|
||||
if view['activity'] == 'DEGRADED':
|
||||
detail = view['note']
|
||||
elif view['event']:
|
||||
detail = view['event'].capitalize()
|
||||
elif view['activity'] == 'GENERATING':
|
||||
detail = view['note']
|
||||
else:
|
||||
detail = 'Archived playback' if view['stored'] else ' / '.join(filter(None, view['backend']))
|
||||
secondary = 'RoadScore' + (' / ' + detail if detail else '')
|
||||
buffer = view['buffered']
|
||||
label = 'BUFFER ' + ('--' if buffer is None else f'{buffer:.0f}s')
|
||||
label_width = rl.measure_text_ex(font, label, 11, 0).x
|
||||
buffer_left = width - label_width - 12
|
||||
text(label, buffer_left, 75, 11, accent)
|
||||
left, right = view['backend']
|
||||
text(left, 12, 75, 11, muted, available=buffer_left - 24)
|
||||
if right:
|
||||
offset = 12 + rl.measure_text_ex(font, left, 11, 0).x
|
||||
# A geometric middle dot avoids missing-glyph boxes in the native font.
|
||||
rl.draw_circle(int(x + offset + 7), int(y + 81), 1.5, muted)
|
||||
text(right, offset + 15, 75, 11, muted, available=buffer_left - offset - 27)
|
||||
if view['note'] and view['event']:
|
||||
# Give road gestures their own space so job timing cannot push them offscreen.
|
||||
event_width = min((width - 36) / 2, rl.measure_text_ex(font, view['event'], 10, 0).x)
|
||||
event_left = width - event_width - 12
|
||||
text(view['note'], 12, 95, 10, accent, available=event_left - 24)
|
||||
text(view['event'], event_left, 95, 10, muted, available=event_width)
|
||||
elif view['note'] or view['event']:
|
||||
text(view['note'] or view['event'], 12, 95, 10, accent)
|
||||
reserve = '--' if buffer is None else f'{buffer:.0f}s'
|
||||
activity_width = measure(view['activity'], 9)
|
||||
max_width = min(300, screen_width * .64, screen_width - 24)
|
||||
width = min(max_width, max(210, measure(primary, 11) + activity_width + 38,
|
||||
measure(secondary, 9) + measure(reserve, 9) + 30))
|
||||
x, y, height = 12, max(12, screen_height - 42), 34
|
||||
# One quiet translucent surface, with no enclosing badge or oversized title.
|
||||
rl.draw_rectangle_rounded(rl.Rectangle(x, y, width, height), .4, 8, rl.Color(8, 13, 18, 184))
|
||||
def text(label, left, top, size, tint, available):
|
||||
label = fit_text(label, max(0, available), lambda value: measure(value, size))
|
||||
rl.draw_text_ex(font, label, rl.Vector2(x + left, y + top), size, 0, tint)
|
||||
activity_left = width - activity_width - 9
|
||||
text(primary, 9, 5, 11, rl.WHITE, activity_left - 24)
|
||||
rl.draw_circle(int(x + activity_left - 7), int(y + 10), 2, accent)
|
||||
text(view['activity'], activity_left, 6, 9, accent, activity_width + 1)
|
||||
reserve_width = measure(reserve, 9)
|
||||
text(secondary, 9, 21, 9, accent if view['activity'] == 'DEGRADED' else muted,
|
||||
width - reserve_width - 29)
|
||||
text(reserve, width - reserve_width - 9, 21, 9, muted, reserve_width + 1)
|
||||
return view
|
||||
|
||||
Reference in New Issue
Block a user