[{"data":1,"prerenderedAt":217},["ShallowReactive",2],{"project-urvis-en":3,"mdc--apkfam-key":31},{"id":4,"title":5,"content":6,"description":7,"endDate":8,"extension":9,"image":8,"meta":10,"poster":27,"startDate":26,"stem":28,"style":19,"tags":29,"url":18,"__hash__":30},"projects_en/en/projects/urvis.yml","UrVis — Multi-Backend 2D Rendering Engine","> Part of **UrStack**, my open-source organization for TypeScript libraries.\nSiblings: [UrColor](/projects/urcolor), [UrCharts](/projects/urcharts), [UrDock](/projects/urdock).\n\n## Overview\n\nUrVis is a retained-mode 2D scene graph with interchangeable rendering backends.\nYou describe a scene once, and UrVis renders it through SVG, Canvas, WebGL or\nWebGPU without a line of backend-specific code.\n\nThe scene graph tracks dirty regions, so a frame only redraws what actually\nchanged. The same graph runs on the server, where it emits SVG directly or\nrasterizes to PNG, JPEG and WebP.\n\n---\n\n## Why I built it\n\nPicking a rendering backend usually happens on day one, before you know what the\nworkload looks like, and reversing that choice later means rewriting the drawing\nlayer. SVG is convenient until the node count climbs. WebGL is fast until you\nneed crisp text or server-side output.\n\nUrVis makes the backend a runtime detail, so the scene description outlives the\ndecision.\n\n---\n\n## Key features\n\n- Four interchangeable renderers behind one scene API: SVG, Canvas, WebGL, WebGPU\n- A retained-mode scene graph whose dirty marking limits redraws to what changed\n- An animation system with keyframes, easings and spring presets, modelled on the\n  Web Animations API\n- Server-side rendering: SVG output, or rasterization to PNG, JPEG and WebP\n  through an optional Node package\n- Plain TypeScript, with no framework runtime required\n- Tree-shakeable ESM, so unused renderers never reach the bundle\n\n---\n\n## Tech stack\n\n::tech-carousel{:tech='[\"typescript\", \"webgl\", \"webgpu\", \"vitepress\"]'}\n::\n\n- **Core**: TypeScript, retained-mode scene graph, ESM\n- **Backends**: SVG, Canvas 2D, WebGL, WebGPU\n- **Server**: Node rasterization to PNG, JPEG, WebP\n- **Docs**: VitePress\n","A framework-agnostic 2D scene graph that renders the same scene through SVG, Canvas, WebGL, or WebGPU, in the browser or on the server.",null,"yml",{"path":11,"body":12},"/en/projects/urvis",{"title":5,"description":7,"poster":13,"url":18,"style":19,"tags":20,"startDate":26,"content":6},{"pattern":14,"gradient":15,"color":16,"bg":17},"triangle","burst","#22d3ee","#0b2430","https://urvis.vercel.app/","projects/urvis-styles.css",[21,22,23,24,25],"UrStack","TypeScript","WebGPU","Rendering","SSR","2026",{"pattern":14,"gradient":15,"color":16,"bg":17},"en/projects/urvis",[21,22,23,24,25],"is_2_A0EXi-T5v7NAP3s5QJHkmhK8iBDCf7nUaEoqnc",{"data":32,"body":33},{},{"type":34,"children":35},"root",[36,79,86,91,96,100,106,111,116,119,125,160,163,169,174],{"type":37,"tag":38,"props":39,"children":40},"element","blockquote",{},[41],{"type":37,"tag":42,"props":43,"children":44},"p",{},[45,48,53,55,62,64,70,71,77],{"type":46,"value":47},"text","Part of ",{"type":37,"tag":49,"props":50,"children":51},"strong",{},[52],{"type":46,"value":21},{"type":46,"value":54},", my open-source organization for TypeScript libraries.\nSiblings: ",{"type":37,"tag":56,"props":57,"children":59},"a",{"href":58},"/projects/urcolor",[60],{"type":46,"value":61},"UrColor",{"type":46,"value":63},", ",{"type":37,"tag":56,"props":65,"children":67},{"href":66},"/projects/urcharts",[68],{"type":46,"value":69},"UrCharts",{"type":46,"value":63},{"type":37,"tag":56,"props":72,"children":74},{"href":73},"/projects/urdock",[75],{"type":46,"value":76},"UrDock",{"type":46,"value":78},".",{"type":37,"tag":80,"props":81,"children":83},"h2",{"id":82},"overview",[84],{"type":46,"value":85},"Overview",{"type":37,"tag":42,"props":87,"children":88},{},[89],{"type":46,"value":90},"UrVis is a retained-mode 2D scene graph with interchangeable rendering backends.\nYou describe a scene once, and UrVis renders it through SVG, Canvas, WebGL or\nWebGPU without a line of backend-specific code.",{"type":37,"tag":42,"props":92,"children":93},{},[94],{"type":46,"value":95},"The scene graph tracks dirty regions, so a frame only redraws what actually\nchanged. The same graph runs on the server, where it emits SVG directly or\nrasterizes to PNG, JPEG and WebP.",{"type":37,"tag":97,"props":98,"children":99},"hr",{},[],{"type":37,"tag":80,"props":101,"children":103},{"id":102},"why-i-built-it",[104],{"type":46,"value":105},"Why I built it",{"type":37,"tag":42,"props":107,"children":108},{},[109],{"type":46,"value":110},"Picking a rendering backend usually happens on day one, before you know what the\nworkload looks like, and reversing that choice later means rewriting the drawing\nlayer. SVG is convenient until the node count climbs. WebGL is fast until you\nneed crisp text or server-side output.",{"type":37,"tag":42,"props":112,"children":113},{},[114],{"type":46,"value":115},"UrVis makes the backend a runtime detail, so the scene description outlives the\ndecision.",{"type":37,"tag":97,"props":117,"children":118},{},[],{"type":37,"tag":80,"props":120,"children":122},{"id":121},"key-features",[123],{"type":46,"value":124},"Key features",{"type":37,"tag":126,"props":127,"children":128},"ul",{},[129,135,140,145,150,155],{"type":37,"tag":130,"props":131,"children":132},"li",{},[133],{"type":46,"value":134},"Four interchangeable renderers behind one scene API: SVG, Canvas, WebGL, WebGPU",{"type":37,"tag":130,"props":136,"children":137},{},[138],{"type":46,"value":139},"A retained-mode scene graph whose dirty marking limits redraws to what changed",{"type":37,"tag":130,"props":141,"children":142},{},[143],{"type":46,"value":144},"An animation system with keyframes, easings and spring presets, modelled on the\nWeb Animations API",{"type":37,"tag":130,"props":146,"children":147},{},[148],{"type":46,"value":149},"Server-side rendering: SVG output, or rasterization to PNG, JPEG and WebP\nthrough an optional Node package",{"type":37,"tag":130,"props":151,"children":152},{},[153],{"type":46,"value":154},"Plain TypeScript, with no framework runtime required",{"type":37,"tag":130,"props":156,"children":157},{},[158],{"type":46,"value":159},"Tree-shakeable ESM, so unused renderers never reach the bundle",{"type":37,"tag":97,"props":161,"children":162},{},[],{"type":37,"tag":80,"props":164,"children":166},{"id":165},"tech-stack",[167],{"type":46,"value":168},"Tech stack",{"type":37,"tag":170,"props":171,"children":173},"tech-carousel",{":tech":172},"[\"typescript\", \"webgl\", \"webgpu\", \"vitepress\"]",[],{"type":37,"tag":126,"props":175,"children":176},{},[177,187,197,207],{"type":37,"tag":130,"props":178,"children":179},{},[180,185],{"type":37,"tag":49,"props":181,"children":182},{},[183],{"type":46,"value":184},"Core",{"type":46,"value":186},": TypeScript, retained-mode scene graph, ESM",{"type":37,"tag":130,"props":188,"children":189},{},[190,195],{"type":37,"tag":49,"props":191,"children":192},{},[193],{"type":46,"value":194},"Backends",{"type":46,"value":196},": SVG, Canvas 2D, WebGL, WebGPU",{"type":37,"tag":130,"props":198,"children":199},{},[200,205],{"type":37,"tag":49,"props":201,"children":202},{},[203],{"type":46,"value":204},"Server",{"type":46,"value":206},": Node rasterization to PNG, JPEG, WebP",{"type":37,"tag":130,"props":208,"children":209},{},[210,215],{"type":37,"tag":49,"props":211,"children":212},{},[213],{"type":46,"value":214},"Docs",{"type":46,"value":216},": VitePress",1785819619262]