πΊ v0.24.0 β Device Frames, Media Players & Agentic Chat
This release is all about showing off your work. It adds pure-CSS Apple Device Frames to mock up screenshots and live UI, a native Playlist audio player, a drag-to-pan 360Β° Viewer, and TikTok/YouTube social previews β every one of them zero-dependency. The Command Palette's AI chat grows up into an agentic page-crafting assistant, and the MCP server gains four new introspection tools (breakpoints, animation, token usage, migration guides). No breaking API changes.
The Design Token System and the Tailwind v4 upgrade shipped ahead of this cut in v0.23.4 β see those notes if you skipped them.
What's New
Device Frame β midwest_device_frame
Pure-CSS, zero-dependency Apple device bezels. Wrap a src: screenshot or a rich screen slot (Video, Carousel, live markup) in an iPhone (Dynamic Island, home indicator, side buttons), iPad, MacBook, Apple Watch (digital crown + band), or Apple TV. Handhelds take orientation: :portrait/:landscape; every frame supports four body color: variants (black/silver/gold/blue), an optional drop shadow:, and a responsive: mode that fluidly scales the whole frame (and its contents) to the parent's width via a container-query design unit.
<%= midwest_device_frame(device: :iphone, color: :black, src: "/screenshot.png") %><%= midwest_device_frame(device: :macbook, responsive: true) do |frame| %> <% frame.with_screen do %> <%= midwest_video(src: "/demo.mp4") %> <% end %><% end %>Playlist & Song β midwest_playlist / midwest_song
A native, zero-dependency audio playlist player. PlaylistComponent orchestrates nested SongComponent slots through a single <audio> element: play/pause, previous/next transport, a click-to-seek progress bar with elapsed/total time, keyboard controls (space/k, arrow keys), and auto-advance on track end. Choose a scrollable track list (view: :playlist) or an album-art focus view (view: :art); per-track artwork: renders cover previews with a blurred backdrop. autoplay:, dark:, and a collapsible list round it out.
<%= midwest_playlist(name: "Focus Mix") do |list| %> <% list.with_song(title: "Intro", artist: "Nomad", src: "/audio/intro.mp3") %> <% list.with_song(title: "Drift", artist: "Nomad", src: "/audio/drift.mp3") %><% end %>Each SongComponent also stands on its own with playing state, artist/album metadata, and optional artwork:
360Β° Viewer β midwest_panorama
A native, zero-dependency drag-to-pan viewer for wide panoramic (360Β°) images and video. PanoramaComponent fills the viewport height and pans horizontally via Pointer Events (unified mouse + touch), keyboard (arrow keys, Home to reset), and release inertia. Images wrap: seamlessly for a true 360Β° loop; video panning is clamped to the frame. Add auto_rotate: drift (pauses on hover/focus/drag and honors prefers-reduced-motion), a fading drag hint + reset button (controls:), a start: position, and a screen-reader live region announcing pan percentage.
<%= midwest_panorama(src: "/panorama.jpg", wrap: true, auto_rotate: 20) %>Social Preview: TikTok & YouTube
Two video-centric platforms join the SocialPreviewComponent family. TikTok renders a vertical 9:16 frame with a right-hand action rail (abbreviated engagement counts), follow badge, and bottom caption + sound row. YouTube renders a 16:9 thumbnail with a duration badge and a watch-row (channel avatar, verified badge, "views Β· timestamp" meta). A shared format_count helper handles the 1.2K / 1.2M abbreviation.
Agentic Command Palette chat β craft pages by conversation
The Command Palette's AI chat (introduced in v0.23.1) becomes agentic: the model can now build and preview pages for you. The Midwest::LlmAgent controller concern is expanded, a new AssistantController proxy relays streams server-side, and a generate_iframe MCP tool lets the assistant render live component markup back into the conversation. Server tools (RubyLLM::Tool) and client-directive command tools stay gated behind a server-side allowlist.
Four new MCP introspection tools
The MCP server grows to 17 tools, completing the milestone's introspection set:
get_breakpointsβ Midwest's design-token breakpoint scale (--breakpoint-*, xsβ2xl), the root-font-size ladder that drives fluid scaling, container-query support, and how the token scale differs from Tailwind's utility-variant defaults. Scope withsection:.get_animation_infoβ per-component motion facts parsed straight from each component's CSS (keyframes, durations, easings, animated properties, reduced-motion support), merged with a curated YAML overlay and checked against the--duration-*/--ease-*tokens. Managed withbin/motion.get_token_usageβ which components use which design tokens (and vice versa), built from CSS + template references. Doubles as an adoption audit. Passcomponent:,token:, or neither for an overview.get_migration_guideβ breaking changes between versions, compiled from the changelog itself via aChangelogParser. Passfrom/toto bound a range ortopic:(e.g.tailwind,tokens) to trace a subsystem across all history.
What Changed
ChartComponent β sparkline mode
A new sparkline: true mode renders a compact, chrome-less trend line: axes, legend, tooltip, and title are hidden, tight-padding presets kick in, and it defaults to a :line chart. Every preset remains overridable.
<%= midwest_chart(data: [4, 6, 5, 8, 7, 9], sparkline: true) %>StatComponent β embedded sparkline & comparison baseline
StatComponent gains an embedded sparkline: (an array, or { data:, type:, color: } β the color follows trend direction) plus a comparison-period baseline via comparison: / comparison_label:.
Dark Mode β broader bare-element coverage
dark-mode.css picks up a :not([class])-scoped foundation for bare elements (text selection, hr, links, inline code/kbd, blockquotes, tables) plus dark overrides for surfaces that assumed light backgrounds β AccordionComponent, TreeViewComponent, and TimelineComponent neutral tokens.
What Was Removed
- Theme Switcher and Theme Builder Panel β cancelled, not shipped. Both were planned for this milestone, but the Lookbook panel context can't load Midwest's CSS/JS reliably. There is no separately-versioned theme system: theme/token migrations live in the changelog and are queryable through
get_migration_guide(topic: "theme"). - No component options, slots, or helpers were removed this release.
Dev Process
- Previews β new Lookbook previews and sidecar templates for Device Frame, Playlist, Song, 360Β° Viewer, and the TikTok/YouTube social platforms, plus
sparkline/with_sparklineexamples for Chart and Stat. - Tooling β
bin/motion(list/show/check) manages the animation metadata backingget_animation_info, drawing facts from component CSS with a curateddata/animation.ymloverlay. - MCP internals β new parsers (
ChangelogParser,MotionParser,TokenReferenceParser) and indexes (ChangelogIndex,AnimationIndex,TokenUsageIndex) feed the four new tools; the demo app adds anAssistantControllerand agenerate_iframetool for agentic chat. - Tests β new suites for the Playlist, Song, Panorama, Device Frame, and Social Preview components; the Chart/Stat sparkline options; the new parsers/tools; and the expanded
Midwest::LlmAgent+ agentic command-palette flow. - Demo β the agentic chat demo wires up the optional RubyLLM gem with a server-owned key/model/system prompt and SSE relay.