2026-07-09 11:48:25 -07:00
2026-07-09 08:54:56 -07:00
2026-07-09 08:54:56 -07:00

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:

  1. Logo / hero branding
  2. Embedded or self-hosted promo video
  3. Short explanatory text
  4. 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.


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: 9601100px
Logo width: 520720px
Video width: 800960px
Text width: 680820px

Tablet

Content width: 90vw
Logo width: 7080vw
Video width: 90vw
Text width: 8090vw

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: 38 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 140160 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: 9001200 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
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.

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.

S
Description
No description provided
Readme
16 MiB
Languages
CSS 64.3%
Svelte 29.1%
JavaScript 1.9%
HTML 1.9%
TypeScript 1.6%
Other 1.2%