Display

Laptop Device Frame

A laptop frame with a 16 / 10 screen and a clip-path trapezoid base: the body tapers downwards without a single image and scales with the screen.

  • frame
  • laptop
  • device
  • mockup

Preview

1440pxHost theme

Use it with AI

  1. 1. Copy the link.
  2. 2. Write to your agent in your own words and drop the link into the sentence.
  3. 3. The agent opens the link and installs the component from the registry.

put this in the header: https://vibeui.ru/c/frame-005?lang=en

Project dashboard

Show the full instructions

What the link says, spelled out. Use it when your agent cannot open links — paste this text instead.

# Install and place "frame-005" (Laptop Device Frame) from VibeUI

## 1. Install first — do not skip, do not recreate
Run this exact command before writing any code:
npx shadcn@latest add https://vibeui.ru/r/frame-005.json

Registry item: https://vibeui.ru/r/frame-005.json
Installs to: components/vibeui/frame-005.tsx (the exact path follows this project's components.json aliases).
npm dependencies: none.
Registry dependencies: none.

Install it from the registry. Do not recreate it from the description,
do not substitute a similar component from another library, and do not
rewrite it to match the project's existing style.

## 2. What it is
A laptop frame with a 16 / 10 screen and a clip-path trapezoid base: the body tapers downwards without a single image and scales with the screen.

A laptop frame: a lid with a 16 / 10 screen and a clip-path trapezoid base. Zero dependencies, one file, no client JS.

## 3. How to use it
import { Frame005 } from "@/components/vibeui/frame-005"

<Frame005 title="Project dashboard" tone="silver">
  <img src="/shots/dashboard.png" alt="Project dashboard" />
</Frame005>

Read the installed file for the full prop list.

## 4. Where to place it
This is a small inline component. Put it exactly where the user asked,
inside the existing markup. Do not create a new page, section or
wrapper for it. If a similar control already sits in that spot,
replace it instead of adding a second one.

Placement: ___
(The user fills this line in. If it is still blank, ask where to put it
instead of guessing.)

## 5. Keep exactly as installed
- the local --vibeui-frame-005-* palette — do not swap it for your theme tokens
- the 16 / 10 screen ratio: at 16 / 9 the silhouette stops reading as a laptop
- the clip-path trapezoid — a rectangular base turns the device into two slabs
- the base being slightly wider than the lid: flush widths lose the perspective
- the white screen inside the body: it keeps contrast on any catalog background
- overflow:hidden on the screen — a screenshot with its own corners otherwise spills past the radius

## 6. You may change
- the demo screen heading through title
- the body finish through tone: silver or graphite
- the screen content — an image or a block in the slot
- the device width through max-width

## 7. Rules
- The base is 8% wider than the lid: a narrow parent with overflow:hidden will clip it.
- Supply the screenshot in a 16 / 10 ratio, otherwise object-fit crops the edges.
- There is deliberately no keyboard or trackpad: body details argue with the screen content.
- Do not lift the CSS variables into globals.css: the component has to stay a single file.

## 8. Verify
- it renders with no console errors;
- it looks like the preview on the VibeUI page you copied this from;
- if it does not, you changed something listed in section 5 — put it back.

For developers

npx shadcn@latest add https://vibeui.ru/r/frame-005.json
https://vibeui.ru/r/frame-005.json

Серверный компонент, хуков нет. Крышка — обычный блок со скруглением сверху, экран держит aspect-ratio 16 / 10 (стандарт ноутбучной матрицы; 16 / 9 читается как телевизор). Основание нарисовано clip-path:polygon и потому сужается книзу без второго прямоугольника и без изображений; оно чуть шире крышки, что и даёт силуэт устройства. Оттенок корпуса переключается атрибутом data-tone: silver и graphite меняют три переменные палитры разом. Экран белый, поэтому конструкция читается и на тёмной подложке каталога; вся типографика демо-содержимого лежит внутри белого экрана.

Component source

The same file your agent installs. Here in case you would rather copy it by hand.

import type { ComponentPropsWithoutRef, CSSProperties, ReactNode } from "react"

export type Frame005Props = Omit<
  ComponentPropsWithoutRef<"figure">,
  "title"
> & {
  title?: string
  tone?: "silver" | "graphite"
  children?: ReactNode
}

// Идея компонента: рамка ноутбука под демо страницы. Основание — не картинка
// и не второй прямоугольник: это трапеция из clip-path, поэтому корпус
// сужается книзу без единого изображения и масштабируется вместе с экраном.
// Экран держит пропорцию 16 / 10 — стандарт ноутбучной матрицы; 16 / 9 даёт
// заметно более плоский силуэт и читается как телевизор.
const STYLES = `
:where([data-vibeui-block="frame-005"]){
--vibeui-frame-005-body:oklch(0.9 0.005 265);
--vibeui-frame-005-edge:oklch(0.76 0.008 265);
--vibeui-frame-005-base:oklch(0.85 0.006 265);
--vibeui-frame-005-screen:oklch(1 0 0);
--vibeui-frame-005-fg:oklch(0.23 0.014 265);
--vibeui-frame-005-muted:oklch(0.56 0.014 265);
--vibeui-frame-005-soft:oklch(0.96 0.004 265);
--vibeui-frame-005-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
[data-vibeui-block="frame-005"]{
display:flex;flex-direction:column;align-items:center;margin:0;
width:100%;max-width:30rem;box-sizing:border-box;
font-family:var(--vibeui-frame-005-font);color:var(--vibeui-frame-005-fg);
}
[data-vibeui-block="frame-005"] *{box-sizing:border-box}
[data-vibeui-block="frame-005"][data-tone="graphite"]{
--vibeui-frame-005-body:oklch(0.42 0.012 265);
--vibeui-frame-005-edge:oklch(0.55 0.012 265);
--vibeui-frame-005-base:oklch(0.36 0.012 265);
}
[data-vibeui-block="frame-005"] [data-part="lid"]{
width:100%;padding:0.5rem 0.5rem 0.625rem;
background:var(--vibeui-frame-005-body);
border:1px solid var(--vibeui-frame-005-edge);
border-radius:0.875rem 0.875rem 0.375rem 0.375rem;
}
[data-vibeui-block="frame-005"] [data-part="cam"]{
display:block;width:0.25rem;height:0.25rem;margin:0 auto 0.375rem;
border-radius:9999px;background:var(--vibeui-frame-005-edge);
}
[data-vibeui-block="frame-005"] [data-part="screen"]{
overflow:hidden;aspect-ratio:16 / 10;
background:var(--vibeui-frame-005-screen);
border-radius:0.375rem;
}
[data-vibeui-block="frame-005"] [data-part="screen"] > *{display:block;width:100%}
[data-vibeui-block="frame-005"] img{display:block;width:100%;height:100%;object-fit:cover}
[data-vibeui-block="frame-005"] [data-part="stub"]{
display:flex;flex-direction:column;gap:0.5rem;height:100%;padding:0.875rem 1rem;
}
[data-vibeui-block="frame-005"] [data-part="stub-title"]{margin:0;font-size:0.875rem;font-weight:700}
[data-vibeui-block="frame-005"] [data-part="grid"]{
display:grid;grid-template-columns:repeat(3,1fr);gap:0.5rem;flex:1 1 auto;
}
[data-vibeui-block="frame-005"] [data-part="cell"]{border-radius:0.5rem;background:var(--vibeui-frame-005-soft)}
/* Трапеция из clip-path: основание сужается книзу без единой картинки. */
[data-vibeui-block="frame-005"] [data-part="base"]{
width:108%;max-width:none;height:0.75rem;
background:var(--vibeui-frame-005-base);
clip-path:polygon(0 0,100% 0,96% 100%,4% 100%);
}
[data-vibeui-block="frame-005"] [data-part="notch"]{
width:18%;height:0.25rem;margin:0 auto;
border-radius:0 0 9999px 9999px;
background:var(--vibeui-frame-005-edge);
}
[data-vibeui-block="frame-005"] figcaption{
margin-top:0.625rem;font-size:0.75rem;color:var(--vibeui-frame-005-muted);text-align:center;
}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="frame-005"] *{animation:none!important;transition:none!important}}
`

/**
 * Рамка ноутбука: крышка с экраном 16 / 10 и трапеция основания на clip-path.
 * Один файл, ноль зависимостей, собственная палитра.
 */
export function Frame005({
  title = "Панель проекта",
  tone = "silver",
  children,
  className,
  style,
  ...props
}: Frame005Props) {
  return (
    <>
      <style href="vibeui-frame-005" precedence="medium">
        {STYLES}
      </style>
      <figure
        {...props}
        data-vibeui-block="frame-005"
        data-tone={tone}
        className={className}
        style={style as CSSProperties}
      >
        <div data-part="lid">
          <span data-part="cam" aria-hidden="true" />
          <div data-part="screen">
            {children ?? (
              <div data-part="stub">
                <p data-part="stub-title">{title}</p>
                <div data-part="grid" aria-hidden="true">
                  <span data-part="cell" />
                  <span data-part="cell" />
                  <span data-part="cell" />
                  <span data-part="cell" />
                  <span data-part="cell" />
                  <span data-part="cell" />
                </div>
              </div>
            )}
          </div>
        </div>
        <div data-part="base" aria-hidden="true">
          <span data-part="notch" />
        </div>
      </figure>
    </>
  )
}