A creative web experience engine. Veyra is the runtime foundation behind ambitious, art-directed websites — immersive campaigns, interactive brand worlds, scroll-driven storytelling — built by Veyra Studio.
It is not a site builder or a component kit. It owns the hard, reusable parts of creative development — time, scroll, motion, layout measurement, typography, rendering quality — and leaves art direction entirely to the project.
import { createStage, horizontal, scenePresets, splitText } from '@veyra/core'
const stage = createStage() // one loop, smooth native scroll
stage.use(horizontal('.gallery', { snap: true })) // plugins: horizontal, draggable, marquee, cursor…
const title = splitText('h1', { type: 'chars' }) // Persian-safe letter splitting
stage.timeline()
.fromTo(title.chars, { y: '0.6em', opacity: 0 }, { y: '0em', opacity: 1 }, { stagger: 0.03 })
.play()
stage.scene('#story', { // scroll → progress
...scenePresets.pinned, // pinned with CSS sticky
onProgress: (p) => (mesh.rotation.y = p * Math.PI * 2), // e.g. a three.js mesh
})Live showcase: Abali — a Persian, RTL campaign concept built on this engine.
| Module | What it does |
|---|---|
| Ticker | One requestAnimationFrame loop with ordered phases (input → scroll → measure → update → render → post). Pauses when hidden, clamps stalls, survives a throwing callback. |
| Motion | Seekable timelines (to / from / fromTo / call / labels / stagger), tweens for numbers, colors, CSS strings and transforms; analytic springs; easing library incl. cubicBezier. |
| Scroll | Smooth wheel scrolling on top of native scroll — sticky, scrollbar, keyboard, find-in-page, anchors and assistive tech keep working. Native on touch and under reduced motion. Anchor links scroll smoothly and move focus. |
| Scenes | Map scroll position to progress with anchors like "top bottom", enter/leave callbacks, CSS-variable output, timeline scrubbing, smoothing and visibility culling. Pinning uses CSS position: sticky. |
| Layout cache | Element rects measured once, viewport positions derived from scroll — no per-frame layout reads (with an opt-in live mode for sticky contexts). |
| Horizontal sections | Vertical scroll becomes horizontal travel in a pinned section — direction-aware (right-to-left rows travel rightward), snapping to panels, per-panel progress, focus-safe. |
| Interaction | draggable with inertia, rubber-band bounds, snapping that keeps the throw and keyboard stepping; holdable — press and hold with a mouse, a finger or a key; magnetic, tilt and a custom cursor on springs. |
| Physics | Light rigid bodies: boxes and spheres (compound too), planes, sub-stepped impulses with friction and bounce, contact events for sound; page elements as walls that follow the scroll (domColliders). |
| Layout motion | flip layout transitions (interruptible, enter fades), stagger patterns (center, edges, random, grids mirrored for RTL), inertia (Decay). |
| Marquee | Endless bands that run in the reading direction, react to scroll velocity, idle offscreen and stay still under reduced motion. |
| Type | Script-aware splitText: Arabic-script letters (Persian, Arabic, Urdu…) keep their joined forms when split, lam-alef stays whole, mixed-direction runs keep their order, screen readers get the text once. Kashida stretches Persian words on calligraphically ranked connections; scrambleText decodes with each script's own letters. |
| Procedural | Seeded gradient noise (noise2/3, fbm) for organic motion; @veyra/core/glsl — hash, noise, SDF, OKLab color and math chunks for your shaders, and noise read from a baked, tiling noise texture (noiseTexture) for full-screen surfaces. Terrain: eroded and ridged noise height fields with baked sun shadows and ambient occlusion — DOM-free, worker-friendly. |
| Image sequences | Scroll-scrubbed frame sequences on a canvas, loaded coarse-to-fine so they respond before every frame has arrived; resolution follows the quality governor. |
| Quality | Adaptive governor: detects refresh rate, judges real frame times (a few hitches don't count), steps quality and pixel ratio down under sustained load and back up with headroom; hold() while a page builds or compiles; tiers that don't flicker. |
| Assets | Weighted preloader for images, fonts, fetches and any promise; failures never block the experience. |
| Sound | Optional audio bus: off by default (or on, defaultOn), persisted per visitor, unlocked on the first click, tap or key and again after the system suspends it, audible on a silent iPhone when the visitor asked for it, muted when the tab is hidden; noise buffers, synthesized tone and burst one-shots; recordings played whole or as faded grains, and voices whose pitch and volume you steer while they play. |
| Debug | ?debug overlay: frame-time graph, FPS, quality, scroll, and a scroll map of every scene's range. |
| three.js (optional) | @veyra/core/three: renderer on the stage loop, pixel-perfect camera (1 unit = 1 CSS px), a canvas that holds still while a phone's address bar moves (stableHeight), lost-context recovery (onRestore), DOM-anchored objects, DOM text mirrored into textures with the browser's own line breaks. Product rendering: turned shapes from measured silhouettes (Profile) with label bands that keep artwork true on cones, studio light baked from code, condensation maps, glossy reflective floors, contact shadows, ray-traced clear solids (ice, glass blocks, crystal: refractiveSolid), terrain meshes. |
| Utilities | whenVisible, stage.media(), stage.onRefresh(), drawElementText (real HTML text into a canvas), supportsWebGL2, toPersianDigits, inlineSign and the math helpers (range, damp, mapRange, …). |
Zero runtime dependencies. Projects ship only what they import: a page with the stage, scenes and text splitting carries ~17 KB min+gzip of engine, adding horizontal sections, dragging and a marquee ~19 KB; everything together is ~31 KB. Stage-dependent capabilities are plugins (stage.use(horizontal(…))), so unused ones cost nothing. three.js is an optional peer dependency used only through @veyra/core/three; shader chunks live in @veyra/core/glsl.
Veyra is installed from GitHub. CI publishes every green build of main to the release branch (see docs/integration.md):
npm install @veyra/core@github:veyra-studio/veyra-core#release
npm install three # only for @veyra/core/threePin a version with a tag: github:veyra-studio/veyra-core#v0.8.0.
npm install
npm run examples # dev server with live examples (http://localhost:5173)
npm test # unit tests (Vitest + jsdom)
npm run typecheck
npm run build # ESM + .d.ts into dist/
npm run examples:build && npm run verify:examples # drive every example in headless Chromium
npm run release:pack # check everything, then pack release/veyra-core-<version>.tgzExamples (in examples/, imported from source):
- Scroll scenes — pinned track, scrubbed timeline, CSS-only progress.
- Persian typography — naive vs. script-aware splitting, kashida, scramble.
- three.js + DOM — grid-anchored shader planes bent by scroll velocity, a mirrored HTML headline, an object anchored to a sticky box.
- Interaction — draggable carousels in English and Persian, FLIP, magnetic buttons, tilt cards, a custom cursor, marquees.
- Horizontal sections — one left-to-right, one right-to-left, both snapping.
- Noise, shaders, sequences — a noise flow field, the GLSL chunks in one shader, a scroll-scrubbed image sequence.
- Product & terrain — a bottle turned from a measured silhouette with a label band, condensation, studio light, a glossy floor and a contact shadow; a baked mountain range.
- Guide — every module with usage
- Architecture & decisions — principles, frame pipeline, what Veyra owns vs. builds on
- Integration — consuming the engine from projects, local co-development, releasing
- Plan & progress — roadmap and status across the Veyra repositories
Evergreen browsers (Chrome/Edge 111+, Safari 16.4+, Firefox 115+). Uses Intl.Segmenter when available for grapheme clustering (with a fallback).
MIT © Veyra Studio