Hasil akhir · harga yang bisa dimainkan
Dua web yang sama, bedanya satu snippet. Di kanan, pengunjung menekan Cicil 3× dan harga tiap paket bergulir ke nominal per cicilan, lengkap dengan total aslinya.
Langkah 1 · Siapkan dulu
Mencari, melihat pratinjau, dan perencanaan lewat agent tidak memakai kuota.
Langkah 2 · Jelajahi katalog
Buka asset.inwebsite.online. Katalognya berisi 172 snippet. Persempit lewat kategori, tempat pemakaian, atau kata kunci.
Langkah 3 · Buka halaman snippet
npm i gsap @gsap/react. Syaratnya React + Tailwind CSS.flat-sale-burst dipakai langsung dari URL-nya, bisa ditukar dengan badge lain dari keluarga yang sama.Langkah 4 · Ambil kodenya
Agent mencari, memilih, dan memasang snippet sendiri. Buka halaman For agents, login, buat API key, lalu salin perintahnya.
Perintah di atas untuk Claude Code. Halaman itu juga punya versi Claude Desktop, Cursor, dan VS Code. Jangan pernah membagikan API key-mu.
Mencari dan perencanaan tanpa kunci. Kodenya (get_snippet) baru keluar dengan API key, dan memakai jatah 5 salinan akun gratis.
Login, buka halaman snippet, tekan Copy di tab Code. Simpan sebagai komponen, lalu pasang sendiri atau kirim ke agent.
Simpan sebagai components/PricingToggleCards.jsx. Tiap Copy memakai 1 dari 5 jatah harian akun gratis.
Langkah 5 · Beri konteks ke agent
Snippet ini aslinya Monthly/Yearly dengan harga dolar. Web contohnya studio branding yang menjual paket proyek, jadi agent perlu tahu datanya, cara bayarnya, dan warnanya. Tanpa itu, kamu dapat tabel langganan dolar.
Ini kode komponen dari asset.inwebsite.online. Pasang di section #paket (src/sections/Packages.jsx) menggantikan tiga kartu harga yang ada. Ambil data dari PACKAGES di src/data.js (harga dalam juta rupiah). Ganti toggle Monthly/Yearly jadi "Bayar lunas" / "Cicil 3×": harga cicilan = total dibagi 3, satu angka desimal, dan tulis totalnya di bawah. Proyek saya React + CSS biasa tanpa Tailwind: pasang Tailwind v4 tanpa preflight supaya gaya lama tidak berubah. Aksen #e8461e, ease tenang (power3.out). Tombol paket tetap memanggil onPick lalu turun ke #kontak. <tempel kode di sini>
# sekali saja: sambungkan MCP $ claude mcp add --transport http InWebAsset https://asset.inwebsite.online/mcp --header "Authorization: Bearer <API key-mu>" # masuk ke folder proyek, jalankan agent $ claude > Pakai InWebAsset MCP. Ambil snippet cards-sections/pricing-toggle-cards dan pasang di section #paket (src/sections/Packages.jsx) menggantikan tiga kartu harga yang ada. Data dari PACKAGES di src/data.js (harga dalam juta rupiah). Ganti toggle Monthly/Yearly jadi "Bayar lunas" / "Cicil 3×": harga per cicilan = total dibagi 3, satu desimal, total ditulis di bawahnya. Proyek saya React + CSS biasa tanpa Tailwind, jadi pasang Tailwind v4 tanpa preflight. Kirim look situs (terang, aksen #e8461e, sudut bulat, gerak tenang) ke get_snippet supaya dapat daftar penyesuaian. Cek dulu dengan includeCode:false, lalu ambil kodenya sekali. Jangan ubah bagian lain.
Yang kamu dapat
Kode di kanan adalah komponen yang terpasang di web contoh. Ini yang diubah dari versi asli di katalog:
Monthly/Yearlyjadi Bayar lunas / Cicil 3×. Harga kedua = total ÷ 3, bukan diskon tahunan.SLOTSditambah koma, supaya angka seperti 9,3 ikut bergulir per digit.$ · /mojadi Rp dan jt / cicilan. Total asli ditulis di bawah harga cicilan.warnabiru, ungu, dan kuning diganti aksen situs #e8461e; glow berputar ikut aksen.easeback dan elastic diganti power3.out, sesuai saran "Fit this site" dari get_snippet.Tailwindweb contoh tidak memakai Tailwind. Dipasang v4 tanpa preflight (hanya theme + utilities) agar gaya lama tetap.tombolmemanggil onPick lalu turun ke form kontak, seperti tombol lamanya./*
* Pricing Toggle Cards — diadaptasi untuk Tandarupa
* Asal: https://asset.inwebsite.online/snippets/cards-sections/pricing-toggle-cards (v1.0.1)
* Perubahan: Monthly/Yearly → Lunas/Cicil 3×, harga Rupiah (juta), warna aksen #e8461e,
* ease back/elastic → power3.out, tombol memilih paket lalu turun ke form kontak.
*/
import { useEffect, useRef, useState } from 'react'
import gsap from 'gsap'
import { useGSAP } from '@gsap/react'
gsap.registerPlugin(useGSAP)
const BADGE = 'https://inassetweb-cdn.inwebsite.online/sprinkles/v1/badges/flat-sale-burst.png'
const SLOTS = [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',']
const GLOW = 'conic-gradient(from 0deg, #e8461e, #ff9a6b, #141311, #e8461e, #ffc4a8, #e8461e)'
const ACCENT = '#e8461e'
// 9.3 → "9,3", 4 → "4"
const fmt = (n) => (Number.isInteger(n) ? String(n) : n.toFixed(1).replace('.', ','))
function reelColumns(a, b) {
const width = Math.max(a.length, b.length)
const pa = a.padStart(width, ' ')
const pb = b.padStart(width, ' ')
return Array.from({ length: width }, (_, i) => ({ a: SLOTS.indexOf(pa[i]), b: SLOTS.indexOf(pb[i]), fromRight: width - 1 - i }))
}
function Check() {
return (
<svg viewBox="0 0 16 16" aria-hidden className="mt-0.5 size-3.5 shrink-0">
<circle cx="8" cy="8" r="8" className="fill-current opacity-15" />
<path d="M4.6 8.3l2.2 2.1 4.6-4.8" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
</svg>
)
}
export default function PricingToggleCards({ plans, onPick }) {
const root = useRef(null)
const mounted = useRef(false)
const wobble = useRef(null)
const [cicil, setCicil] = useState(false)
const priced = plans.map((p) => {
const per = Math.round((p.total / 3) * 10) / 10
return { ...p, per, columns: reelColumns(fmt(p.total), fmt(per)) }
})
// Masuk + bingkai glow yang berputar pelan
useGSAP(
() => {
gsap.set('.ptc-spin', { xPercent: -50, yPercent: -50 })
gsap.from('.ptc-card', { y: 28, autoAlpha: 0, duration: 0.7, ease: 'power3.out', stagger: 0.08 })
gsap.to('.ptc-spin', { rotation: 360, duration: 6, ease: 'none', repeat: -1 })
},
{ scope: root },
)
// Tiap ganti cara bayar: angka bergulir, thumb bergeser, badge muncul
useGSAP(
(context) => {
const instant = !mounted.current
mounted.current = true
const q = gsap.utils.selector(root)
context.ignore(() => {
q('.ptc-price').forEach((price, plan) => {
price.querySelectorAll('.ptc-col').forEach((col) => {
const index = Number(cicil ? col.dataset.b : col.dataset.a)
const reel = col.firstElementChild
const reelVars = { yPercent: (-index * 100) / SLOTS.length }
const colVars = { width: index === 0 ? 0 : SLOTS[index] === ',' ? '0.28em' : '0.6em' }
if (instant) {
gsap.set(reel, reelVars)
gsap.set(col, colVars)
return
}
const delay = Number(col.dataset.r) * 0.07 + plan * 0.06
gsap.to(reel, { ...reelVars, duration: 0.85, ease: 'power3.out', delay, overwrite: true })
gsap.to(col, { ...colVars, duration: 0.5, ease: 'power3.inOut', delay, overwrite: true })
})
})
const active = q(`[data-ptc-seg="${cicil ? 'cicil' : 'lunas'}"]`)[0]
if (active) {
const vars = { x: active.offsetLeft, width: active.offsetWidth }
if (instant) gsap.set(q('.ptc-thumb'), vars)
else gsap.to(q('.ptc-thumb'), { ...vars, duration: 0.55, ease: 'power3.out', overwrite: 'auto' })
}
wobble.current?.kill()
if (cicil) {
if (instant) gsap.set(q('.ptc-badge'), { scale: 1, rotation: -12, autoAlpha: 1 })
else {
gsap.fromTo(q('.ptc-badge'), { scale: 0, rotation: -70, autoAlpha: 1 }, { scale: 1, rotation: -12, duration: 0.7, ease: 'power3.out', overwrite: true })
wobble.current = gsap.to(q('.ptc-badge'), { rotation: -4, scale: 1.05, duration: 0.8, ease: 'power2.inOut', yoyo: true, repeat: -1, delay: 0.7 })
}
} else if (instant) gsap.set(q('.ptc-badge'), { scale: 0, autoAlpha: 0 })
else gsap.to(q('.ptc-badge'), { scale: 0, rotation: 25, autoAlpha: 0, duration: 0.3, ease: 'power2.in', overwrite: true })
if (!instant) gsap.fromTo(q('.ptc-note'), { y: 6, autoAlpha: 0 }, { y: 0, autoAlpha: 1, duration: 0.4, delay: 0.15, stagger: 0.05 })
})
},
{ scope: root, dependencies: [cicil, plans], revertOnUpdate: false },
)
useEffect(
() => () => {
wobble.current?.kill()
mounted.current = false
},
[],
)
const segment = 'relative z-10 cursor-pointer rounded-full border-0 bg-transparent px-5 py-2.5 text-[15px] font-semibold transition-colors focus-visible:outline-none'
return (
<div ref={root} className="mx-auto w-full max-w-[1440px] text-[#141311]">
<div className="mb-8 flex justify-center pt-4">
<div role="group" aria-label="Cara bayar" className="relative flex rounded-full bg-white p-1 shadow-sm ring-1 ring-black/10">
<span aria-hidden className="ptc-thumb absolute top-1 bottom-1 left-0 rounded-full bg-[#141311] shadow-md" />
<button type="button" data-ptc-seg="lunas" aria-pressed={!cicil} onClick={() => setCicil(false)} className={`${segment} ${cicil ? 'text-[#5b5750]' : 'text-[#f1ede4]'}`}>
Bayar lunas
</button>
<button type="button" data-ptc-seg="cicil" aria-pressed={cicil} onClick={() => setCicil(true)} className={`${segment} ${cicil ? 'text-[#f1ede4]' : 'text-[#5b5750]'}`}>
Cicil 3×
</button>
<span aria-hidden className="ptc-badge pointer-events-none invisible absolute -top-7 -right-10 grid size-[68px] place-items-center">
<img src={BADGE} alt="" className="absolute inset-0 size-full drop-shadow-md" />
<span className="relative text-center leading-none font-black text-white">
<span className="block text-[8px] tracking-[0.18em]">CICIL</span>
<span className="block text-[17px]">3×</span>
</span>
</span>
</div>
</div>
<div className="grid gap-4 md:grid-cols-3">
{priced.map((plan) => {
const body = (
<div className={`relative flex h-full flex-col gap-3 rounded-[22px] p-6 md:p-7 ${plan.featured ? 'bg-[#141311] text-[#f1ede4]' : 'bg-white/60 ring-1 ring-black/10'}`}>
<div>
<div className="flex items-center gap-2">
<h3 className="m-0 text-[26px] font-bold tracking-[-0.03em]">{plan.name}</h3>
{plan.featured && <span className="rounded-full px-2 py-0.5 text-[10px] font-semibold tracking-wide text-white uppercase" style={{ background: ACCENT }}>Terlaris</span>}
</div>
<p className="m-0 mt-1 min-h-[3em] text-[15px] opacity-65">{plan.for}</p>
</div>
<div className="mt-2">
<div className="flex items-end gap-1">
<span className="mb-auto pt-1 text-lg font-semibold opacity-80">Rp</span>
<span aria-hidden className="ptc-price flex text-[56px] leading-none font-extrabold tracking-tight tabular-nums">
{plan.columns.map((c, i) => (
<span key={i} data-a={c.a} data-b={c.b} data-r={c.fromRight} className="ptc-col relative block h-[1em] w-[0.6em] overflow-hidden">
<span className="block">
{SLOTS.map((s, si) => (
<span key={si} className="block h-[1em] text-center">{s}</span>
))}
</span>
</span>
))}
</span>
<span className="sr-only">Rp {cicil ? fmt(plan.per) : fmt(plan.total)} juta</span>
<span className="mb-1.5 ml-1 text-sm font-semibold opacity-70">jt{cicil ? ' / cicilan' : ''}</span>
</div>
<p className="m-0 mt-2 h-5 text-[13px] opacity-60">
<span className="ptc-note inline-block">{cicil ? `3× cicilan · total Rp ${fmt(plan.total)} jt` : `dibayar sekali · ± ${plan.time}`}</span>
</p>
</div>
<ul className="m-0 mt-3 flex-1 list-none space-y-2.5 p-0 text-[15px]">
{plan.items.map((f) => (
<li key={f} className={`flex gap-2 ${plan.featured ? 'text-white/85' : 'opacity-85'}`}>
<span style={{ color: ACCENT }}><Check /></span>
{f}
</li>
))}
</ul>
<button
type="button"
onClick={() => onPick?.(plan.name)}
className={`mt-4 min-h-[48px] cursor-pointer rounded-full border-0 px-5 text-[15px] font-semibold transition-transform hover:-translate-y-0.5 ${plan.featured ? 'text-white' : 'bg-[#141311] text-[#f1ede4]'}`}
style={plan.featured ? { background: ACCENT } : undefined}
>
Pilih {plan.name}
</button>
</div>
)
return plan.featured ? (
<div key={plan.name} className="ptc-card relative">
<div aria-hidden className="absolute -inset-1 overflow-hidden rounded-[28px] opacity-50 blur-xl">
<span className="ptc-spin absolute top-1/2 left-1/2 aspect-square w-[220%]" style={{ background: GLOW }} />
</div>
<div className="relative h-full overflow-hidden rounded-[24px] p-[2px]">
<span aria-hidden className="ptc-spin absolute top-1/2 left-1/2 aspect-square w-[220%]" style={{ background: GLOW }} />
{body}
</div>
</div>
) : (
<div key={plan.name} className="ptc-card relative">{body}</div>
)
})}
</div>
</div>
)
}
Langkah 6 · Bandingkan
Di layar lebar, kartu kanan hidup: tekan Bayar lunas / Cicil 3× di dalamnya. Di HP, kartu menampilkan rekamannya.
Mau halaman harga seperti ini tanpa memasangnya sendiri? Tim InWebsite bisa bikinin web-mu.
Lihat paket InWebsite →