Files
hermes-ui/docs/chat-chain-changes/2026-10-19-chat-cyber-skeleton-pass.md
T
toor 5e1003ceb7
Build / build (push) Canceled after 0s
Playwright / e2e (push) Canceled after 0s
replace the monochrome theme with the CYBER neon-cyan skin
The project shipped a black-and-white theme that was only half converted:
the login page looked right, the message page was halfway, and the
settings page had not been started. This finishes the move to the CYBER
reference in prototype_reference/.

Colors now come from a single token source (styles/variables.scss), where
every semantic color is declared twice: once as OKLCH for the CSS, and
once as an RGB triple so translucent variants can be built as
rgba(var(--*-rgb), alpha). Cyan is the system itself, amber means the user
has to intervene, green means the machine is working, and red only ever
means something broke. The RGB triples are derived from the OKLCH values
so the two declarations cannot drift apart.

Pages adopt the .cy-* shell classes from the reference (view, panel,
kpis, tabs, grid, table, field) instead of ad-hoc markup, which is what
makes 19 of 26 views consistent. The remaining seven are deliberately
bespoke: chat streams, the kanban board, the workflow canvas, the
terminal, and the missing-agent screen.

The chart palette and the kanban column colors move into single-source
modules so they cannot drift either. A new guard test rejects raw hex
colors, named colors, and literal RGB triples anywhere in the client
source, with an explicit exemption list for the places that genuinely
cannot read a CSS variable. The existing chat semantics spec keeps the
chat chain honest.

No behavior changes: no logic, no i18n keys, no data structures, and the
/chat-run event contract is untouched.
2026-10-20 11:17:46 +08:00

4.2 KiB

date, pr, feature, impact
date pr feature impact
2026-10-19 pending Chat view CYBER pass — single-colour live ring, send-key neon tube, status LED, responsive outline The chat chain's "machine is working" indicator is now a single lime pulse instead of a six-colour cycle, the send key renders as a neon tube with the standard sweep instead of a flat grey block, the header carries a connection LED and a cyan press-light, and the Outline panel becomes an overlay at ≤1180px. Rendering-layer only — no store logic, no `/chat-run` payload, no markup semantics beyond one decorative status span, no event wiring changed.

Chat view CYBER pass

Follow-up to 2026-10-19-three-colour-semantics.md. That change split the palette by meaning but left several call sites hardcoded, and the chat view was still missing the page-level treatment the rest of the app had.

rainbow-glow collapsed into one keyframe

Three components each carried their own copy of a 44-line rainbow-glow keyframes block and cycled #ff6b6b → #feca57 → #48dbfb → #ff9ff3 → #54a0ff → #5f27cd. Four semantic hues flashing in one animation means the indicator carries no meaning at all — which is exactly what the three-colour rule exists to prevent.

live-ring is now defined once in global.scss and pulses --success (lime) between a dim and a bright ring. All three call sites use it:

  • MessageItem.vue — .speech-playing on the message bubble
  • SessionListItem.vue — .streaming ring on the agent logo
  • GroupMessageItem.vue — .speech-playing on the group-chat bubble

All three are "the machine is doing something right now", which is one meaning, so they share one colour and one animation.

Send key

ChatInput.vue had border: 0 !important and box-shadow: none !important on .send-button, which erased the neon tube that global.scss gives every .arco-btn-primary. The disabled state was also a solid #9f9f9f block — a hardcoded grey outside the palette. Both are gone; the button now inherits the global tube + neon-sheen sweep and uses the standard dimmed-tube disabled treatment.

Added .send-button--stop: while a run is streaming, the same button becomes the stop control, which is a "needs you" action rather than a "system" action, so it turns amber — the same semantic the approval card uses.

Status LED

New .cy-led in global.scss: a 7px dot, lime with a glow and a slow breathe when connected, red and static when not. A dead connection should not look like it is still doing work, so the breathe animation only runs in the connected state. Bound to appStore.connected in the chat header, reusing the existing sidebar.connected / sidebar.disconnected strings.

Session list current item

.session-item.active already had the soft cyan fill; the prototype's defining feature is the 2px glowing left bar. Added via inset box-shadow rather than border-left, which would have shifted the row's content by 2px.

Header press-light

.chat-header gets a radial-gradient cyan wash from the top edge. Radial, not linear — a linear gradient lights the whole strip evenly and loses the "pressed from above" quality.

Responsive

Verified the real implementation had only the 768px tier. Added the one tier that was genuinely missing:

  • ≤1180px — OutlinePanel becomes a position: absolute overlay. Below this width the message stream, Outline and tool panel cannot coexist as three columns; the header's Outline button already toggles it, so no extra close control is needed. Below 768px it keeps its existing narrower width.
  • ≤900px — the workspace badge hides. The session sidebar deliberately does not hide at this width: it is controlled by the header toggle, and removing the column would leave no way to open it.

Not implemented

Three items in the tracking doc were already done by 2026-10-19-three-colour-semantics.md and are recorded there, not repeated here: bubble role colours (cyan right edge on user, lime left edge on assistant), the approval card's amber zone, and the three-segment context meter.

Verification

npm run harness:check, npm run test and npm run build pass. The LED, the send key's enabled/disabled/stop states, the active session row, and both new breakpoints were checked in a browser.