- Create robots.txt to allow all user agents and specify sitemap location - Add site.webmanifest for PWA support with app details - Initialize sitemap.xml with the homepage URL and metadata - Set up svelte.config.js for SvelteKit with static adapter and prerendering - Configure TypeScript with tsconfig.json for strict type checking and module resolution - Establish Vite configuration in vite.config.ts for SvelteKit integration
24 KiB
Squiggleverse Landing Page Design Document / Spec Sheet
1. Project Summary
Project: Squiggleverse landing page
Primary goal: Present Squiggleverse as a whimsical, polished, education-through-play platform using a simple, high-performing homepage structure.
Recommended layout:
- Logo / hero branding
- Embedded or self-hosted promo video
- Short explanatory text
- Optional CTA row: “Watch Demo,” “Join Mailing List,” “Contact Us”
Core positioning text:
Squiggleverse is a modular, multi-platform, game-based “stealth” learning system that teaches grammar, usage, and style through innovative gameplay, whimsical characters, and creative narratives co-authored by the player.
The page should feel like a lightweight marketing splash page rather than a heavy SaaS homepage.
2. Recommended Web Stack
Framework
Use SvelteKit as the primary framework.
SvelteKit is appropriate here because the landing page can be statically rendered, very fast, SEO-friendly, and simple to deploy. SvelteKit supports prerendering/static generation and server-side rendering options per route, which is ideal for a marketing page that may later grow into a larger app or dashboard.
Suggested stack
SvelteKit
TypeScript
Vite
CSS / SCSS / PostCSS
Static adapter or platform adapter
PNPM
ESLint + Prettier
Deployment targets
Good options:
Cloudflare Pages
Netlify
Vercel
Static hosting behind nginx/Caddy
CapRover container deployment
For this page, static generation is preferred unless the site needs dynamic personalization, server-side forms, authentication, or CMS previews.
Recommended SvelteKit page config:
// src/routes/+page.ts
export const prerender = true;
export const ssr = true;
For a landing page, keep SSR/prerendering enabled so the logo, text, metadata, and canonical content are present in the initial HTML.
3. Page Structure
Route
/
File layout
src/
lib/
assets/
squiggleverse-logo.webp
squiggleverse-bg.webp
squiggleverse-poster.webp
squiggleverse-demo.mp4
components/
HeroLogo.svelte
VideoCard.svelte
IntroText.svelte
CTAButtons.svelte
StarBackground.svelte
routes/
+layout.svelte
+layout.ts
+page.svelte
+page.ts
+error.svelte
app.html
app.css
static/
favicon.svg
robots.txt
site.webmanifest
og-image.webp
4. Visual Design Direction
Overall style
The landing page should use:
Whimsical
Space-themed
Purple/violet palette
Soft glow effects
Rounded cards
Centered single-column layout
Large readable text
Minimal navigation
Layout wireframe
┌─────────────────────────────────────┐
│ │
│ Logo │
│ │
│ ┌───────────────────┐ │
│ │ │ │
│ │ Video │ │
│ │ │ │
│ └───────────────────┘ │
│ │
│ Short description text │
│ │
│ [ Watch Demo ] [ Contact ] │
│ │
└─────────────────────────────────────┘
Responsive behavior
Desktop
Max content width: 960–1100px
Logo width: 520–720px
Video width: 800–960px
Text width: 680–820px
Tablet
Content width: 90vw
Logo width: 70–80vw
Video width: 90vw
Text width: 80–90vw
Mobile
Single column
Logo width: 86vw
Video width: 92vw
Text centered or slightly left-aligned if readability suffers
Font size reduced carefully
5. Color System
Use a constrained purple palette.
:root {
--color-bg-deep: #070014;
--color-bg-space: #160030;
--color-purple-dark: #2a0f56;
--color-purple: #6b3fb3;
--color-purple-light: #b58cff;
--color-lavender: #f1e7ff;
--color-white: #ffffff;
--color-cyan-accent: #43d8ff;
--glow-purple: 0 0 32px rgba(159, 95, 255, 0.45);
--border-purple: rgba(190, 143, 255, 0.38);
}
Background
Use the provided starry background as a fullscreen visual layer.
Recommended CSS:
.page {
min-height: 100svh;
background:
linear-gradient(
to bottom,
rgba(7, 0, 20, 0.2),
rgba(54, 0, 95, 0.35)
),
url('/assets/squiggleverse-bg.webp');
background-size: cover;
background-position: center top;
background-attachment: fixed;
}
For mobile, avoid background-attachment: fixed because it can cause jank.
@media (max-width: 768px) {
.page {
background-attachment: scroll;
}
}
6. Typography
Primary recommendation
Use a highly readable sans-serif for body copy.
Good options:
Atkinson Hyperlegible
Nunito Sans
Inter
Lexend
Source Sans 3
For an educational product, Atkinson Hyperlegible or Lexend would fit well because they emphasize readability.
Font loading
Prefer self-hosted fonts using @font-face.
@font-face {
font-family: 'Atkinson Hyperlegible';
src: url('/fonts/AtkinsonHyperlegible-Regular.woff2') format('woff2');
font-weight: 400;
font-display: swap;
}
Use font-display: swap to avoid invisible text during load.
7. Component Specification
HeroLogo.svelte
Purpose:
Displays the Squiggleverse logo centered at the top.
Requirements:
Use actual provided logo asset.
Do not recreate the logo in text.
Use responsive sizing.
Include alt text.
Avoid layout shift by declaring width/height or aspect ratio.
Example:
<script lang="ts">
import logo from '$lib/assets/squiggleverse-logo.webp';
</script>
<div class="hero-logo">
<img
src={logo}
alt="Squiggleverse"
width="900"
height="420"
decoding="async"
/>
</div>
CSS:
.hero-logo {
display: flex;
justify-content: center;
margin-inline: auto;
}
.hero-logo img {
width: min(720px, 88vw);
height: auto;
filter: drop-shadow(0 0 28px rgba(159, 95, 255, 0.45));
}
VideoCard.svelte
Purpose:
Displays the main Squiggleverse video or poster/video preview.
Preferred implementation:
Use native <video> for self-hosted promo video.
Use poster image.
Lazy-load if below fold, but in this layout it is likely above fold.
Avoid YouTube iframe unless necessary.
Native video gives better branding control, fewer third-party scripts, and better privacy/performance.
Example:
<script lang="ts">
import poster from '$lib/assets/squiggleverse-poster.webp';
import video from '$lib/assets/squiggleverse-demo.mp4';
</script>
<section class="video-card" aria-label="Squiggleverse demo video">
<video
controls
preload="metadata"
poster={poster}
playsinline
>
<source src={video} type="video/mp4" />
Your browser does not support the video tag.
</video>
</section>
CSS:
.video-card {
width: min(940px, 92vw);
margin: 2rem auto 2.25rem;
padding: clamp(0.5rem, 1.2vw, 0.9rem);
border: 1px solid var(--border-purple);
border-radius: 2rem;
background:
linear-gradient(
180deg,
rgba(28, 10, 72, 0.72),
rgba(12, 4, 38, 0.78)
);
box-shadow:
var(--glow-purple),
inset 0 0 40px rgba(255, 255, 255, 0.04);
backdrop-filter: blur(8px);
}
.video-card video {
display: block;
width: 100%;
aspect-ratio: 16 / 9;
border-radius: 1.45rem;
background: #090019;
}
Video asset requirements
Format: MP4/H.264 baseline or high profile
Optional: WebM VP9/AV1 for modern browsers
Poster: WebP or AVIF
Resolution: 1280×720 minimum
Max video size target: 3–8 MB for landing page
Audio: compressed AAC, normalized
Captions: WebVTT file if voiceover exists
Add captions if there is spoken content:
<track
kind="captions"
src="/captions/squiggleverse-demo.vtt"
srclang="en"
label="English"
/>
IntroText.svelte
Purpose:
Displays the main product positioning copy.
Requirements:
Exact text preserved.
Readable line length.
High contrast.
No image-rendered text.
Example:
<section class="intro" aria-labelledby="intro-title">
<h1 id="intro-title" class="sr-only">About Squiggleverse</h1>
<p>
Squiggleverse is a modular, multi-platform, game-based “stealth” learning
system that teaches grammar, usage, and style through innovative gameplay,
whimsical characters, and creative narratives co-authored by the player.
</p>
</section>
CSS:
.intro {
width: min(820px, 88vw);
margin: 0 auto;
text-align: center;
}
.intro p {
margin: 0;
color: var(--color-lavender);
font-size: clamp(1.2rem, 2.2vw, 2rem);
line-height: 1.45;
letter-spacing: 0.01em;
text-shadow: 0 2px 18px rgba(0, 0, 0, 0.45);
}
Optional CTAButtons.svelte
Even if the initial page is simple, adding a CTA is useful for conversion.
Recommended CTAs:
Primary: Watch Demo
Secondary: Contact Us
Optional: Join Mailing List
Example:
<div class="cta-row">
<a class="button button-primary" href="#demo">Watch Demo</a>
<a class="button button-secondary" href="mailto:hello@squiggleverse.com">
Contact Us
</a>
</div>
8. Accessibility Requirements
Required
Logo must have meaningful alt text.
Video must have controls.
Video needs captions if it contains speech.
Text must not be baked into images.
All interactive elements need visible focus states.
Color contrast should meet WCAG AA.
Animations/glows should respect prefers-reduced-motion.
Page must be keyboard navigable.
Reduced motion
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
scroll-behavior: auto !important;
}
}
Focus styling
:focus-visible {
outline: 3px solid var(--color-cyan-accent);
outline-offset: 4px;
}
9. SEO Specification
Rendering
Use prerendered HTML for the homepage. Search engines should receive real text content, not an empty SPA shell. SvelteKit can prerender static routes into static files, which fits this use case well.
Metadata
Implement in +page.svelte:
<svelte:head>
<title>Squiggleverse | Game-Based Grammar, Usage, and Style Learning</title>
<meta
name="description"
content="Squiggleverse is a modular, multi-platform, game-based stealth learning system for grammar, usage, and style."
/>
<link rel="canonical" href="https://squiggleverse.com/" />
<meta property="og:type" content="website" />
<meta property="og:title" content="Squiggleverse" />
<meta
property="og:description"
content="A whimsical game-based learning system for grammar, usage, and style."
/>
<meta property="og:image" content="https://squiggleverse.com/og-image.webp" />
<meta property="og:url" content="https://squiggleverse.com/" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Squiggleverse" />
<meta
name="twitter:description"
content="A whimsical game-based learning system for grammar, usage, and style."
/>
<meta name="twitter:image" content="https://squiggleverse.com/og-image.webp" />
</svelte:head>
Suggested title variants
Squiggleverse | Game-Based Grammar Learning
Squiggleverse | Learn Grammar Through Play
Squiggleverse | Stealth Learning Through Whimsical Gameplay
Suggested meta description
Squiggleverse is a modular, multi-platform, game-based stealth learning system that teaches grammar, usage, and style through whimsical gameplay.
Keep meta descriptions around 140–160 characters when possible.
Heading structure
Recommended:
<h1>Squiggleverse</h1>
Because the logo is graphical, include a visually hidden H1.
<h1 class="sr-only">Squiggleverse</h1>
Use only one H1 on the page.
Structured data
Add basic WebSite and Organization JSON-LD.
<svelte:head>
<script type="application/ld+json">
{JSON.stringify({
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'Squiggleverse',
url: 'https://squiggleverse.com/',
description:
'A modular, multi-platform, game-based stealth learning system for grammar, usage, and style.'
})}
</script>
</svelte:head>
If a company/entity name exists, add Organization.
Robots
static/robots.txt:
User-agent: *
Allow: /
Sitemap: https://squiggleverse.com/sitemap.xml
Sitemap
For one page, the sitemap is simple:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://squiggleverse.com/</loc>
<changefreq>monthly</changefreq>
<priority>1.0</priority>
</url>
</urlset>
10. Performance Requirements
Core Web Vitals targets
Use these targets:
LCP: ≤ 2.5s
CLS: ≤ 0.1
INP: ≤ 200ms
Total JS: ideally under 100 KB compressed for this page
Initial image payload: ideally under 500 KB before video
Video: do not autoplay large media
LCP optimization
Likely LCP candidate:
Logo image
or
intro text block
or
video poster image
Recommendations:
Use optimized WebP/AVIF.
Declare image dimensions.
Preload the logo only if it is the true LCP element.
Avoid client-only rendering for hero content.
Do not load heavy JS before first paint.
Example preload:
<svelte:head>
<link
rel="preload"
as="image"
href="/assets/squiggleverse-logo.webp"
type="image/webp"
/>
</svelte:head>
Only preload the logo if testing confirms it improves LCP.
CLS prevention
Set width/height on images.
Use aspect-ratio for video card.
Avoid late-loading web fonts without fallback sizing.
Reserve space for video controls/poster.
Avoid injecting CTA/forms above existing content after hydration.
Video performance
Use:
preload="metadata"
poster="/assets/squiggleverse-poster.webp"
playsinline
controls
Avoid:
autoplay
preload="auto"
large uncompressed MOV files
third-party iframe on first load
If YouTube/Vimeo is required, use a “lite embed” strategy:
Show poster image first.
Load iframe only after click.
Image optimization
Generate:
logo.webp
logo.avif
background.webp
background.avif
poster.webp
poster.avif
og-image.webp
Recommended sizes:
Logo: 900–1200 px wide
Background: 1920 px wide desktop, 960 px mobile variant
Poster: 1280×720
OG image: 1200×630
Use srcset for the background or use CSS media queries.
11. Security Specification
Content Security Policy
SvelteKit supports CSP configuration that helps restrict where scripts, styles, images, fonts, and other resources can load from. CSP is specifically useful for reducing XSS exposure.
Example starter CSP in svelte.config.js:
const config = {
kit: {
csp: {
mode: 'auto',
directives: {
'default-src': ['self'],
'script-src': ['self'],
'style-src': ['self', 'unsafe-inline'],
'img-src': ['self', 'data:'],
'font-src': ['self'],
'media-src': ['self'],
'connect-src': ['self'],
'frame-src': ['self'],
'object-src': ['none'],
'base-uri': ['self'],
'form-action': ['self'],
'frame-ancestors': ['none']
}
}
}
};
export default config;
Notes:
Avoid unsafe-inline for scripts.
Style unsafe-inline may be necessary depending on SvelteKit output and deployment mode.
If using YouTube/Vimeo, frame-src and img-src need additional domains.
If using analytics, connect-src/script-src must include that provider.
Security headers
Recommended headers:
Content-Security-Policy
Strict-Transport-Security
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy
X-Frame-Options: DENY or CSP frame-ancestors 'none'
Cross-Origin-Opener-Policy: same-origin
Example SvelteKit hook:
// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
const response = await resolve(event);
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
response.headers.set(
'Permissions-Policy',
'camera=(), microphone=(), geolocation=(), payment=()'
);
return response;
};
For fully static deployment, set these headers at the host/CDN level instead.
Forms
If adding a mailing list form:
Use server-side validation.
Add rate limiting.
Use CSRF protection where applicable.
Never expose API secrets in client-side env vars.
Use honeypot field or Turnstile/hCaptcha if spam becomes a problem.
Environment variables
Use:
.env
PRIVATE_*
PUBLIC_*
Do not put API secrets in PUBLIC_*.
12. Privacy Considerations
Recommended:
Avoid third-party trackers initially.
Avoid third-party video if possible.
Self-host fonts.
Self-host video.
Self-host images.
Use privacy-friendly analytics only if needed.
Good analytics options:
Plausible
Fathom
Umami self-hosted
Cloudflare Web Analytics
No analytics for MVP
If analytics are added, update:
Privacy policy
Cookie notice if cookies are used
CSP domains
13. SvelteKit Implementation Sketch
src/routes/+page.svelte
<script lang="ts">
import HeroLogo from '$lib/components/HeroLogo.svelte';
import VideoCard from '$lib/components/VideoCard.svelte';
import IntroText from '$lib/components/IntroText.svelte';
import CTAButtons from '$lib/components/CTAButtons.svelte';
</script>
<svelte:head>
<title>Squiggleverse | Game-Based Grammar, Usage, and Style Learning</title>
<meta
name="description"
content="Squiggleverse is a modular, multi-platform, game-based stealth learning system that teaches grammar, usage, and style through whimsical gameplay."
/>
<link rel="canonical" href="https://squiggleverse.com/" />
</svelte:head>
<main class="landing-page">
<h1 class="sr-only">Squiggleverse</h1>
<section class="hero" aria-label="Squiggleverse landing page">
<HeroLogo />
<VideoCard />
<IntroText />
<CTAButtons />
</section>
</main>
src/app.css
:root {
color-scheme: dark;
--color-bg-deep: #070014;
--color-bg-space: #160030;
--color-purple-dark: #2a0f56;
--color-purple: #6b3fb3;
--color-purple-light: #b58cff;
--color-lavender: #f1e7ff;
--color-white: #ffffff;
--color-cyan-accent: #43d8ff;
--glow-purple: 0 0 32px rgba(159, 95, 255, 0.45);
--border-purple: rgba(190, 143, 255, 0.38);
font-family:
'Atkinson Hyperlegible',
system-ui,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
sans-serif;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
min-width: 320px;
background: var(--color-bg-deep);
color: var(--color-white);
}
img,
video {
max-width: 100%;
}
.landing-page {
min-height: 100svh;
background:
radial-gradient(circle at top, rgba(123, 69, 202, 0.35), transparent 45%),
linear-gradient(to bottom, rgba(7, 0, 20, 0.4), rgba(54, 0, 95, 0.45)),
url('/assets/squiggleverse-bg.webp');
background-size: cover;
background-position: center top;
}
.hero {
width: min(1120px, 100%);
margin-inline: auto;
padding: clamp(2rem, 5vw, 4.5rem) 1rem clamp(3rem, 7vw, 6rem);
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
:focus-visible {
outline: 3px solid var(--color-cyan-accent);
outline-offset: 4px;
}
@media (max-width: 768px) {
.landing-page {
background-attachment: scroll;
}
}
14. Build and Tooling
Package setup
pnpm create svelte@latest squiggleverse-landing
cd squiggleverse-landing
pnpm install
pnpm dev
Recommended dependencies
pnpm add -D prettier eslint typescript svelte-check vite
Optional:
pnpm add -D @sveltejs/adapter-static
Static adapter config
// svelte.config.js
import adapter from '@sveltejs/adapter-static';
const config = {
kit: {
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: undefined,
precompress: true,
strict: true
})
}
};
export default config;
Quality checks
pnpm check
pnpm lint
pnpm build
pnpm preview
15. Performance Budget
Recommended launch budget:
HTML: < 30 KB
CSS: < 50 KB compressed
JS: < 100 KB compressed
Logo: < 200 KB
Background: < 300 KB desktop, < 150 KB mobile
Poster: < 250 KB
Video: < 8 MB
Third-party scripts: 0 initially
Fonts: < 150 KB total
Testing tools
Lighthouse
PageSpeed Insights
WebPageTest
Chrome DevTools Performance tab
SvelteKit build output
16. Browser Support
Target:
Latest Chrome
Latest Firefox
Latest Safari
Latest Edge
iOS Safari
Android Chrome
Graceful degradation:
No backdrop-filter required for usability.
No autoplay dependency.
No JavaScript dependency for reading core page content.
17. Content Requirements
Required homepage copy
Use exact copy unless changed by brand team:
Squiggleverse is a modular, multi-platform, game-based “stealth” learning system that teaches grammar, usage, and style through innovative gameplay, whimsical characters, and creative narratives co-authored by the player.
Optional additional copy
Use only if the page needs more conversion support:
Learn by playing.
Build stories with whimsical characters.
Practice grammar, usage, and style without worksheets.
Designed for modular, multi-platform deployment.
18. Launch Checklist
Visual
Logo displays crisply on desktop and mobile.
Video card scales correctly.
Background does not overpower text.
Text remains readable at all breakpoints.
CTA buttons, if used, are obvious but not visually noisy.
SEO
Unique title.
Meta description.
Canonical URL.
Open Graph tags.
Twitter card tags.
Robots.txt.
Sitemap.xml.
Visible/indexable body text.
Single H1.
No accidental noindex.
Performance
Images compressed.
Video uses poster and preload=metadata.
No unnecessary JS libraries.
No large animation library.
No layout shift.
Passes Lighthouse performance target.
Accessibility
Keyboard navigable.
Visible focus styles.
Video controls available.
Captions if voiceover exists.
Color contrast passes.
Reduced-motion support.
No text-only information inside images.
Security
HTTPS enforced.
CSP configured.
Security headers configured.
No exposed secrets.
No unnecessary third-party scripts.
Forms validated server-side if present.
19. Recommended MVP Scope
For the first version, build:
Static SvelteKit landing page
Logo hero
Self-hosted video with poster
Main descriptive paragraph
One CTA: Contact Us or Watch Demo
SEO metadata
OG image
robots.txt
sitemap.xml
Basic security headers
Optimized image/video assets
Avoid for MVP:
CMS
Animation framework
User accounts
Heavy analytics
YouTube embed
Complex routing
Newsletter provider scripts loaded on first paint
The best implementation is a prerendered SvelteKit page with the brand assets self-hosted, minimal JavaScript, real HTML text, and a tightly optimized media pipeline.