Alasan Mengapa Semua Landing Page Buatan AI Terlihat Sama dan Solusinya
TuBrief 편집팀
2026년 8월 22일
0
Computing/Software원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
커뮤니티의 다른 글
댓글 (0)
Log in to leave a comment
아직 작성된 글이 없습니다
원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
Log in to leave a comment
아직 작성된 글이 없습니다
Bagi pengembang solo yang menangani semuanya sendiri mulai dari perencanaan hingga penerapan, Cursor atau Claude Code terasa seperti penyelamat. Hanya dengan beberapa baris prompt, halaman web yang layak langsung jadi dalam waktu 10 menit.
Masalahnya ada setelah itu. Saat Anda menekan tombol deploy dan melihat layar, muncul perasaan déjà vu. Tombol gradasi ungu, font Inter, tata letak 3 kartu yang terpatri pas di tengah. Bau templat yang entah di mana pernah terlihat tercium kuat. Sekilas terlihat rapi, tetapi tidak berujung pada pembayaran atau pendaftaran pengguna. Orang-orang dengan sangat mahir dapat mengenali halaman yang tampak seperti buatan pabrik dan langsung menutup tab.
LLM bekerja berdasarkan rata-rata statistik. Jika Anda tidak memberikan aturan, mereka akan kembali ke preset bawaan Tailwind dan nilai bawaan Shadcn UI yang paling sering digunakan di web. Begitu Anda melontarkan prompt seperti "Buatlah landing page yang rapi dan elegan", AI akan memuntahkan nilai piksel inline yang tidak jelas seperti w-[320px], top-[117px], dan merusak tata letak.
M mencoba mengatasi masalah ini dengan modifikasi prompt saja akan membuat Anda kelelahan. Anda harus membangun sebuah pipa (pipeline) yang memaksa aturan merek setiap kali kode dihasilkan, dan secara fisik memblokir kode yang melanggar pada tahap commit.
Cursor membaca .cursor/rules/*.mdc, Claude Code membaca CLAUDE.md, dan alat sumber terbuka membaca AGENTS.md. Jika Anda mendefinisikan token desain merek di file ini, AI tidak akan bisa menggunakan gaya sembarangan sejak tahap pembuatan kode.
Jika file aturan melebihi 500 baris, biaya konteks untuk membaca setiap sesi akan meningkat dan tingkat kepatuhan model juga akan menurun. Anda harus menulisnya dengan jelas sekitar 200–300 baris.
Buat .cursor/rules/design-system.mdc di root proyek dan masukkan konten berikut.
bg-[#123456] or h-[117px].pnpm lint:style to verify token compliance before completing tasks.var(--color-bg-primary) (Tailwind: bg-brand-primary)var(--color-bg-secondary) (Tailwind: bg-brand-secondary)var(--color-text-main) (Tailwind: text-brand-main)var(--color-text-muted) (Tailwind: text-brand-muted)var(--color-accent-default) (Tailwind: bg-brand-accent)var(--space-1): 0.25rem (4px)var(--space-2): 0.5rem (8px)var(--space-4): 1.0rem (16px)var(--space-6): 1.5rem (24px)var(--space-8): 2.0rem (32px)text-brand-h1 -> Font: Inter, Weight: 700, Size: 2.5rem, Tracking: -0.02emtext-brand-body -> Font: Inter, Weight: 400, Size: 1.0rem, Leading: 1.5`
Dengan memasukkan aturan ini, frekuensi AI menyuntikkan nilai arbitrase tanda kurung siku atau kode Hex secara langsung akan berkurang secara drastis.
Prompt saja tidak cukup. AI sering kali mengabaikan aturan dan diam-diam mencampur nilai piksel inline. Kita menggabungkan Stylelint dan Git Pre-commit hook untuk memblokir jalur masuk gaya yang di-hardcode ke dalam repositori.
Instal alat-alatnya dan inisialisasi Husky.
`bash
pnpm add -D husky lint-staged stylelint stylelint-declaration-strict-value
npx husky init
`
Buat stylelint.config.mjs di root proyek. Ini adalah pengaturan untuk memunculkan error build jika kode warna atau nilai piksel arbitrer dimasukkan.
`javascript
import type { Config } from "stylelint";
export default {
plugins: ["stylelint-declaration-strict-value"],
rules: {
"scale-unlimited/declaration-strict-value": [
["/color/", "font-size", "/margin/", "/padding/"],
{
ignoreVariables: false,
ignoreFunctions: false,
ignoreKeywords: {
"": ["transparent", "inherit", "currentColor", "auto", "0"]
},
message: "Design System Violation: Hardcoded value for '{property}' is forbidden. Use CSS Design Tokens instead."
}
]
}
} satisfies Config;
`
Tambahkan konfigurasi lint-staged ke package.json.
`json
{
"lint-staged": {
"*.{css,scss,tsx,jsx}": [
"stylelint --fix",
"eslint --max-warnings=0"
]
}
}
`
Daftarkan satu baris berikut ke dalam file .husky/pre-commit.
`bash
npx lint-staged
`
Sekarang setiap kali Anda mengetik git commit, kode yang di-staging akan dianalisis secara statis. Jika ada kode seperti margin: 17px yang dimasukkan sesuka hati oleh AI, proses commit itu sendiri akan gagal. Anda dapat menghemat sekitar 5 jam waktu per minggu yang biasa dihabiskan untuk perbaikan gaya.
Analisis statis hanya memeriksa aturan teks. Masalah seperti elemen yang saling tumpang tindih atau menu seluler yang rusak di layar ponsel baru bisa diketahui jika browser benar-benar dijalankan. Kita tidak mungkin memperkecil dan memperbesar viewport secara manual setiap saat, jadi kita mengotomatiskan perbandingan snapshot dengan Playwright.
Buat file playwright.config.ts.
`typescript
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/visual',
snapshotPixelRatioTemplate: '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{ext}',
expect: {
toHaveScreenshot: {
maxDiffPixelRatio: 0.01,
threshold: 0.2,
animations: 'disabled',
},
},
webServer: {
command: 'pnpm dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 120 * 1000,
},
projects: [
{ name: 'Desktop Chrome', use: { ...devices['Desktop Chrome'] } },
{ name: 'Mobile Safari', use: { ...devices['iPhone 13'] } },
],
});
`
Tulis skrip pengujian (tests/visual/landing-page.spec.ts) yang memverifikasi 5 titik UI utama.
`typescript
import { test, expect } from '@playwright/test';
test.describe('Visual Regression Guardrails', () => {
test.beforeEach(async ({ page }) => {
await page.goto('http://localhost:3000');
await page.evaluate(() => document.fonts.ready);
});
test('TC1: Rendering Bagian Hero Desktop', async ({ page }) => {
await page.setViewportSize({ width: 1440, height: 900 });
const heroSection = page.locator('section#hero');
await expect(heroSection).toBeVisible();
await expect(heroSection).toHaveScreenshot('hero-desktop.png', { maxDiffPixelRatio: 0.01 });
});
test('TC2: Rendering Viewport Menu Navigasi Seluler', async ({ page }) => {
await page.setViewportSize({ width: 375, height: 812 });
const navBar = page.locator('header#main-nav');
await expect(navBar).toHaveScreenshot('nav-mobile.png');
});
test('TC3: Penyelarasan Grid Kartu Harga', async ({ page }) => {
await page.setViewportSize({ width: 1280, height: 800 });
const pricingGrid = page.locator('div#pricing-cards');
await expect(pricingGrid).toHaveScreenshot('pricing-grid.png', {
mask: [page.locator('.dynamic-price-timestamp')]
});
});
test('TC4: Status Hover Tombol CTA Utama', async ({ page }) => {
const ctaButton = page.locator('button#primary-cta');
await ctaButton.hover();
await expect(ctaButton).toHaveScreenshot('cta-button-hover.png');
});
test('TC5: Tata Letak Modal Masuk', async ({ page }) => {
await page.click('button#open-login-modal');
const modalDialog = page.locator('div[role="dialog"]');
await expect(modalDialog).toBeVisible();
await expect(modalDialog).toHaveScreenshot('login-modal.png');
});
});
`
Daftarkan perintah ke package.json.
`json
{
"scripts": {
"test:visual": "playwright test",
"test:visual:update": "playwright test --update-snapshots"
}
}
`
Hanya dengan menjalankan satu baris pnpm test:visual di terminal, tata letak yang rusak pada viewport desktop dan seluler dapat dideteksi dalam waktu 1 menit. Pekerjaan melelahkan yang mengharuskan Anda menyesuaikan ukuran layar satu per satu dengan mata telanjang dapat disingkirkan.
Jika Anda memiliki struktur di mana input AI dikendalikan oleh file aturan, masuknya gaya yang salah dicegah oleh Git hook, dan kerusakan layar diperiksa menggunakan Playwright, Anda dapat mempertahankan konsistensi desain bahkan dalam proyek pengembangan solo.