Compare commits

...

69 Commits

Author SHA1 Message Date
mwinter bd9fa9cf65 fixing minor sorting bug in talks 3 months ago
mwinter 206575f0ca manual manip of upcoming 6 months ago
mwinter 2ccdfb0047 flipping on upcoming - need to make that automatic 7 months ago
mwinter d0eb84d412 updating current date - ned to make automatic 7 months ago
mwinter 59a810a55c removing hdp site link 12 months ago
mwinter 8eb389cb43 fixing map link 1 year ago
mwinter 4af8008333 adding lichthof map 1 year ago
mwinter 082aa740cc adding exhibition poster to exhibition site 1 year ago
mwinter 47e8212af9 adding exhibition poster to hdp site 1 year ago
mwinter 4cf39815c8 updating hdp km28 donations 1 year ago
mwinter 1fbbb9a66e changing to eventbrite for hdp 1 year ago
mwinter 553eea69dd more hdp tweaks 1 year ago
mwinter 2258b1354c adding some text about the scuplture to hdp subsite 1 year ago
mwinter f8ed27a884 adding mathplus logo 1 year ago
mwinter ceebaa9cbe adding hdp link on home page for now 1 year ago
mwinter cdcfdb11c0 adding press/contact page to hdp site 1 year ago
mwinter 14bf6e1b4d updating upcoming date limit 1 year ago
mwinter b112e5f178 making text on hdp site selectable 1 year ago
mwinter 92dc35271f updating hdp site 1 year ago
mwinter 3ee0b7cdb5 updating hdp site 1 year ago
mwinter 386a404b3b updating date 1 year ago
mwinter d226a2f3fe hdp page update based on Gaetan suggestions 1 year ago
mwinter eb96142b11 hdp page update based on Gaetan suggestions 1 year ago
mwinter a0d4b61993 hdp page update based on Gaetan suggestions 1 year ago
mwinter 2ae47b27dd hdp page update based on Gaetan suggestions 1 year ago
mwinter fb4fb18894 hdp page update based on Gaetan suggestions 1 year ago
mwinter 41cf5daa28 hdp page update based on Gaetan suggestions 1 year ago
mwinter 2e583339a7 hdp page update based on Gaetan suggestions 1 year ago
mwinter ffc5653186 updating hdp page 1 year ago
mwinter 149e398b5b unfortunately back to static on upcoming date 1 year ago
mwinter 0e42aef3da upcoming events based on dynamic date 1 year ago
mwinter 25e3ba69d5 tweaks to hdp description 1 year ago
mwinter 4be1409514 incorporating suggestions 1 year ago
mwinter 31235cea67 fixing mobile fail 1 year ago
mwinter ad1dd4044e event slider and hdp page 1 year ago
Michael Winter f17ccd3094 trying to make starting autimatically work 1 year ago
Michael Winter 0c1b9bd52a adding handling for hdp in legacy site for works list 1 year ago
mwinter df5495fd60 fixing ampersands 1 year ago
mwinter 4a60c31991 fixing typo in bibtex 1 year ago
mwinter 6eed3527b6 pub order correction for forthcoming 1 year ago
mwinter bf2ff1fbd7 fixing italics in bibtex entries 1 year ago
mwinter f36e672288 hopefully fixing italic problem 1 year ago
mwinter 43f374baaa fixing pub sort 1 year ago
mwinter c4d2ddc6b3 reversing pub sort 1 year ago
mwinter 1eac040262 sorting pubs by citation key 1 year ago
mwinter 5159eebaeb small tweaks based on recs 1 year ago
mwinter 113a8f70c2 hopefully solving footer problem 1 year ago
mwinter 1374ea18d6 mobile scaling (hopefully) 1 year ago
mwinter 7a3f47d610 clicking a score button now loads the soundcloud track if there is one 1 year ago
Michael Winter 0eb34a549e nginx change header for pdfs should now be working 1 year ago
Michael Winter 0b780adbc3 header change fail removal 1 year ago
mwinter 8dd1855399 buttons hopefully working on high res screens and pdf always having correct content type 1 year ago
Michael Winter 697267f3b0 fixing typo and pushing from prod 1 year ago
mwinter 91b0441759 ready for launch with titles and routes 1 year ago
mwinter 02c93b1b5b obfuscated mail link and dockerfile actually working from scratch 1 year ago
mwinter d52bf602f5 images page works and adding title 1 year ago
mwinter 7b4f8a9b3f more work towards final deployment 1 year ago
mwinter a3a64a5913 more final tweaks in prep for deployment 1 year ago
mwinter 6d1b0b7c9c several fixes and initial preparation for docker deployment with legacy support 1 year ago
mwinter 4293f44262 working with deploy options 1 year ago
mwinter a822753cb3 about page added 1 year ago
mwinter e823d99bcd finished works page for the most part and started on events page 1 year ago
mwinter 540e66a39b modal implemented more efficiently now 1 year ago
mwinter e432d9ac7e analytics and sliders working 1 year ago
mwinter bd6efb24b6 modal with vimeo player 1 year ago
mwinter 0511ab89cd added pinia for stores and buttons coming alive 1 year ago
mwinter ad4c66fc6a buttons are now components 1 year ago
mwinter 548733be82 major dev on nuxt 1 year ago
mwinter 741171a221 slow transition to nuxt 1 year ago

2
.gitignore vendored

@ -7,3 +7,5 @@ nginx/conf.d/default.conf
nextcloud/
gitea/
.env
portfolio-nuxt/.nuxt/
portfolio-nuxt/node_modules/

@ -60,11 +60,13 @@ services:
- ./portfolio/src:/src
environment:
- VIRTUAL_HOST=${DOMAIN},www.${DOMAIN}
- VIRTUAL_PATH=/
#- VIRTUAL_DEST=/
#- VIRTUAL_PATH=/
# For subdirectory baseURL needs to be set in app.js for static files and routes
- VIRTUAL_PATH=/legacy
- VIRTUAL_DEST=/legacy
- VIRTUAL_PORT=3000
- LETSENCRYPT_HOST=${DOMAIN},www.${DOMAIN},gitea.${DOMAIN} #this last one is for legacy support
- LETSENCRYPT_EMAIL=${EMAIL}
#- LETSENCRYPT_HOST=${DOMAIN},www.${DOMAIN},gitea.${DOMAIN} #this last one is for legacy support
#- LETSENCRYPT_EMAIL=${EMAIL}
ports:
- "3000:3000"
restart: always
@ -76,6 +78,39 @@ services:
#labels:
# com.github.nginx-proxy.nginx-proxy.keepalive: "64"
portfolio-nuxt:
# NOTE: This is the rewrite of the frontend
# NOTE: The build process for nuxt seems to require that sharp be reinstalled in the .output folder
container_name: portfolio-nuxt
build: ./portfolio-nuxt
# To rebuild the site and the server run this
command: bash -c "npm run build && node .output/server/index.mjs"
# To just start the server run this
#command: bash -c "node .output/server/index.mjs"
# To start the server in dev mode
#command: bash -c "npm run dev -o"
volumes:
- portfolio-nuxt:/src/node_modules
- ./portfolio-nuxt:/src
environment:
- VIRTUAL_HOST=${DOMAIN},www.${DOMAIN}
- VIRTUAL_PATH=/
#- VIRTUAL_DEST=/dev
# For subdirectory baseURL needs to be set in nuxt config
#- VIRTUAL_PATH=/dev
#- VIRTUAL_DEST=/dev
- VIRTUAL_PORT=5000
- LETSENCRYPT_HOST=${DOMAIN},www.${DOMAIN},gitea.${DOMAIN} #this last one is for legacy support
- LETSENCRYPT_EMAIL=${EMAIL}
ports:
- "5000:5000"
restart: always
depends_on:
- restheart
- nginx-proxy
#labels:
# com.github.nginx-proxy.nginx-proxy.keepalive: "64"
mongo:
container_name: mongo
# using mongo4 or mongo5 as opposed to mongo:6 for server status in mongo-express and because of bugs
@ -349,3 +384,4 @@ volumes:
#nextcloud:
acme:
portfolio:
portfolio-nuxt:

@ -9,6 +9,14 @@ location ^~ /.well-known/acme-challenge/ {
}
## End of configuration add by letsencrypt container
# This is to set the content type to prevent downloading until I actually implement a proper pdf viewer
location ~ ^/api/(scores|pubs)(.*)/binary$ {
proxy_pass http://unboundedpress.org-357322ae39f93f572e23cd9edd3307e2ac5a321f;
# types { } default_type application/pdf;
proxy_hide_header Content-Type;
add_header Content-Type "application/pdf";
}
# The following are all for collabora routing

@ -0,0 +1,11 @@
node_modules
*.log*
.nuxt
.nitro
.cache
.output
.env
dist
.DS_Store
.fleet
.idea

@ -0,0 +1,2 @@
shamefully-hoist=true
strict-peer-dependencies=false

@ -0,0 +1,17 @@
FROM node:18-alpine
WORKDIR /src
COPY package*.json ./
COPY . .
RUN apk add bash
RUN npm install
ENV NITRO_HOST=0.0.0.0
ENV NITRO_PORT=5000
EXPOSE 5000
# ENTRYPOINT ["npm", "run", "build", "node", ".output/server/index.mjs"]

@ -0,0 +1,25 @@
<template>
<div class="bg-white min-w-[800px] min-h-[80vh]">
<NuxtLayout>
<NuxtPage/>
</NuxtLayout>
</div>
</template>
<script setup>
useHead({
titleTemplate: 'Michael Winter'
})
</script>
<style>
.page-enter-active,
.page-leave-active {
transition: all 0.2s;
}
.page-enter-from,
.page-leave-to {
opacity: 0;
filter: blur(1rem);
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

@ -0,0 +1,313 @@
<script>
export default {
name: 'CollapseTransition',
props: {
name: {
type: String,
required: false,
default: 'collapse',
},
dimension: {
type: String,
required: false,
default: 'height',
validator: (value) => {
return ['height', 'width'].includes(value)
},
},
duration: {
type: Number,
required: false,
default: 300,
},
easing: {
type: String,
required: false,
default: 'ease-in-out',
},
},
emits: ['before-appear', 'appear', 'after-appear', 'appear-cancelled', 'before-enter', 'enter', 'after-enter', 'enter-cancelled', 'before-leave', 'leave', 'after-leave', 'leave-cancelled'],
data() {
return {
cachedStyles: null,
}
},
computed: {
transition() {
const transitions = []
Object.keys(this.cachedStyles).forEach((key) => {
transitions.push(
`${this.convertToCssProperty(key)} ${this.duration}ms ${this.easing}`,
)
})
return transitions.join(', ')
},
},
watch: {
dimension() {
this.clearCachedDimensions()
},
},
methods: {
beforeAppear(el) {
// Emit the event to the parent
this.$emit('before-appear', el)
},
appear(el) {
// Emit the event to the parent
this.$emit('appear', el)
},
afterAppear(el) {
// Emit the event to the parent
this.$emit('after-appear', el)
},
appearCancelled(el) {
// Emit the event to the parent
this.$emit('appear-cancelled', el)
},
beforeEnter(el) {
// Emit the event to the parent
this.$emit('before-enter', el)
},
enter(el, done) {
// Because width and height may be 'auto',
// first detect and cache the dimensions
this.detectAndCacheDimensions(el)
// The order of applying styles is important:
// - 1. Set styles for state before transition
// - 2. Force repaint
// - 3. Add transition style
// - 4. Set styles for state after transition
// If the order is not right and you open any 2nd level submenu
// for the first time, the transition will not work.
this.setClosedDimensions(el)
this.hideOverflow(el)
this.forceRepaint(el)
this.setTransition(el)
this.setOpenedDimensions(el)
// Emit the event to the parent
this.$emit('enter', el, done)
// Call done() when the transition ends
// to trigger the @after-enter event.
setTimeout(done, this.duration)
},
afterEnter(el) {
// Clean up inline styles
this.unsetOverflow(el)
this.unsetTransition(el)
this.unsetDimensions(el)
this.clearCachedDimensions()
// Emit the event to the parent
this.$emit('after-enter', el)
},
enterCancelled(el) {
// Emit the event to the parent
this.$emit('enter-cancelled', el)
},
beforeLeave(el) {
// Emit the event to the parent
this.$emit('before-leave', el)
},
leave(el, done) {
// For some reason, @leave triggered when starting
// from open state on page load. So for safety,
// check if the dimensions have been cached.
this.detectAndCacheDimensions(el)
// The order of applying styles is less important
// than in the enter phase, as long as we repaint
// before setting the closed dimensions.
// But it is probably best to use the same
// order as the enter phase.
this.setOpenedDimensions(el)
this.hideOverflow(el)
this.forceRepaint(el)
this.setTransition(el)
this.setClosedDimensions(el)
// Emit the event to the parent
this.$emit('leave', el, done)
// Call done() when the transition ends
// to trigger the @after-leave event.
// This will also cause v-show
// to reapply 'display: none'.
setTimeout(done, this.duration)
},
afterLeave(el) {
// Clean up inline styles
this.unsetOverflow(el)
this.unsetTransition(el)
this.unsetDimensions(el)
this.clearCachedDimensions()
// Emit the event to the parent
this.$emit('after-leave', el)
},
leaveCancelled(el) {
// Emit the event to the parent
this.$emit('leave-cancelled', el)
},
detectAndCacheDimensions(el) {
// Cache actual dimensions
// only once to void invalid values when
// triggering during a transition
if (this.cachedStyles)
return
const visibility = el.style.visibility
const display = el.style.display
// Trick to get the width and
// height of a hidden element
el.style.visibility = 'hidden'
el.style.display = ''
this.cachedStyles = this.detectRelevantDimensions(el)
// Restore any original styling
el.style.visibility = visibility
el.style.display = display
},
clearCachedDimensions() {
this.cachedStyles = null
},
detectRelevantDimensions(el) {
// These properties will be transitioned
if (this.dimension === 'height') {
return {
height: `${el.offsetHeight}px`,
paddingTop:
el.style.paddingTop || this.getCssValue(el, 'padding-top'),
paddingBottom:
el.style.paddingBottom || this.getCssValue(el, 'padding-bottom'),
}
}
if (this.dimension === 'width') {
return {
width: `${el.offsetWidth}px`,
paddingLeft:
el.style.paddingLeft || this.getCssValue(el, 'padding-left'),
paddingRight:
el.style.paddingRight || this.getCssValue(el, 'padding-right'),
}
}
return {}
},
setTransition(el) {
el.style.transition = this.transition
},
unsetTransition(el) {
el.style.transition = ''
},
hideOverflow(el) {
el.style.overflow = 'hidden'
},
unsetOverflow(el) {
el.style.overflow = ''
},
setClosedDimensions(el) {
Object.keys(this.cachedStyles).forEach((key) => {
el.style[key] = '0'
})
},
setOpenedDimensions(el) {
Object.keys(this.cachedStyles).forEach((key) => {
el.style[key] = this.cachedStyles[key]
})
},
unsetDimensions(el) {
Object.keys(this.cachedStyles).forEach((key) => {
el.style[key] = ''
})
},
forceRepaint(el) {
// Force repaint to make sure the animation is triggered correctly.
// Thanks: https://markus.oberlehner.net/blog/transition-to-height-auto-with-vue/
// eslint-disable-next-line no-unused-expressions
getComputedStyle(el)[this.dimension]
},
getCssValue(el, style) {
return getComputedStyle(el, null).getPropertyValue(style)
},
convertToCssProperty(style) {
// Example: convert 'paddingTop' to 'padding-top'
// Thanks: https://gist.github.com/tan-yuki/3450323
const upperChars = style.match(/([A-Z])/g)
if (!upperChars)
return style
for (let i = 0, n = upperChars.length; i < n; i++) {
style = style.replace(
new RegExp(upperChars[i]),
`-${upperChars[i].toLowerCase()}`,
)
}
if (style.slice(0, 1) === '-')
style = style.slice(1)
return style
},
},
}
</script>
<template>
<transition
:name="name"
@before-appear="beforeAppear"
@appear="appear"
@after-appear="afterAppear"
@appear-cancelled="appearCancelled"
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
@before-leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@leave-cancelled="leaveCancelled"
>
<slot />
</transition>
</template>

@ -0,0 +1,25 @@
import type { Story } from '@storybook/vue3'
import Collapsible from './Collapsible.vue'
export default {
title: 'Components/Collapsible',
component: Collapsible,
args: {
modelValue: false,
title: 'Item',
content: 'lorem ipsum dolor sit amet',
},
}
const Template: Story = (args, { argTypes }) => ({
components: { Collapsible },
setup() {
return { args, argTypes }
},
template: `
<Collapsible v-bind="args"/>
`,
})
export const Default = Template.bind({})
Default.args = {}

@ -0,0 +1,91 @@
<script lang="ts" setup>
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/vue'
import { ref, toRefs, watch } from 'vue'
import CollapseTransition from './CollapseTransition.vue'
import Modal from '../Modal/Modal.vue';
const props = withDefaults(
defineProps<{
modelValue?: boolean
title: string
content?: string
classes?: {
wrapper?: string
button?: string
title?: string
panel?: string
}
}>(),
{
modelValue: false,
},
)
const emit = defineEmits([
'update:modelValue',
'change',
'toggle',
'open',
'close',
])
const { modelValue } = toRefs(props)
const isOpen = ref(modelValue.value)
watch(modelValue, (val) => {
isOpen.value = val
})
watch(isOpen, (val) => {
emit('update:modelValue', val)
emit('change', val)
if (val)
emit('open')
else
emit('close')
})
const toggle = () => {
emit('toggle')
isOpen.value = !isOpen.value
}
</script>
<template>
<Disclosure v-slot="{ open }" as="div">
<DisclosureButton
class="
flex
items-center
justify-between
w-full
text-left
rounded-lg
focus:outline-none
focus-visible:ring
focus-visible:ring-blue-50
focus-visible:ring-opacity-75
"
:class="classes?.button"
type="button"
@click="toggle"
>
<div class="inline-flex w-full">
<Icon
name="heroicons:chevron-down"
:class="isOpen ? 'transform rotate-180' : ''"
class="w-5 h-5"
/>
<slot name="title"></slot>
</div>
</DisclosureButton>
<CollapseTransition>
<div v-show="isOpen">
<DisclosurePanel static class="pb-2 text-15" :class="classes?.panel">
<slot name="content"></slot>
</DisclosurePanel>
</div>
</CollapseTransition>
</Disclosure>
</template>

@ -0,0 +1,38 @@
import type { Story } from '@storybook/vue3'
import CollapsibleGroup from './CollapsibleGroup.vue'
const genItems = (length = 5): any[] =>
Array.from({ length }, (_, v) => ({
title: `Item ${v + 1}`,
content: `lorem ipsum ${v + 1}`,
}))
const items = genItems(5)
export default {
title: 'Components/CollapsibleGroup',
component: CollapsibleGroup,
args: {
modelValue: false,
accordion: false,
items,
},
}
const Template: Story = (args, { argTypes }) => ({
components: { CollapsibleGroup },
setup() {
return { args, argTypes }
},
template: `
<CollapsibleGroup v-bind="args"/>
`,
})
export const Default = Template.bind({})
Default.args = {}
export const Accordion = Template.bind({})
Accordion.args = {
accordion: true,
}

@ -0,0 +1,55 @@
<script lang="ts" setup>
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/vue'
import { ref, toRefs, watch } from 'vue'
import Icon from '../Icon/index.vue'
import Collapsible from './Collapsible.vue'
interface CollapsibleItem {
title: string
content: string
isOpen?: boolean
}
const props
= defineProps<{
items?: CollapsibleItem[]
classes?: {
wrapper?: string
button?: string
title?: string
panel?: string
}
accordion?: boolean
}>()
const { items } = toRefs(props)
const children = ref(props.items)
watch(items, (val) => {
children.value = val
})
const onToggle = (item: CollapsibleItem) => {
if (props.accordion) {
children.value.forEach((child) => {
child.isOpen = false
})
item.isOpen = true
}
}
</script>
<template>
<div class="w-full p-2" :class="classes?.wrapper">
<slot>
<Collapsible
v-for="(item, idx) in children"
:key="idx"
v-bind="item"
v-model="item.isOpen"
@toggle="onToggle(item)"
/>
</slot>
</div>
</template>

@ -0,0 +1,61 @@
<template>
<Swiper
:autoHeight="true"
:loop="true"
:spaceBetween="30"
:centeredSlides="true"
:autoplay="{
delay: 6000,
disableOnInteraction: false,
pauseOnMouseEnter: true
}"
:effect="'fade'"
:fadeEffect="{
crossFade: true
}"
:pagination="{
clickable: true,
}"
:style="{
'--swiper-navigation-color': 'rgb(71 85 105)',
'--swiper-pagination-color': 'rgb(71 85 105)',
'--swiper-pagination-bottom': '0%'
}"
:modules="[SwiperAutoplay, SwiperPagination, SwiperNavigation, SwiperEffectFade]"
>
<SwiperSlide v-for="(item, index) in upcoming_events" class="bg-zinc-100 h-full">
<div class="gap-1 w-[100%] mt-1 mb-1 text-sm h-full">
<div>
{{ item.formatted_date }}: {{item.venue.city}}, {{item.venue.state}}
<div class="text-[#7F7F7F]">
{{ item.venue.name }}
</div>
</div>
</div>
<!-- Comment
<div v-for="performance in item.program">
<div class="italic text-sm ml-16 pt-1">{{performance.work}}</div>
<div v-if="performance.ensemble" class="ml-20">
{{ performance.ensemble }}
</div>
<div v-for="performer in performance.performers" class="ml-20">
{{ performer.name }} -
<span v-for="(instrument, index) in performer.instrument_tags">
<span v-if="index !== 0">, </span>
{{ instrument }}
</span>
</div>
</div>
-->
</SwiperSlide>
</Swiper>
</template>
<script>
export default {
props: ['upcoming_events']
}
</script>

@ -0,0 +1,54 @@
<template>
<div class="inline-flex p-1 min-w-[25px]">
<div v-show="visible" class="bg-black rounded-full text-xs inline-flex" >
<NuxtLink @click.native="audioPlayerStore.setSoundCloudTrackID(work.soundcloud_trackid)" v-if="type === 'score'" class="inline-flex p-1" :to="link">
<Icon name="ion:book-sharp" color="white" />
</NuxtLink>
<NuxtLink v-else-if="type === 'document'" class="inline-flex p-1" :to="link">
<Icon name="ion:book-sharp" color="white" />
</NuxtLink>
<NuxtLink v-else-if="type === 'buy'" class="inline-flex p-1" :to="link">
<Icon name="bxs:purchase-tag" color="white" />
</NuxtLink>
<NuxtLink v-else-if="type === 'email'" class="inline-flex p-1" :to="link">
<Icon name="ic:baseline-email" color="white" />
</NuxtLink>
<NuxtLink v-else-if="type === 'discogs'" class="inline-flex p-1" :to="link">
<Icon name="simple-icons:discogs" color="white" />
</NuxtLink>
<button @click="audioPlayerStore.setSoundCloudTrackID(work.soundcloud_trackid)" v-else-if="type === 'audio'" class="inline-flex p-1">
<Icon name="wpf:speaker" color="white" />
</button>
<button @click="modalStore.setModalProps('video', 'aspect-video', true, '', '', work.vimeo_trackid)" v-else-if="type === 'video'" class="inline-flex p-1">
<Icon name="fluent:video-48-filled" color="white" />
</button>
<button @click="modalStore.setModalProps('image', 'aspect-auto', true, 'images', work.gallery, '')" v-else="type === 'image'" class="inline-flex p-1">
<Icon name="mdi:camera" color="white" />
</button>
</div>
</div>
</template>
<script setup>
import { useAudioPlayerStore } from "@/stores/AudioPlayerStore"
import { useModalStore } from "@/stores/ModalStore"
const audioPlayerStore = useAudioPlayerStore()
const modalStore = useModalStore()
</script>
<script>
export default {
props: ['type', 'work', 'visible', 'link']
}
</script>

@ -0,0 +1,37 @@
<template>
<Swiper
:autoHeight="true"
:loop="true"
:spaceBetween="30"
:centeredSlides="true"
:autoplay="{
delay: 4000,
disableOnInteraction: false,
pauseOnMouseEnter: true
}"
:pagination="{
clickable: true,
}"
:navigation="true"
:style="{
'--swiper-navigation-color': 'rgb(71 85 105)',
'--swiper-pagination-color': 'rgb(71 85 105)',
'--swiper-pagination-bottom': 'auto',
'--swiper-pagination-top': '1rem',
'--swiper-navigation-top-offset': '5rem'
}"
:modules="[SwiperAutoplay, SwiperPagination, SwiperNavigation]"
>
<SwiperSlide v-for="image in gallery" class="p-10 bg-zinc-100">
<nuxt-img :src="'https://unboundedpress.org/api/' + bucket + '.files/' + image.image_id + '/binary'"
quality="50"/>
</SwiperSlide>
</Swiper>
</template>
<script>
export default {
props: ['gallery', 'bucket']
}
</script>

@ -0,0 +1,3 @@
<template>
<div class="fixed inset-0 bg-black/50 z-15 transition duration-300" />
</template>

@ -0,0 +1,110 @@
<script setup lang="ts">
import { ref } from 'vue'
import {
Dialog,
DialogPanel,
TransitionChild,
TransitionRoot,
} from '@headlessui/vue'
const props = withDefaults(
defineProps<{
modelValue?: boolean
persistent?: boolean
fullscreen?: boolean
}>(),
{
modelValue: false,
persistent: false,
fullscreen: false,
},
)
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void
}>()
const { modelValue } = toRefs(props)
const isOpen = ref(modelValue.value)
watch(modelValue, (value) => {
isOpen.value = value
})
function closeModal() {
isOpen.value = false
}
function openModal() {
isOpen.value = true
}
function onModalClose() {
if (!props.persistent)
closeModal()
}
watch(isOpen, (value) => {
emit('update:modelValue', value)
})
const api = {
isOpen,
open: openModal,
close: closeModal,
}
provide('modal', api)
</script>
<template>
<slot name="activator" :open="openModal" :on="{ click: openModal }" />
<TransitionRoot appear :show="isOpen" as="template">
<Dialog as="div" class="relative z-20" @close="onModalClose">
<TransitionChild
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0"
enter-to="opacity-100"
leave="duration-200 ease-in"
leave-from="opacity-100"
leave-to="opacity-0"
>
<div class="fixed inset-0 bg-black bg-opacity-25" />
</TransitionChild>
<div class="fixed inset-0 overflow-y-auto">
<div
class="flex min-h-full items-center justify-center text-center"
:class="{
'p-4': !fullscreen,
}"
>
<TransitionChild
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0 scale-95"
enter-to="opacity-100 scale-100"
leave="duration-200 ease-in"
leave-from="opacity-100 scale-100"
leave-to="opacity-0 scale-95"
>
<DialogPanel
class="w-full transform overflow-hidden bg-white text-left align-middle shadow-xl transition-all"
:class="{
'h-screen': fullscreen,
'max-w-[85vw] rounded-lg': !fullscreen,
}"
>
<slot />
</DialogPanel>
</TransitionChild>
</div>
</div>
</Dialog>
</TransitionRoot>
</template>

@ -0,0 +1,9 @@
<script setup lang="ts">
import { DialogDescription } from '@headlessui/vue'
</script>
<template>
<DialogDescription class="px-4 py-3 text-sm text-gray-800">
<slot />
</DialogDescription>
</template>

@ -0,0 +1,9 @@
<script setup lang="ts">
// import { ref } from 'vue'
</script>
<template>
<div class="px-4 py-3">
<slot />
</div>
</template>

@ -0,0 +1,34 @@
<script setup lang="ts">
import { DialogTitle } from '@headlessui/vue'
interface Props {
dismissable?: boolean
titleClass?: string
}
defineProps<Props>()
const api = inject('modal')
</script>
<template>
<DialogTitle
as="div"
class="flex gap-2 justify-between items-center px-4 pt-3"
>
<h3
class="text-lg font-medium leading-6 text-gray-900"
:class="titleClass"
>
<slot />
</h3>
<slot v-if="dismissable" name="dismissable">
<button
class="text-2xl text-gray-500 appearance-none px-2 -mr-2"
@click="api.close"
>
&times;
</button>
</slot>
</DialogTitle>
</template>

@ -0,0 +1,79 @@
<template>
<div class="grid grid-cols-[63%,35%] w-full font-thin sticky top-0 bg-white p-2 z-20">
<div>
<div class="text-5xl p-2"> <NuxtLink to='/'>michael winter</NuxtLink></div>
<div class="inline-flex text-2xl ml-4">
<NuxtLink class="px-3" to='/'>works</NuxtLink>
<NuxtLink class="px-3" to='/events'>events</NuxtLink>
<NuxtLink class="px-3" to='/about'>about</NuxtLink>
<NuxtLink class="px-3" to='https://unboundedpress.org/code'>code</NuxtLink>
<NuxtLink class="px-3 block" to='https://unboundedpress.org/legacy'>legacy</NuxtLink>
</div>
<!-- hdp link while active -->
<!------
<div class="inline-flex text-2xl ml-4 font-bold">
<NuxtLink class="px-3" to='/a_history_of_the_domino_problem'>A HISTORY OF THE DOMINO PROBLEM | 17.11 - 01.12.2023 </NuxtLink>
</div>
--->
</div>
<!-- TODO: this needs to be automatically flipped off when there are no upcoming events-->
<!------
<div class="px-1 bg-zinc-100 rounded-lg text-center">
<div class="text-sm">upcoming events</div>
<EventSlider :upcoming_events="upcoming_events" class="max-w-[95%] min-h-[80%]"></EventSlider>
</div>
-->
</div>
<slot /> <!-- required here only -->
<div class="fixed bottom-0 bg-white p-2 w-full flex justify-center z-20">
<iframe width="400rem" height="20px" scrolling="no" frameborder="no" allow="autoplay" v-if="audioPlayerStore.soundcloud_trackid !== 'undefined'"
:src="'https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/' + audioPlayerStore.soundcloud_trackid + '&inverse=false&auto_play=true&show_user=false'"></iframe>
</div>
<Modal v-model="modalStore.isOpen">
<ModalBody :class="modalStore.aspect">
<ImageSlider v-if="modalStore.type === 'image'" :bucket="modalStore.bucket" :gallery="modalStore.gallery"></ImageSlider>
<iframe v-if="modalStore.type === 'video'" :src="'https://player.vimeo.com/video/' + modalStore.vimeo_trackid" width="100%" height="100%" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</ModalBody>
</Modal>
</template>
<script setup>
import { useAudioPlayerStore } from "@/stores/AudioPlayerStore"
import { useModalStore } from "@/stores/ModalStore"
const audioPlayerStore = useAudioPlayerStore()
const modalStore = useModalStore()
const route = useRoute()
if(route.params.files == 'scores') {
const { data: work } = await useFetch('https://unboundedpress.org/api/works?filter={"score":"' + route.params.filename + '"}', {
transform: (work) => {
if(work[0].soundcloud_trackid){
audioPlayerStore.setSoundCloudTrackID(work[0].soundcloud_trackid)
} else {
audioPlayerStore.clearSoundCloudTrackID()
}
return work[0]
}
})
}
//const today = Date.now(); //annoying this does not work
const today = 1715247305793;
const { data: upcoming_events } = await useFetch("https://unboundedpress.org/api/events?filter={'start_date':{'$gte':{'$date':" + today + "}}}", {
transform: (upcoming_events) => {
for (const event of upcoming_events) {
let date = new Date(event.start_date.$date)
event.formatted_date = ("0" + (date.getMonth() + 1)).slice(-2) + "." + ("0" + date.getDate()).slice(-2) + "." + date.getFullYear()
}
return upcoming_events.sort((a,b) => a.start_date.$date - b.start_date.$date)
}
})
</script>

@ -0,0 +1,35 @@
//import { defineNuxtConfig } from 'nuxt3'
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
modules: ['@nuxtjs/tailwindcss', '@nuxt/image', 'nuxt-icon', '@pinia/nuxt', 'nuxt-headlessui', 'nuxt-swiper'],
extends: ['nuxt-umami'],
image: {
domains: ['unboundedpress.org']
},
app: {
//baseURL: "/dev/",
pageTransition: { name: 'page', mode: 'out-in' },
head: {
viewport: 'width=device-width'
},
},
appConfig: {
umami: {
id: '51f4f246-9c2e-4a86-9ffb-7a7967d9013d',
host: 'https://analytics.umami.is/',
version: 2
},
},
routeRules: {
'/cv': { redirect: '/legacy/cv' },
'/works_list': { redirect: '/legacy/works_list' },
'/hdp': { redirect: '/a_history_of_the_domino_problem' },
},
nitro: {
prerender: { crawlLinks: true}
},
experimental: {
payloadExtraction: true
}
})

File diff suppressed because it is too large Load Diff

@ -0,0 +1,26 @@
{
"name": "nuxt-app",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"devDependencies": {
"@nuxt/image": "^1.0.0-rc.1",
"@nuxtjs/tailwindcss": "^6.7.0",
"@types/node": "^18",
"nuxt-headlessui": "^1.1.4",
"nuxt-icon": "^0.4.1"
},
"dependencies": {
"nuxt": "^3.6.0",
"@pinia/nuxt": "^0.4.11",
"nuxt-swiper": "^1.1.0",
"nuxt-umami": "^2.4.2",
"pinia": "^2.1.3",
"sharp": "^0.32.1"
}
}

@ -0,0 +1,27 @@
<template>
<div class="flex min-h-full items-center justify-center text-center">
<embed v-if="route.params.filename.split('.').pop()==='pdf'" :src="'https://unboundedpress.org/api/' + route.params.files + '.files/' + file_metadata._id.$oid + '/binary'" class="w-[85%] h-[88vh]"/>
<nuxt-img v-else-if="route.params.filename.split('.').pop()==='jpg'" :src="'https://unboundedpress.org/api/' + route.params.files + '.files/' + file_metadata._id.$oid + '/binary'" class="w-[85%]"/>
</div>
</template>
<script setup>
import { useAudioPlayerStore } from "@/stores/AudioPlayerStore"
const audioPlayerStore = useAudioPlayerStore()
const route = useRoute()
const { data: file_metadata } = await useFetch('https://unboundedpress.org/api/' + route.params.files + '.files?filter={"filename":"' + route.params.filename + '"}', {
//lazy: true,
//server: false,
transform: (file_metadata) => {
return file_metadata[0]
}
})
useHead({
titleTemplate: 'Michael Winter - Files - ' + route.params.filename
})
</script>

@ -0,0 +1,346 @@
<template>
<div class="bg-contain bg-no-repeat bg-center rounded-lg m-5 gap-10 bg-[#0A0A19] py-4 text-2xl text-white py-4 mb-10 overflow-hidden" :style="{ backgroundImage: `url(${image})`}">
<div class="rounded-lg w-full sticky top-[10px] grid grid-cols-[63%,35%]">
<div>
<div class="p-5 text-5xl font-bold">a history of the domino problem</div>
<div>
<div class="inline-flex text-2xl ml-4 mb-5">
<a href="#about" class="px-3">about</a>
<a href="#exhibition" class="px-3">exhibition</a>
<a href="#events" class="px-3">events</a>
<a href="#participants" class="px-3">participants</a>
</div>
<div class="inline-flex text-2xl ml-4 mb-5">
<a href="#media" class="px-3">media</a>
<a href="#contributors" class="px-3">contributors</a>
<a href="#resources" class="px-3">resources</a>
<a href="#contact" class="px-3">contact/press</a>
</div>
</div>
</div>
<div>
For the Lecture-Concert on 22 Nov 2023, Registration recommended. Sign up <NuxtLink class="text-2xl font-bold" to='https://www.eventbrite.de/e/a-history-of-the-domino-problem-lecture-concert-tickets-707700981687'>HERE</NuxtLink>.
</div>
</div>
<!---
<Swiper
:loop="true"
:spaceBetween="30"
:centeredSlides="true"
:pagination='{
clickable: true,
renderBullet: function (index, className) {
return "<span class=" + className + ">" + ["about", "exhibition", "events", "participants"][index] + "</span>";
}
}'
:navigation="false"
:style="{
'--swiper-pagination-color': 'rgb(255 255 255)',
'--swiper-pagination-bullet-horizontal-gap': '80px',
'--swiper-pagination-bullet-inactive-opacity': '0.8',
'--swiper-pagination-bullet-size': '0px',
'--swiper-pagination-bottom': 'auto',
'--swiper-pagination-top': '1rem',
'--swiper-pagination-margin-left': '0px',
}"
:hashNavigation="{
watchState: true,
}"
:modules="[SwiperAutoplay, SwiperPagination, SwiperNavigation, SwiperHashNavigation]"
class="max-w-[95vw]"
>
--->
<Swiper
:loop="true"
:spaceBetween="30"
:centeredSlides="true"
:pagination="false"
:navigation="false"
:hashNavigation="{
watchState: true,
}"
:modules="[SwiperAutoplay, SwiperPagination, SwiperNavigation, SwiperHashNavigation]"
>
<SwiperSlide data-hash="about" class="p-10 text-xl overflow-hidden">
<span class="swiper-no-swiping">
<div class="overflow-auto">
<p class="mb-5">
<span class="italic">a history of the domino problem</span> is a performance-installation that traces the history of an epistemological problem in mathematics about how things that one could never imagine fitting together, actually come together and unify in unexpected ways. The work comprises a set of musical compositions and a kinetic sculpture that sonify and visualize rare tilings (more commonly known as mosaics) constructed from dominoes. The dominoes in these tilings are similar yet slightly different than those used in the popular game of the same name. As opposed to rectangles divided into two regions with numbers between 1 and 6, they are squares where each of the 4 edges is assigned a number (typically represented by a corresponding color or alternatively, pattern) called <NuxtLink to='https://en.wikipedia.org/wiki/Wang_tile'>Wang tiles</NuxtLink>. Like in the game, the rule is that edges of adjacent dominoes in a tiling must match.
</p>
<p class="mb-5">
The tilings sonified and visualized in <span class="italic">a history of the domino problem</span> are rare because there is no systematic way to find them. This is due to the fact that they are <NuxtLink to='https://en.wikipedia.org/wiki/Aperiodic_tiling'><span class="italic">aperiodic</span></NuxtLink>. One can think of an aperiodic tiling as an infinite puzzle with a peculiar characteristic: given unlimited copies of dominoes with a finite set of color/pattern combinations for the edges, on can form a tiling that expands infinitely. However, in that solution, any repeating structure in the tiling will eventually be interrupted. This phenomenon is one of the most intriguing aspects of the work. As the music and the visuals are derived from the tilings, the resulting textures are always shifting ever so slightly.
</p>
<p>
The original Domino Problem asked if there exists an algorithm/computer program that, when given as input a finite set of dominoes with varying color combinations for the edges, can output a binary answer, `yes' or `no', whether or not copies of that set can form an infinite tiling. The problem was first posed by Hao Wang in 1961, who conjectured that the answer is positive and that such an algorithm does exist. The existence of aperiodic tilings would mean that such an algorithm <span class="italic">does not</span> exist. However, in 1964, his student, Robert Berger, proved him wrong by discovering an infinite, aperiodic tiling constructed with copies of a set of 20,426 dominoes. The resolution of Wang's original question led to new questions and mathematicians took on the challenge of finding the smallest set of dominoes that would construct an infinite aperiodic tiling. Over the past 60 years, this number has been continually reduced with the contributions of many different mathematicians until the most recent discovery of a set of 11 dominoes along with a proof that no smaller sets exist. It is a remarkable narrative/history of a particular epistemological problem that challenged a group of people not only to solve it, but to understand it to the extent possible.
</p>
</div>
</span>
</SwiperSlide>
<SwiperSlide data-hash="exhibition" class="p-10 text-xl overflow-hidden">
<span class="swiper-no-swiping">
<div class="overflow-auto">
<div class="mb-5 text-3xl italic font-bold">
a few thoughts on how things fit together...
</div>
<div class="mb-5">
(free entrance)
</div>
<br>
<div class="mb-5">
in collaboration with MAREIKE YIN-YEE LEE
</div>
<div class="mb-5">
Exhibition Opening - 17 Nov 2023 | 19 Uhr
</div>
<div class="mb-5">
Exhibition Closing - 01 Dec 2023 | 19 Uhr
</div>
<div class="mb-5">
Gallery Hours - Wednesday to Friday | 13 - 19 Uhr & Saturday | 12 - 18 Uhr
</div>
<div class="mb-5">
Lichthof Ost, HU Berlin Hauptgebäude, Campus Mitte, Unter den Linden 6 (U-Bahn Unter den Linden oder Museuminsel)
</div>
<div class="mb-5">
<NuxtLink class="px-3" to='https://unboundedpress.org/pubs/a_few_thoughts_exhibition_poster.pdf'><nuxt-img class="w-[500px]" src="/hdp_images/hdp_exhibition_poster_digital.jpeg"/></NuxtLink>
</div>
<div class="mb-5">
<NuxtLink class="px-3" to='https://unboundedpress.org/hdp_images/lichthof_ost_map.jpeg'><nuxt-img class="w-[500px]" src="/hdp_images/lichthof_ost_map.jpeg"/></NuxtLink>
</div>
<div class="mb-5">
<span class="font-bold">About the Exhibition</span>
<br>
<br>
The exhibition will feature individual and collaborative works by Michael Winter and Mareike Yin-Yee Lee in a constellation designed specifically for the Lichthof Ost exhibition room of the Humboldt University. The original kinetic sculpture Winter created to visualize the aperiodic tilings of the history of the domino problem will be juxtaposed with recent works by Yin-Yee Lee as well as collaboratively created realizations of the tilings. The works on display by Yin-Yee Lee will highlight selections from her Hidden Lakes and Missing Pieces series in which enigmatic outlines of lakes and various shapes encourage observers to perceive similarities and differences in form, pattern, and repetition between the pieces and to mentally fill in blank space. The collaborative realizations of the tilings will include prints generated by Winter with the aid of a computer that incorporate images and color schemes by Yin-Yee Lee as well as a floor mosaic of drawings on mirrors. The exhibition plays on the macro versus the micro, transformation, and how topologies of various color combinations, relationships between shapes and gradients reflect in space in order to illuminate "a few thoughts on how things fit together..."
</div>
<br>
<div class="mb-5">
<span class="font-bold">About the Kinetic Sculpture</span>
<br>
<br>
The kinetic sculpture displays the mosaics using visual cryptography. In visual cryptography, a message is encrypted by dividing the information of the message into two `shadow' images, which look completely random and independent of each other. The message is decrypted and revealed when the shadow images are combined/overlayed in a precise orientation. In the kinetic sculpture of a history of the domino problem, the shadow images are printed on photomasks, which are essentially high-resolution transparencies: quartz wafers with a chrome coating etched at a pixel size ranging from nano- to micrometers. A high-precision, motorized multiaxis stage aligns the finely printed shadow images to reveal the mosaics (along with 3 other images of poetic texts inspired by the history of the Domino Problem).
</div>
</div>
</span>
</SwiperSlide>
<SwiperSlide data-hash="events" class="p-10 text-xl overflow-hidden">
<span class="swiper-no-swiping">
<div class="overflow-auto">
<div class="mb-5">
<span class="font-bold">Exhibition Opening - 17 Nov 2023 | 19 Uhr</span>
<br>
Lichthof Ost, HU Berlin Hauptgebäude, Campus Mitte, Unter den Linden 6 (U-Bahn Unter den Linden oder Museuminsel)
</div>
<div class="mb-5">
<span class="font-bold">Exhibition Closing - 01 Dec 2023 | 19 Uhr</span>
<br>
Lichthof Ost, HU Berlin Hauptgebäude, Campus Mitte, Unter den Linden 6 (U-Bahn Unter den Linden oder Museuminsel)
</div>
<div class="mb-5">
<span class="font-bold">Public lecture + Concert (free entrance) - 22 Nov 2023 | 19:30 Uhr (doors open at 19:00 Uhr)</span>
<br>
with Prof. JARKKO KARI (Turku University), moderated by Prof. Dr. GAËTAN BOROT (HU Berlin)
<br>
the abstract of Prof. JARKKO KARI's Lecture is provided below
<br>
performance by KALI ENSEMBLE
<br>
Fritz-Reuter-Saal, HU Berlin Universitätsgebäude (am Hegelplatz), Dorotheenstraße 24 (U-Bahn Unter den Linden oder Museuminsel)
</div>
<div class="mb-5">
<span class="font-bold">Concert - 23 Nov 2023 | 20:30 Uhr (doors open at 20:00 Uhr)</span>
<br>
performance by KALI ENSEMBLE
<br>
<NuxtLink to='https://www.km28.de/'>KM28</NuxtLink>
<br>
Karl-Marx-Str. 28, 12043 Berlin (U-Bahn Karl-Marx-Platz)
<br>
(entry by donation, with proceeds going to the Kali Ensemble)
</div>
<br>
<div class="mb-5">
<br>
About the Public lecture
<br>
<span class="font-bold">From Wang Tiles to the Domino Problem: A Tale of Aperiodicity</span>
<br>
<br>
This presentation delves into the remarkable history of aperiodic tilings and the domino problem. Aperiodic tile sets refer to collections of tiles that can only tile the plane in a non-repeating, or non-periodic, manner. Such sets were not believed to exist until 1964 when R. Berger introduced the first aperiodic set consisting of an astonishing 20,426 Wang tiles. Over the years, ongoing research led to significant advancements, culminating in 2015 with the discovery of a mere 11 Wang tiles by E. Jeandel and M. Rao, alongside a computer-assisted proof of their minimality. Simultaneously, researchers found even smaller aperiodic sets composed of polygon-shaped tiles. Notably, Penrose's kite and dart tiles emerged as early examples, and most recently, a groundbreaking discovery was made - a solitary aperiodic tile known as the "hat" that can tile the plane exclusively in a non-periodic manner. Aperiodic tile sets are intimately connected with the domino problem that asserts how certain tile sets can tile the plane without us ever being able to establish their tiling nature with absolute certainty. Moreover, aperiodic tilings hold a distinct visual aesthetic allure. In today's musical presentation, their artistic appeal transcends the visual domain and extends into the realm of music.
<br>
-Jarkko Kari
</div>
</div>
</span>
</SwiperSlide>
<SwiperSlide data-hash="participants" class="p-10 text-xl overflow-hidden">
<span class="swiper-no-swiping">
<div class="max-h-[800px] overflow-auto">
<div class="mb-5 py-10">
<NuxtLink class="text-3xl font-bold" to='https://unboundedpress.org/'>Michael Winter - composer | sound artist</NuxtLink>
<div class="grid grid-cols-[20%,70%] p-5">
<nuxt-img src="/hdp_images/michael.jpg"/>
<div class="px-5">
<p class="mb-5">
My practice as a composer and sound artist is diverse, ranging from music created by digital and acoustic instruments to installations and kinetic sculptures. Each piece typically explores one simple process and often reflects various related interests of mine such as phenomenology, mathematics, epistemology, algorithmic information theory, and the history of science. To me, everything we experience is computable. Given this digital philosophy, I acknowledge even my most open works as algorithmic; and, while not always apparent on the surface of any given piece, the considerations of computability and epistemology are integral to my practice. I often reconcile epistemological limits with artistic practicality by considering and addressing the limits of computation from an artistic and experiential vantage point and by collaborating with other artists, mathematicians, and scientists in order to integrate objects, ideas, and texts from various domains as structural elements in my pieces. My work also aims to subvert discriminatory conventions and hierarchies by exploring alternative forms of presentation and interaction, often with minimal resources and low information.
</p>
<p>
My work has been presented at venues and festivals throughout the world such as REDCAT, in Los Angeles; the Ostrava Festival of New Music in the Czech Republic; Tsonami Arte Sonoro Festival in Valparaiso, Chile; the Huddersfield New Music Festival in the United Kingdom; and Umbral Sesiones at the Museo de Arte Contemporáneo in Oaxaca, Mexico. Recordings of my music have been released by XI Records, Another Timbre, New World Records, Edition Wandelweiser, Bahn Mi Verlag, Tsonami Records, and Pogus Productions. In 2008, I co-founded the wulf., a Los Angeles-based organization dedicated to experimental performance and art. From 2018 to 2019, I was a fellow / artist-in-residence at the Akademie Schloss Solitude in Stuttgart, Germany. I currently reside in Berlin.
</p>
</div>
</div>
</div>
<div class="mb-5 py-10">
<NuxtLink class="text-3xl font-bold" to='http://www.mareikelee.com/'>MAREIKE YIN-YEE LEE - visual artist</NuxtLink>
<div class="grid grid-cols-[20%,70%] p-5">
<nuxt-img src="/hdp_images/mareike.jpg"/>
<div class="px-5">
Mareike YinYee Lees multidisciplinary practice encompasses drawing, video, sculpture, found and made objects, printmaking, and artist books. Current works include installations, recordings and live performances produced in collaboration with musicians and composers with an emphasis on the relation between sight and sound. How we approach, perceive and respond to these form the basis of her recent works manifestations. Her immersive, site-specific installations explore the complex and tenuous nature of communication and how we experience space, drawing on gesture, sound, and memory to elicit responses that cannot be put into words. She redefines the architecture and temporality of the spaces in which she works. Lees work plays with the spaces between, across, and beyond, embracing the undefinable and subtle gradations, forging a language of colour, tone and space that seeks to articulate microcosms of daily life and sustained contemplation. Lee studied at Universität der Künste, Berlin, Germany; University of Toronto, Toronto, Canada; and Nova Scotia College of Art and Design, Nova Scotia, Canada, where she was awarded the Joseph Beuys Scholarship and the Canada Millennium Award of Excellence. Recent projects include exhibitions and performances at Kunsthaus Kule Berlin (2020), Kunstmuseum Kloster Unser Lieben Frauen Magdeburg (2019), Galerie Kunstpunkt Berlin (2018), Kunstbezirk Stuttgart, Kunst(zeug)haus Rapperswil- Jona Switzerland (2017), Kunsthaus Interlaken (2017), Neuer Kunstverein, Aschaffenburg (2016), and KW Institute for Contemporary Art, Berlin (2016).
</div>
</div>
</div>
<div class="mb-5 py-10">
<NuxtLink class="text-3xl font-bold" to='https://www.facebook.com/KaliEnsemble'>KALI - performing ensemble</NuxtLink>
<div class="grid grid-cols-[20%,70%] p-5">
<nuxt-img src="/hdp_images/kali.jpg"/>
<div class="px-5">
Kali is a new music ensemble based in the Hague. They primarily work with composers with whom they can collaborate and experiment over long periods. They aim to develop an artistic practice unique to their relationship with their collaborators. Over the past years, they have formed close and active relationships with several composers based in The Hague and abroad realizing many large-scale projects with great attention to detail.
</div>
</div>
</div>
<div class="mb-5 py-10">
<NuxtLink class="text-3xl font-bold" to='https://users.utu.fi/jkari/'>Jarkko Kari - mathematician | invited guest</NuxtLink>
<div class="grid grid-cols-[20%,70%] p-5">
<nuxt-img class="w-full" src="/hdp_images/jarkko.jpg"/>
<div class="px-5">
Jarkko Kari received his MSc and PhD degrees in mathematics from the University of Turku in Finland in 1986 and 1990, respectively. He then worked for the Academy of Finland, and for Iterated Systems Inc. and the University of Iowa in the USA. Since year 2000 he has been a professor of mathematics at the University of Turku. His research interests include automata theory and the theory of computation, with emphasis on cellular automata, tilings and symbolic dynamics. Jarkko Kari has supervised twelve PhD theses, published over one hundred peer reviewed research articles and edited twenty conference proceedings and special issues on these topics. He serves in the editorial boards of eight scientific journals, and is currently a co-editor-in-chief of the journal Natural Computing. Jarkko Kari is a member of the Finnish Academy of Science and Letters since 2014.
</div>
</div>
</div>
<div class="mb-5 py-10">
<NuxtLink class="text-3xl font-bold" to='https://www.mathematik.hu-berlin.de/de/forschung/forschungsgebiete/mathematische-physik/borot-mp-homepage'>Gaëtan Borot - mathematician | organizer | moderator</NuxtLink>
<div class="grid grid-cols-[20%,70%] p-5">
<nuxt-img class="w-full" src="/hdp_images/gaetan.jpg"/>
<div class="px-5">
Gaëtan Borot was trained at École Normale Supérieure (Paris) in theoretical physicist and progressively moved to pure mathematics. He received his PhD from Universite d'Orsay / CEA Saclay in 2011. After a postdoctorate in Geneva and a visiting scholarship at MIT, he worked as a Group Leader at the Max Planck Institute for Mathematics in Bonn. Since 2020, he holds a bridge professorship between the Institute of Mathematics and the Institute of Physics of the Humboldt University of Berlin. He has worked on enumerative geometry, combinatorics, random matrix theory and mathematical aspects of quantum field theory, and likes to investigate the unexpected relations between seemingly different problems. He is also interested in scientific outreach.
</div>
</div>
</div>
</div>
</span>
</SwiperSlide>
<SwiperSlide data-hash="media" class="p-20 text-xl overflow-hidden">
<div class="flex justify-center">
<iframe src="https://player.vimeo.com/video/375784136" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen ></iframe>
</div>
</SwiperSlide>
<SwiperSlide data-hash="contributors" class="p-10 text-xl overflow-hidden">
<div class="max-h-[calc(100vh-27rem)] overflow-auto">
<div class="grid grid-cols-5 p-5 items-center">
<NuxtLink class="px-3" to='https://www.hu-berlin.de/en'><nuxt-img class="w-[100px]" src="/hdp_images/hu_logo.png"/></NuxtLink>
<NuxtLink class="px-3" to='https://www.km28.de/'><nuxt-img class="w-[100px]" src="/hdp_images/km28_logo.png"/></NuxtLink>
<NuxtLink class="px-3" to='https://www.ims-chips.com/'><nuxt-img class="w-[250px]" src="/hdp_images/ims_chips_logo.png"/></NuxtLink>
<NuxtLink class="px-3" to='https://www.akademie-solitude.de/'><nuxt-img class="w-[100px]" src="/hdp_images/akademie_schloss_solitude_logo.png"/></NuxtLink>
<NuxtLink class="px-3" to='https://mathplus.de/'><nuxt-img class="w-[200px]" src="/hdp_images/mathplus_logo_gray.png"/></NuxtLink>
</div>
</div>
</SwiperSlide>
<SwiperSlide data-hash="resources" class="p-10 text-xl overflow-hidden">
<span class="swiper-no-swiping">
<div class="overflow-auto">
<div class="mb-5 text-2xl font-bold">
a few selected articles:
</div>
<div class="mb-5">
Hao Wang (1961), Proving theorems by pattern recognitionII, Bell System Technical Journal, Volume: 40, Issue: 1.
</div>
<div class="mb-5">
Robert Berger (1966), The undecidability of the domino problem, American Mathematical Society, Volume 1, 1966.
</div>
<div class="mb-5">
Jarkko Kari (1996), A small aperiodic set of Wang tiles, Discrete Mathematics, Volume 160.
</div>
<div class="mb-5">
Emmanuel Jeandel and Michael Rao, An aperiodic set of 11 Wang tiles, Advances in Combinatorics, Volume 1.
</div>
<br>
<div class="mb-5 text-2xl font-bold">
a definitive book on tilings and patterns:
</div>
<div class="mb-5">
Branko Grunbaum and G.C. Shephard, Tilings and Patterns, Dover Books (originally published 1986)
</div>
<br>
<div class="mb-5 text-2xl font-bold">
a few useful links:
</div>
<div class="mb-5">
<NuxtLink to='https://grahamshawcross.com/2012/10/12/aperiodic-tiling/'>https://grahamshawcross.com/2012/10/12/aperiodic-tiling/</NuxtLink>
</div>
<div class="mb-5">
<NuxtLink to='https://grahamshawcross.com/2012/10/12/wang-tiles-and-aperiodic-tiling/'>https://grahamshawcross.com/2012/10/12/wang-tiles-and-aperiodic-tiling/</NuxtLink>
</div>
<div class="mb-5">
<NuxtLink to='https://en.wikipedia.org/wiki/Wang_tile'>https://en.wikipedia.org/wiki/Wang_tile</NuxtLink>
</div>
<div class="mb-5">
<NuxtLink to='https://en.wikipedia.org/wiki/Aperiodic_tiling'>https://en.wikipedia.org/wiki/Aperiodic_tiling</NuxtLink>
</div>
</div>
</span>
</SwiperSlide>
<SwiperSlide data-hash="contact" class="p-10 text-xl overflow-hidden">
<span class="swiper-no-swiping">
<div class="overflow-auto">
<div class="mb-5 text-2xl">
For information or any inquiries email Michael Winter by clicking
<NuxtLink class="inline-flex p-1" to='javascript:location="mailto:\u006d\u0077\u0069\u006e\u0074\u0065\u0072\u0040\u0075\u006e\u0062\u006f\u0075\u006e\u0064\u0065\u0064\u0070\u0072\u0065\u0073\u0073\u002e\u006f\u0072\u0067";void 0'>
<span class="font-bold">HERE</span>
</NuxtLink>
</div>
<div class="mb-5 text-2xl">
To download the poster for the project, click
<NuxtLink class="inline-flex p-1" to='https://unboundedpress.org/pubs/hdp_poster.pdf'>
<span class="font-bold">HERE</span>
</NuxtLink>
</div>
<div class="mb-5 text-2xl">
To download the poster specifically for the exhibition, click
<NuxtLink class="inline-flex p-1" to='https://unboundedpress.org/pubs/a_few_thoughts_exhibition_poster.pdf'>
<span class="font-bold">HERE</span>
</NuxtLink>
</div>
</div>
</span>
</SwiperSlide>
</Swiper>
</div>
</template>
<script>
import hdp_background from "assets/hdp_background.png";
export default {
data() {
return {
image: hdp_background, };
}
};
</script>
<script setup>
import { useAudioPlayerStore } from "@/stores/AudioPlayerStore"
const audioPlayerStore = useAudioPlayerStore()
audioPlayerStore.setSoundCloudTrackID(324252345)
</script>

@ -0,0 +1,100 @@
<template>
<div class="bg-zinc-100 rounded-lg m-5 grid grid-cols-[60%,35%] gap-10 divide-x divide-solid divide-black py-4 min-h-[calc(100vh-10.5rem)]">
<div class="px-5">
<p class="text-lg">about</p>
<div class="leading-tight py-2 ml-3 text-sm">
<div class="leading-tight py-2">
My practice as a composer and sound artist is diverse, ranging from music created by digital and acoustic instruments to installations and kinetic sculptures. Each piece typically explores one simple process and often reflects various related interests of mine such as phenomenology, mathematics, epistemology, algorithmic information theory, and the history of science. To me, everything we experience is computable. Given this digital philosophy, I acknowledge even my most open works as algorithmic; and, while not always apparent on the surface of any given piece, the considerations of computability and epistemology are integral to my practice. I often reconcile epistemological limits with artistic practicality by considering and addressing the limits of computation from an artistic and experiential vantage point and by collaborating with other artists, mathematicians, and scientists in order to integrate objects, ideas, and texts from various domains as structural elements in my pieces. My work also aims to subvert discriminatory conventions and hierarchies by exploring alternative forms of presentation and interaction, often with minimal resources and low information.
</div>
<div class="leading-tight py-2">
My work has been presented at venues and festivals throughout the world such as REDCAT, in Los Angeles; the Ostrava Festival of New Music in the Czech Republic; Tsonami Arte Sonoro Festival in Valparaiso, Chile; the Huddersfield New Music Festival in the United Kingdom; and Umbral Sesiones at the Museo de Arte Contemporáneo in Oaxaca, Mexico. Recordings of my music have been released by XI Records, Another Timbre, New World Records, Edition Wandelweiser, Bahn Mi Verlag, Tsonami Records, and Pogus Productions. In 2008, I co-founded <em>the wulf.</em>, a Los Angeles-based organization dedicated to experimental performance and art. From 2018 to 2019, I was a fellow / artist-in-residence at the Akademie Schloss Solitude in Stuttgart, Germany. I currently reside in Berlin.
</div>
<br>
<br>
<div id="mc_embed_signup">
<form action="https://unboundedpress.us12.list-manage.com/subscribe/post?u=bdadd25738fedf704641f3a80&amp;id=01c5761ebb&amp;f_id=00f143e0f0" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_self">
<label for="mce-EMAIL">subscribe to my mailing list to know about upcoming events</label>
<input id="mce-EMAIL" type="email" value="" name="EMAIL" placeholder="email address" required="" class="email">
<div style="position: absolute; left: -5000px;" aria-hidden="true">
<input type="text" name="b_bdadd25738fedf704641f3a80_01c5761ebb" tabindex="-1" value="">
</div>
<div id="mce-responses" class="clear foot">
<div class="response" id="mce-error-response" style="display:none"></div>
<div class="response" id="mce-success-response" style="display:none"></div>
</div> <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
<div class="clear">
<input id="mc-embedded-subscribe" type="submit" value="subscribe" name="subscribe" class="button">
</div>
</form>
</div>
<br>
<br>
<div class="inline-flex place-items-center p-2">
Contact
<div>
<IconButton :visible="true" type="email" work="placeholder" link="javascript:location='mailto:\u006d\u0077\u0069\u006e\u0074\u0065\u0072\u0040\u0075\u006e\u0062\u006f\u0075\u006e\u0064\u0065\u0064\u0070\u0072\u0065\u0073\u0073\u002e\u006f\u0072\u0067';void 0"></IconButton>
</div>
</div>
<br>
<div class="inline-flex place-items-center p-2">
CV
<div>
<IconButton :visible="true" type="document" work="placeholder" link="https://unboundedpress.org/legacy/cv"></IconButton>
</div>
</div>
<br>
<div class="inline-flex place-items-center p-2">
Works List with Presentation History
<div>
<IconButton :visible="true" type="document" work="placeholder" link="https://unboundedpress.org/legacy/works_list"></IconButton>
</div>
</div>
<br>
<br>
</div>
</div>
<div class="px-5">
<ImageSlider bucket="images" :gallery="gallery" class="max-w-[90%]"></ImageSlider>
</div>
</div>
</template>
<script setup>
const { data: images } = await useFetch('https://unboundedpress.org/api/images.files?pagesize=200')
const { data: gallery } = await useFetch('https://unboundedpress.org/api/my_image_gallery?pagesize=200', {
transform: (gallery) => {
for (const item of gallery) {
item.image_id = images.value.find(obj => {return obj.filename === item.image})._id.$oid
}
return gallery //.sort((a,b) => a.priority - b.priority)
}
})
useHead({
titleTemplate: 'Michael Winter - About - Short Bio, Contact, CV, Works List, and Mailing List'
})
</script>
<style>
#mc_embed_signup form {text-align:left; padding:2px 0 2px 0;}
.mc-field-group { display: inline-block; } /* positions input field horizontally */
#mc_embed_signup input.email {border: 1px solid #ABB0B2; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; color: #343434; background-color: #fff; box-sizing:border-box; height:32px; padding: 0px 0.4em; display: inline-block; margin: 0; width:350px; vertical-align:top;}
#mc_embed_signup label {display:block; padding-bottom:10px;}
#mc_embed_signup .clear {display: inline-block;} /* positions button horizontally in line with input */
#mc_embed_signup .button {font-size: 13px; border: none; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; letter-spacing: .03em; color: #fff; background-color: #aaa; box-sizing:border-box; height:32px; line-height:32px; padding:0 18px; display: inline-block; margin: 0; transition: all 0.23s ease-in-out 0s;}
#mc_embed_signup .button:hover {background-color:#777; cursor:pointer;}
#mc_embed_signup div#mce-responses {float:left; top:-1.4em; padding:0em .5em 0em .5em; overflow:hidden; width:90%;margin: 0 5%; clear: both;}
#mc_embed_signup div.response {margin:1em 0; padding:1em .5em .5em 0; font-weight:bold; float:left; top:-1.5em; z-index:1; width:80%;}
#mc_embed_signup #mce-error-response {display:none;}
#mc_embed_signup #mce-success-response {color:#529214; display:none;}
#mc_embed_signup label.error {display:block; float:none; width:auto; margin-left:1.05em; text-align:left; padding:.5em 0;}
@media (max-width: 768px) {
#mc_embed_signup input.email {width:100%; margin-bottom:5px;}
#mc_embed_signup .clear {display: block; width: 100% }
#mc_embed_signup .button {width: 100%; margin:0; }
}
#mc_embed_signup{clear:left; width:100%;}
</style>

@ -0,0 +1,92 @@
<template>
<div class="bg-zinc-100 rounded-lg m-5 grid grid-cols-2 gap-10 divide-x divide-solid divide-black py-4 mb-10">
<div class="px-5">
<p class="text-lg">performances</p>
<div v-for="(item, index) in events">
<Collapsible title='placeholder' :modelValue='index <= 10' class="leading-tight py-2 ml-3 text-sm">
<template v-slot:title>
<div class="gap-1 w-[95%] px-2">
<div>
{{ item.formatted_date }}: {{item.venue.city}}, {{item.venue.state}}
<div class="ml-4 text-[#7F7F7F]">
{{ item.venue.name }}
</div>
</div>
</div>
</template>
<template v-slot:content>
<div v-for="performance in item.program">
<div class="italic text-sm ml-16 pt-1">{{performance.work}}</div>
<div v-if="performance.ensemble" class="ml-20">
{{ performance.ensemble }}
</div>
<div v-for="performer in performance.performers" class="ml-20">
{{ performer.name }} -
<span v-for="(instrument, index) in performer.instrument_tags">
<span v-if="index !== 0">, </span>
{{ instrument }}
</span>
</div>
</div>
<div class="italic text-sm ml-16 pt-1">{{item.legacy_program}}</div>
<div class="ml-20">{{item.legacy_performers}}</div>
</template>
</Collapsible>
</div>
</div>
<div class="px-5">
<p class="text-lg">lectures</p>
<div class="leading-tight py-2 ml-3 text-sm" v-for="item in lectures">
<div class="gap-1">
<div>
{{ item.formatted_date }}: {{item.location}}
<div v-for="talk in item.talks" class="ml-4 text-[#7F7F7F]">
{{ talk.title }}
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
const { data: events } = await useFetch('https://unboundedpress.org/api/events?pagesize=200', {
transform: (events) => {
for (const event of events) {
let date = new Date(event.start_date.$date)
event.formatted_date = ("0" + (date.getMonth() + 1)).slice(-2) + "." + ("0" + date.getDate()).slice(-2) + "." + date.getFullYear()
}
return events.sort((a,b) => b.start_date.$date - a.start_date.$date)
}
})
const { data: lectures } = await useFetch('https://unboundedpress.org/api/talks?pagesize=200', {
transform: (events) => {
for (const event of events) {
let date = new Date(event.date)
event.date = date
event.formatted_date = ("0" + (date.getMonth() + 1)).slice(-2) + "." + ("0" + date.getDate()).slice(-2) + "." + date.getFullYear()
if(typeof event.title === 'string' || event.title instanceof String) {event.talks = [{'title': event.title}]
} else {
let talks = []
for(const talk of event.title){
talks.push({"title": talk})
}
event.talks = talks
}
}
return events.sort((a,b) => b.date - a.date)
}
})
useHead({
titleTemplate: 'Michael Winter - Events - Performances and Lectures'
})
</script>

@ -0,0 +1,198 @@
<template>
<div class="bg-zinc-100 rounded-lg m-5 grid grid-cols-3 gap-10 divide-x divide-solid divide-black py-4 mb-10">
<div class="px-5">
<p class="text-lg">pieces</p>
<div class="py-2 ml-3" v-for="item in works">
<p class="font-thin">{{ item.year }}</p>
<div class="leading-tight py-1 ml-3" v-for="work in item.works">
<div class="grid grid-cols-[65%,30%] gap-1 font-thin">
<div class="italic text-sm">{{ work.title }}</div>
<div class="inline-flex">
<div>
<IconButton :visible="work.score" type="score" :work="work" :link="work.score" class="inline-flex p-1"></IconButton>
</div>
<div>
<IconButton :visible="work.soundcloud_trackid" type="audio" :work="work" class="inline-flex p-1"></IconButton>
</div>
<div>
<IconButton :visible="work.vimeo_trackid" type="video" :work="work" class="inline-flex p-1"></IconButton>
</div>
<div>
<IconButton :visible="work.gallery" type="image" :work="work" class="inline-flex p-1"></IconButton>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="px-5">
<p class="text-lg">writings</p>
<div class="leading-tight py-2 ml-3 text-sm" v-for="item in pubs">
<div class="grid grid-cols-[95%,5%] gap-1">
<div>
<span v-html="item.entryTags.title"></span>
<div class="ml-4 text-[#7F7F7F]">
{{ item.entryTags.author }}
<span v-if=item.entryTags.booktitle>{{ item.entryTags.booktitle}}.&nbsp;</span>
<span v-if=item.entryTags.journal>{{item.entryTags.journal}}.&nbsp;</span>
<span v-if=item.entryTags.editor>editors {{item.entryTags.editor}}&nbsp;</span>
<span v-if=item.entryTags.volume>volume {{item.entryTags.volume}}.</span>
<span v-if=item.entryTags.publisher>{{item.entryTags.publisher}}.</span>
{{ item.entryTags.year }}.
</div>
</div>
<div>
<IconButton :visible=item.entryTags.howpublished type="document" :link="item.entryTags.howpublished" class="inline-flex p-1"></IconButton>
</div>
</div>
</div>
</div>
<div class="px-5">
<p class="text-lg">albums</p>
<div class="leading-tight py-4 ml-3 text-sm" v-for="item in releases">
<p class="text-center leading-tight py-2">{{ item.title }}</p>
<button @click="modalStore.setModalProps('image', 'aspect-auto', true, 'album_art', [{image_id: item.album_art_id}], '')">
<nuxt-img :src="'https://unboundedpress.org/api/album_art.files/' + item.album_art_id + '/binary'"
quality="50"/>
</button>
<div class="flex place-content-center place-items-center">
<IconButton :visible="item.discogs_id" type="discogs" :link="'https://www.discogs.com/release/' + item.discogs_id"></IconButton>
<IconButton :visible="item.buy_link" type="buy" :link="item.buy_link"></IconButton>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { useModalStore } from "@/stores/ModalStore"
const modalStore = useModalStore()
const groupBy = (x,f)=>x.reduce((a,b,i)=>((a[f(b,i,x)]||=[]).push(b),a),{});
const isValidUrl = urlString => {
/*
var urlPattern = new RegExp('^(https?:\\/\\/)?'+ // validate protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // validate domain name
'((\\d{1,3}\\.){3}\\d{1,3}))'+ // validate OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // validate port and path
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // validate query string
'(\\#[-a-z\\d_]*)?$','i'); // validate fragment locator
return !!urlPattern.test(urlString);
*/
var pattern = /^((http|https|ftp):\/\/)/;
return pattern.test(urlString)
}
const { data: images } = await useFetch('https://unboundedpress.org/api/images.files?pagesize=200')
const { data: works } = await useFetch('https://unboundedpress.org/api/works?pagesize=200', {
transform: (works) => {
for (const work of works) {
if(work.score){
work.score = "/scores/" + work.score
}
/*
if(work.images){
let image_ids = [];
for (const image of work.images){
image_ids.push(images.value.find(obj => {return obj.filename === image.filename})._id.$oid)
}
work.image_ids = image_ids
}
*/
if(work.images){
let gallery = [];
for (const image of work.images){
gallery.push({
image_id: images.value.find(obj => {return obj.filename === image.filename})._id.$oid,
})
}
work.gallery = gallery
}
}
let priorityGroups = groupBy(works, work => work.priority)
let groups = groupBy(priorityGroups["1"], work => new Date(work.date.$date).getFullYear())
groups = Object.keys(groups).map((year) => {
return {
year,
works: groups[year].sort((a,b) => b.date.$date - a.date.$date)
};
});
groups.sort((a,b) => b.year - a.year)
groups.push({year: "miscellany", works: priorityGroups["2"].sort((a,b) => b.date.$date - a.date.$date)})
return groups
}
})
//const { data: pubs } = await useFetch('https://unboundedpress.org/api/publications/_aggrs/publications?pagesize=200')
//const { data: pubs } = await useFetch('https://unboundedpress.org/api/publications?sort=-entryTags.year&pagesize=200')
const { data: pubs } = await useFetch('https://unboundedpress.org/api/publications?pagesize=200', {
transform: (pubs) => {
for (const pub of pubs) {
if(pub.entryTags.howpublished && !(isValidUrl(pub.entryTags.howpublished))){
pub.entryTags.howpublished = "/pubs/" + pub.entryTags.howpublished
}
}
return pubs.sort((a,b) => (a.citationKey > b.citationKey) ? -1 : ((b.citationKey > a.citationKey) ? 1 : 0))
/*
return pubs.sort((a,b) => {
let aPrime = 5000
let bPrime = 5000
if(a.entryTags.year === 'forthcoming'){aPrime = 5000} else {aPrime = a.entryTags.year}
if(b.entryTags.year === 'forthcoming'){bPrime = 5000} else {bPrime = b.entryTags.year}
return bPrime - aPrime
})
*/
}
})
const { data: album_art } = await useFetch('https://unboundedpress.org/api/album_art.files?pagesize=200')
const { data: releases } = await useFetch('https://unboundedpress.org/api/releases?pagesize=200', {
//lazy: true,
//server: false,
transform: (releases) => {
for (const release of releases) {
release.album_art_id = album_art.value.find(obj => {return obj.filename === release.album_art})._id.$oid
}
return releases.sort((a,b) => b.date - a.date)
}
})
/*
watch(releases, (response)=>{
//console.log(response)
for (const item of response) {
useFetch(`https://unboundedpress.org/api/album_art.files?filter={"filename":"${item.album_art}"}`).then((response) => {
item.album_art_id = response.data.value[0]._id.$oid
})
}
return response
}, {
//deep: true,
immediate: true
})
*/
useHead({
titleTemplate: 'Michael Winter - Home / Works - Pieces, Publications, and Albums'
})
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

@ -0,0 +1,3 @@
{
"extends": "../.nuxt/tsconfig.server.json"
}

@ -0,0 +1,15 @@
import {defineStore} from "pinia";
export const useAudioPlayerStore = defineStore("AudioPlayerStore", {
state: () => ({"soundcloud_trackid": "1032587794"}),
actions: {
setSoundCloudTrackID(trackid) {
if (typeof trackid !== 'undefined') {
this.soundcloud_trackid = trackid
}
},
clearSoundCloudTrackID() {
this.soundcloud_trackid = 'undefined'
}
}
})

@ -0,0 +1,15 @@
import {defineStore} from "pinia";
export const useModalStore = defineStore("ModalStore", {
state: () => ({"type": "", "aspect":"", "isOpen":false, "bucket":"", "gallery":"", "vimeo_trackid":""}),
actions: {
setModalProps(type, aspect, isOpen, bucket, gallery, vimeo_trackid) {
this.type = type
this.aspect = aspect
this.isOpen = isOpen
this.bucket = bucket
this.gallery = gallery
this.vimeo_trackid = vimeo_trackid
}
}
})

@ -0,0 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
}

@ -62,7 +62,8 @@ app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// change first argument here to be on subdirectory
app.use('/legacy', express.static(path.join(__dirname, 'public')));
// Make our db accessible to our router
app.use(function(req,res,next){
@ -70,7 +71,8 @@ app.use(function(req,res,next){
next();
});
app.use('/', routes);
// change first argument here to be on subdirectory
app.use('/legacy/', routes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {

@ -1,3 +1,15 @@
@article{Winter23c,
author = {with Abrahão, F., Zenil, H., Porto, F., Wehmuth, K. and D'Ottaviano, I.},
title = {A simplicity bubble problem in formal-theoretic learning systems},
year = {forthcoming},
}
@article{Winter23b,
author = {with Abrahão, F., Cavassane, R. and D'Ottaviano, I.},
title = {The simplicity bubble effect as a zemblanitous phenomenon in learning systems},
year = {forthcoming},
}
@article{Winter20c,
author = {with Dantas, P.},
title = {Evolving curricula: reflections on The Quarantine Seminars},
@ -5,24 +17,24 @@ year = {forthcoming},
howpublished = {reflections_on_the_quarantine_seminars.pdf}
}
@misc{Winter20b,
author = {},
title = {Liner notes to the album "the yggdrasil-soli" by Ulrich Krieger},
publisher = {Winds Measures Recordings},
year = {2020},
howpublished = {krieger_yggdrasil_soli_liner_notes.pdf}
}
@incollection{Winter20a,
@incollection{Winter20b,
author = {},
title = {Meta+phenomenology: primer towards a phenomenology formally based on algorithmic information theory and metabiology},
editor = {Doria, F. & Wuppuluri, S.},
editor = {Doria, F. and Wuppuluri, S.},
booktitle = {Unravelling Complexity: Life and Work of Gregory Chaitin},
publisher = {World Scientific},
year = {2020},
howpublished = {https://www.worldscientific.com/worldscibooks/10.1142/11270}
}
@misc{Winter20a,
author = {},
title = {Liner notes to the album <em>the yggdrasil-soli</em> by Ulrich Krieger},
publisher = {Winds Measures Recordings},
year = {2020},
howpublished = {krieger_yggdrasil_soli_liner_notes.pdf}
}
@incollection{Winter19c,
author = {},
title = {A few more thoughts about Leibniz: the prediction of harmonic distance in harmonic space (with text to preliminary thoughts)},
@ -46,13 +58,13 @@ howpublished = {reflections_on_the_quarantine_seminars.pdf}
@misc{Winter19a,
author = {with Polansky, L.},
title = {liner notes to the album <em>"Changes"</em> by James Tenney},
title = {liner notes to the album <em>Changes</em> by James Tenney},
publisher = {New World Records},
year = {2019},
howpublished = {tenney_changes_liner_notes.pdf}
}
@incollection{Winter17,
@incollection{Winter17a,
author = {},
title = {On minimal change musical morphologies},
editor = {Pareyon, G., Pina-Romero, S., Agustin-Aquino, O.A., and Lluis-Puebla, E.},
@ -63,15 +75,15 @@ howpublished = {reflections_on_the_quarantine_seminars.pdf}
}
@misc{Winter16,
@misc{Winter16a,
author = {},
title = {Liner notes to the album "Three Pieces for Two Pianos" by Larry Polansky},
title = {Liner notes to the album <em>Three Pieces for Two Pianos</em> by Larry Polansky},
publisher = {New World Records},
year = {2016},
howpublished = {polansky_piano_liner_notes.pdf}
}
@Book{Tenney15,
@Book{Winter15a,
author = {Tenney, J.},
title = {From Scratch: Writings in Music Theory},
editor = {Polansky, L., Pratt, L., Wannamaker, R., and Winter, M.},
@ -80,7 +92,7 @@ editor = {Polansky, L., Pratt, L., Wannamaker, R., and Winter, M.},
howpublished = {https://www.press.uillinois.edu/books/catalog/78det5km.html}
}
@misc{grove,
@misc{Winter14b,
author = {},
title = {Approximating Omega},
journal = {Carbono (online)},
@ -91,7 +103,7 @@ editor = {Polansky, L., Pratt, L., Wannamaker, R., and Winter, M.},
@article{Winter10,
@article{Winter14a,
author = {with Akhmedov, A.},
title = {Chordal and timbral morphologies using Hamiltonian cycles},
journal = {Journal of Mathematics and Music},
@ -102,10 +114,10 @@ year = {2014},
howpublished = {Chordal_and_timbral_morphologies_using_Hamiltonian_cycles.pdf}
}
@incollection{Winter12,
@incollection{Winter12a,
author = {},
title = {Relativity and scalability with respect to sound and silence},
editor = {Lely, J. & Saunders, M.},
editor = {Lely, J. and Saunders, M.},
booktitle = {Word Events: Perspectives on Verbal Notation},
publisher = {Bloomsbury},
year = {2012},
@ -113,8 +125,8 @@ howpublished = {Chordal_and_timbral_morphologies_using_Hamiltonian_cycles.pdf}
}
@article{Polansky11,
author = {with Polansky, L. & Barnett, A.},
@article{Winter11a,
author = {with Polansky, L. and Barnett, A.},
title = {A few more words about James Tenney: dissonant counterpoint and statistical feedback},
journal = {Journal of Mathematics and Music},
volume = {5},
@ -124,7 +136,7 @@ year = {2011},
howpublished = {Dissonant_counterpoint_and_statistical_feedback.pdf}
}
@misc{emy,
@misc{Winter10d,
author = {},
title = {Notes on a new economics for a new music},
journal = {Experimental Music Yearbook (online)},
@ -133,7 +145,7 @@ howpublished = {Dissonant_counterpoint_and_statistical_feedback.pdf}
howpublished = {https://experimentalmusicyearbook.com/filter/Michael-Winter/notes-on-a-new-economics-for-a-new-art}
}
@article{doi:10.1080/07494467.2010.509594,
@article{Winter10c,
author = {with Barrett, G.D.},
title = {LiveScore: realtime notation in the music of Harris Wulfson},
journal = {Contemporary Music Review},
@ -146,7 +158,7 @@ howpublished = {Livescore.pdf}
@phdthesis{WinterDiss10,
@phdthesis{Winter10b,
type = {Dissertation},
title = {Structural Metrics: an epistemology},
author = {},
@ -157,7 +169,7 @@ howpublished = {Livescore.pdf}
}
@article{SAM:7914368,
@article{Winter10a,
author = {},
title = {James Tenney: Selected Works 19611969 (review)},
journal = {Journal of the Society for American Music},
@ -168,7 +180,7 @@ year = {2010},
pages = {531533}
}
@misc{grove,
@misc{Winter09a,
author = {with Hanson, S., Streb, C., and Polansky, L.},
title = {James Tenney biographical entry},
booktitle = {Grove Dictionary of American Music},
@ -176,9 +188,9 @@ pages = {531533}
year = {2009}
}
@article{doi:10.1080/07494460701671566,
@article{Winter08a,
author = {},
title = {On James Tenney's Arbor Vitae for string quartet},
title = {On James Tenney's <em>Arbor Vitae</em> for string quartet},
journal = {Contemporary Music Review},
volume = {27},
number = {1},
@ -187,7 +199,7 @@ year = {2008},
howpublished = {On_Arbor_Vitae.pdf}
}
@article{Winter07,
@article{Winter07b,
author = {},
title = {Mavericks on mavericks: James Tenneys last courses at CalArts},
journal = {MusikTexte},
@ -199,8 +211,8 @@ howpublished = {https://musiktexte.de/epages/dc91cfee-4fdc-41fe-82da-0c2b88528c1
}
@inproceedings{Wulfson:2007,
author = {with Barrett, G.D. & Wulfson, H.},
@inproceedings{Winter07a,
author = {with Barrett, G.D. and Wulfson, H.},
title = {Automatic Notation Generators},
booktitle = {Proceedings of the 7th International NIME Conference},
series = {NIME '07},

@ -1,3 +1,15 @@
@article{Winter23c,
author = {with Abrahão, F., Zenil, H., Porto, F., Wehmuth, K. and D'Ottaviano, I.},
title = {A simplicity bubble problem in formal-theoretic learning systems},
year = {forthcoming},
}
@article{Winter23b,
author = {with Abrahão, F., Cavassane, R. and D'Ottaviano, I.},
title = {The simplicity bubble effect as a zemblanitous phenomenon in learning systems},
year = {forthcoming},
}
@article{Winter20c,
author = {with Dantas, P.},
title = {Evolving curricula: reflections on The Quarantine Seminars},
@ -5,24 +17,24 @@ year = {forthcoming},
howpublished = {reflections_on_the_quarantine_seminars.pdf}
}
@misc{Winter20b,
author = {},
title = {Liner notes to the album <em>the yggdrasil-soli</em> by Ulrich Krieger},
publisher = {Winds Measures Recordings},
year = {2020},
howpublished = {krieger_yggdrasil_soli_liner_notes.pdf}
}
@incollection{Winter20a,
@incollection{Winter20b,
author = {},
title = {Meta+phenomenology: primer towards a phenomenology formally based on algorithmic information theory and metabiology},
editor = {Doria, F. & Wuppuluri, S.},
editor = {Doria, F. and Wuppuluri, S.},
booktitle = {Unravelling Complexity: Life and Work of Gregory Chaitin},
publisher = {World Scientific},
year = {2020},
howpublished = {https://www.worldscientific.com/worldscibooks/10.1142/11270}
}
@misc{Winter20a,
author = {},
title = {Liner notes to the album <em>the yggdrasil-soli</em> by Ulrich Krieger},
publisher = {Winds Measures Recordings},
year = {2020},
howpublished = {krieger_yggdrasil_soli_liner_notes.pdf}
}
@incollection{Winter19c,
author = {},
title = {A few more thoughts about Leibniz: the prediction of harmonic distance in harmonic space (with text to preliminary thoughts)},
@ -52,7 +64,7 @@ howpublished = {reflections_on_the_quarantine_seminars.pdf}
howpublished = {tenney_changes_liner_notes.pdf}
}
@incollection{Winter17,
@incollection{Winter17a,
author = {},
title = {On minimal change musical morphologies},
editor = {Pareyon, G., Pina-Romero, S., Agustin-Aquino, O.A., and Lluis-Puebla, E.},
@ -63,7 +75,7 @@ howpublished = {reflections_on_the_quarantine_seminars.pdf}
}
@misc{Winter16,
@misc{Winter16a,
author = {},
title = {Liner notes to the album <em>Three Pieces for Two Pianos</em> by Larry Polansky},
publisher = {New World Records},
@ -71,7 +83,7 @@ howpublished = {reflections_on_the_quarantine_seminars.pdf}
howpublished = {polansky_piano_liner_notes.pdf}
}
@Book{Tenney15,
@Book{Winter15a,
author = {Tenney, J.},
title = {From Scratch: Writings in Music Theory},
editor = {Polansky, L., Pratt, L., Wannamaker, R., and Winter, M.},
@ -80,7 +92,7 @@ editor = {Polansky, L., Pratt, L., Wannamaker, R., and Winter, M.},
howpublished = {https://www.press.uillinois.edu/books/catalog/78det5km.html}
}
@misc{grove,
@misc{Winter14b,
author = {},
title = {Approximating Omega},
journal = {Carbono (online)},
@ -91,7 +103,7 @@ editor = {Polansky, L., Pratt, L., Wannamaker, R., and Winter, M.},
@article{Winter10,
@article{Winter14a,
author = {with Akhmedov, A.},
title = {Chordal and timbral morphologies using Hamiltonian cycles},
journal = {Journal of Mathematics and Music},
@ -102,10 +114,10 @@ year = {2014},
howpublished = {Chordal_and_timbral_morphologies_using_Hamiltonian_cycles.pdf}
}
@incollection{Winter12,
@incollection{Winter12a,
author = {},
title = {Relativity and scalability with respect to sound and silence},
editor = {Lely, J. & Saunders, M.},
editor = {Lely, J. and Saunders, M.},
booktitle = {Word Events: Perspectives on Verbal Notation},
publisher = {Bloomsbury},
year = {2012},
@ -113,8 +125,8 @@ howpublished = {Chordal_and_timbral_morphologies_using_Hamiltonian_cycles.pdf}
}
@article{Polansky11,
author = {with Polansky, L. & Barnett, A.},
@article{Winter11a,
author = {with Polansky, L. and Barnett, A.},
title = {A few more words about James Tenney: dissonant counterpoint and statistical feedback},
journal = {Journal of Mathematics and Music},
volume = {5},
@ -124,7 +136,7 @@ year = {2011},
howpublished = {Dissonant_counterpoint_and_statistical_feedback.pdf}
}
@misc{emy,
@misc{Winter10d,
author = {},
title = {Notes on a new economics for a new music},
journal = {Experimental Music Yearbook (online)},
@ -133,7 +145,7 @@ howpublished = {Dissonant_counterpoint_and_statistical_feedback.pdf}
howpublished = {https://experimentalmusicyearbook.com/filter/Michael-Winter/notes-on-a-new-economics-for-a-new-art}
}
@article{doi:10.1080/07494467.2010.509594,
@article{Winter10c,
author = {with Barrett, G.D.},
title = {LiveScore: realtime notation in the music of Harris Wulfson},
journal = {Contemporary Music Review},
@ -146,7 +158,7 @@ howpublished = {Livescore.pdf}
@phdthesis{WinterDiss10,
@phdthesis{Winter10b,
type = {Dissertation},
title = {Structural Metrics: an epistemology},
author = {},
@ -157,7 +169,7 @@ howpublished = {Livescore.pdf}
}
@article{SAM:7914368,
@article{Winter10a,
author = {},
title = {James Tenney: Selected Works 19611969 (review)},
journal = {Journal of the Society for American Music},
@ -168,7 +180,7 @@ year = {2010},
pages = {531533}
}
@misc{grove,
@misc{Winter09a,
author = {with Hanson, S., Streb, C., and Polansky, L.},
title = {James Tenney biographical entry},
booktitle = {Grove Dictionary of American Music},
@ -176,7 +188,7 @@ pages = {531533}
year = {2009}
}
@article{doi:10.1080/07494460701671566,
@article{Winter078a,
author = {},
title = {On James Tenney's <em>Arbor Vitae</em> for string quartet},
journal = {Contemporary Music Review},
@ -187,7 +199,7 @@ year = {2008},
howpublished = {On_Arbor_Vitae.pdf}
}
@article{Winter07,
@article{Winter07b,
author = {},
title = {Mavericks on mavericks: James Tenneys last courses at CalArts},
journal = {MusikTexte},
@ -199,8 +211,8 @@ howpublished = {https://musiktexte.de/epages/dc91cfee-4fdc-41fe-82da-0c2b88528c1
}
@inproceedings{Wulfson:2007,
author = {with Barrett, G.D. & Wulfson, H.},
@inproceedings{Winter07a,
author = {with Barrett, G.D. and Wulfson, H.},
title = {Automatic Notation Generators},
booktitle = {Proceedings of the 7th International NIME Conference},
series = {NIME '07},

@ -18,9 +18,13 @@ $(document).ready(function() {
populateAbout();
populateGallerySelector();
// I am not sure why I was changing the url here, but for legacy more I am taking this out
/*
if (window.location.href.split('/').pop().substring(0,3) != "#lg") {
window.history.replaceState("object or string", "Title", "/");
}
*/
}
$( window ).resize(function() {
@ -863,11 +867,11 @@ function populatePublications() {
var wlButton = $("<button id=cv_button>").attr({title: "Works List with Presentation History"}).addClass('score_icon');
cvButton.click(function() {
window.open('/cv');
window.open(window.location.href + 'cv');
});
wlButton.click(function() {
window.open('/works_list');
window.open(window.location.href + 'works_list');
});
/*

@ -126,6 +126,10 @@ router.get('/works_list', function(req, res, next) {
if( (titleToSearch.indexOf('one') !== -1) && (titleToSearch.indexOf('two') !== -1)){
titleToSearch = 'two';
}
if( (titleToSearch == 'berger-knuth') || (titleToSearch == 'robinson') || (titleToSearch == 'penrose') || (titleToSearch == 'ammann') || (titleToSearch == 'kari-culik') || (titleToSearch == 'jaendel-rao')){
titleToSearch = 'a history of the domino problem';
}
// bug: why is mercado san juan or first not updating?
db.collection('events').find( { $text: { $search: "\"" + titleToSearch + "\"" } } ).toArray(function (err, events1) {
db.collection('events').find( { 'program' : { "$elemMatch" : { 'work' : { $regex : titleToSearch.replace('(','\\(').replace(')','\\)'), $options : 'i' } } } } ).toArray(function (err, events2) {

@ -6,7 +6,7 @@ html
link(rel='stylesheet', href='lightslider/css/lightslider.css')
link(rel='stylesheet', href='lightgallery/css/lightgallery.css')
link(rel='stylesheet', href='/stylesheets/style.css')
link(rel='stylesheet', href='stylesheets/style.css')
link(rel='stylesheet', href='//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css')
@ -17,8 +17,8 @@ html
script(src='//code.jquery.com/jquery-2.1.4.min.js')
script(src='//code.jquery.com/ui/1.11.4/jquery-ui.min.js')
script(src='/javascripts/global.js')
script(src='/javascripts/file.js')
script(src='javascripts/global.js')
script(src='javascripts/file.js')
//script(src="http://bibtex-js.googlecode.com/svn/trunk/src/bibtex_js.js")
@ -29,7 +29,7 @@ html
script(src="lightgallery/js/lightgallery.js")
script(src="lightgallery/js/lg-hash.js")
script(src="/javascripts/pluralize.js")
script(src="javascripts/pluralize.js")
script.

Loading…
Cancel
Save