Why Scroll?
Simple Syntax
Like Markdown, but more powerful. No parentheses needed.
Extendible
Build your own custom parsers.
Beautiful Output
Create stunning documents with minimal effort.
Fast & Light
Built on the efficient PPS Stack.
Prompt: website
Agent: deepseek
Model: deepseek-chat
You are an expert web developer. Create a website based on this request: "import React, { useState, useEffect, useCallback, useRef } from 'react'; import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { RotateCw, Volume2, Forward, HelpCircle, RefreshCw } from 'lucide-react'; function SpeakAndSpell() { const successSoundRef = useRef(null); const errorSoundRef = useRef(null); const DIFFICULTWORDS = [ 'accommodate', 'accordance', 'acquisition', 'ambiguous', 'bureaucracy', 'characteristic', 'circumstantial', 'coincidence', 'colleague', 'commemorate', 'commissary', 'commitment', 'committee', 'competitive', 'completely', 'concurrence', 'conflagration', 'conscientious', 'consistent', 'convenient', 'correspondence', 'definitely', 'development', 'difference', 'discipline', 'dissimilar', 'efficient', 'embarrass', 'especially', 'exhilarate', 'experience', 'fascinating', 'government', 'grandiloquent', 'guarantee', 'harassment', 'hierarchy', 'humorous', 'hypocrite', 'ignominious', 'immediate', 'incandescent', 'incredible', 'independent', 'industrial', 'infinitesimal', 'influential', 'inspiration', 'intelligence', 'maintenance', 'medieval', 'millennium', 'miniature', 'necessary', 'obstinate', 'occurrence', 'opportunity', 'parliament', 'perseverance', 'personnel', 'perspective', 'phenomenon', 'preference', 'prejudice', 'prevalent' ]; const KEYBOARDLAYOUT = [ ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'], ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'], ['Z', 'X', 'C', 'V', 'B', 'N', 'M'] ]; const [availableWords, setAvailableWords] = useState([...DIFFICULTWORDS]); const [currentWord, setCurrentWord] = useState(''); const [userInput, setUserInput] = useState(''); const [stats, setStats] = useState({ correct: 0, attempted: 0, skipped: 0 }); const [showSuccess, setShowSuccess] = useState(false); const [showError, setShowError] = useState(false); const [showHint, setShowHint] = useState(false); const [isLoading, setIsLoading] = useState(false); // Create beep oscillator for success/error sounds const playSuccessSound = () => { if (typeof window !== 'undefined' && window.AudioContext) { const audioContext = new AudioContext(); const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.connect(gainNode); gainNode.connect(audioContext.destination); oscillator.type = 'sine'; oscillator.frequency.setValueAtTime(800, audioContext.currentTime); // Higher pitch for success gainNode.gain.setValueAtTime(0.5, audioContext.currentTime); oscillator.start(); gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5); oscillator.stop(audioContext.currentTime + 0.5); } }; const playErrorSound = () => { if (typeof window !== 'undefined' && window.AudioContext) { const audioContext = new AudioContext(); const oscillator = audioContext.createOscillator(); const gainNode = audioContext.createGain(); oscillator.connect(gainNode); gainNode.connect(audioContext.destination); oscillator.type = 'sine'; oscillator.frequency.setValueAtTime(200, audioContext.currentTime); // Lower pitch for error gainNode.gain.setValueAtTime(0.5, audioContext.currentTime); oscillator.start(); gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5); oscillator.stop(audioContext.currentTime + 0.5); } }; useEffect(() => { if (!currentWord) { selectNewWord(); } }, [currentWord]); const selectNewWord = useCallback(() => { if (availableWords.length === 0) { setAvailableWords([...DIFFICULTWORDS]); return; } const index = Math.floor(Math.random() availableWords.length); const word = availableWords[index]; setAvailableWords(prev => prev.filter((, i) => i !== index)); setCurrentWord(word); }, [availableWords]); const speakWord = (word) => { setIsLoading(true); const utterance = new SpeechSynthesisUtterance(word); const voices = window.speechSynthesis.getVoices(); const maleVoice = voices.find( voice => voice.name.includes('Male') || voice.name.includes('male') || voice.name.includes('David') || voice.name.includes('James') || voice.name.includes('Daniel') ); if (maleVoice) { utterance.voice = maleVoice; } utterance.rate = 0.9; utterance.pitch = 0.8; utterance.volume = 1.0; utterance.onend = () => setIsLoading(false); window.speechSynthesis.speak(utterance); }; const speakLetter = (letter) => { const utterance = new SpeechSynthesisUtterance(letter.toLowerCase()); const voices = window.speechSynthesis.getVoices(); const maleVoice = voices.find( voice => voice.name.includes('Male') || voice.name.includes('male') || voice.name.includes('David') || voice.name.includes('James') || voice.name.includes('Daniel') ); if (maleVoice) { utterance.voice = maleVoice; } utterance.rate = 0.9; utterance.pitch = 0.8; utterance.volume = 1.0; window.speechSynthesis.speak(utterance); }; const handleKeyPress = (letter) => { if (userInput.length < currentWord.length) { setUserInput(prev => prev + letter); speakLetter(letter); } }; const handleBackspace = () => { setUserInput(prev => prev.slice(0, -1)); }; useEffect(() => { const handlePhysicalKeyboard = (e) => { if (e.key === 'Backspace') { e.preventDefault(); handleBackspace(); } else if (e.key === 'Enter') { e.preventDefault(); handleSubmit(); } else if (e.key.length === 1 && e.key.match(/[a-zA-Z]/i)) { e.preventDefault(); handleKeyPress(e.key.toUpperCase()); } }; window.addEventListener('keydown', handlePhysicalKeyboard); return () => window.removeEventListener('keydown', handlePhysicalKeyboard); }, [userInput, currentWord]); const handleSkip = () => { setStats(prev => ({ ...prev, skipped: prev.skipped + 1 })); setUserInput(''); setShowHint(false); selectNewWord(); }; const handleSubmit = () => { if (userInput.toLowerCase() === currentWord.toLowerCase()) { setShowSuccess(true); setShowError(false); setStats(prev => ({ ...prev, correct: prev.correct + 1, attempted: prev.attempted + 1 })); playSuccessSound(); setTimeout(() => { setShowSuccess(false); setUserInput(''); setShowHint(false); selectNewWord(); }, 1500); } else { setShowError(true); setShowSuccess(false); setStats(prev => ({ ...prev, attempted: prev.attempted + 1 })); playErrorSound(); setTimeout(() => { setShowError(false); setUserInput(''); }, 1500); } }; const handleHint = () => { setShowHint(!showHint); }; const handleReset = () => { setAvailableWords([...DIFFICULTWORDS]); setCurrentWord(''); setUserInput(''); setStats({ correct: 0, attempted: 0, skipped: 0 }); setShowSuccess(false); setShowError(false); setShowHint(false); }; return (
Requirements:
As a refresher, for doing the html body, Scroll is a whitespace based language that uses a single indented space to mark a line (aka particle) as a subparticle of a parent line.
For example:
The extendible markup language that makes source beautiful and compiles to anything
Get StartedLike Markdown, but more powerful. No parentheses needed.
Build your own custom parsers.
Create stunning documents with minimal effort.
Built on the efficient PPS Stack.
First suggest a short, memorable domain name ending in scroll.pub that represents this website. Then provide the website files. Use this exact format:
---domain---
(domainscroll.pub here)
---index.scroll---
(body content here. no blank lines please.)
---style.css---
(CSS content here)
---script.js---
(JavaScript content here)
---end---