أنشئ تأثيرات نصية مذهلة مع Pretext و Next.js — من تخطيطات المجلات إلى الفن التفاعلي

مطوّر من Midjourney اخترق "أعماق الجحيم" ليمنحنا Pretext — مكتبة بحجم 15 كيلوبايت تقيس النصوص وتنسّقها بسرعة تفوق المتصفح بـ 500 مرة، دون أن تلمس الـ DOM.
المطوّرون بدأوا يُبدعون بها بالفعل. أحدهم بنى لعبة Text Invaders. وآخرون ينشئون تخطيطات بجودة المجلات، وطباعة حركية، ونصوصاً تتدفق حول الأشكال.
في هذا الدرس، ستبني 4 تأثيرات نصية إبداعية باستخدام Pretext و Next.js — والأخيرة منها تُعرض هذا المقال نفسه بطباعة بجودة مجلة راقية. ألا تبدو فكرة مثيرة؟
المتطلبات الأساسية
- Node.js 18+
- Next.js 14+ (App Router)
- معرفة أساسية بـ React/TypeScript
- إحساس بالطموح الجمالي
الإعداد
npx create-next-app@latest pretext-creative --typescript --tailwind --app
cd pretext-creative
npm install pretextالتأثير الأول: نص يتدفق حول الصور (تخطيط المجلة)
الحيلة الكلاسيكية التي فشل CSS في تحقيقها لـ 30 عاماً. مع Pretext، يلتفّ النص حول أشكال عشوائية — ليس فقط المستطيلات.
// app/magazine/page.tsx
'use client';
import { useEffect, useRef } from 'react';
import { prepare, layoutWithLines } from 'pretext';
export default function MagazinePage() {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d')!;
canvas.width = 800;
canvas.height = 600;
const article = `The web has treated text as a second-class citizen for three decades. While print designers flowed paragraphs around images and wrapped columns with ease, browsers offered none of that without expensive DOM reflows. Until now. Pretext changes everything about how we think about text on the web. Magazine layouts, kinetic typography, and text art — all at 120fps.`;
// Prepare text measurements (cached, ~19ms for 500 paragraphs)
const prepared = prepare(ctx, article, {
fontFamily: 'Georgia',
fontSize: 18,
lineHeight: 28,
});
// Define an obstacle (circular image area)
const obstacle = { x: 500, y: 50, radius: 120 };
// Layout with variable widths per line to flow around obstacle
let y = 40;
const lines = layoutWithLines(prepared, 720);
// Draw obstacle
ctx.beginPath();
ctx.arc(obstacle.x, obstacle.y + 80, obstacle.radius, 0, Math.PI * 2);
ctx.fillStyle = '#f0f0f0';
ctx.fill();
ctx.fillStyle = '#999';
ctx.font = '14px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('Your image here', obstacle.x, obstacle.y + 85);
// Draw text flowing around obstacle
ctx.fillStyle = '#1a1a1a';
ctx.font = '18px Georgia';
ctx.textAlign = 'left';
lines.forEach((line) => {
const lineCenter = y + 14;
const dy = lineCenter - (obstacle.y + 80);
let xStart = 40;
let maxWidth = 720;
// If line overlaps with obstacle, indent
if (Math.abs(dy) < obstacle.radius) {
const indent = Math.sqrt(obstacle.radius ** 2 - dy ** 2);
maxWidth = obstacle.x - indent - 60;
}
ctx.fillText(line.text.trim(), xStart, y + 20);
y += 28;
});
}, []);
return (
<main className="min-h-screen bg-white flex items-center justify-center p-8">
<div>
<h1 className="text-3xl font-bold mb-6">Magazine Text Flow</h1>
<canvas ref={canvasRef} className="border border-gray-200 rounded-lg shadow-sm" />
<p className="text-sm text-gray-500 mt-4">
Text flows around the circular obstacle — no DOM reflows, no CSS hacks.
</p>
</div>
</main>
);
}ما الذي يحدث هنا: prepare() تخزّن جميع قياسات النص باستخدام Canvas (وليس الـ DOM). ثم نحسب عرض كل سطر بناءً على شكل العائق. يلتفّ النص بشكل طبيعي حول الدائرة — بمعدل 120 إطاراً في الثانية.
التأثير الثاني: الطباعة الحركية (أنيميشن ظهور النص)
النوع من التأثيرات الذي تُقدّم وكالات التصميم الإبداعي فاتورة بـ 5000 دولار عليه. كلمات تنزلق داخل الشاشة بتوقيت متدرج وأحجام متغيرة.
// app/kinetic/page.tsx
'use client';
import { useEffect, useRef, useState } from 'react';
import { prepare, layout } from 'pretext';
const words = [
{ text: 'AI AGENTS', size: 72, weight: 'bold', color: '#0070F4' },
{ text: 'SHIP CODE', size: 64, weight: 'bold', color: '#1a1a1a' },
{ text: 'RUN AUDITS', size: 56, weight: 'normal', color: '#3ABAB4' },
{ text: 'MANAGE PROJECTS', size: 48, weight: 'normal', color: '#666' },
{ text: '$45/HR', size: 80, weight: 'bold', color: '#0070F4' },
{ text: 'HUMAN IN THE LOOP', size: 40, weight: 'normal', color: '#999' },
];
export default function KineticPage() {
const canvasRef = useRef<HTMLCanvasElement>(null);
const [frame, setFrame] = useState(0);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d')!;
canvas.width = 900;
canvas.height = 600;
let animFrame: number;
let startTime = Date.now();
const animate = () => {
const elapsed = (Date.now() - startTime) / 1000;
ctx.clearRect(0, 0, 900, 600);
ctx.fillStyle = '#fafafa';
ctx.fillRect(0, 0, 900, 600);
let y = 60;
words.forEach((word, i) => {
const delay = i * 0.3;
const progress = Math.min(1, Math.max(0, (elapsed - delay) / 0.5));
const eased = 1 - Math.pow(1 - progress, 3); // ease-out cubic
const alpha = eased;
const offsetX = (1 - eased) * 100;
// Use Pretext to measure exact width for centering
ctx.font = `${word.weight} ${word.size}px "Inter", sans-serif`;
const prepared = prepare(ctx, word.text, {
fontFamily: '"Inter", sans-serif',
fontSize: word.size,
fontWeight: word.weight,
});
const height = layout(prepared, 900);
ctx.globalAlpha = alpha;
ctx.fillStyle = word.color;
ctx.fillText(word.text, 50 + offsetX, y + word.size * 0.8);
ctx.globalAlpha = 1;
y += word.size + 16;
});
animFrame = requestAnimationFrame(animate);
};
animate();
return () => cancelAnimationFrame(animFrame);
}, []);
return (
<main className="min-h-screen bg-gray-50 flex items-center justify-center p-8">
<div>
<h1 className="text-2xl font-bold mb-4">Kinetic Typography</h1>
<canvas ref={canvasRef} className="rounded-xl shadow-lg" />
<p className="text-sm text-gray-500 mt-4">
Each line slides in with staggered timing. Pretext measures text instantly for perfect positioning.
</p>
</div>
</main>
);
}لماذا Pretext مهمة هنا: بدون Pretext، يتطلب حساب عرض النص للمحاذاة أو التوسيط إدراج عناصر في الـ DOM ثم انتظار إعادة الرسم. في أنيميشن 60 إطاراً في الثانية، هذا كارثي. Pretext تفعل ذلك في 0.09 ميلي ثانية.
التأثير الثالث: نص بشكل كائن (الشعر البصري)
اجعل النص يملأ أي شكل عشوائي — دائرة، قلب، مخطط شعار. النوع من الأشياء الذي يصبح فيروسياً على تويتر.
// app/shape-text/page.tsx
'use client';
import { useEffect, useRef } from 'react';
import { prepare, layoutNextLine } from 'pretext';
export default function ShapeTextPage() {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d')!;
canvas.width = 600;
canvas.height = 600;
const text = `Pretext measures and lays out multiline text without triggering DOM reflows. It uses the Canvas measureText API to build its own measurement cache. From that cache, it calculates paragraph heights, returns individual line objects, and lays out text line by line with variable widths. This makes text flow around obstacles, wrap into columns, and fit into arbitrary shapes — capabilities that were impossible on the web before. Built by Cheng Lou, a Midjourney engineer and former React core team member, Pretext delivers magazine quality typography at 120 frames per second. The library is just 15 kilobytes and works with DOM, Canvas, and SVG.`;
const prepared = prepare(ctx, text, {
fontFamily: 'Georgia',
fontSize: 14,
lineHeight: 20,
});
// Circle shape: calculate width per line based on circle equation
const centerX = 300;
const centerY = 300;
const radius = 250;
const lineHeight = 20;
ctx.fillStyle = '#1a1a1a';
ctx.font = '14px Georgia';
let y = centerY - radius + 20;
let remaining = text;
while (y < centerY + radius - 20 && remaining.length > 0) {
const dy = y - centerY;
const halfWidth = Math.sqrt(Math.max(0, radius * radius - dy * dy));
const lineWidth = halfWidth * 2 - 40; // padding
if (lineWidth > 50) {
const x = centerX - halfWidth + 20;
// Use layoutNextLine to get exactly one line at this width
const linePrepared = prepare(ctx, remaining, {
fontFamily: 'Georgia',
fontSize: 14,
lineHeight: 20,
});
// Approximate: measure how many chars fit in lineWidth
let charCount = 0;
let measuredWidth = 0;
for (let i = 0; i < remaining.length; i++) {
const w = ctx.measureText(remaining.substring(0, i + 1)).width;
if (w > lineWidth) break;
charCount = i + 1;
// Break at word boundary
if (remaining[i] === ' ') measuredWidth = i + 1;
}
const breakAt = measuredWidth || charCount;
const lineText = remaining.substring(0, breakAt).trim();
remaining = remaining.substring(breakAt);
ctx.fillText(lineText, x, y);
}
y += lineHeight;
}
// Draw subtle circle outline
ctx.strokeStyle = '#e0e0e0';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
ctx.stroke();
}, []);
return (
<main className="min-h-screen bg-white flex items-center justify-center p-8">
<div className="text-center">
<h1 className="text-2xl font-bold mb-4">Text in a Circle</h1>
<canvas ref={canvasRef} className="mx-auto" />
<p className="text-sm text-gray-500 mt-4">
Text fills a circular shape with per-line width calculations. Pure Canvas, zero DOM.
</p>
</div>
</main>
);
}الزاوية التي تجذب التفاعل على تويتر: هذا هو النوع من المرئيات الذي يحصد 10 آلاف إعجاب. "جعلت النص يملأ دائرة باستخدام 15 كيلوبايت من JavaScript. لا CSS. لا DOM. مجرد رياضيات."
التأثير الرابع: مقال يعرض نفسه (هذا المقال بأسلوب مجلة)
الخاتمة المدهشة: مكوّن يأخذ محتوى هذا الدرس بصيغة markdown ويعرضه بطباعة راقية بأسلوب مجلة — مع حروف أولية كبيرة، وأعمدة متدفقة، واقتباسات بارزة.
// app/article-renderer/page.tsx
'use client';
import { useEffect, useRef } from 'react';
import { prepare, layoutWithLines } from 'pretext';
const articleContent = {
title: 'The 15KB Library That Changed Web Typography',
subtitle: 'How Pretext makes magazine layouts possible at 120fps',
body: `For 30 years, the web has treated text as a second-class citizen. While print designers flowed paragraphs around images, wrapped columns, and fit type into arbitrary shapes, browsers offered none of that without expensive DOM reflows.
Pretext changes everything. A 15KB TypeScript library by Midjourney engineer Cheng Lou, it measures and lays out multiline text up to 500 times faster than traditional browser methods.
The secret is simple: instead of inserting text into the DOM and measuring the result, Pretext uses the Canvas measureText API to build its own measurement cache. From that cache, it calculates heights, returns line objects, and flows text around obstacles.
Developers are already building text games, magazine layouts, and kinetic typography with it. The library handles every script including Arabic, emoji, and bidirectional text.
This is not an incremental improvement. This is the missing piece of web typography.`,
pullQuote: '"I crawled through depths of hell to bring you this." — Cheng Lou',
};
export default function ArticleRenderer() {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d')!;
canvas.width = 900;
canvas.height = 1000;
// Background
ctx.fillStyle = '#FFFDF7';
ctx.fillRect(0, 0, 900, 1000);
// Title
ctx.fillStyle = '#1a1a1a';
ctx.font = 'bold 36px Georgia';
ctx.fillText(articleContent.title, 60, 80);
// Subtitle
ctx.fillStyle = '#666';
ctx.font = 'italic 18px Georgia';
ctx.fillText(articleContent.subtitle, 60, 115);
// Divider
ctx.strokeStyle = '#0070F4';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(60, 135);
ctx.lineTo(200, 135);
ctx.stroke();
// Body text with drop cap
const paragraphs = articleContent.body.split('\n\n');
let y = 170;
paragraphs.forEach((para, pIdx) => {
const prepared = prepare(ctx, para, {
fontFamily: 'Georgia',
fontSize: 16,
lineHeight: 26,
});
const lines = layoutWithLines(prepared, pIdx === 0 ? 680 : 780);
if (pIdx === 0 && lines.length > 0) {
// Drop cap for first paragraph
const firstChar = para[0];
ctx.fillStyle = '#0070F4';
ctx.font = 'bold 72px Georgia';
ctx.fillText(firstChar, 60, y + 60);
// Indent first 3 lines
ctx.fillStyle = '#1a1a1a';
ctx.font = '16px Georgia';
const dropCapWidth = 70;
lines.forEach((line, lIdx) => {
const x = lIdx < 3 ? 60 + dropCapWidth : 60;
ctx.fillText(line.text.trim(), x, y);
y += 26;
});
} else {
ctx.fillStyle = '#1a1a1a';
ctx.font = '16px Georgia';
lines.forEach((line) => {
ctx.fillText(line.text.trim(), 60, y);
y += 26;
});
}
y += 16; // paragraph spacing
// Insert pull quote after second paragraph
if (pIdx === 1) {
ctx.fillStyle = '#0070F4';
ctx.fillRect(60, y, 4, 60);
ctx.fillStyle = '#333';
ctx.font = 'italic 20px Georgia';
ctx.fillText(articleContent.pullQuote, 80, y + 30);
y += 90;
}
});
// Footer
ctx.fillStyle = '#ccc';
ctx.font = '12px sans-serif';
ctx.fillText('Rendered with Pretext — 0 DOM reflows', 60, y + 30);
}, []);
return (
<main className="min-h-screen bg-gray-100 flex items-center justify-center p-8">
<div className="text-center">
<h1 className="text-2xl font-bold mb-4">Self-Rendering Magazine Article</h1>
<canvas ref={canvasRef} className="rounded-xl shadow-xl mx-auto" />
<p className="text-sm text-gray-500 mt-4">
This article about Pretext is rendered BY Pretext. Drop caps, pull quotes, flowing columns — zero DOM.
</p>
</div>
</main>
);
}ما الذي بنيته
| التأثير | التقنية المستخدمة | القوة الفيروسية |
|---|---|---|
| تدفق أسلوب المجلة | نص حول العوائق | "CSS لم تستطع يوماً هذا" |
| الطباعة الحركية | نص متحرك بـ 120fps | جودة وكالة، بدون ميزانية |
| الشعر البصري | نص يملأ الأشكال | "صُنع بـ 15 كيلوبايت من JS" |
| مقال يعرض نفسه | تخطيط مجلة ميتا | "هذا المقال يعرض نفسه" |
لماذا تغيّر Pretext قواعد اللعبة
قبل Pretext، كان كل تأثير نصي إبداعي يستلزم إما:
- التلاعب بالـ DOM (بطيء، يُفعّل إعادة الرسم، يتعثّر على نطاق واسع)
- صور مُسبقة التوليد (لا يمكن فهرستها، لا يمكن الوصول إليها، غير متجاوبة)
- WebGL (تكلفة باهظة لمجرد نص)
Pretext تمنحك طباعة بجودة الطباعة الورقية بسرعة الويب الأصيلة. تتعامل المكتبة مع العربية، والإيموجي، والنصوص ثنائية الاتجاه، وكل الخطوط — بـ 15 كيلوبايت فقط.
الويب أخيراً حصل على محرك نصوص يُعامل الكلمات كمادة إبداعية من الدرجة الأولى.
🚀 هل تبني تطبيقاً غنياً بالمحتوى أو أداة إبداعية؟ وكلاؤنا يُشحنون Next.js إنتاجياً مع طباعة متقدمة وأنيميشن وتحسين للأداء — بـ 45 دولاراً في الساعة، مع إشراف بشري. احجز مكالمة مجانية ←
ماذا تبني بعد ذلك
- موقع محفظة أعمال بتخطيطات مقالات بجودة المجلات
- مولّد بطاقات وسائل التواصل الاجتماعي بنصوص على أشكال (مثل Canva لكن أسرع)
- قصة تفاعلية يُعيد فيها النص تدفّقه مع تمرير القارئ
- مدونة مباشرة تعرض المقالات بحروف أولية كبيرة واقتباسات بارزة في الوقت الفعلي
مجتمع البرمجة الإبداعية على تويتر يدفع حدود Pretext بالفعل. أحدهم بنى Text Invaders. ماذا ستبني أنت؟
💡 تحتاج مساعدة في بناء منتج ويب إبداعي؟ من محركات الطباعة إلى التجارب التفاعلية، وكلاؤنا الذكيون يتكفّلون بالكود بينما تركّز أنت على الرؤية. تحدّث مع وكيل ←
مزيد من القراءة
- Pretext: المكتبة الصغيرة التي تجعل تخطيط النصوص على الويب أسرع بـ 500 مرة
- أفضل محرر كود بالذكاء الاصطناعي لعام 2026: Windsurf مقابل Cursor مقابل Copilot
الويب كان يمتلك الصور والفيديو والثلاثي الأبعاد لسنوات. النص وحده ظلّ عالقاً في التسعينيات. لم يعد هذا ينطبق اليوم.
ناقش مشروعك معنا
نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.
دعنا نجد أفضل الحلول لاحتياجاتك.
مقالات ذات صلة

الدليل التفصيلي لتثبيت وهيكلة تطبيقك في Next.js لأداء أمثل
الدليل التفصيلي لتثبيت وهيكلة تطبيقك في Next.js لأداء أمثل: عزز تطبيق Next.js الخاص بك باستخدام هذا الدليل الشامل حول التثبيت وأفضل الممارسات لهيكلة مشروعك لتحقيق الأداء الأمثل.

بناء تطبيق ذكاء اصطناعي محادثي مع Next.js
تعلم كيفية بناء تطبيق ويب يتيح محادثات صوتية في الوقت الفعلي مع وكلاء الذكاء الاصطناعي باستخدام Next.js وElevenLabs.

بناء تطبيق متعدد المستأجرين مع Next.js
تعلم كيفية بناء تطبيق متعدد المستأجرين كامل باستخدام Next.js وVercel والتقنيات الحديثة الأخرى.