{"id":20951179,"url":"https://github.com/lingdong-/psvg","last_synced_at":"2025-04-06T02:07:17.158Z","repository":{"id":43773635,"uuid":"313171780","full_name":"LingDong-/psvg","owner":"LingDong-","description":"Programmable Scalable Vector Graphics -- drawings that draw themselves","archived":false,"fork":false,"pushed_at":"2023-01-23T16:17:47.000Z","size":768,"stargazers_count":307,"open_issues_count":3,"forks_count":14,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-30T01:09:05.197Z","etag":null,"topics":["image-format","programming-language","svg","vector-graphics"],"latest_commit_sha":null,"homepage":"https://psvg.netlify.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LingDong-.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-16T02:33:35.000Z","updated_at":"2025-03-14T06:51:19.000Z","dependencies_parsed_at":"2023-02-13T00:45:40.701Z","dependency_job_id":null,"html_url":"https://github.com/LingDong-/psvg","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LingDong-%2Fpsvg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LingDong-%2Fpsvg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LingDong-%2Fpsvg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LingDong-%2Fpsvg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LingDong-","download_url":"https://codeload.github.com/LingDong-/psvg/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247423512,"owners_count":20936626,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["image-format","programming-language","svg","vector-graphics"],"created_at":"2024-11-19T00:57:22.265Z","updated_at":"2025-04-06T02:07:17.138Z","avatar_url":"https://github.com/LingDong-.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![](examples/textanim.svg)](examples/textanim.psvg)\n\n# PSVG - Programmable SVG\n\n**[Doc](QUICKSTART.md) | [Playground](https://psvg.netlify.app/) | [Examples](examples/) | [NPM](https://www.npmjs.com/package/@lingdong/psvg)**\n\nPSVG is an extension of the SVG (Scalable Vector Graphics) format that introduces programming language features like functions, control flows, and variables -- Instead of writing a program that draws a picture, write a picture that draws itself!\n\nPSVG is compliant with XML and HTML specs, so it can be easily embedded in a webpage or edited with an XML editor.\n\nThis repo contains a [PSVG→SVG complier](psvg.ts) that transforms PSVG files to just regular SVG's. It can also automatically render all PSVG's on an HTML page when included as a `\u003cscript\u003e`.\n\n\u003e Note: Experimental and under development, currently the compiler is not very friendly and might misbehave at times; Contributions/Issues welcome.\n\nFor example, define a recursive function that draws the Sierpiński's triangle:\n\n```xml\n\u003cpsvg width=\"300\" height=\"260\"\u003e\n\n  \u003cdef-sierptri x1=\"{WIDTH/2}\" y1=\"0\" x2=\"{WIDTH}\" y2=\"{HEIGHT}\" x3=\"0\" y3=\"{HEIGHT}\" d=\"7\"\u003e\n    \u003cpath d=\"M{x1} {y1} L{x2} {y2} L{x3} {y3} z\"/\u003e\n    \u003cif false=\"{d}\"\u003e\n      \u003creturn/\u003e\n    \u003c/if\u003e\n    \u003csierptri x1=\"{x1}\" y1=\"{y1}\" x2=\"{(x1+x2)/2}\" y2=\"{(y1+y2)/2}\" x3=\"{(x3+x1)/2}\" y3=\"{(y3+y1)/2}\" d=\"{d-1}\"/\u003e\n    \u003csierptri x1=\"{x2}\" y1=\"{y2}\" x2=\"{(x2+x3)/2}\" y2=\"{(y2+y3)/2}\" x3=\"{(x1+x2)/2}\" y3=\"{(y1+y2)/2}\" d=\"{d-1}\"/\u003e\n    \u003csierptri x1=\"{x3}\" y1=\"{y3}\" x2=\"{(x3+x1)/2}\" y2=\"{(y3+y1)/2}\" x3=\"{(x2+x3)/2}\" y3=\"{(y2+y3)/2}\" d=\"{d-1}\"/\u003e\n  \u003c/def-sierptri\u003e\n\n  \u003cfill opacity=\"0.1\"/\u003e\n  \u003csierptri/\u003e\n\n\u003c/psvg\u003e\n```\n\nWhich looks like this (after running it through the PSVG to SVG complier):\n\n![](examples/sierpinski.svg)\n\nSince PSVG is a superset of SVG, all the elements in SVG are also in PSVG, and all of them are programmable. For example, you can use a `for` loop to generate a bunch of gradients whose `stop`s are determined by a function of the index.\n\n```xml\n\u003cvar n=\"12\"/\u003e\n\n\u003cdefs\u003e\n  \u003cfor i=\"0\" true=\"{i\u003cn}\" step=\"1\"\u003e\n    \u003cvar t=\"{i/(n-1)}\"/\u003e\n    \u003clinearGradient id=\"grad{i}\"\u003e\n      \u003cstop offset=\"0%\"   stop-color=\"black\"/\u003e\n      \u003cstop offset=\"100%\" stop-color=\"rgb(200,{FLOOR(LERP(0,255,t))},0)\"/\u003e\n    \u003c/linearGradient\u003e\n  \u003c/for\u003e\n\u003c/defs\u003e\n```\n\nWhich will generate gradients with `id`s `grad0`, `grad1`, `grad2`, ... To use, simply write:\n\n```xml\n\u003crect fill=\"url(#grad7)\"/\u003e\n```\n\nThe above is a simplified excerpt from [`examples/pythagoras.psvg`](examples/pythagoras.psvg), which utilizes this \"gradient of gradient\" to colorize a tree:\n\n![](examples/pythagoras.svg)\n\n\n\nTo transform shapes in vanilla SVG, the \"group\" metaphor (`\u003cg transform=\"...\"\u003e`) is often used. In addition to groups, PSVG also introduces Processing/p5.js-like `pushMatrix()` `popMatrix()` metaphors. For example, from the same `examples/pythagoras.psvg` as above, the `\u003cpush\u003e\u003c/push\u003e` tag combined with `\u003ctranslate/\u003e` `\u003croatate/\u003e` are used to draw a fractal tree:\n\n```xml\n\u003cdef-pythtree w=\"\" d=\"{depth}\"\u003e\n  \u003cpush\u003e\n    \u003cfill color=\"url(#grad{depth-d})\"/\u003e\n    \u003cpath d=\"M0 {w/2} L{w/2} 0 L{w/2} {-w} L{-w/2} {-w} L{-w/2} 0 z\"/\u003e\n  \u003c/push\u003e\n\n  \u003cif true=\"{d==0}\"\u003e\n    \u003creturn/\u003e\n  \u003c/if\u003e\n  \u003cpush\u003e\n    \u003ctranslate x=\"{-w/4}\" y=\"{-w-w/4}\"/\u003e\n    \u003crotate deg=\"-45\"/\u003e\n    \u003cpythtree w=\"{w/SQRT(2)}\" d=\"{d-1}\"/\u003e\n  \u003c/push\u003e\n  \u003cpush\u003e\n    \u003ctranslate x=\"{w/4}\" y=\"{-w-w/4}\"/\u003e\n    \u003crotate deg=\"45\"/\u003e\n    \u003cpythtree w=\"{w/SQRT(2)}\" d=\"{d-1}\"/\u003e\n  \u003c/push\u003e\n\u003c/def-pythtree\u003e\n```\n\nYou can have your own pick of degree or radians: `\u003crotate deg=\"45\"\u003e` or `\u003crotate rad=\"{PI/4}\"/\u003e` are the same. You can also use `\u003cscale x=\"2\" y=\"2\"/\u003e` to scale subsequent drawings.\n\nSimilarly, styling can also be written as commands to effect subsequent draw calls:\n\n```xml\n\u003cstroke color=\"red\" cap=\"round\"/\u003e\n\u003cfill color=\"green\"/\u003e\n\n\u003cpath d=\"...\"\u003e\n\u003cpolyline points=\"...\"\u003e\n```\n\nIn addition to simple fractals shown above, PSVG is also capable of implementing complex algorithms, as it's a full programming language. For example, an implementation of Poisson disk sampling described in [this paper](https://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf), [`examples/poisson.psvg`](examples/poisson.psvg):\n\n![](examples/poisson.svg)\n\n\n## The PSVG to SVG Compiler\n\nA baseline PSVG to SVG complier is included in this repo. It is a very \"quick-and-dirty\" implementation that `eval()`s transpiled JavaScript. So for now, don't compile files you don't trust!\n\n### As command-line tool\n\nInstall it globally via [`npm`](https://www.npmjs.com/)\n\n\u003cpre\u003e\nnpm i -g \u003ca href=\"http://npmjs.com/package/@lingdong/psvg\"\u003e@lingdong/psvg\u003c/a\u003e\n\u003c/pre\u003e\n\nand use it with:\n\n```\npsvg input.svg \u003e output.svg\n```\n\nFor example, to compile the hilbert curve example in this repo:\n\n```\npsvg examples/hilbert.psvg \u003e examples/hibert.svg\n```\n\nor try it without installing via [`npx`](https://www.npmjs.com/package/npx) (comes together with npm)\n\n```\nnpx -s @lingdong/psvg input.svg \u003e output.svg\n```\n\n### For the browser\n\nPSVG is also available for browser via CDN, or [directly download](http://unpkg.com/@lingdong/psvg)\n\n```html\n\u003cscript src=\"http://unpkg.com/@lingdong/psvg\"\u003e\u003c/script\u003e\n```\n\nBy including the script, all the `\u003cpsvg\u003e` elements on the webpage will be compiled to `\u003csvg\u003e` when the page loads. Again, don't include PSVG files that you don't trust.\n\n### As a library\n\nInstall locally in your project via npm\n\n```\nnpm i @lingdong/psvg\n```\n\n```js\nimport { compilePSVG } from \"@lingdong/psvg\"\n\nconsole.log(compilePSVG(\"\u003cpsvg\u003e...\u003c/psvg\u003e\"))\n```\n\nor\n\n```js\nconst { compilePSVG } = require(\"@lingdong/psvg\")\n\nconsole.log(compilePSVG(\"\u003cpsvg\u003e...\u003c/psvg\u003e\"))\n```\n\nAdditionally, `parsePSVG()` `transpilePSVG()` and `evalPSVG()` which are individual steps of compilation are also exported.\n\nIn browsers, functions are exported under the global variable `PSVG`.\n\n**Check out [QUICKSTART.md](QUICKSTART.md) for a quick introduction to the PSVG language.**\n\n## Editor Support\n\nSyntax highlighting and auto-completion can be configured for editors by:\n\n### VS Code\n\nAdd the following lines to your `settting.json`. [details](https://code.visualstudio.com/docs/languages/overview#_can-i-map-additional-file-extensions-to-a-language)\n\n```json\n  \"files.associations\": {\n    \"*.psvg\": \"xml\"\n  }\n```\n\n### GitHub\n\nTo get highlighting for PSVG files in your repositories on GitHub, create `.gitattributes` file at the root of your repo with the following content. [details](https://github.com/github/linguist#using-gitattributes)\n\n```ini\n*.psvg linguist-language=SVG\n```\n\n### Other editors\n\nSince PSVG is compliant with XML and HTML specs, you can always alias your language id to XML or SVG via the corresponding config on your editor.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flingdong-%2Fpsvg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flingdong-%2Fpsvg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flingdong-%2Fpsvg/lists"}