├── src
├── utils
│ ├── expresssion.ts
│ ├── dark.ts
│ ├── stringify.ts
│ ├── load.ts
│ ├── canvas.ts
│ ├── index.ts
│ ├── vector.ts
│ ├── shake.ts
│ └── colors.ts
├── App.vue
├── window.d.ts
├── pages
│ ├── 014.vue
│ ├── _template.vue
│ ├── 014.psvg
│ ├── [...miss].vue
│ ├── _template_p5.vue
│ ├── 009.vue
│ ├── plum.psvg
│ ├── 000.vue
│ ├── index.vue
│ ├── 038.vue
│ ├── 001.vue
│ ├── 007.vue
│ ├── 016.vue
│ ├── 027.vue
│ ├── 036.vue
│ ├── 037.vue
│ ├── 033.vue
│ ├── 026.vue
│ ├── 030.vue
│ ├── 031.vue
│ ├── 034.vue
│ ├── 039.vue
│ ├── 025.vue
│ ├── 017.vue
│ ├── 010.vue
│ ├── 013.vue
│ ├── 029.vue
│ ├── 024.vue
│ ├── x-shadow.vue
│ ├── 015.vue
│ ├── 028.vue
│ ├── 012.vue
│ ├── 002.vue
│ ├── 021.vue
│ ├── 035.vue
│ ├── 011.vue
│ ├── x-lifetime-playground.vue
│ ├── 008.vue
│ ├── 023.vue
│ ├── 022.vue
│ ├── 019.vue
│ ├── 003.vue
│ ├── 018.vue
│ ├── 020.vue
│ ├── 006.vue
│ ├── 032.vue
│ ├── 004.vue
│ └── 005.vue
├── main.ts
├── components
│ ├── Toggle.vue
│ ├── Turns.vue
│ ├── Note.vue
│ ├── Paper.vue
│ └── PlaygroundX.vue
├── main.postcss
└── works.ts
├── .github
└── FUNDING.yml
├── .tazerc.json
├── public
├── shots
│ ├── 001.png
│ ├── 002.png
│ ├── 003.png
│ ├── 004.png
│ ├── 005.png
│ ├── 006.png
│ ├── 007.png
│ ├── 008.png
│ ├── 009.png
│ ├── 010.png
│ ├── 011.png
│ ├── 012.png
│ ├── 013.png
│ ├── 014.png
│ ├── 015.png
│ ├── 016.png
│ ├── 017.png
│ ├── 018.png
│ ├── 019.png
│ ├── 020.png
│ ├── 021.png
│ ├── 022.png
│ ├── 023.png
│ ├── 024.png
│ ├── 025.png
│ ├── 026.png
│ ├── 027.png
│ ├── 028.png
│ ├── 029.png
│ ├── 030.png
│ ├── 031.png
│ ├── 032.png
│ ├── 033.png
│ ├── 034.png
│ ├── 035.png
│ ├── 036.png
│ ├── 037.png
│ └── index.png
├── 020-goldfish.png
├── 019-tree.svg
├── favicon.svg
└── 037.svg
├── .gitignore
├── netlify.toml
├── .vscode
├── extensions.json
└── settings.json
├── eslint.config.js
├── tsconfig.json
├── uno.config.ts
├── index.html
├── components.d.ts
├── vite.config.ts
├── LICENSE
├── README.md
├── scripts
├── postbuild.ts
└── screenshot.ts
└── package.json
/src/utils/expresssion.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: antfu
2 |
--------------------------------------------------------------------------------
/.tazerc.json:
--------------------------------------------------------------------------------
1 | {
2 | "exclude": [
3 | "three"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/public/shots/001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/001.png
--------------------------------------------------------------------------------
/public/shots/002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/002.png
--------------------------------------------------------------------------------
/public/shots/003.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/003.png
--------------------------------------------------------------------------------
/public/shots/004.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/004.png
--------------------------------------------------------------------------------
/public/shots/005.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/005.png
--------------------------------------------------------------------------------
/public/shots/006.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/006.png
--------------------------------------------------------------------------------
/public/shots/007.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/007.png
--------------------------------------------------------------------------------
/public/shots/008.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/008.png
--------------------------------------------------------------------------------
/public/shots/009.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/009.png
--------------------------------------------------------------------------------
/public/shots/010.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/010.png
--------------------------------------------------------------------------------
/public/shots/011.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/011.png
--------------------------------------------------------------------------------
/public/shots/012.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/012.png
--------------------------------------------------------------------------------
/public/shots/013.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/013.png
--------------------------------------------------------------------------------
/public/shots/014.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/014.png
--------------------------------------------------------------------------------
/public/shots/015.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/015.png
--------------------------------------------------------------------------------
/public/shots/016.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/016.png
--------------------------------------------------------------------------------
/public/shots/017.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/017.png
--------------------------------------------------------------------------------
/public/shots/018.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/018.png
--------------------------------------------------------------------------------
/public/shots/019.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/019.png
--------------------------------------------------------------------------------
/public/shots/020.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/020.png
--------------------------------------------------------------------------------
/public/shots/021.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/021.png
--------------------------------------------------------------------------------
/public/shots/022.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/022.png
--------------------------------------------------------------------------------
/public/shots/023.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/023.png
--------------------------------------------------------------------------------
/public/shots/024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/024.png
--------------------------------------------------------------------------------
/public/shots/025.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/025.png
--------------------------------------------------------------------------------
/public/shots/026.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/026.png
--------------------------------------------------------------------------------
/public/shots/027.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/027.png
--------------------------------------------------------------------------------
/public/shots/028.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/028.png
--------------------------------------------------------------------------------
/public/shots/029.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/029.png
--------------------------------------------------------------------------------
/public/shots/030.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/030.png
--------------------------------------------------------------------------------
/public/shots/031.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/031.png
--------------------------------------------------------------------------------
/public/shots/032.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/032.png
--------------------------------------------------------------------------------
/public/shots/033.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/033.png
--------------------------------------------------------------------------------
/public/shots/034.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/034.png
--------------------------------------------------------------------------------
/public/shots/035.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/035.png
--------------------------------------------------------------------------------
/public/shots/036.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/036.png
--------------------------------------------------------------------------------
/public/shots/037.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/037.png
--------------------------------------------------------------------------------
/public/020-goldfish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/020-goldfish.png
--------------------------------------------------------------------------------
/public/shots/index.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antfu/100/main/public/shots/index.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 | *.local
5 | scripts/screenshots
6 | *.tsbuildinfo
7 |
--------------------------------------------------------------------------------
/src/utils/dark.ts:
--------------------------------------------------------------------------------
1 | import { useDark } from '@vueuse/core'
2 |
3 | export const isDark = useDark()
4 |
5 | export function toggleDark() {
6 | isDark.value = !isDark.value
7 | }
8 |
--------------------------------------------------------------------------------
/src/window.d.ts:
--------------------------------------------------------------------------------
1 | import type Matter from '@types/matter-js'
2 | import type * as THREE from 'three'
3 |
4 | declare interface Window {
5 | Matter: Matter
6 | THREE: THREE
7 | }
8 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "dist"
3 | command = "pnpm run build"
4 |
5 | [build.environment]
6 | NODE_VERSION = "20"
7 |
8 | [[redirects]]
9 | from = "/*"
10 | to = "/index.html"
11 | status = 200
12 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "octref.vetur",
4 | "antfu.i18n-ally",
5 | "antfu.iconify",
6 | "dbaeumer.vscode-eslint",
7 | "bradlc.vscode-tailwindcss"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import antfu from '@antfu/eslint-config'
2 |
3 | export default antfu({
4 | formatters: true,
5 | unocss: true,
6 | vue: true,
7 | })
8 | .removeRules(
9 | 'unused-imports/no-unused-vars',
10 | )
11 |
--------------------------------------------------------------------------------
/src/pages/014.vue:
--------------------------------------------------------------------------------
1 |
2 | paper
3 | .box.overflow-hidden
4 | img(src='./014.psvg' width='400' height='400')
5 |
6 | note
7 | .p PSVG !
8 |
9 |
--------------------------------------------------------------------------------
/public/019-tree.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/utils/stringify.ts:
--------------------------------------------------------------------------------
1 | export function stringify(obj: any) {
2 | return JSON.stringify(obj)
3 | .replace(/"/g, '\'')
4 | .replace(/:/g, ': ')
5 | .replace(/\{/g, '{ ')
6 | .replace(/\}/g, ' }')
7 | .replace(/,/g, ', ')
8 | .replace(/'(\w+)':/g, '$1:')
9 | .replace(/'(\d+)'/g, '$1')
10 | }
11 |
--------------------------------------------------------------------------------
/src/utils/load.ts:
--------------------------------------------------------------------------------
1 | export function load(url: string) {
2 | return new Promise((resolve) => {
3 | if (document.head.querySelector(`script[src="${url}"]`))
4 | return resolve()
5 |
6 | const script = document.createElement('script')
7 | script.src = url
8 | script.onload = () => resolve()
9 | document.head.appendChild(script)
10 | })
11 | }
12 |
--------------------------------------------------------------------------------
/src/pages/_template.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 | paper
13 | .box.centered(ref='box')
14 |
15 |
16 |
19 |
--------------------------------------------------------------------------------
/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "incremental": true,
4 | "target": "ESNext",
5 | "lib": ["DOM", "ESNext"],
6 | "baseUrl": ".",
7 | "module": "ESNext",
8 | "moduleResolution": "node",
9 | "paths": {
10 | "/~/*": ["src/*"]
11 | },
12 | "resolveJsonModule": true,
13 | "strict": true,
14 | "esModuleInterop": true,
15 | "skipLibCheck": true
16 | },
17 | "exclude": ["dist", "node_modules"]
18 | }
19 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import { createApp } from 'vue'
4 | import { createRouter, createWebHistory } from 'vue-router'
5 | import routes from '~pages'
6 |
7 | import App from './App.vue'
8 | import '@unocss/reset/tailwind.css'
9 |
10 | import './main.postcss'
11 |
12 | import 'uno.css'
13 |
14 | const app = createApp(App)
15 | const router = createRouter({
16 | history: createWebHistory(),
17 | routes,
18 | })
19 |
20 | app.use(router)
21 | app.mount('#app')
22 |
--------------------------------------------------------------------------------
/src/components/Toggle.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 | .toggle(:class='{active: modelValue}' @click='toggle')
13 | slot
14 |
15 |
16 |
25 |
--------------------------------------------------------------------------------
/uno.config.ts:
--------------------------------------------------------------------------------
1 | import extractorPug from '@unocss/extractor-pug'
2 | import {
3 | defineConfig,
4 | presetUno,
5 | presetWebFonts,
6 | transformerDirectives,
7 | } from 'unocss'
8 |
9 | export default defineConfig({
10 | presets: [
11 | presetUno(),
12 | presetWebFonts({
13 | fonts: {
14 | code: 'DM Mono',
15 | sans: 'DM Sans',
16 | serif: 'DM Serif Display',
17 | },
18 | }),
19 | ],
20 | transformers: [
21 | transformerDirectives(),
22 | ],
23 | extractors: [
24 | extractorPug(),
25 | ],
26 | })
27 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 100 days
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/pages/014.psvg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/utils/canvas.ts:
--------------------------------------------------------------------------------
1 | export function initCanvas(canvas: HTMLCanvasElement, width = 400, height = 400, _dpi?: number) {
2 | const ctx = canvas.getContext('2d')!
3 |
4 | const dpr = window.devicePixelRatio || 1
5 | // @ts-expect-error vendor prefix
6 | const bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1
7 |
8 | const dpi = _dpi || dpr / bsr
9 |
10 | canvas.style.width = `${width}px`
11 | canvas.style.height = `${height}px`
12 | canvas.width = dpi * width
13 | canvas.height = dpi * height
14 | ctx.scale(dpi, dpi)
15 |
16 | return { ctx, dpi }
17 | }
18 |
--------------------------------------------------------------------------------
/src/pages/[...miss].vue:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 | paper
23 | .not-found.box(ref='box')
24 | .not-found.text Not Found
25 |
26 |
27 |
38 |
--------------------------------------------------------------------------------
/src/components/Turns.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 | .turns(:class='{active: modelValue}' @click='toggle') {{modelValue}}
24 |
25 |
26 |
32 |
--------------------------------------------------------------------------------
/components.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // @ts-nocheck
3 | // Generated by unplugin-vue-components
4 | // Read more: https://github.com/vuejs/core/pull/3399
5 | export {}
6 |
7 | /* prettier-ignore */
8 | declare module 'vue' {
9 | export interface GlobalComponents {
10 | CarbonChevronLeft: typeof import('~icons/carbon/chevron-left')['default']
11 | Note: typeof import('./src/components/Note.vue')['default']
12 | Paper: typeof import('./src/components/Paper.vue')['default']
13 | PlaygroundX: typeof import('./src/components/PlaygroundX.vue')['default']
14 | RouterLink: typeof import('vue-router')['RouterLink']
15 | RouterView: typeof import('vue-router')['RouterView']
16 | Toggle: typeof import('./src/components/Toggle.vue')['default']
17 | Turns: typeof import('./src/components/Turns.vue')['default']
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/pages/_template_p5.vue:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 | paper
25 | .box.overflow-hidden.borderless(ref='el')
26 |
27 | note
28 | p Unknown Pleasures
29 | br
30 | p Day 3 of #Codecember
31 |
32 |
--------------------------------------------------------------------------------
/src/pages/009.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 | paper
28 | playground-x(ref='playground' v-model:x='expX' v-model:y='expY' :iterations='speed')
29 | .box-description.py-1(v-if='!shot')
30 | turns.inline-block.mr-2(v-model='speedLevel' :options='speeds')
31 |
32 | note
33 | p x = x + (random() - 0.5) * 8
34 | p y = y + (random() - 0.5) * 8
35 | br
36 | a.link(@click='playground.f.start()') restart
37 |
38 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import type { UserConfig } from 'vite'
2 | import Vue from '@vitejs/plugin-vue'
3 | import UnoCSS from 'unocss/vite'
4 | import AutoImport from 'unplugin-auto-import/vite'
5 | import IconsResolver from 'unplugin-icons/resolver'
6 | import Icons from 'unplugin-icons/vite'
7 | import Components from 'unplugin-vue-components/vite'
8 | import Pages from 'vite-plugin-pages'
9 | import PSVG from 'vite-plugin-psvg'
10 |
11 | const config: UserConfig = {
12 | optimizeDeps: {
13 | include: [
14 | '@vueuse/core',
15 | '@vueuse/shared',
16 | '@vueuse/router',
17 | 'three',
18 | 'lodash-es',
19 | 'p5i',
20 | 'matter-js',
21 | 'matter-attractors',
22 | ],
23 | },
24 | plugins: [
25 | Vue(),
26 | Pages(),
27 | Components({
28 | resolvers: [
29 | IconsResolver({
30 | prefix: '',
31 | }),
32 | ],
33 | }),
34 | Icons(),
35 | PSVG(),
36 | UnoCSS(),
37 | AutoImport({
38 | imports: [
39 | 'vue',
40 | '@vueuse/core',
41 | ],
42 | }),
43 | ],
44 | }
45 |
46 | export default config
47 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import { useRafFn } from '@vueuse/core'
2 | import { ref } from 'vue'
3 |
4 | export * from './canvas'
5 | export * from './colors'
6 | export * from './load'
7 | export * from './shake'
8 | export * from './stringify'
9 | export * from './vector'
10 |
11 | export function noop() {}
12 |
13 | export function shuffle(arr: T[]): T[] {
14 | const array = arr.slice(0)
15 | for (let i = array.length - 1; i > 0; i--) {
16 | const j = Math.floor(Math.random() * (i + 1));
17 | [array[i], array[j]] = [array[j], array[i]]
18 | }
19 | return array
20 | }
21 |
22 | export function range(to: number) {
23 | return Array.from({ length: to }).fill(0).map((_, i) => i)
24 | }
25 |
26 | export function useWindowPosition() {
27 | const screenTop = ref(window.screenTop)
28 | const screenLeft = ref(window.screenLeft)
29 |
30 | const timeout = useRafFn(() => {
31 | screenTop.value = window.screenTop
32 | screenLeft.value = window.screenLeft
33 | })
34 |
35 | return { screenLeft, screenTop, timeout }
36 | }
37 |
38 | export function random(max = 1, min = 0) {
39 | return Math.random() * (max - min) + min
40 | }
41 |
--------------------------------------------------------------------------------
/src/pages/plum.psvg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Anthony Fu // free feel to change it to your name.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/pages/000.vue:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 | paper
22 | .box.overflow-hidden.relative.frame(
23 | :class='{loading}'
24 | @click='next'
25 | )
26 | iframe.box.pointer-events-none(
27 | :class='{loading}'
28 | :src='src'
29 | width='400'
30 | height='400'
31 | @load='loading=false'
32 | )
33 | note
34 | p no man's land
35 | br
36 | a.link(:href='url') {{url}}
37 |
38 |
39 |
57 |
--------------------------------------------------------------------------------
/src/pages/index.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 | .paper
13 | .centered.index-page
14 | h1.font-mono.mb-2.text-lg.font-bold.mb-4 100 days
15 | pre.grid.gap-x-4.gap-y-1(class="grid-cols-1 sm:grid-cols-2 lg:grid-cols-3")
16 | router-link.link.block.mr-4(v-for='work of avaliable_works' :key='work.no' :to='`/${work.no}`')
17 | span.mr-2.opacity-50 {{ work.no }}
18 | b {{ work.name }}
19 | h1.font-mono.mb-2.mt-8
20 | a.link(href='https://antfu.me' target='_blank') @antfu
21 | span.mx-1.op75 .
22 | a.link(href='https://twitter.com/antfu7/status/1325977074813739009' target='_blank') twitter
23 | span.mx-1.op75 .
24 | a.link(href='https://github.com/antfu/100' target='_blank') github
25 | span.mx-1.op75 .
26 | a.link(href='https://codecember.netlify.app' target='_blank') codecember
27 | span.mx-1.op75 .
28 | button.link(@click="toggleDark()") {{ isDark ? 'dark' : 'light' }}
29 | br
30 | span.text-gray-300 from 2020/11/06
31 |
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 100
2 |
3 | My 100 day project of exploring design, compform, and new things.
4 |
5 | [100.antfu.me](http://100.antfu.me/) | [updates on Twitter](https://twitter.com/antfu7/status/1325977074813739009)
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | ## Join us!
14 |
15 | [@octref](https://github.com/octref)(100.matsu.io) and me started our 100-day challenges as we wanted to learn creative coding while having fun.
16 |
17 | We would love to share the journey with you and have you learning and doing sketches together. **Join us in [Codecember](https://codecember.netlify.app/)**,
18 | we'll give you a prompt every day that includes an artwork, its source code and a blurb, throughout December, 2020.
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | ## Sponsors
27 |
28 | This project is part of my Sponsor Program
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | ## License
37 |
38 | MIT
39 |
--------------------------------------------------------------------------------
/src/pages/038.vue:
--------------------------------------------------------------------------------
1 |
65 |
66 |
67 | paper
68 | .box.overflow-hidden(ref='el')
69 |
70 |
--------------------------------------------------------------------------------
/src/pages/001.vue:
--------------------------------------------------------------------------------
1 |
51 |
52 |
53 | paper
54 | .box.centered.overflow-hidden(@click='f.add' ref='canvas')
55 |
56 | note
57 | p hands-on Matter.js
58 |
59 |
--------------------------------------------------------------------------------
/src/main.postcss:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | #app {
4 | margin: 0;
5 | padding: 0;
6 | @apply font-mono font-light;
7 | }
8 |
9 | html.dark {
10 | filter: invert(1) hue-rotate(180deg);
11 | }
12 |
13 | body {
14 | background: white;
15 | }
16 |
17 | .paper {
18 | @apply fixed top-0 left-0 right-0 bottom-0 grid;
19 | place-items: center;
20 | user-select: none;
21 | justify-content: center;
22 | }
23 |
24 | .link {
25 | @apply text-true-gray-400 hover:text-true-gray-700 transition select-none;
26 | }
27 |
28 | del {
29 | @apply opacity-50;
30 | }
31 |
32 | .centered {
33 | position: fixed;
34 | top: 50%;
35 | left: 50%;
36 | transform: translate(-50%, -50%);
37 | }
38 |
39 | .index-page {
40 | max-height: 100%;
41 | padding: 60px 40px 30px 40px;
42 | overflow: auto;
43 |
44 | @apply w-full md:w-auto;
45 | }
46 |
47 | .box {
48 | width: 400px;
49 | height: 400px;
50 | }
51 |
52 | .large.box {
53 | width: 800px;
54 | height: 800px;
55 | }
56 |
57 | .box:not(.borderless) {
58 | border: 1px solid black;
59 | }
60 |
61 | .box-heading {
62 | position: fixed;
63 | left: calc(50% - 200px);
64 | width: 400px;
65 | bottom: calc(50% + 200px);
66 | }
67 |
68 | .box-description {
69 | position: fixed;
70 | left: calc(50% - 200px);
71 | width: 400px;
72 | top: calc(50% + 200px);
73 | }
74 |
75 | a[target='_blank']:not(.link) {
76 | @apply underline opacity-75 hover:opacity-100 transition-opacity;
77 | }
78 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "i18n-ally.localesPaths": "locales",
3 | "i18n-ally.keystyle": "nested",
4 | "i18n-ally.sortKeys": true,
5 |
6 | // Enable the ESlint flat config support
7 | "eslint.experimental.useFlatConfig": true,
8 |
9 | // Disable the default formatter, use eslint instead
10 | "prettier.enable": false,
11 | "editor.formatOnSave": false,
12 |
13 | // Auto fix
14 | "editor.codeActionsOnSave": {
15 | "source.fixAll.eslint": "explicit",
16 | "source.organizeImports": "never"
17 | },
18 |
19 | // Silent the stylistic rules in you IDE, but still auto fix them
20 | "eslint.rules.customizations": [
21 | { "rule": "style/*", "severity": "off" },
22 | { "rule": "format/*", "severity": "off" },
23 | { "rule": "*-indent", "severity": "off" },
24 | { "rule": "*-spacing", "severity": "off" },
25 | { "rule": "*-spaces", "severity": "off" },
26 | { "rule": "*-order", "severity": "off" },
27 | { "rule": "*-dangle", "severity": "off" },
28 | { "rule": "*-newline", "severity": "off" },
29 | { "rule": "*quotes", "severity": "off" },
30 | { "rule": "*semi", "severity": "off" }
31 | ],
32 |
33 | // Enable eslint for all supported languages
34 | "eslint.validate": [
35 | "javascript",
36 | "javascriptreact",
37 | "typescript",
38 | "typescriptreact",
39 | "vue",
40 | "html",
41 | "markdown",
42 | "json",
43 | "jsonc",
44 | "yaml",
45 | "toml",
46 | "astro"
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/scripts/postbuild.ts:
--------------------------------------------------------------------------------
1 | import cheerio from 'cheerio'
2 | import fs from 'fs-extra'
3 | import { works } from '../src/works'
4 |
5 | const DOMAIN = 'https://100.antfu.me'
6 |
7 | export async function postBuild() {
8 | // console.log('post build!')
9 |
10 | const indexHTML = await fs.readFile('dist/index.html', 'utf-8')
11 |
12 | for (const work of works) {
13 | const $ = cheerio.load(indexHTML)
14 |
15 | const head = $('head')
16 | const title = `${work.no}. ${work.name}`
17 | $('title').text(title)
18 |
19 | head.append($(` `))
20 |
21 | if (fs.existsSync(`public/shots/${work.no}.png`)) {
22 | head.append($(` `))
23 | head.append($(' '))
24 | }
25 | head.append($(' '))
26 |
27 | await fs.writeFile(`dist/${work.no}.html`, $.html(), 'utf-8')
28 | }
29 |
30 | const $ = cheerio.load(indexHTML)
31 | const head = $('head')
32 | const title = $('title').text()
33 |
34 | head.append($(` `))
35 | head.append($(` `))
36 | head.append($(' '))
37 | head.append($(' '))
38 |
39 | await fs.writeFile('dist/index.html', $.html(), 'utf-8')
40 | }
41 |
42 | postBuild()
43 |
--------------------------------------------------------------------------------
/src/components/Note.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | .note.font-normal.font-mono(:class='{active}' v-if='!hide')
16 | .handle.fixed.border.border-gray-200.text-center.p-2.op50.bg-white.bg-opacity-50(@click='active=true') i
17 | .modal-bg.bg-black.fixed.top-0.left-0.right-0.bottom-0(@click='active=false')
18 | .content.border.border-gray-200.p-8.fixed.bottom-0.bg-white.shadow
19 | slot
20 |
21 | br
22 | a.link.mr-3(:href='`https://github.com/antfu/100/blob/main/src/pages/${no}.vue`') source
23 |
24 |
25 |
57 |
--------------------------------------------------------------------------------
/src/utils/vector.ts:
--------------------------------------------------------------------------------
1 | export type Vector = [number, number]
2 |
3 | export const r180 = Math.PI
4 | export const r90 = Math.PI / 2
5 | export const r60 = Math.PI / 3
6 | export const r30 = Math.PI / 6
7 | export const r15 = Math.PI / 12
8 | export const r120 = Math.PI / 3 * 2
9 | export const r360 = Math.PI * 2
10 |
11 | export const SQRT_3 = Math.sqrt(3)
12 | export const SQRT_2 = Math.sqrt(2)
13 |
14 | export function exclude(arr: T[], v: T) {
15 | return arr.filter(i => i !== v)
16 | }
17 |
18 | export function square(a: number) {
19 | return a ** 2
20 | }
21 |
22 | export function addVec([x1, y1]: Vector, [x2, y2]: Vector): Vector {
23 | return [x1 + x2, y1 + y2]
24 | }
25 |
26 | export function vec2mat([x, y]: Vector) {
27 | return { x, y }
28 | }
29 |
30 | export function distance([x1, y1]: Vector, [x2, y2]: Vector) {
31 | return Math.sqrt(square(x1 - x2) + square(y1 - y2))
32 | }
33 |
34 | export function get(arr: T[], index: number) {
35 | return arr[index % arr.length]
36 | }
37 |
38 | export function pick(arr: T[], current?: T): T {
39 | if (current)
40 | return pick(exclude(arr, current))
41 |
42 | return arr[Math.round(Math.random() * (arr.length - 1))]
43 | }
44 |
45 | export function next(arr: T[], current: T): T {
46 | const index = arr.indexOf(current)
47 | if (index < 0)
48 | return pick(arr)
49 | return get(arr, index + 1)
50 | }
51 |
52 | export function polar2cart(x = 0, y = 0, r = 0, theta = 0) {
53 | const dx = r * Math.cos(theta)
54 | const dy = r * Math.sin(theta)
55 | return [x + dx, y + dy]
56 | }
57 |
58 | export function inbound([x, y]: Vector, width = 400, height = 400) {
59 | return x >= 0 && x < width && y >= 0 && y < height
60 | }
61 |
--------------------------------------------------------------------------------
/src/pages/007.vue:
--------------------------------------------------------------------------------
1 |
32 |
33 |
34 | paper(:style='transformStyle')
35 | .box.centered.rounded-full
36 | .anchor.overflow-visable.w-0.h-0.fixed
37 | .text
38 | p.pt-12 A ship in harbor is safe, but that is not what ships are built for.
39 | br
40 | em.op50 — John A. Shedd
41 |
42 | .box-description.py-3
43 | .op50.text-center.tip(v-if='!mobile && !shot') use phone to visit
44 | .div.p-4(v-if='debug')
45 | p Gamma {{ gamma }}
46 | p Beta {{ beta }}
47 | p Theta {{ theta }}
48 | p Alpha {{ alpha }}
49 |
50 | note
51 |
52 |
53 |
63 |
--------------------------------------------------------------------------------
/src/utils/shake.ts:
--------------------------------------------------------------------------------
1 | import { useDeviceMotion } from '@vueuse/core'
2 | import { watch } from 'vue'
3 |
4 | export function useShake(fn: () => void) {
5 | const options = {
6 | threshold: 10, // default velocity threshold for shake to register
7 | timeout: 500, // default interval between events
8 | }
9 |
10 | const { accelerationIncludingGravity } = useDeviceMotion()
11 |
12 | let lastX: number | null = null
13 | let lastY: number | null = null
14 | let lastZ: number | null = null
15 | let lastTime = new Date()
16 |
17 | watch(accelerationIncludingGravity, () => {
18 | const current = accelerationIncludingGravity.value
19 | if (!current)
20 | return
21 |
22 | let currentTime
23 | let timeDifference
24 | let deltaX = 0
25 | let deltaY = 0
26 | let deltaZ = 0
27 |
28 | if (lastX === null || lastY === null || lastZ === null) {
29 | lastX = current.x
30 | lastY = current.y
31 | lastZ = current.z
32 | return
33 | }
34 |
35 | deltaX = Math.abs(lastX - current.x!)
36 | deltaY = Math.abs(lastY - current.y!)
37 | deltaZ = Math.abs(lastZ - current.z!)
38 |
39 | if (((deltaX > options.threshold) && (deltaY > options.threshold)) || ((deltaX > options.threshold) && (deltaZ > options.threshold)) || ((deltaY > options.threshold) && (deltaZ > options.threshold))) {
40 | // calculate time in milliseconds since last shake registered
41 | currentTime = new Date()
42 | timeDifference = currentTime.getTime() - lastTime.getTime()
43 |
44 | if (timeDifference > options.timeout) {
45 | fn()
46 | lastTime = new Date()
47 | }
48 | }
49 |
50 | lastX = current.x
51 | lastY = current.y
52 | lastZ = current.z
53 | })
54 | }
55 |
--------------------------------------------------------------------------------
/src/pages/016.vue:
--------------------------------------------------------------------------------
1 |
64 |
65 |
66 | paper
67 | .box.overflow-hidden
68 | canvas(ref='el' width='400' height='400')
69 |
70 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "100d",
3 | "type": "module",
4 | "private": true,
5 | "packageManager": "pnpm@9.15.1",
6 | "scripts": {
7 | "dev": "vite --port 3333 --open",
8 | "build": "cross-env NODE_ENV=production vite build && esno scripts/postbuild.ts",
9 | "shot": "esno scripts/screenshot.ts",
10 | "lint": "eslint .",
11 | "typecheck": "vue-tsc --noEmit"
12 | },
13 | "dependencies": {
14 | "@iconify/iconify": "^3.1.1",
15 | "@unocss/extractor-pug": "^0.65.3",
16 | "@vueuse/core": "^12.2.0",
17 | "@vueuse/router": "^12.2.0",
18 | "@vueuse/shared": "^12.2.0",
19 | "dayjs": "^1.11.13",
20 | "lodash-es": "^4.17.21",
21 | "matter-attractors": "^0.1.6",
22 | "matter-js": "^0.19.0",
23 | "moveable": "^0.28.0",
24 | "opentype.js": "^1.3.4",
25 | "p5i": "^0.6.0",
26 | "poly-decomp": "^0.3.0",
27 | "simplex-noise": "^4.0.3",
28 | "three": "0.124.0",
29 | "vue": "^3.5.13",
30 | "vue-router": "^4.5.0"
31 | },
32 | "devDependencies": {
33 | "@antfu/eslint-config": "^3.12.1",
34 | "@iconify/json": "^2.2.288",
35 | "@types/cheerio": "^0.22.35",
36 | "@types/fs-extra": "^11.0.4",
37 | "@types/lodash-es": "^4.17.12",
38 | "@types/matter-js": "^0.19.8",
39 | "@unocss/eslint-plugin": "^0.65.3",
40 | "@unocss/reset": "^0.65.3",
41 | "@vitejs/plugin-vue": "^5.2.1",
42 | "cheerio": "^1.0.0",
43 | "cross-env": "^7.0.3",
44 | "eslint": "^9.17.0",
45 | "eslint-plugin-format": "^0.1.3",
46 | "esno": "^4.8.0",
47 | "fs-extra": "^11.2.0",
48 | "playwright": "^1.49.1",
49 | "pug": "^3.0.3",
50 | "stylus": "^0.64.0",
51 | "typescript": "^5.7.2",
52 | "unocss": "^0.65.3",
53 | "unplugin-auto-import": "^0.19.0",
54 | "unplugin-icons": "^0.22.0",
55 | "unplugin-vue-components": "^0.28.0",
56 | "vite": "^6.0.5",
57 | "vite-plugin-pages": "^0.32.4",
58 | "vite-plugin-psvg": "^0.3.0",
59 | "vue-tsc": "^2.2.0"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/pages/027.vue:
--------------------------------------------------------------------------------
1 |
89 |
90 |
91 | paper
92 | .box.large.borderless.centered.overflow-hidden(ref='el')
93 |
94 | note
95 | p line ⟷ circle
96 | br
97 | p Day 2 of #Codecember
98 |
99 |
--------------------------------------------------------------------------------
/src/pages/036.vue:
--------------------------------------------------------------------------------
1 |
39 |
40 |
41 | paper
42 | .box.borderless.centered(ref='box' :style='style')
43 | img.select-none(src='/036.svg')
44 | img.fixed.top-0.left-0(
45 | src='/036.svg' ref='el'
46 | style='opacity: 0.9; transform: matrix(0.998506, -0.0546418, 0.0546418, 0.998506, 0, 0) rotate(1.50557deg); left: -2px; top: 1px;'
47 | )
48 |
49 | note
50 | p Reproduce of an art device in the AUDIO ARCHITECTURE exhibition.
51 |
52 |
53 |
59 |
60 |
75 |
--------------------------------------------------------------------------------
/src/pages/037.vue:
--------------------------------------------------------------------------------
1 |
39 |
40 |
41 | paper
42 | .box.borderless.centered(ref='box' :style='style')
43 | img.select-none(src='/037.svg')
44 | img.fixed.top-0.left-0(
45 | src='/037.svg' ref='el'
46 | style='opacity: 0.9; transform: matrix(0.997729, -0.0673475, 0.0673475, 0.997729, 0, 0) rotate(-4.64737deg); left: 3px; top: 2px;'
47 | )
48 |
49 | note
50 | p Reproduce of an art device in the AUDIO ARCHITECTURE exhibition.
51 |
52 |
53 |
59 |
60 |
75 |
--------------------------------------------------------------------------------
/src/utils/colors.ts:
--------------------------------------------------------------------------------
1 | import { clamp } from '@vueuse/core'
2 |
3 | export type ColorVector = [number, number, number]
4 |
5 | export function hexToRgb(hex: string): ColorVector {
6 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!
7 | return [
8 | Number.parseInt(result[1], 16),
9 | Number.parseInt(result[2], 16),
10 | Number.parseInt(result[3], 16),
11 | ]
12 | }
13 |
14 | export function toHex(c: number) {
15 | return c.toString(16).padStart(2, '0')
16 | }
17 |
18 | export function rgbToHex(r = 0, g = 0, b = 0) {
19 | return `#${toHex(r)}${toHex(g)}${toHex(b)}`
20 | }
21 |
22 | /**
23 | * @param vectors
24 | * @param num 0~1
25 | */
26 | export function colorInterpration(vectors: ColorVector[], n: number) {
27 | if (n >= 1)
28 | return vectors[vectors.length - 1]
29 |
30 | const normalized = clamp(n, 0, 1) * (vectors.length - 1)
31 | const integer = Math.trunc(normalized)
32 | const frac = normalized - integer
33 | const nfrac = 1 - frac
34 |
35 | const [a1, a2, a3] = vectors[integer]
36 | const [b1, b2, b3] = vectors[integer + 1]
37 |
38 | return [
39 | a1 * nfrac + b1 * frac,
40 | a2 * nfrac + b2 * frac,
41 | a3 * nfrac + b3 * frac,
42 | ]
43 | }
44 |
45 | export function hslToRgb(h: number, s: number, l: number): [number, number, number] {
46 | let r, g, b
47 |
48 | if (s === 0) {
49 | r = g = b = l // achromatic
50 | }
51 | else {
52 | const hue2rgb = function hue2rgb(p: number, q: number, t: number) {
53 | if (t < 0)
54 | t += 1
55 | if (t > 1)
56 | t -= 1
57 | if (t < 1 / 6)
58 | return p + (q - p) * 6 * t
59 | if (t < 1 / 2)
60 | return q
61 | if (t < 2 / 3)
62 | return p + (q - p) * (2 / 3 - t) * 6
63 | return p
64 | }
65 |
66 | const q = l < 0.5 ? l * (1 + s) : l + s - l * s
67 | const p = 2 * l - q
68 | r = hue2rgb(p, q, h + 1 / 3)
69 | g = hue2rgb(p, q, h)
70 | b = hue2rgb(p, q, h - 1 / 3)
71 | }
72 |
73 | return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]
74 | }
75 |
--------------------------------------------------------------------------------
/src/pages/033.vue:
--------------------------------------------------------------------------------
1 |
69 |
70 |
71 | paper
72 | .box.overflow-hidden(ref="el" @click='toggle')
73 |
74 | note
75 | p Day 8 of #Codecember
76 |
77 |
--------------------------------------------------------------------------------
/src/components/Paper.vue:
--------------------------------------------------------------------------------
1 |
36 |
37 |
38 | .paper(:class='{shot}')
39 | .bottom-nav.font-mono.flex.z-10.items-end(v-if='work && !hideFrame')
40 | .nav-links
41 | router-link.prev.link(v-if='prev' :to='`/${prev.no}`')
42 | span {{prev.name}}
43 | span.mx-1.opacity-25 {{prev.no}}
44 | .current
45 | span.font-bold {{work.name}}
46 | span.mx-1.opacity-50 {{work.no}}
47 | router-link.next.link(v-if='next' :to='`/${next.no}`')
48 | span {{next.name}}
49 | span.mx-1.opacity-25 {{next.no}}
50 | .flex-auto
51 | .flex.flex-col.items-end.group
52 | .flex-auto
53 | button.link.op0(@click="toggleDark" class="group-hover:op100") {{ isDark ? 'dark' : 'light' }}
54 | span.op20 {{work.date}}
55 | .nav.font-mono(v-if='!shot && !hideFrame')
56 | router-link.link.text-xl.block.pt-1(to='/')
57 | carbon-chevron-left
58 |
59 | slot(:work='work')
60 |
61 |
62 |
95 |
--------------------------------------------------------------------------------
/src/pages/026.vue:
--------------------------------------------------------------------------------
1 |
88 |
89 |
90 | paper
91 | .box.borderless.centered.overflow-hidden(ref='el')
92 |
93 | note
94 | p Day 1 of #Codecember
95 |
96 |
--------------------------------------------------------------------------------
/src/pages/030.vue:
--------------------------------------------------------------------------------
1 |
102 |
103 |
104 | paper
105 | .box.overflow-hidden(ref='el' @click='restart')
106 |
107 | note
108 | p Perlin Noise
109 | br
110 | p Day 5 of #Codecember
111 |
112 |
--------------------------------------------------------------------------------
/src/pages/031.vue:
--------------------------------------------------------------------------------
1 |
108 |
109 |
110 | paper
111 | .box.overflow-hidden(ref='el')
112 |
113 | note
114 | p Tonhalle – Beethoven
115 | br
116 | p Day 6 of #Codecember
117 |
118 |
--------------------------------------------------------------------------------
/src/pages/034.vue:
--------------------------------------------------------------------------------
1 |
106 |
107 |
108 | paper
109 | .box.overflow-hidden(ref="el" @click='toggle')
110 |
111 | note
112 | p Day 10 of #Codecember
113 |
114 |
--------------------------------------------------------------------------------
/src/pages/039.vue:
--------------------------------------------------------------------------------
1 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/src/pages/025.vue:
--------------------------------------------------------------------------------
1 |
95 |
96 |
97 | paper
98 | .box.centered.overflow-hidden
99 | canvas(ref='el' width='400' height='400' @click='f.next()')
100 | .box-description.py-2.flex(v-if='!shot')
101 | .flex(@click='edges = (edges -1) % 14 + 2')
102 | .op50 edges
103 | .text-gray-500.bold.px-2 {{edges}}
104 | .flex-auto
105 | .link(@click='f.reset()') reset
106 |
107 | note
108 |
109 |
--------------------------------------------------------------------------------
/src/pages/017.vue:
--------------------------------------------------------------------------------
1 |
108 |
109 |
110 | paper
111 | .box.borderless(@click='reset')
112 | canvas(ref='el' width='400' height='400')
113 |
114 |
--------------------------------------------------------------------------------
/scripts/screenshot.ts:
--------------------------------------------------------------------------------
1 | import { chromium } from 'playwright'
2 |
3 | async function run() {
4 | const browser = await chromium.launch({ headless: false })
5 | const context = await browser.newContext({
6 | viewport: {
7 | width: 960,
8 | height: 500,
9 | },
10 | deviceScaleFactor: 2,
11 | })
12 |
13 | async function take(no: string, retry = 3, delay = 1000, take = 1, query = '', delayBetweenShot = 0, prefix = '') {
14 | for (let i = 0; i < retry; i++) {
15 | const page = await context.newPage()
16 | await page.goto(`http://localhost:3333/${no}?shot=true${query}`)
17 | await page.waitForTimeout(delay)
18 | for (let j = 0; j < take; j++) {
19 | await page.screenshot({ path: `scripts/screenshots/${prefix}${no}-${i}-${j}.png` })
20 | if (delayBetweenShot)
21 | await page.waitForTimeout(delayBetweenShot)
22 | }
23 |
24 | page.close()
25 | }
26 | }
27 |
28 | async function open(no: string, query = '') {
29 | const page = await context.newPage()
30 | await page.goto(`http://localhost:3333/${no}?shot=true${query}`)
31 | await page.waitForEvent('close')
32 | return page
33 | }
34 |
35 | // await take('', 1)
36 | // await take('001', 3, 800, 4)
37 | // await take('002', 8, 500)
38 | // await take('003', 1, 1500, 5)
39 | // await take('004', 1, 500)
40 | // await take('005', 5, 1000, 20, '&q=th%20-%20sin(r)%20*%20cos(t)')
41 | // await take('006', 4, 3000, 5, '&shake=true')
42 | // await take('007', 1, 500)
43 | // await take('008', 1, 500, 8)
44 | // await take('009', 10, 1500)
45 | // await take('010', 1, 500)
46 | // await take('011', 10, 500)
47 | // await take('012', 10, 500, 4)
48 | // await take('013', 20, 3000, 3)
49 | // await take('014', 1, 10000, 5)
50 | // await take('015', 2, 7000, 10, '', 1000)
51 | // await take('016', 1, 500, 10, '', 500)
52 | // await take('017', 1, 3000, 5)
53 | // await take('018', 1, 2000, 20, '', 900)
54 | // await take('019', 1, 1000, 1)
55 | // await take('020', 30, 1500, 1)
56 | // await take('021', 20, 1000, 1)
57 | // await take('022', 2, 2000, 1)
58 | // await Promise.all([
59 | // take('023', 3, 10000, 1, '', 2000, 'c'),
60 | // take('023', 3, 10000, 1, '', 2000, 'd'),
61 | // take('023', 3, 10000, 1, '', 2000, 'e'),
62 | // ])
63 | // await take('024', 5, 3000, 3, '', 500)
64 | // await take('025', 5, 10000, 3, '', 1000)
65 | // await take('026', 1, 5000, 3, '', 1000)
66 | // await take('027', 1, 1000, 50, '', 1000)
67 | // await take('028', 4, 1000)
68 | // await open('028')
69 | // await take('029', 20, 1000)
70 | // await take('030', 10, 2000)
71 | // await open('030')
72 | // await take('031', 5, 1000)
73 | // await take('032', 5, 1000, 5)
74 | // await open('032')
75 | // await take('033', 1, 1000, 10, '', 1000)
76 | // await take('034', 5, 1000)
77 | // await take('035', 20, 8000)
78 | // await take('036', 1, 1000)
79 | await take('037', 1, 1000)
80 |
81 | await browser.close()
82 | }
83 |
84 | run()
85 |
--------------------------------------------------------------------------------
/src/pages/010.vue:
--------------------------------------------------------------------------------
1 |
105 |
106 |
107 | paper
108 | .box.borderless.centered
109 | canvas(ref='el' width='400' height='400')
110 |
111 | note
112 | p 方 - Square
113 | p 圓 - Circle
114 |
115 |
116 |
119 |
--------------------------------------------------------------------------------
/src/works.ts:
--------------------------------------------------------------------------------
1 | export const info = [
2 | {
3 | name: 'Mass',
4 | date: '2020/11/06',
5 | draft: false,
6 | },
7 | {
8 | name: 'Hex',
9 | date: '2020/11/07',
10 | },
11 | {
12 | name: 'Three',
13 | date: '2020/11/08',
14 | },
15 | {
16 | name: 'Scope',
17 | date: '2020/11/09',
18 | },
19 | {
20 | name: 'Polar',
21 | date: '2020/11/10',
22 | },
23 | {
24 | name: 'M & M',
25 | date: '2020/11/11',
26 | },
27 | {
28 | name: 'Ship',
29 | date: '2020/11/12',
30 | },
31 | {
32 | name: 'Negative',
33 | date: '2020/11/13',
34 | },
35 | {
36 | name: 'Unreproducible',
37 | date: '2020/11/14',
38 | },
39 | {
40 | name: '方圓',
41 | date: '2020/11/15',
42 | },
43 | {
44 | name: 'Box',
45 | date: '2020/11/16',
46 | },
47 | {
48 | name: 'Displace',
49 | date: '2020/11/17',
50 | },
51 | {
52 | name: 'Plum',
53 | date: '2020/11/18',
54 | },
55 | {
56 | name: 'Orbit',
57 | date: '2020/11/19',
58 | },
59 | {
60 | name: 'Rust',
61 | date: '2020/11/20',
62 | },
63 | {
64 | name: 'Connect',
65 | date: '2020/11/21',
66 | },
67 | {
68 | name: 'Gravity',
69 | date: '2020/11/22',
70 | },
71 | {
72 | name: 'Field 1',
73 | date: '2020/11/23',
74 | },
75 | {
76 | name: 'Fractal 1',
77 | date: '2020/11/24',
78 | },
79 | {
80 | name: 'Clone',
81 | date: '2020/11/25',
82 | },
83 | {
84 | name: 'Cross',
85 | date: '2020/11/26',
86 | },
87 | {
88 | name: 'ㄇㄈㄩコロ',
89 | date: '2020/11/27',
90 | },
91 | {
92 | name: 'Knitting',
93 | date: '2020/11/28',
94 | },
95 | {
96 | name: 'Cast',
97 | date: '2020/11/30',
98 | },
99 | {
100 | name: 'Kaleidoscope',
101 | date: '2020/12/01',
102 | },
103 | {
104 | name: 'Lines',
105 | date: '2020/12/02',
106 | },
107 | {
108 | name: 'Flat',
109 | date: '2020/12/03',
110 | },
111 | {
112 | name: 'Joy',
113 | date: '2020/12/04',
114 | },
115 | {
116 | name: 'Attractor',
117 | date: '2020/12/05',
118 | },
119 | {
120 | name: 'River',
121 | date: '2020/12/06',
122 | },
123 | {
124 | name: 'Arc',
125 | date: '2020/12/07',
126 | },
127 | {
128 | name: 'z = tixy',
129 | date: '2020/12/08',
130 | },
131 | {
132 | name: 'Glass',
133 | date: '2020/12/15',
134 | },
135 | {
136 | name: 'Moiré',
137 | date: '2020/12/15',
138 | },
139 | {
140 | name: 'Window',
141 | date: '2020/12/15',
142 | },
143 | {
144 | name: 'Arch 1',
145 | date: '2021/01/30',
146 | },
147 | {
148 | name: 'Arch 2',
149 | date: '2021/01/30',
150 | },
151 | {
152 | name: 'Boxes',
153 | date: '2020/12/06',
154 | },
155 | {
156 | name: 'Dots',
157 | date: '2020/12/06',
158 | },
159 | ]
160 |
161 | export const works = info.map((info, idx) => {
162 | return {
163 | ...info,
164 | no: `${idx + 1}`.padStart(3, '0'),
165 | }
166 | })
167 |
--------------------------------------------------------------------------------
/src/pages/013.vue:
--------------------------------------------------------------------------------
1 |
91 |
92 |
93 | paper
94 | .box.overflow-hidden(@click='f.start')
95 | canvas(ref='el' width='400' height='400')
96 | .box-description.py-2.flex(v-if='!shot')
97 | .flex(@click='init = init % 8 + 1')
98 | .op50 init
99 | .text-gray-500.bold.px-2 {{init}}
100 | .flex.ml-3(@click='len = len % 8 + 1')
101 | .op50 len
102 | .text-gray-500.bold.px-2 {{len}}
103 | .flex-auto
104 | .op50(v-if='!stopped') *
105 |
106 | note
107 | .p for each node, there is 50% chance for growing a new branch for its two branches.
108 | br
109 | .p init - the initial iterations that guaranteed having 100% to grow.
110 | .p len - max length for each branch.
111 |
112 |
--------------------------------------------------------------------------------
/src/pages/029.vue:
--------------------------------------------------------------------------------
1 |
98 |
99 |
100 | paper
101 | .box.overflow-hidden.borderless(@click='shuffle')
102 | canvas(ref="el")
103 | .box-description.py-4.flex.justify-center(v-if='!shot')
104 | .mx-4.text-right.text-gray-500(@click='roll(0)') a {{a<0?'':'+'}}{{a.toFixed(2)}}
105 | .mx-4.text-right.text-gray-500(@click='roll(1)') b {{b<0?'':'+'}}{{b.toFixed(2)}}
106 | .mx-4.text-right.text-gray-500(@click='roll(2)') c {{c<0?'':'+'}}{{c.toFixed(2)}}
107 | .mx-4.text-right.text-gray-500(@click='roll(3)') d {{d<0?'':'+'}}{{d.toFixed(2)}}
108 | note
109 | p Peter de Jong Attractor
110 | br
111 | p Day 4 of #Codecember
112 |
113 |
--------------------------------------------------------------------------------
/src/pages/024.vue:
--------------------------------------------------------------------------------
1 |
128 |
129 |
130 | paper
131 | .box.centered.overflow-hidden
132 | canvas(ref='el' width='400' height='400' @click='f.reset()')
133 |
134 |
--------------------------------------------------------------------------------
/src/pages/x-shadow.vue:
--------------------------------------------------------------------------------
1 |
131 |
132 |
133 | paper
134 | .box.centered.overflow-hidden(ref='box')
135 |
136 |
137 |
140 |
--------------------------------------------------------------------------------
/src/pages/015.vue:
--------------------------------------------------------------------------------
1 |
161 |
162 |
163 | paper
164 | .box.overflow-hidden(@click='f.start' style='border-color: #592A2A')
165 | canvas(ref='el' width='400' height='400')
166 |
167 |
--------------------------------------------------------------------------------
/src/pages/028.vue:
--------------------------------------------------------------------------------
1 |
122 |
123 |
124 | paper
125 | .box.overflow-hidden.borderless(ref='el')
126 |
127 | note
128 | p Unknown Pleasures
129 | br
130 | p Day 3 of #Codecember
131 | br
132 | p Strength
133 | p ↑
134 | p |
135 | p |
136 | P +-------> Speed
137 |
138 |
--------------------------------------------------------------------------------
/src/pages/012.vue:
--------------------------------------------------------------------------------
1 |
137 |
138 |
139 | paper
140 | .box.overflow-hidden(@click='roll')
141 | canvas(ref='el' width='400' height='400' :style='filterStyle')
142 | .box-description.py-4(v-if='!shot')
143 | template(v-for='c,idx in coeff')
144 | .inline-block.w-12.mx-2.text-right(
145 | :class='[c < 0 ? "text-gray-300" : "text-gray-500"]'
146 | @click='rollAt(idx)'
147 | ) {{ c.toFixed(2) }}
148 | br(v-if='idx % 6 === 5')
149 |
150 |
--------------------------------------------------------------------------------
/src/pages/002.vue:
--------------------------------------------------------------------------------
1 |
135 |
136 |
137 | paper
138 | .box.centered.overflow-hidden
139 | canvas(ref='el' width='400' height='400' @click='f.run()')
140 | .box-description.py-1
141 | turns.inline-block.mr-2(v-model='mode' :options='patterns')
142 | toggle.inline-block.mr-2(v-model='showHexagon') hex
143 |
144 | note
145 | p inspired by this CodePen
146 | br
147 | p extend reading Hexagonal Grids
148 |
149 |
150 |
153 |
--------------------------------------------------------------------------------
/src/pages/021.vue:
--------------------------------------------------------------------------------
1 |
172 |
173 |
174 | paper
175 | .box.centered.overflow-hidden
176 | canvas(ref='el' width='400' height='400' @click='f.reset()')
177 |
178 |
--------------------------------------------------------------------------------
/src/pages/035.vue:
--------------------------------------------------------------------------------
1 |
186 |
187 |
188 | paper
189 | .box.overflow-hidden(ref="el" @click='start')
190 |
191 | note
192 | p Day 11 of #Codecember
193 |
194 |
--------------------------------------------------------------------------------
/src/pages/011.vue:
--------------------------------------------------------------------------------
1 |
159 |
160 |
161 | paper
162 | .large.box.borderless.centered.overflow-hidden(ref='el')
163 |
164 |
165 |
168 |
--------------------------------------------------------------------------------
/src/pages/x-lifetime-playground.vue:
--------------------------------------------------------------------------------
1 |
168 |
169 |
170 | paper
171 | .box.centered.overflow-hidden
172 | canvas(ref='el' width='400' height='400')
173 | .box-description
174 | pre {{JSON.stringify(data, null, 2)}}
175 |
176 | note
177 | p Will I get my PS5?
178 |
179 |
--------------------------------------------------------------------------------
/src/pages/008.vue:
--------------------------------------------------------------------------------
1 |
170 |
171 |
172 | paper
173 | .box.centered.overflow-hidden
174 | canvas(ref='el' width='400' height='400')
175 | .box-description.py-1(v-if='!shot')
176 | toggle.inline-block.mr-2(v-model='wireframe') wireframe
177 | turns.inline-block.mr-2(v-model='speedLevel' :options='speeds')
178 |
179 | note
180 | p inspired by
181 | a(href='https://twitter.com/beesandbombs/status/1320394711182528515?s=20' target='_blank') this tweet
182 | | from
183 | a(href='https://twitter.com/beesandbombs' target='_blank') @beesandbombs
184 |
185 |
186 |
189 |
--------------------------------------------------------------------------------
/src/pages/023.vue:
--------------------------------------------------------------------------------
1 |
175 |
176 |
177 | paper
178 | .box.centered.overflow-hidden
179 | canvas(ref='el' width='400' height='400' @click='f.reset()')
180 |
181 |
--------------------------------------------------------------------------------
/src/pages/022.vue:
--------------------------------------------------------------------------------
1 |
184 |
185 |
186 | paper
187 | .fixed.top-0.bottom-0.left-0.right-0(ref='el' style='filter:invert(1) brightness(1.5);')
188 | //- .box
189 |
190 |
191 |
194 |
--------------------------------------------------------------------------------
/src/components/PlaygroundX.vue:
--------------------------------------------------------------------------------
1 |
194 |
195 |
196 | div
197 | .box.overflow-hidden
198 | .canvas-wrapper
199 | canvas(ref='el')
200 | .box-description(v-show='controls')
201 | .flex.flex-col.mt-2
202 | p.op50 (t,x,y) =>
203 | .flex
204 | .mr-2.op50 x =
205 | input.flex-auto.outline-none(
206 | v-model='expX'
207 | :maxlength='32'
208 | autocomplete='false'
209 | spellcheck='false'
210 | )
211 | .flex
212 | .mr-2.op50 y =
213 | input.flex-auto.outline-none(
214 | v-model='expY'
215 | maxlength='32'
216 | autocomplete='false'
217 | spellcheck='false'
218 | )
219 | iframe.none.h-0(ref='runner' sandbox='allow-same-origin')
220 |
221 |
222 |
224 |
--------------------------------------------------------------------------------
/src/pages/019.vue:
--------------------------------------------------------------------------------
1 |
163 |
164 |
165 | paper
166 | .box.centered.overflow-hidden
167 | canvas(:class='{shake}' ref='el' width='400' height='400' @click='f.next()')
168 | .box-description.py-1(v-if='!shot')
169 | p.op50 click
170 |
171 |
172 |
191 |
--------------------------------------------------------------------------------
/src/pages/003.vue:
--------------------------------------------------------------------------------
1 |
172 |
173 |
174 | paper
175 | .box.centered.overflow-hidden(ref='box')
176 |
177 | note
178 | p.font-bold hands-on three.js
179 | br
180 | p following this guide
181 |
182 |
183 |
186 |
--------------------------------------------------------------------------------
/src/pages/018.vue:
--------------------------------------------------------------------------------
1 |
176 |
177 |
178 | paper
179 | .box.centered.overflow-hidden(@click='roll' ref='el')
180 | canvas.absolute.left-0.top-0.opacity-25(ref='canvas' width='400' height='400')
181 | .box-description(v-if='false')
182 | .flex.flex-col.mt-2
183 | p.op50 (t,x,y) =>
184 | .flex
185 | .mr-2.op50 x =
186 | input.flex-auto.outline-none(
187 | v-model='expX'
188 | maxlength='32'
189 | autocomplete='false'
190 | spellcheck='false'
191 | )
192 | .flex
193 | .mr-2.op50 y =
194 | input.flex-auto.outline-none(
195 | v-model='expY'
196 | maxlength='32'
197 | autocomplete='false'
198 | spellcheck='false'
199 | )
200 | iframe.none.h-0(ref='runner' sandbox='allow-same-origin')
201 |
202 |
--------------------------------------------------------------------------------
/src/pages/020.vue:
--------------------------------------------------------------------------------
1 |
190 |
191 |
192 | paper
193 | .box.overflow-hidden(ref='el')
194 |
195 | note
196 | template(v-if='!seenEgg')
197 | p it's not always perfect to make clones.
198 | template(v-else)
199 | p Congrats!
200 | p It's our pet goldfish drew by my girlfriend Inès . Hope you had fun with this little game and you can definitely show off a bit on Twitter :)
201 | p.op50 (let me know by pinning @antfu7)
202 |
203 |
204 |
207 |
--------------------------------------------------------------------------------
/src/pages/006.vue:
--------------------------------------------------------------------------------
1 |
212 |
213 |
214 | paper
215 | .fixed.top-0.bottom-0.left-0.right-0(ref='el')
216 |
217 | note
218 | p drag them, or shake your phone
219 | br
220 | a.link(@click='toggleShape') toggle shape
221 |
222 |
223 |
226 |
--------------------------------------------------------------------------------
/src/pages/032.vue:
--------------------------------------------------------------------------------
1 |
176 |
177 |
178 | paper
179 | .box.borderless.z-10(@click='next')
180 | #day32(ref='el')
181 | .box-description(v-show='!shot')
182 | .flex.mt-6
183 | p.op50 (t,i,x,y) =>
184 | input.flex-auto.outline-none.ml-2.bg-transparent(
185 | v-model='expression'
186 | maxlength='32'
187 | autocomplete='false'
188 | spellcheck='false'
189 | )
190 | p.op50(:class='{"hidden": !author}') by @{{author}}
191 | iframe.none.h-0(ref='runner' sandbox='allow-same-origin')
192 |
193 | note
194 | p z = tixy
195 | br
196 | p Day 7 of #Codecember
197 | br
198 | p another port from tixy.land
199 | br
200 | p t time passed in seconds
201 | p i 1 -> 144
202 | p x, y 1 -> 12
203 | br
204 | p return value -> z axis of the boxes
205 | p null and error will make box invisible
206 | br
207 | p Math. can be omitted
208 | p 2 * t can be written as 2t
209 | p link is sharable
210 | br
211 | p 👇🏼 add your formulas!
212 |
213 |
214 |
221 |
--------------------------------------------------------------------------------
/src/pages/004.vue:
--------------------------------------------------------------------------------
1 |
47 |
48 |
49 | paper(@mouseup='mouseup' @touchend='mouseup')
50 | .box.fixed.overflow-hidden.bg-white(
51 | ref='box'
52 | :style='{top: px(boxY), left: px(boxX) }'
53 | @mousedown='mousedown'
54 | @touchstart='mousedown'
55 | )
56 | .inner.absolute.p-10(:style='{top: px(innerY), left: px(innerX), height: px(screenHeight), width: px(screenWidth)}')
57 | h3.font-bold.mt-4.mb-2 The standard Lorem Ipsum passage, used since the 1500s
58 | p "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
59 | h3.font-bold.mt-4.mb-2 Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
60 | p "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"
61 | h3.font-bold.mt-4.mb-2 1914 translation by H. Rackham
62 | p "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
63 | h3.font-bold.mt-4.mb-2 Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
64 | p "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."
65 | h3.font-bold.mt-4.mb-2 1914 translation by H. Rackham
66 | p "On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."
67 |
68 | note
69 | p drag box & window
70 | br
71 | p texts are from lipsum.com
72 |
73 |
--------------------------------------------------------------------------------
/public/037.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/005.vue:
--------------------------------------------------------------------------------
1 |
232 |
233 |
234 | paper
235 | .box.centered.overflow-hidden(@click='next' :class='{"rounded-full": rounded}')
236 | .canvas-wrapper
237 | canvas(ref='el')
238 | .box-description
239 | .flex.mt-2(:class='{"text-center": rounded, "flex-col": rounded}')
240 | p.op50 (t,r,th) =>
241 | input.flex-auto.outline-none(
242 | v-model='expression'
243 | :class='{ "text-center": rounded, "ml-3": !rounded }'
244 | ref='input'
245 | maxlength='32'
246 | autocomplete='false'
247 | spellcheck='false'
248 | )
249 | p.op50(:class='{"opacity-0": !author, "text-center": rounded, "mt-4": rounded}') by @{{author}}
250 | iframe.none.h-0(ref='runner' sandbox='allow-same-origin')
251 |
252 | note
253 | p.font-bold.mb-1 polar = (t,r,th)
254 | p inspired by tixy.land but in polar coordinates
255 | br
256 | pre t - seconds passed
257 | pre r - radial (-1 ~ 1)
258 | pre th - angular θ (-1 ~ 1)
259 | br
260 | p return value should be in -1 to 1
261 | p 0 -> black / 1 -> A / -1 -> B
262 | p color A & B will be picked randomly
263 | br
264 | p `Math.` can be omitted
265 | p `2 * t` can be written as `2t`
266 | p link is sharable
267 | br
268 | p(@click='recolor') c - change colors
269 | p(@click='f.start') r - reset `t`
270 | p(@click='toggleShape') s - canvas shape
271 |
272 |
273 |
282 |
--------------------------------------------------------------------------------