├── .eslintignore ├── .eslintrc.cjs ├── .github └── workflows │ └── .deploy.yml ├── .gitignore ├── .husky └── pre-commit ├── .npmrc ├── .prettierignore ├── .prettierrc ├── LICENSE ├── PROOF.md ├── README.md ├── package-lock.json ├── package.json ├── postcss.config.cjs ├── src ├── app.css ├── app.d.ts ├── app.html ├── components │ ├── API.svelte │ ├── Github.svelte │ ├── Install.svelte │ ├── NPM.svelte │ ├── NotByAI.svelte │ ├── Signature.svelte │ ├── scenes │ │ ├── Animation.svelte │ │ ├── Eye.svelte │ │ ├── Guy.svelte │ │ └── castle │ │ │ ├── Castle.svelte │ │ │ └── Wall.svelte │ └── snippets │ │ ├── AnimationSnippet.svelte │ │ └── EyeSnippet.svelte ├── lib │ ├── Illustration.svelte │ ├── index.ts │ ├── primitives │ │ ├── Anchor.svelte │ │ ├── Box.svelte │ │ ├── Cone.svelte │ │ ├── Cylinder.svelte │ │ ├── Ellipse.svelte │ │ ├── Group.svelte │ │ ├── Hemisphere.svelte │ │ ├── Polygon.svelte │ │ ├── Rect.svelte │ │ ├── RoundedRect.svelte │ │ └── Shape.svelte │ └── types.ts └── routes │ ├── +error.svelte │ ├── +layout.svelte │ ├── +layout.ts │ ├── +page.svelte │ └── docs │ └── +page.svelte ├── static ├── .nojekyll ├── cover.png ├── favicon.ico ├── manifest.json └── og.png ├── svelte.config.js ├── tailwind.config.cjs ├── tsconfig.json └── vite.config.ts /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: [ 4 | 'eslint:recommended', 5 | 'plugin:@typescript-eslint/recommended', 6 | 'plugin:svelte/recommended', 7 | 'prettier', 8 | ], 9 | parser: '@typescript-eslint/parser', 10 | plugins: ['@typescript-eslint'], 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020, 14 | extraFileExtensions: ['.svelte'], 15 | }, 16 | env: { 17 | browser: true, 18 | es2017: true, 19 | node: true, 20 | }, 21 | overrides: [ 22 | { 23 | files: ['*.svelte'], 24 | parser: 'svelte-eslint-parser', 25 | parserOptions: { 26 | parser: '@typescript-eslint/parser', 27 | }, 28 | }, 29 | ], 30 | rules: { 31 | '@typescript-eslint/no-empty-interface': [ 32 | 'error', 33 | { 34 | allowSingleExtends: true, 35 | }, 36 | ], 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /.github/workflows/.deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build Website 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | permissions: 7 | contents: write 8 | 9 | jobs: 10 | build-and-deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: 🛎️ checkout 14 | uses: actions/checkout@v3 15 | 16 | - name: 💾 install 17 | run: npm i --include=dev 18 | 19 | - name: 🚧 build 20 | run: npm run build 21 | 22 | - name: 🚀 deploy 23 | uses: JamesIves/github-pages-deploy-action@v4 24 | with: 25 | folder: build 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /dist 5 | /.svelte-kit 6 | /package 7 | .env 8 | .env.* 9 | !.env.example 10 | vite.config.js.timestamp-* 11 | vite.config.ts.timestamp-* 12 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": false, 4 | "bracketSpacing": true, 5 | "endOfLine": "lf", 6 | "jsxSingleQuote": false, 7 | "printWidth": 80, 8 | "proseWrap": "preserve", 9 | "quoteProps": "as-needed", 10 | "semi": false, 11 | "singleQuote": true, 12 | "tabWidth": 2, 13 | "trailingComma": "es5", 14 | "useTabs": false, 15 | "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], 16 | "pluginSearchDirs": ["."], 17 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 Carlos Aguilar 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /PROOF.md: -------------------------------------------------------------------------------- 1 | I added this to prove I spoke to [Kev](https://twitter.com/kevmodrome) ! 🧡 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | [![svelte-zdog](static/cover.png)](https://carlos-aguilar.com/svelte-zdog) 4 | 5 | [![npm](https://img.shields.io/npm/v/svelte-zdog?logo=npm&style=flat-square)](https://npm.im/svelte-zdog) 6 | [![web build](https://img.shields.io/github/actions/workflow/status/wh0am1-dev/svelte-zdog/.deploy.yml?logo=github&label=docs&style=flat-square)](https://github.com/wh0am1-dev/svelte-zdog/actions/workflows/.deploy.yml) 7 | 8 | svelte components for [zdog](https://zzz.dog) 3D renders 9 | 10 | [read the docs](https://carlos-aguilar.com/svelte-zdog) for more info 11 | 12 | ## dev 13 | 14 | 🚧 dev server 15 | `npm run dev` 16 | 17 | 🏗 build site 18 | `npm run build` 19 | 20 | 📦 package 21 | `npm run package` 22 | 23 |
24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-zdog", 3 | "version": "0.4.0", 4 | "license": "MIT", 5 | "homepage": "https://carlos-aguilar.com/svelte-zdog", 6 | "description": "svelte components for zdog 3D renders", 7 | "author": { 8 | "name": "Carlos Aguilar", 9 | "email": "hey@carlos-aguilar.com", 10 | "url": "https://carlos-aguilar.com" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/wh0am1-dev/svelte-zdog" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/wh0am1-dev/svelte-zdog/issues" 18 | }, 19 | "keywords": [ 20 | "svelte", 21 | "components", 22 | "zdog", 23 | "3D", 24 | "canvas", 25 | "svg" 26 | ], 27 | "type": "module", 28 | "svelte": "./dist/index.js", 29 | "types": "./dist/index.d.ts", 30 | "files": [ 31 | "dist" 32 | ], 33 | "exports": { 34 | ".": { 35 | "types": "./dist/index.d.ts", 36 | "svelte": "./dist/index.js" 37 | } 38 | }, 39 | "scripts": { 40 | "dev": "vite dev --host 0.0.0.0", 41 | "build": "vite build && npm run package", 42 | "preview": "vite preview", 43 | "prepare": "husky install", 44 | "package": "svelte-kit sync && svelte-package && publint", 45 | "prepublishOnly": "npm run package", 46 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 47 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 48 | "lint": "prettier --plugin-search-dir . --check . && eslint .", 49 | "format": "prettier --plugin-search-dir . --write ." 50 | }, 51 | "lint-staged": { 52 | "*.{ts,svelte}": [ 53 | "svelte-kit sync", 54 | "svelte-check --tsconfig ./tsconfig.json", 55 | "eslint", 56 | "prettier -w -u" 57 | ], 58 | "*.!(ts|svelte)": [ 59 | "prettier -w -u" 60 | ] 61 | }, 62 | "dependencies": { 63 | "@types/zdog": "^1.1.2", 64 | "zdog": "^1.1.3" 65 | }, 66 | "peerDependencies": { 67 | "svelte": "^4.0.0" 68 | }, 69 | "devDependencies": { 70 | "@fontsource/fira-code": "^5.0.3", 71 | "@fontsource/outfit": "^5.0.3", 72 | "@sveltejs/adapter-static": "^2.0.2", 73 | "@sveltejs/kit": "^1.20.5", 74 | "@sveltejs/package": "^2.1.0", 75 | "@typescript-eslint/eslint-plugin": "^5.60.0", 76 | "@typescript-eslint/parser": "^5.60.0", 77 | "autoprefixer": "^10.4.14", 78 | "eslint": "^8.43.0", 79 | "eslint-config-prettier": "^8.8.0", 80 | "eslint-plugin-svelte": "^2.31.0", 81 | "husky": "^8.0.3", 82 | "lint-staged": "^13.2.2", 83 | "postcss": "^8.4.24", 84 | "prettier": "^2.8.8", 85 | "prettier-plugin-svelte": "^2.10.1", 86 | "prettier-plugin-tailwindcss": "^0.3.0", 87 | "publint": "^0.1.12", 88 | "svelte": "^4.0.0", 89 | "svelte-check": "^3.4.4", 90 | "tailwindcss": "^3.3.2", 91 | "tslib": "^2.5.3", 92 | "typescript": "^5.1.3", 93 | "vite": "^4.3.9" 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | body { 7 | @apply bg-stone-900 text-stone-100; 8 | } 9 | 10 | ::selection { 11 | @apply bg-amber-400 text-stone-900; 12 | } 13 | 14 | h1 { 15 | @apply my-8 text-6xl font-bold; 16 | } 17 | 18 | h2 { 19 | @apply my-4 text-4xl font-bold; 20 | } 21 | 22 | p { 23 | @apply my-2 text-center text-base; 24 | } 25 | 26 | a { 27 | @apply px-1 text-amber-400 hover:bg-amber-400 hover:text-stone-800; 28 | } 29 | 30 | a:has(> img, > svg) { 31 | @apply p-0 hover:bg-transparent; 32 | } 33 | 34 | ul { 35 | @apply list-disc marker:text-stone-100; 36 | } 37 | 38 | code { 39 | @apply font-mono; 40 | } 41 | 42 | .min-h-mobile { 43 | min-height: 90vh; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {} 13 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | svelte-zdog 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | 24 | %sveltekit.head% 25 | 26 | 27 |
%sveltekit.body%
28 | 29 | 30 | -------------------------------------------------------------------------------- /src/components/API.svelte: -------------------------------------------------------------------------------- 1 |
2 |
3 |

root

4 | 9 | 10 |

utils

11 | 28 |
29 | 30 |
31 |

nodes

32 | 67 |
68 |
69 | -------------------------------------------------------------------------------- /src/components/Github.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 16 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/components/Install.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 22 | 23 |

24 | copied to clipboard ! 25 |

26 | -------------------------------------------------------------------------------- /src/components/NPM.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | npm 12 | 13 | -------------------------------------------------------------------------------- /src/components/NotByAI.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | (hover = true)} 12 | on:mouseleave={() => (hover = false)} 13 | > 14 | {#if hover} 15 | 22 | written by human, not by AI 23 | 28 | 34 | 38 | 42 | 46 | 50 | 54 | 58 | 62 | 66 | 70 | 74 | 78 | 82 | 86 | 90 | 94 | 98 | 102 | 106 | 110 | 114 | 118 | 122 | 126 | 127 | {:else} 128 | 135 | written by human, not by AI 136 | 141 | 147 | 151 | 155 | 159 | 163 | 167 | 171 | 175 | 176 | 177 | 181 | 185 | 189 | 193 | 197 | 201 | 205 | 209 | 213 | 217 | 221 | 225 | 229 | 233 | 234 | {/if} 235 | 236 | -------------------------------------------------------------------------------- /src/components/Signature.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | by 8 | carlos-aguilar.com 9 | 10 | -------------------------------------------------------------------------------- /src/components/scenes/Animation.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | (rotate = false)} 12 | onDragEnd={() => (rotate = true)} 13 | update={node => delta => { 14 | if (rotate) { 15 | node.rotate.x += delta / 800 16 | node.rotate.y += delta / 1600 17 | node.rotate.z += delta / 2400 18 | } 19 | }} 20 | > 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/components/scenes/Eye.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/components/scenes/Guy.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | (rotate = false)} 22 | onDragEnd={() => (rotate = true)} 23 | update={scene => delta => { 24 | if (rotate) scene.rotate.y += delta / 2000 25 | }} 26 | > 27 | 28 | 34 | 35 | 42 | 43 | 53 | 54 | 55 | 56 | 57 | 64 | 65 | 75 | 76 | 77 | 78 | 79 | 86 | 87 | 88 | 89 | 98 | 107 | 108 | 119 | 120 | 121 | 122 | 123 | 130 | 131 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 152 | 153 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /src/components/scenes/castle/Castle.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | (rotate = false)} 17 | onDragEnd={() => (rotate = true)} 18 | update={scene => delta => { 19 | if (rotate) scene.rotate.y += delta / 2000 20 | }} 21 | > 22 | 23 | 31 | 39 | 47 | 48 | -------------------------------------------------------------------------------- /src/components/scenes/castle/Wall.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 36 | 46 | 56 | 66 | 76 | 77 | 78 | 79 | 80 | 89 | 99 | 109 | 119 | 129 | 130 | 131 | 132 | 142 | 152 | 153 | 154 | 172 | 191 | 192 | 193 | 212 | 232 | 233 | 234 | 243 | 252 | 253 | 254 | 264 | 274 | 275 | 276 | 299 | 323 | 324 | 325 | 335 | 336 | 337 | 338 | 339 | -------------------------------------------------------------------------------- /src/components/snippets/AnimationSnippet.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
<script>
 11 |   import { Illustration, Ellipse, TAU } from 'svelte-zdog'
 15 |   let rotate = true
 18 | </script>
 21 | 
 22 | <Illustration
 23 |   element="svg"
 24 |   width={240}
 25 |   height={240}
 26 |   dragRotate
 27 |   onDragStart={() => (rotate = false)}
 31 |   onDragEnd={() => (rotate = true)}
 35 |   update={node => (delta, ms) => {
 40 |     if (rotate) {
 41 |       node.rotate.x += delta / 800
 46 |       node.rotate.y += delta / 1600
 51 |       node.rotate.z += delta / 2400
 56 |     }
 57 |   }}
 58 | >
 59 |   <Ellipse diameter={128} stroke={4} color="#ef4444" />
 64 |   <Ellipse diameter={128} stroke={4} color="#84cc16" rotate={{ x: TAU / 4 }} />
 71 |   <Ellipse diameter={128} stroke={4} color="#0ea5e9" rotate={{ y: TAU / 4 }} />
 78 | </Illustration>
 79 | 
80 | 81 | 106 | -------------------------------------------------------------------------------- /src/components/snippets/EyeSnippet.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
<script>
11 |   import { Illustration, Group, Ellipse } from 'svelte-zdog'
15 | </script>
18 | 
19 | <Illustration element="svg" width={240} height={240} dragRotate>
26 |   <Group translate={{ z: 20 }}>
30 |     <Ellipse width={180} height={100} color="#f5f5f4" stroke={10} fill />
38 |     <Ellipse diameter={80} color="#fbbf24" stroke={10} fill />
43 |     <Ellipse diameter={40} color="#1c1917" stroke={10} fill />
48 |     <Ellipse
49 |       translate={{ x: 20, y: -20 }}
53 |       diameter={30}
55 |       color="#f5f5f4"
56 |       stroke={10}
58 |       fill
59 |     />
60 |   </Group>
61 | </Illustration>
62 | 
63 | 64 | 89 | -------------------------------------------------------------------------------- /src/lib/Illustration.svelte: -------------------------------------------------------------------------------- 1 | 92 | 93 | {#if element === 'canvas'} 94 | 95 | {:else if element === 'svg'} 96 | 97 | {/if} 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext, onMount, onDestroy } from 'svelte' 2 | import Zdog from 'zdog' 3 | import type { 4 | ZdogContext, 5 | Subscription, 6 | Primitive, 7 | PrimitiveOptions, 8 | PrimitiveConstructor, 9 | PrimitiveProps, 10 | } from './types' 11 | 12 | // Root context 13 | // ================================ 14 | 15 | const zdogCtx = Symbol() 16 | /** Returns the main scene anchor */ 17 | export const getScene = () => getContext(zdogCtx).scene 18 | /** Zdog context setter */ 19 | export const setZdog = (ctx: ZdogContext) => 20 | setContext(zdogCtx, ctx) 21 | /** Subscribe update function */ 22 | export const subscribe = (fn: Subscription) => 23 | onDestroy(getContext(zdogCtx).subscribe(fn)) 24 | 25 | // Parent context 26 | // ================================ 27 | 28 | const parentCtx = Symbol() 29 | /** Get parent node */ 30 | export const getParent = () => getContext(parentCtx) 31 | /** Set parent node */ 32 | export const setParent = (parent: Primitive) => 33 | setContext(parentCtx, parent) 34 | 35 | // Mount node function 36 | // ================================ 37 | 38 | /** Mount Zdog primitive into the tree */ 39 | export const mount =

( 40 | /** Zdog primitive */ 41 | primitive: PrimitiveConstructor

, 42 | /** Primitive options */ 43 | options: PrimitiveProps

44 | ) => { 45 | const scene = getScene() 46 | const parent = getParent() 47 | const { update, ...rest } = options 48 | const node = new primitive(rest as PrimitiveOptions

) 49 | 50 | setParent(node) 51 | if (update) subscribe(update(node)) 52 | 53 | onMount(() => { 54 | parent.addChild(node) 55 | scene.updateGraph() 56 | 57 | return () => { 58 | parent.removeChild(node) 59 | parent.updateGraph() 60 | scene.updateGraph() 61 | } 62 | }) 63 | 64 | return node 65 | } 66 | 67 | // Re-exports 68 | // ================================ 69 | 70 | export { default as Illustration } from '$lib/Illustration.svelte' 71 | 72 | export { default as Anchor } from '$lib/primitives/Anchor.svelte' 73 | export { default as Box } from '$lib/primitives/Box.svelte' 74 | export { default as Cone } from '$lib/primitives/Cone.svelte' 75 | export { default as Cylinder } from '$lib/primitives/Cylinder.svelte' 76 | export { default as Ellipse } from '$lib/primitives/Ellipse.svelte' 77 | export { default as Group } from '$lib/primitives/Group.svelte' 78 | export { default as Hemisphere } from '$lib/primitives/Hemisphere.svelte' 79 | export { default as Polygon } from '$lib/primitives/Polygon.svelte' 80 | export { default as Rect } from '$lib/primitives/Rect.svelte' 81 | export { default as RoundedRect } from '$lib/primitives/RoundedRect.svelte' 82 | export { default as Shape } from '$lib/primitives/Shape.svelte' 83 | 84 | export const { TAU, Vector, easeInOut, lerp, modulo } = Zdog 85 | -------------------------------------------------------------------------------- /src/lib/primitives/Anchor.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/primitives/Box.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/primitives/Cone.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/primitives/Cylinder.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/primitives/Ellipse.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/primitives/Group.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/primitives/Hemisphere.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/primitives/Polygon.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/primitives/Rect.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/primitives/RoundedRect.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/primitives/Shape.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import type Zdog from 'zdog' 2 | 3 | /** Zdog primitive */ 4 | export type Primitive = 5 | | Zdog.Anchor 6 | | Zdog.Box 7 | | Zdog.Cone 8 | | Zdog.Cylinder 9 | | Zdog.Ellipse 10 | | Zdog.Group 11 | | Zdog.Hemisphere 12 | | Zdog.Polygon 13 | | Zdog.Rect 14 | | Zdog.RoundedRect 15 | | Zdog.Shape 16 | 17 | /** Zdog primitive options */ 18 | export type PrimitiveOptions

= P extends Zdog.Box 19 | ? Zdog.BoxOptions 20 | : P extends Zdog.Cone 21 | ? Zdog.ConeOptions 22 | : P extends Zdog.Hemisphere 23 | ? Zdog.HemisphereOptions 24 | : P extends Zdog.Cylinder 25 | ? Zdog.CylinderOptions 26 | : P extends Zdog.Ellipse 27 | ? Zdog.EllipseOptions 28 | : P extends Zdog.RoundedRect 29 | ? Zdog.RoundedRectOptions 30 | : P extends Zdog.Rect 31 | ? Zdog.RectOptions 32 | : P extends Zdog.Polygon 33 | ? Zdog.PolygonOptions 34 | : P extends Zdog.Shape 35 | ? Zdog.ShapeOptions 36 | : P extends Zdog.Group 37 | ? Zdog.GroupOptions 38 | : P extends Zdog.Anchor 39 | ? Zdog.AnchorOptions 40 | : never 41 | 42 | /** Zdog primitive constructor */ 43 | export type PrimitiveConstructor

= { 44 | new (options: PrimitiveOptions

): P 45 | } 46 | 47 | /** Zdog primitive props */ 48 | export type PrimitiveProps

= PrimitiveOptions

& { 49 | update?: Subscriber

50 | } 51 | 52 | /** Update subscription registrant */ 53 | export type Subscriber

= (node: P) => Subscription 54 | /** Lifecycle subscription */ 55 | export type Subscription = (delta: number, ms: number) => void 56 | /** Subscription destructor */ 57 | export type Destructor = () => void 58 | 59 | /** Zdog context */ 60 | export interface ZdogContext { 61 | /** Root anchor of the scene */ 62 | scene: Zdog.Anchor 63 | /** List of update subscriptions */ 64 | subscribers: Array 65 | /** Subscribe new update function */ 66 | subscribe: (sub?: Subscription) => Destructor 67 | } 68 | 69 | /** Zdog element type */ 70 | export type ZdogElement = 'svg' | 'canvas' 71 | 72 | /** Illustration resize callback */ 73 | export type OnResize = ( 74 | scene: Zdog.Illustration, 75 | width: number, 76 | height: number 77 | ) => void 78 | 79 | /** Illustration prerender callback */ 80 | export type OnPrerender = ( 81 | scene: Zdog.Illustration, 82 | context: CanvasRenderingContext2D | SVGSVGElement 83 | ) => void 84 | 85 | /** Illustration drag start callback */ 86 | export type OnDragStart = ( 87 | scene: Zdog.Dragger, 88 | pointer: Zdog.PointerPosition 89 | ) => void 90 | 91 | /** Illustration drag move callback */ 92 | export type OnDragMove = ( 93 | scene: Zdog.Dragger, 94 | pointer: Zdog.PointerPosition, 95 | moveX: number, 96 | moveY: number 97 | ) => void 98 | 99 | /** Illustration drag end callback */ 100 | export type OnDragEnd = (illu: Zdog.Dragger) => void 101 | 102 | /** Zdog illustration props */ 103 | export interface IllustrationProps 104 | extends Omit< 105 | Zdog.IllustrationOptions, 106 | | 'element' 107 | | 'onResize' 108 | | 'onPrerender' 109 | | 'onDragStart' 110 | | 'onDragMove' 111 | | 'onDragEnd' 112 | > { 113 | /** Illustration width */ 114 | width: number 115 | /** Illustration height */ 116 | height: number 117 | /** css classes */ 118 | className?: string 119 | /** Render to SVG or canvas */ 120 | element?: ZdogElement 121 | /** Update loop subscription */ 122 | update?: Subscriber 123 | /** Illustration resize callback */ 124 | onResize?: OnResize 125 | /** Illustration prerender callback */ 126 | onPrerender?: OnPrerender 127 | /** Illustration drag start callback */ 128 | onDragStart?: OnDragStart 129 | /** Illustration drag move callback */ 130 | onDragMove?: OnDragMove 131 | /** Illustration drag end callback */ 132 | onDragEnd?: OnDragEnd 133 | } 134 | -------------------------------------------------------------------------------- /src/routes/+error.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |

{$page.status}: {$page.error?.message}

6 | -------------------------------------------------------------------------------- /src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/routes/+layout.ts: -------------------------------------------------------------------------------- 1 | export const prerender = true 2 | export const trailingSlash = 'always' 3 | -------------------------------------------------------------------------------- /src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
16 | 17 | 18 | 24 | 25 |

26 | made with 27 | svelte-zdog 28 |

29 | 30 | 34 | docs 35 | 36 |
37 | -------------------------------------------------------------------------------- /src/routes/docs/+page.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | svelte-zdog · docs 17 | 18 | 19 |
22 | 23 |

svelte-zdog

24 |

svelte components for zdog 3D renders

25 | 26 |

🧰 install

27 | 28 | 29 |

📐 create

30 | 31 | 32 |

33 | build using declarative tree-like structs,
34 | components expose all primitive options as props
35 |

36 | 37 |

🎬 animate

38 | 39 | 40 |

41 | props are not reactive,
42 | components accept an update function 43 |

44 |

45 | node → primitive reference
46 | delta → ms since last frame
47 | ms → total ms elapsed 48 |

49 | 50 |

📦 pkg exports

51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 |
59 | -------------------------------------------------------------------------------- /static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wh0am1-dev/svelte-zdog/e6eede84bed23690babdd45d673c4f0d87a5d150/static/.nojekyll -------------------------------------------------------------------------------- /static/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wh0am1-dev/svelte-zdog/e6eede84bed23690babdd45d673c4f0d87a5d150/static/cover.png -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wh0am1-dev/svelte-zdog/e6eede84bed23690babdd45d673c4f0d87a5d150/static/favicon.ico -------------------------------------------------------------------------------- /static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "/svelte-zdog", 3 | "short_name": "svelte-zdog", 4 | "name": "svelte-zdog", 5 | "description": "svelte components for zdog 3D renders", 6 | "start_url": ".", 7 | "scope": ".", 8 | "display": "standalone", 9 | "theme_color": "#fbbf24", 10 | "background_color": "#1c1917", 11 | "icons": [ 12 | { 13 | "src": "favicon.ico", 14 | "sizes": "256x256", 15 | "type": "image/x-icon" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /static/og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wh0am1-dev/svelte-zdog/e6eede84bed23690babdd45d673c4f0d87a5d150/static/og.png -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-static' 2 | import { vitePreprocess } from '@sveltejs/kit/vite' 3 | 4 | const dev = process.argv.includes('dev') 5 | 6 | /** @type {import('@sveltejs/kit').Config} */ 7 | const config = { 8 | preprocess: vitePreprocess(), 9 | kit: { 10 | adapter: adapter(), 11 | paths: { 12 | base: dev ? '' : '/svelte-zdog', 13 | relative: false, 14 | }, 15 | }, 16 | } 17 | 18 | export default config 19 | -------------------------------------------------------------------------------- /tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | const theme = require('tailwindcss/defaultTheme') 2 | 3 | /** @type {import('tailwindcss').Config} */ 4 | module.exports = { 5 | content: ['./src/**/*.{html,js,ts,svelte}'], 6 | theme: { 7 | extend: { 8 | fontFamily: { 9 | sans: ['Outfit', ...theme.fontFamily.sans], 10 | mono: ['Fira Code', ...theme.fontFamily.mono], 11 | }, 12 | }, 13 | }, 14 | plugins: [], 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()] 6 | }); 7 | --------------------------------------------------------------------------------