diff options
| -rw-r--r-- | README.museum.md | 2 | ||||
| -rw-r--r-- | frontend/site/projects/museum/constants.js | 13 | ||||
| -rw-r--r-- | frontend/site/projects/museum/views/home.js | 2 | ||||
| -rw-r--r-- | frontend/site/projects/museum/views/petros.nav.css | 11 | ||||
| -rw-r--r-- | frontend/site/projects/museum/views/petros.nav.js | 82 | ||||
| -rw-r--r-- | frontend/site/site/site.actions.js | 4 | ||||
| -rw-r--r-- | frontend/site/site/site.reducer.js | 6 | ||||
| -rw-r--r-- | frontend/site/types.js | 2 | ||||
| -rw-r--r-- | frontend/site/viewer/viewer.container.js | 2 |
9 files changed, 94 insertions, 30 deletions
diff --git a/README.museum.md b/README.museum.md index 67524d9..6419890 100644 --- a/README.museum.md +++ b/README.museum.md @@ -29,3 +29,5 @@ rsync -rlptuvz ./data_store/exports/thelastmuseum/ lens@garden:swimmer/data_stor - Update constants.js with the artist name, bio, etc - Font size might change for CSS: `.page-artists .artist-big-name` - Upload their cursors +- Update frontend/site/projects/museum/views/home.js + - the line `history.push("/thelastmuseum/...")` should point at the new start page diff --git a/frontend/site/projects/museum/constants.js b/frontend/site/projects/museum/constants.js index ac73faf..b90ceb0 100644 --- a/frontend/site/projects/museum/constants.js +++ b/frontend/site/projects/museum/constants.js @@ -10,8 +10,8 @@ export const ARTISTS = { petros: { name: "Petros Moris", location: { - en: "Abandoned textile factory, Laurium, Greece", - de: "Verlassene Textilfabrik, Laurium, Greece", + en: "Aegeon Textile Factory, Laurium, Greece", + de: "Aegeon Textilfabrik, Laurium, Greece", }, start: "petros-1", homepage: "https://petrosmoris.com/", @@ -21,13 +21,16 @@ export const ARTISTS = { }, statement: { en: `<p> - <i>Oracle</i> occurs in a derelict textile factory in Laurium, a seaside town in Attica that used to be a significant silver mine territory since antiquity, the main source of ancient Athenian wealth and naval power. Those mines were reworked from the late 19th century to the 1980’s for ore extraction, an activity that left its grave environmental impact on the area’s soil to this day. Once part of the local industrial economy that collapsed before the turn of the millennium, this specific industrial ruin was recently leaked to be the future site of a datacenter complex to be built by one of the so-called “Big Five” multinational information technology corporations for the purpose of running dedicated Cloud, IoT and AI services. + <i>Oracle</i> is set in a derelict textile factory in Laurium—a seaside town in Attica, associated with silver mining since antiquity. Long a source of Athenian wealth and naval power, in the late 19th Century its mines were re-worked for ore extraction, with grave environmental consequences. Later, at the turn of the millennium, this industry collapsed and its massive industrial facilities laid in ruin, awaiting an uncertain future. This new artwork responds to that future: According to leaked information, the site will soon house a data-center complex to be built a “Big Five” multinational information technology corporation (for the purpose of running dedicated Cloud, IoT and AI services). Conceptually locating his work between Larium’s past and its future, <i>Oracle</i> is a response to the context – and to the mythos of the oracle in Greek culture. </p> <p> - Sculptural appearances inhabit the entropic spaces of this industrial ghost site, hybrids between human-resembling and non-human facial forms, seeding from chimeric compositions between archaeological photogrammetric scans and online-found threedimensional models referencing contemporary technocultures. Their metallic materiality reflects the local geological heritage and the mineral composition of the electronic hardware that enables the uncanny machinic intelligence and the haunting abstraction of computational operations. The digital interface of <i>Oracle</i> is permeated by a haunting soundtrack composed by Bill Kouligas, and becomes infiltrated by formations of visual coding and synthetic written language generated by simulated processes of pattern recognition, predictive mutations, and artificial apophenia. The physical and psychic underground space is still the origin of such forms of contemporary oracular production, where the ancient practices of hallucination deriving from subterranean chemical fumes gave their place to the extractivism of minerals and psychosocial data that feeds the deep-dreaming of the algorithmic Cloud. + <i>Oracle</i>’s sculptures inhabit the entropic spaces of Larium’s industrial ghost site. Resembling hybrids between human and non-human faces, these mask-like objects are chimeric compositions that borrow from archaeological photogrametric scans and ‘found’ three-dimensional models gathered online. Their metallic sheen reflects the local geological heritage. Additionally, their mineral composition references how electronic hardware enables uncanny machinic intelligence, and the haunting abstraction of computational operations. </p> <p> - As a place of memory and a place to become, an assemblage of mythological, historical, and technological entities, a generative process, or a resulting outcome left for interpretation, <i>Oracle</i> becomes a mediative entanglement of collapsing timelines, of imaginaries and anxieties bound to technological, socioeconomic and environmental transformation. + Both the setting and the digital interface of <i>Oracle</i> are permeated by visual coding, and soundscapes generated by simulated processes. In this work, Larium’s physical and psychic underground space is still the origin of contemporary oracular production—where ancient practices of hallucination deriving from subterranean chemical fumes give way to the extractivism of minerals and psychosocial data, powering the deep-dreaming of the algorithmic Cloud. + </p> + <p> + As a place of memory and a place of becoming (and an assemblage of myth, history, and technology) <i>Oracle</i> meditates on entangled timelines, imaginaries, and anxieties bound up with socioeconomic and environmental transformation. </p>`, de: `<p>TBD</p>`, }, diff --git a/frontend/site/projects/museum/views/home.js b/frontend/site/projects/museum/views/home.js index 9c06c10..86e53c7 100644 --- a/frontend/site/projects/museum/views/home.js +++ b/frontend/site/projects/museum/views/home.js @@ -71,7 +71,7 @@ class Home extends Component { } else { this.ref.current.className = "home orange-text orange-bg open" setTimeout(() => { - history.push("/thelastmuseum/stankievech-1") + history.push("/thelastmuseum/petros-1") }, FLASH_TIME) } } diff --git a/frontend/site/projects/museum/views/petros.nav.css b/frontend/site/projects/museum/views/petros.nav.css index 554d690..1a68032 100644 --- a/frontend/site/projects/museum/views/petros.nav.css +++ b/frontend/site/projects/museum/views/petros.nav.css @@ -4,7 +4,7 @@ left: 40px; cursor: pointer; opacity: 0.0; - transition: opacity 0.2s; + transition: opacity 0.4s; pointer-events: none; } .petros-right { @@ -13,16 +13,15 @@ right: 40px; cursor: pointer; opacity: 0.0; - transition: opacity 0.2s; + transition: opacity 0.4s; pointer-events: none; } .petros-text { position: absolute; - top: 40px; - right: 40px; + top: 50%; left: 50%; cursor: pointer; opacity: 0.0; - transition: opacity 0.2s; + transition: opacity 0.5s; pointer-events: none; } @@ -45,5 +44,5 @@ pointer-events: none; color: #fff; text-shadow: 0 0 3px #fff; - transition: opacity 0.2s; + transition: opacity 0.4s; } diff --git a/frontend/site/projects/museum/views/petros.nav.js b/frontend/site/projects/museum/views/petros.nav.js index 232e1d0..db7737b 100644 --- a/frontend/site/projects/museum/views/petros.nav.js +++ b/frontend/site/projects/museum/views/petros.nav.js @@ -10,6 +10,7 @@ import './petros.nav.css' import { history } from "site/store" import { preloadImage } from "app/utils" import actions from "site/actions" +import { generateTransform } from 'app/views/tile/tile.utils' const RESET_STATE = { ready: false, @@ -21,6 +22,17 @@ const RESET_STATE = { text: null, } +const NAV_GLYPH = { + 0: { left: 6, right: 1 }, + 1: { left: 6, right: 1 }, + 2: { left: 2, right: 3 }, + 3: { left: 1, right: 5 }, + 4: { left: 3, right: 4 }, + 5: { left: 5, right: 7 }, + 6: { left: 4, right: 6 }, + 7: { left: 7, right: 2 }, +} + const MOVEMENT = "movement" const LOOP = "loop" @@ -34,17 +46,21 @@ const INITIAL_VIEW = { 7: LOOP, } -const LOOP_TIMEOUT = 20 -const MOVEMENT_TIMEOUT = 40000 -const TEXT_LOAD_TIMEOUT = 15000 +// set this to 0.1 in development, 1.0 otherwise :) +const FASTFORWARD = 0.1 + +const LOOP_TIMEOUT = 6000 * FASTFORWARD +const MOVEMENT_TIMEOUT = 40000 * FASTFORWARD +const TEXT_LOAD_TIMEOUT = 15000 * FASTFORWARD const TEXT_SHOW_TIMEOUT = 20 -const TEXT_HIDE_TIMEOUT = 15000 +const TEXT_HIDE_TIMEOUT = 15000 *FASTFORWARD const SUBTITLE_COUNT = 12 class PetrosNav extends Component { state = { - ...RESET_STATE + ...RESET_STATE, + glyphTransform: {}, } constructor(props) { @@ -68,6 +84,9 @@ class PetrosNav extends Component { ) { this.load(prevProps.match && prevProps.match.params) } + if (this.props.page && this.props.page !== prevProps.page && this.props.page.path.match("petros-")) { + this.findGlyphPosition() + } } load(lastParams) { @@ -81,6 +100,7 @@ class PetrosNav extends Component { clearTimeout(this.textTimeout) this.setState({ ...RESET_STATE, + index: 0, // setting this unloads the component }) return } @@ -99,6 +119,26 @@ class PetrosNav extends Component { }, INITIAL_VIEW[index] === MOVEMENT ? MOVEMENT_TIMEOUT : LOOP_TIMEOUT) } + findGlyphPosition() { + const { page } = this.props + const bounds = { width: window.innerWidth, height: window.innerHeight } + const videoBounds = { + width: page.tiles[0].settings.width, + height: page.tiles[0].settings.height, + } + page.tiles.some(tile => { + if (tile.settings.popup_group === "glyph") { + let transform = generateTransform(tile, null, bounds, videoBounds) + transform = transform.replace(/scale(\d+\.\d+)/g, "") + this.setState({ + glyphTransform: { + transform + } + }) + } + }) + } + handleEnter(event) { const side = event.target.className.match(/-(\w+)/)[1] this.setState({ hovering: side }) @@ -116,11 +156,14 @@ class PetrosNav extends Component { textOpacity: 0.0, text: null }) + // Turn on the glyph - actions.site.setPopups({ - ...this.props.popups, - glyph: true, - }) + setTimeout(() => { + actions.site.setPopups({ + ...this.props.popups, + glyph: true, + }) + }, 500) // Fetch the subtitles const subtitle_index = 1 @@ -130,7 +173,6 @@ class PetrosNav extends Component { }) .then(res => res.text()) .then(text => this.setState({ text: text.trim() })) - .catch(err => this.setState({ text: "Flowing into the atmosphere through the cracks,\nthe fluid rock creates mountains that look alike the skin of serpents" })) this.textTimeout = setTimeout(() => { this.setState({ @@ -163,7 +205,6 @@ class PetrosNav extends Component { if (textActive) return const side = event.target.className.match(/-(\w+)/)[1] // if navigating to the left, just navigate. - console.log(side, index) if (side === "left") { if (index !== leftIndex) { history.push(`/thelastmuseum/petros-${leftIndex}`) @@ -171,13 +212,13 @@ class PetrosNav extends Component { } else if (side === "right") { // if this page starts with the loop, switch to movement // this will autoadvance when the video is done (set in tile settings) - console.log(INITIAL_VIEW[index]) if (INITIAL_VIEW[index] === LOOP) { actions.site.setPopups({ ...this.props.popups, movement: true, }) - this.setState({ ready: false }) + this.setState({ ready: false, iconFade: false, textOpacity: 0 }) + clearTimeout(this.textTimeout) } else { // otherwise, just advance immediately. history.push(`/thelastmuseum/petros-${rightIndex}`) @@ -186,14 +227,20 @@ class PetrosNav extends Component { } render() { - const { index, ready, hovering, textActive, textDone, textOpacity, iconFade, text } = this.state + const { + index, ready, + hovering, iconFade, + textActive, textDone, textOpacity, text, + glyphTransform, + } = this.state if (!this.props.interactive || (!index)) return null - const leftIndex = Math.max(1, index - 1) - const rightIndex = Math.min(7, index + 1) + const leftIndex = NAV_GLYPH[index].left + const rightIndex = NAV_GLYPH[index].right return ( <div> <img - className={ready ? "petros-text visible" : "petros-text"} + className={(ready && !(textActive || textDone)) ? "petros-text visible" : "petros-text"} + style={glyphTransform} src={(hovering === "text" || textActive || textDone) ? `/thelastmuseum/static/media/last-museum/petros-moris/OracleTextButton${index}-White.png` : `/thelastmuseum/static/media/last-museum/petros-moris/OracleTextButton${index}.png` @@ -243,6 +290,7 @@ const randint = n => Math.floor(Math.random() * n) const mapStateToProps = state => ({ interactive: state.site.interactive, popups: state.site.popups, + page: state.site.page, }) diff --git a/frontend/site/site/site.actions.js b/frontend/site/site/site.actions.js index 91c3936..36e873b 100644 --- a/frontend/site/site/site.actions.js +++ b/frontend/site/site/site.actions.js @@ -28,6 +28,10 @@ export const setPopups = popups => dispatch => ( dispatch({ type: types.site.set_popups, popups }) ) +export const setPage = page => dispatch => ( + dispatch({ type: types.site.set_page, page }) +) + export const changeLanguage = language => dispatch => { dispatch({ type: types.site.change_language, language }) } diff --git a/frontend/site/site/site.reducer.js b/frontend/site/site/site.reducer.js index aceb6d5..ac11406 100644 --- a/frontend/site/site/site.reducer.js +++ b/frontend/site/site/site.reducer.js @@ -48,6 +48,12 @@ export default function siteReducer(state = initialState, action) { popups: action.popups, } + case types.site.set_page: + return { + ...state, + page: action.page, + } + case types.site.change_language: return { ...state, diff --git a/frontend/site/types.js b/frontend/site/types.js index 9b020b9..acddfaa 100644 --- a/frontend/site/types.js +++ b/frontend/site/types.js @@ -2,7 +2,7 @@ import { with_type } from 'app/api/crud.types' export const site = with_type('site', [ 'set_site_title', 'loading', 'loaded', 'error', - 'load_site', 'interact', 'set_popups', + 'load_site', 'interact', 'set_page', 'set_popups', 'mute_audio', 'unmute_audio', 'change_language', ]) diff --git a/frontend/site/viewer/viewer.container.js b/frontend/site/viewer/viewer.container.js index a007308..a3c8085 100644 --- a/frontend/site/viewer/viewer.container.js +++ b/frontend/site/viewer/viewer.container.js @@ -82,9 +82,11 @@ class ViewerContainer extends Component { // page !== pages[home_page] && if (!this.props.interactive && hasAutoplay(page)) { this.setState({ page, hidden: {}, roadblock: true, unloaded: false }) + actions.site.setPage(page) actions.site.setPopups({}) } else { this.setState({ page, hidden: {}, roadblock: false, unloaded: false }) + actions.site.setPage(page) actions.site.setPopups({}) actions.site.interact() this.props.audio.player.playPage(page) |
