hcengineering/platform
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·July 25, 2026
More findings
Verdict
A working control shell hides a broken interaction underneath: touch users can lose video controls entirely with no way back. The Kanban row proves this team can do centralized, layered state well, but that discipline hasn't reached the accessibility-critical paths yet.
Files Rams reviewed
packages/hls/src/components/HlsVideo.svelte
packages/kanban/src/components/Kanban.svelte
packages/kanban/src/components/KanbanRow.svelte
packages/panel/src/components/Panel.svelte
packages/presentation/src/components/ActionContext.svelte
packages/presentation/src/components/AttributeBarEditor.svelte
packages/presentation/src/components/AttributeEditor.svelte
packages/presentation/src/components/AttributesBar.svelte
packages/presentation/src/components/Card.svelte
packages/presentation/src/components/DocPopup.svelte
packages/presentation/src/components/DownloadFileButton.svelte
packages/presentation/src/components/DrawingBoard.svelte
packages/presentation/src/components/DrawingBoardColorSelectorIcon.svelte
packages/presentation/src/components/DrawingBoardToolbar.svelte
packages/presentation/src/components/DrawingBoardToolbarColorIcon.svelte
packages/presentation/src/components/FilePreview.svelte
packages/presentation/src/components/FilePreviewPopup.svelte
packages/presentation/src/components/FileTypeIcon.svelte
packages/presentation/src/components/HTMLViewer.svelte
packages/presentation/src/components/IconWithEmoji.svelte
packages/presentation/src/components/Image.svelte
packages/presentation/src/components/InlineAttributeBar.svelte
packages/presentation/src/components/InlineAttributeBarEditor.svelte
packages/presentation/src/components/LiteMessageViewer.svelte
packages/presentation/src/components/MessageBox.svelte
packages/presentation/src/components/MessageViewer.svelte
packages/presentation/src/components/NavLink.svelte
packages/presentation/src/components/ObjectPopup.svelte
packages/presentation/src/components/ObjectSearchPopup.svelte
packages/presentation/src/components/PDFViewer.svelte
Accessibility
packages/hls/src/components/HlsVideo.svelte:199
Video controls vanish on touch devices with no way to bring them back
The Plyr control bar in HlsVideo.svelte is hidden with `:global(.plyr.plyr--stopped:not(:hover) .plyr__controls)`, setting `opacity: 0`, `pointer-events: none`, and `transform: translateY(100%)`. This rule has no `@media (hover: hover)` guard, so it applies unconditionally on touch devices where `:hover` never persists after a tap. A touch user loads a stopped video, taps it once, the controls never render because pointer-events stays off, and there's no remaining path to press play.
Why it matters
Touch and mobile users, a large share of video traffic, cannot start playback at all: the play button is invisible and unclickable at the same time.
Fix
Scope the hover-hide behavior to hover-capable pointers only, and keep controls visible by default on touch.
// Hide controls when video is stopped and not hovered
:global(.plyr.plyr--stopped:not(:hover) .plyr__controls) {
opacity: 0;
pointer-events: none;
transform: translateY(100%);
}// Hide controls when video is stopped and not hovered (hover-capable pointers only)
@media (hover: hover) {
:global(.plyr.plyr--stopped:not(:hover) .plyr__controls) {
opacity: 0;
pointer-events: none;
transform: translateY(100%);
}
}packages/hls/src/components/HlsVideo.svelte:129
Captions are hard-disabled with no track element to enable
HlsVideo.svelte sets `options.captions = { active: false }` when constructing the Plyr player, and there is no `<track kind="captions">` anywhere in the component. Even if a viewer opens Plyr's settings menu looking for a captions toggle, there's nothing to turn on.
Why it matters
Deaf and hard-of-hearing viewers have no path to captions on this video at all, not even a hidden or off-by-default option.
Fix
Add a caption track element and enable Plyr's captions option so users can turn captions on when a track source exists.
options.captions = {
active: false
}options.captions = {
active: false,
update: true
}
// add a matching <track kind="captions" srclang="en" label="English" src={captionsSrc} /> inside the <video> element when a track is availablepackages/hls/src/components/HlsVideo.svelte:171
Missing-caption lint warning suppressed instead of fixed on the video element
The `<video>` element in HlsVideo.svelte is preceded by `<!-- svelte-ignore a11y-media-has-caption -->`, which silences Svelte's built-in warning about missing captions rather than adding a `<track>` child to resolve it.
Why it matters
Suppressing the linter hides the gap from future contributors, so the missing-captions problem persists silently across every video that reuses this component.
Fix
Remove the ignore comment and add a real `<track>` element (or conditionally render one) so the linter passes on substance rather than suppression.
<!-- svelte-ignore a11y-media-has-caption -->
<video bind:this={video} width="100%" height="100%" preload={preload ? 'auto' : 'none'} disablepictureinpicture /><video bind:this={video} width="100%" height="100%" preload={preload ? 'auto' : 'none'} disablepictureinpicture>
{#if captionsSrc}
<track kind="captions" srclang="en" label="English" src={captionsSrc} />
{/if}
</video>UX
packages/presentation/src/components/AttributeEditor.svelte:62
Attribute editor has no error state when its dynamic component fails to load
In AttributeEditor.svelte, `{#await editor}...{:then instance}` renders the resolved editor component but defines no `{:catch}` branch. If the `getResource(editorMixin.inlineEditor)` promise rejects, the block stays on the pending placeholder `...` indefinitely.
Why it matters
A failed dynamic import (network blip, bad module path) leaves the field permanently stuck on a loading ellipsis with no retry or error message, and the user can't tell if the app is broken or just slow.
Fix
Add a `{:catch}` branch to the await block that surfaces a visible error state instead of an indefinite pending placeholder.
{#await editor}
...
{:then instance}{#await editor}
...
{:then instance}
<!-- existing component render -->
{:catch error}
<span class="error">Failed to load editor</span>
{/await}Typography
Color
Spacing
Components
Motion
Craft
Working well
- The `.selection` and `.checked` states in KanbanRow.svelte are layered with distinct box-shadow and background treatments rather than color alone, so checked+selected cards stay visually distinguishable from either state individually.
- AttributeEditor.svelte derives `isReadonly` as a reactive statement from `attribute.readonly` and `editable`, keeping the template's conditional logic out of the markup and easy to audit in one place.
- The custom HLS loader rewrites blob URLs and injects the auth header per-request, keeping token handling centralized in one place rather than scattered across call sites.
Scored July 25, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 22, 2026: 59/100. This rescore on v0.0.3: 59/100.
This page is an automated design review of hcengineering/platform’s UI code: 30 files read against 291 versioned rules covering accessibility, color, typography, spacing, components, UX, motion, and craft. The score is out of 100; confirmed criticals cap it — one at 59, two at 49, three or more at 39.
More design scores
Score your own repo.
Free on public repos, no account. The same engine that scored this page reads your UI code and mints a score page like this one.
Public repos only. The full engine reviews the UI code and mints a public score page — we email you the link too. Already-scored repos open instantly.