diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..327d3f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +_site/ +.sass-cache/ +.jekyll-cache/ +.jekyll-metadata \ No newline at end of file diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..e82698c --- /dev/null +++ b/_config.yml @@ -0,0 +1,14 @@ +collections: + projects: + output: true + +defaults: + - scope: + path: "" + type: "projects" + values: + layout: "project" + - scope: + path: "" + values: + layout: "default" \ No newline at end of file diff --git a/_includes/navigation.html b/_includes/navigation.html new file mode 100644 index 0000000..46c089b --- /dev/null +++ b/_includes/navigation.html @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 0000000..229d1c9 --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,43 @@ + + + + + + {{ page.title }} + + + + + + + + {% if page.url == '/' %} + + {% elsif page.layout == 'project' %} + + {% else %} + + {% endif %} + + + + {% if page.layout == 'default' %} + + + {% if page.url == '/' %} + + {% else %} + + {% endif %} + {% else %} + + {% endif %} + + + + {% assign page_layout = page.layout %} + {% assign page_title = page.title %} + {% include navigation.html layout=page_layout title=page_title %} + {{ content }} + + \ No newline at end of file diff --git a/_layouts/project.html b/_layouts/project.html new file mode 100644 index 0000000..b3f11aa --- /dev/null +++ b/_layouts/project.html @@ -0,0 +1,58 @@ +--- +layout: default +--- +{% capture the_collection %}{{page.collection}}{% endcapture %} +{% if page.collection %} + {% assign document = site[the_collection] | sort: 'order' %} + {% assign length = document | size | minus: 1 %} +{% endif %} +{% for links in document %} + {% if links.title == page.title %} + {% unless forloop.first %} + {% assign prevurl = prev.url %} + {% endunless %} + {% unless forloop.last %} + {% assign next = document[forloop.index] %} + {% assign nexturl = next.url %} + {% endunless %} + {% endif %} + {% assign prev = links %} +{% endfor %} +
+
+

{{ page.title }}

+

{{ page.subtitle }}

+
+
+

With

+ {% for name in page.team %} +

{{ name }}

+ {% endfor %} +
+
+

Year

+

{{ page.year }}

+
+
+

Role

+

{{ page.role }}

+
+
+

Technology

+ {% for tech in page.technology %} +

{{ tech }}

+ {% endfor %} +
+
+ {{ page.link.title }} +
+
+
+ {{ content }} +
+ \ No newline at end of file diff --git a/_projects/dd-image-tagging-tool.html b/_projects/dd-image-tagging-tool.html new file mode 100644 index 0000000..84fb37e --- /dev/null +++ b/_projects/dd-image-tagging-tool.html @@ -0,0 +1,45 @@ +--- +title: DD image tagging tool +subtitle: An interface to the Clarifai API +team: + - DensityDesign Research Lab +year: 2018 +role: design and development +technology: + - Clarifai API +link: + title: densitydesign.github.io/dd-image-tagging + url: "https://densitydesign.github.io/dd-image-tagging/" +thumbnail: dd-image-tagging.png +order: 5 +--- +
+
+

The image tagging tool is a javascript interface built on top of the Clarifai API that let users tag a series of images with one of the image content recognition models developed by Clarifai.

+
+
+
+
+

Process

+
+
+

For information designers and social scientists working with Digital Methods, content recognition algorithms can be very helpful in categorizing large corpuses of images. They can be employed, for example, as a way to place images in a space based on their content similarity, or to roughly categorize and filter only the images relevant to the research.

+

This small project comes from the need of having an easy interface where researchers could use a content recognition algorithm without the burden of having to learn how to code or how to call an API. While inside the lab we had a routine set up to perform the various operations needed to label a corpus of images, this was not ideal in our teaching activities. It implied a series of scripts that took time and know-how to learn and made the passage of knowledge, especially during workshops, challenging and often not very effective.

+

The tool is specifically designed to work in combination with spreadsheet softwares as they are, most of the time, what comes before and after in this kind of research processes. This is why the interface accepts only a list of image urls in the form of a csv file and outputs another csv file with the results of the algorithm.

+

Clarifai was chosen for various reasons:

+ +
+
+
+
+

Thoughts

+
+
+

The image tagging tool works well for its intended use, but it could be greatly improved. Its aim is really focused on the specific task it was created for, making it less flexible to change. For example, a research question that requires an output formatted differently would render the tool useless.

+

As future developments we could also improve the inputs it handles by also excepting images directly instead of just csvs.

+
+
\ No newline at end of file diff --git a/_projects/densitydesign-fsds-14ed.html b/_projects/densitydesign-fsds-14ed.html new file mode 100644 index 0000000..d2415d4 --- /dev/null +++ b/_projects/densitydesign-fsds-14ed.html @@ -0,0 +1,46 @@ +--- +title: DensityDesign F.S.D.S 14th ed. +subtitle: A website to showcase student's work +team: + - DensityDesign Research Lab +year: 2018 +role: design and development +technology: + - jekyll +link: + title: densitydesign.github.io/teaching-dd14 + url: "https://densitydesign.github.io/teaching-dd14/" +thumbnail: dd-website.png +order: 2 +--- +
+
+

Every year, the results made by students of the Final Synthesis Design Studio run by DensityDesign Research Lab are showcased in a website that gathers all the material produced during the course. This was the redesign made for the 14th edition of the course (a.a. 2018-2019).

+
+
+
+
+

Process

+
+
+

During the course, students have to face ongoing and controversial issues – such as migration, hate speech, misinformation, climate change, etc. – by using Communication Design and Data Visualization to explore the given topic, share research methods and results and finally engage with a public. In this process, students will realize that their perspective is situated in a network of agents and relationships by which a controversy is defined and, at some point, they will also have to place themselves in this network when visually communicating the results.

+

This idea is what stands behind the course’s motto “You are here” and is borrowed from the social sciences, namely the methodological approach of actor-network theory developed by Bruno Latour and others.

+

Conceptually the redesign of the 14th edition’s websites lays its foundations on these core concepts and builds on the metaphor of the map, an imagined map where the controversy is the territory and actors and relations are the features of said map. “You are here” is both the ability to orient yourself in the map as well as the realization that you are now a feature of the map.

+
+ +
+

The inspiration for the visual elements comes from topographic maps with adaptations of grid lines, annotated borders and isohypses. The small dot wondering in the header section of the home page wants to be a reminder of the path followed by students while getting to know their controversy.

+ Header screenshot +
+
+
+
+

Thoughts

+
+
+

I expect next year’s version to evolve and maybe be completely different again, as this is the nature of this course. Every year it’s meticulously reshaped and adapted in order to experiment new ways and improve.

+
+
\ No newline at end of file diff --git a/_projects/privacy-and-black-boxes.html b/_projects/privacy-and-black-boxes.html new file mode 100644 index 0000000..d0fbd44 --- /dev/null +++ b/_projects/privacy-and-black-boxes.html @@ -0,0 +1,60 @@ +--- +title: Privacy and black boxes +subtitle: Communicating the opaque processes produced by digital technology +team: + - "-" +year: 2016 +role: personal M.Sc. thesis +technology: + - d3.js + - nightmare.js + - node.js +link: + title: politesi.polimi.it + url: "https://www.politesi.polimi.it/handle/10589/133042?mode=full&submit_simple=Show+full+thesis+record" +thumbnail: privacy.png +order: 4 +--- +
+
+

“Privacy and black boxes” is my master’s thesis, a journey documenting my explorations of the relationship between communication design and technology, with a special focus on those technological processes that were made invisible and opaque by technical complexity or by design.

+
+
+
+
+

Process

+
+
+

The issue of “opacity” in technology has been increasingly relevant to me, even more so as our society tends to believe that technology is or will soon be the solution to the world’s problems and thus tries to implement it in almost every aspect of life. By opacity, I mean the difficulty or inability to analyze, understand or control part of a technological process that somehow affects us.

+

In my thesis I was particularly interested in two examples of opaque processes, both tied to our production of digital traces (data) when we use digital devices such as iphones, computers, etc. and both still missing a consolidated and standardize legal framework:

+ +

As a designer, my research questions in investigating these issues were mainly methodological: How can we map processes that are invisible, opaque, or protected by legal barriers? How these characteristics influence the design process? Are the tools and methods that we use enough or do we need to modify them or make new ones?

+

The first step was to perform an adequate literary review of the topic of data and privacy, as well as to set up a series of experiments to see what kind of data I could get about myself, for example. Embracing the approach of Digital Methods, I analyzed how the issue was represented by the scientific community (using Scopus as a proxy), by domain expert bloggers (Ars Technical and Medium), and by encyclopedic knowledge in different language spheres (Wikipedia).

+ Scopus analysis +

I also tried to get as much information as possible from my social media accounts, focusing mainly on what I could see by retrieving all the location data Google had on me.

+ Google location analysis analysis +

Once I was better acquainted with the issue, I had the great opportunity to collaborate with two groups of people that were working exactly on the two aspects that interested me and both were happy to have a designer that could help them.

+

The first was a team of researchers from the Computer and Information Science department at Northeastern University, lead by David Choffnes. They were developing an app, ReCon, that could monitor and block any personally identifying information requested knowingly or unknowingly by apps on a user’s phone. Here I tried to design an interface that introduced the user on how ReCon worked and that exposed the data collected, giving back the user control on what to share.

+ ReCon experiment +

The second collaboration was with a group of activists led by Claudio Agosti that, among other projects, is developing a tool called facebook.tracking.exposed. At the time the aim of the project was, as the name implies, to try to exposed the News Feed algorithm used by Facebook by showing how it affected the user experience with the platform. I thus tried to design an interface that could present each user their feed from a different perspective, highlighting changes in ranking, typology of posts, evolution in time, etc.

+
+ +
+

In both projects my main objective was always to design solutions that could remove at least in part the veil that covered these invisible processes covered by technological complexity.

+
+
+
+
+

Thoughts

+
+
+

The experimental nature of the thesis made my journey necessarily a work in progress and also highlighted the dire need of new methods and tools to investigate the opaque processes of collection and use of personal data.

+

This was nonetheless a very productive starting point in the analysis of this context from the perspective of a designer, which underlined a great opportunity for communication design: we need to keep working on solutions that can put people in the position to make informed choices about the technological environment they live in.

+
+
\ No newline at end of file diff --git a/_projects/switzerland-istitutional-landscape.html b/_projects/switzerland-istitutional-landscape.html new file mode 100644 index 0000000..5bd2559 --- /dev/null +++ b/_projects/switzerland-istitutional-landscape.html @@ -0,0 +1,69 @@ +--- +title: Switzerland's institutional landscape 1933–1980 +subtitle: An analysis of administrative detention through data visualization +team: + - Independent Expert Commission + - Tommaso Elli + - Andrea Benedetti + - Michele Mauri +year: 2017 +role: design and development +technology: + - d3.js + - node.js + - OpenRefine +link: + title: toxicwasteroutes.github.io + url: "https://toxicwasteroutes.github.io/" +thumbnail: switzerland.png +order: 3 +--- +
+
+

This interactive report, developed by DensityDesign for the Swiss Independent Expert Commission (IEC) on Administrative Detention, was designed to display part of the research done by the commission in order to both present their work to the general public in Switzerland as well as to make it available to other researchers interested in the study of the phenomenon.

+
+
+
+
+

Process

+
+
+

As most information design projects, a considerable part of the work was dedicated to get the data ready to be used. Namely, since IEC’s researchers had to collect and categorize a set of registers made by different institutions in different points in time from 1933 until 1980, all the data had to be reformatted and made uniform.

+

Here in particular the main challenge was to assign a unique id to each institution because, in those 60 years, some changed typology, location or were either combined in a bigger cluster or split up in sub-institutions. Moreover, the administrative boundaries of Switzerland changed through time, with the creation or evolution of its cantons. Thanks to the combined effort of the research lab and the commission we were able to reconcile each institute with an id and a historical path.

+

In terms of design, the aim of the report was two-fold: on one side it needed to inform Swiss citizens about the use of administrative detention up to 1981, while also providing a reference for other research groups and scholars for their publications. For this reason the final website was designed to keep a connection between the narrative sphere and the academic sphere by having each element of all interactive visualizations linked in a glossary to the original data, ready for citation.

+
+ +
+

This element was key for both partners because it can be a challenge to present the original data behind an information visualization artifact in a way that is usable by others than the creators of said artifact. Thus, we designed two glossaries with a visual interface that helps navigate and contextualize the data:

+ +

If the need for a source of citation was very clear from the commission requests, much freedom was given to us in terms of what should – or would be interesting to – be shown in the report. Since the early stages of the project then, numerous hypotheses and explorations were iterated in close collaboration with them to decide what, how and in which order was best to present the data available.

+

One thing that really emerged was that geography – by being a proxy of cultural differences – was a major component in the administrative detention’s history, both in how it affected the distribution and characteristics of the institutions as well as in the relationship between different facilities.

+

The final report follows a scrollytelling approach with interactive visualizations that are introduced and evolve with the scrolling of a textual explanation. One of the design challenges was to represent all the institutions geographically without aggregating the ones that belonged to the same city or anyhow too close together: they needed to be shown singularly to emphasize the breadth of the phenomenon as well as the existing patterns between their location and their typology, religious affiliation and accepted genders, while keeping the visualization as legible as possible. We ended up with an acceptable compromise where institutions are slightly repositioned geographically every time they overlap.

+
+ +
+
+
+
+
+

Thoughts

+
+
+

The interactive report was very well received by the members of the commission as well as their scientific community and it’s now touring (at the time of writing, spring 2019) around Switzerland in conferences and events.

+

That said, some improvements could be added as potential future developments, mainly in the design of the interaction and the affordance of visualizations:

+ +

We tried to limit these issues by providing examples and explanation boxes in the text, but we could potentially find better solutions that don’t need to interrupt the narrative structure.

+
+
\ No newline at end of file diff --git a/_projects/toxic-waste-routes.html b/_projects/toxic-waste-routes.html new file mode 100644 index 0000000..747834e --- /dev/null +++ b/_projects/toxic-waste-routes.html @@ -0,0 +1,75 @@ +--- +title: Toxic waste routes +subtitle: Tracing the global path of hazardous garbage +team: + - Guia Baggi + - Zanna McKay + - Michele Mauri +year: 2016 +role: design and development +technology: + - d3.js + - OpenRefine +link: + title: toxicwasteroutes.github.io + url: "https://toxicwasteroutes.github.io/" +thumbnail: toxic-wastes.png +order: 1 +--- +
+
+

"Toxic waste routes" is a joint project between DensityDesign Lab and Guia Baggi, aimed at enhancing transparency on toxic wastes movements across the world. The current tool is a first prototype based on Basel Convention annual reports, and the visualization reflects data features: inconsistencies and missing reports are often the norm, and there is a clear need for a better data transparency on the topic.

+
+ +
+
+
+
+
+

Process

+
+
+

The project posed a series of challenges that had to be overcome in order to create a meaningful design. The data provided by the Secretariat of the Basel Convention were partial and inconsistently formatted due to lack of rigor by submitting countries.

+

Furthermore, the Convention's website collects an archive of all the reports submitted in the past, but the structure of the archive has changed during the years, making it difficult to easily get what we needed. The complete dataset was gathered by italian journalist Guia Baggi and later cleaned and merged with additional data (countries informations, geo coordinates, etc…) to make it accessible to work with. In the end we focused on the type and the amount of hazardous waste traded, since they were the core of the dataset as well as the most consistent data throughout the corpus.

+

A second issue was choosing if it was best to show only the exports, the imports or both at the same time. Even if in the overall picture representing both flows would result in doubling the data, at the country level having both informations helps to highlight behavior patterns: countries that are only exporting, countries that did not submit the annual report but show imports data based on other countries' report, etc…

+

Initially we also wanted to emphasize the movements of cargos between nations, in order to single out those exchanges that were taking thousands of kilometers to complete. Later on, after various attempts, the feature was dropped mainly for two reasons:

+ +

The last challenge was to maintain both the temporal and spatial dimensions of the phenomenon.

+

After a few iterations of different visual models, we went with a mixed approach: treemaps, representing the amount of waste related to each country, are arranged in space as if they were part of a Demers cartogram hence simulating as closely as possible the relative position of countries on a geographic map. This raised a new challenge: a round of user testing sessions brought up the need to bridge the gap of abstraction between the visualization and a real map. For this reason the user is introduced to the final design through a sort of tutorial where countries are first placed on a map and then “transformed” step by step in treemaps, introducing one at a time all the visual encoding variables.

+

The data can then be filtered by year and by category of waste.

+
+ +
+

By clicking on a single country, a more in-depth view is provided. The color of the treemap divides the imports from the exports, while the two different levels of subdivisions highlight where the waste was imported from/exported to (level 1 — solid border) and what kind of waste were moved (level 2 — dashed border).

+
+ +
+
+
+
+
+

Thoughts

+
+
+

The tool is a good first prototype for the exploration of the Basel Convention data and it let us experiment with different visual solutions, testing their effectiveness in that particular situation. We can find of course some drawbacks:

+ +

As further steps it would be interesting to find a better way to highlight specific cargos in order to trace them better on the map, as well as adding the actual route of every waste movement with animations to have a better understanding of the phenomenon.

+
+
diff --git a/_sass/main.scss b/_sass/main.scss new file mode 100644 index 0000000..1f91f2f --- /dev/null +++ b/_sass/main.scss @@ -0,0 +1,78 @@ +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-style: normal; + font-named-instance: 'Regular'; + src: url("/assets/fonts/Inter-upright.var.woff2") format("woff2"); +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-style: italic; + font-named-instance: 'Italic'; + src: url("/assets/fonts/Inter-italic.var.woff2") format("woff2"); +} + +html { + --color-dark: #000000; + --color-light: #ffffff; + --color-blue: #4469DD; + --color-red: #F53D3D; + font-family: "Inter var", "Helvetica", sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + --font-regular: 400; + --font-bold: 700; + --margin: 20px; + --margin-optimized: calc(var(--margin) * 0.8); +} + +body { + margin: var(--margin-optimized) var(--margin) var(--margin); + overflow-x: hidden; +} + +h3, h4, h5, ul { + margin: 0; + padding: 0; +} + +h3 { + font-size: 1rem; +} + +h5 { + font-size: 1rem; + font-variation-settings: 'wght' var(--font-regular); + text-transform: uppercase; +} + +a { + color: var(--color-dark); + text-decoration: none; + font-variation-settings: 'wght' var(--font-regular); +} + +::selection { + color: var(--color-light); + background-color: var(--color-dark); +} + +span.show--small { + display: inline; +} + +span.show--big { + display: none; +} + +@media (min-width: 576px) { + span.show--small { + display: none; + } + + span.show--big { + display: inline; + } +} diff --git a/_sass/navigation.scss b/_sass/navigation.scss new file mode 100644 index 0000000..47efdd4 --- /dev/null +++ b/_sass/navigation.scss @@ -0,0 +1,69 @@ +nav { + position: fixed; + width: calc(100% - var(--margin) * 2); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +nav > div { + max-width: 60%; +} + +nav h3 span { + -webkit-transition: color 0.3s; + transition: color 0.3s; +} + +nav h4 { + font-size: 16px; + font-variation-settings: 'wght' var(--font-regular); +} + +nav h4 span { + position: relative; + -webkit-transition: left 0.4s ease; + transition: left 0.4s ease; +} + +nav h5 { + position: absolute; + width: 100%; + text-align: center; + opacity: 0; + -webkit-transition: opacity 0.3s; + transition: opacity 0.3s; + z-index: -1; +} + +nav h5.title--shown { + opacity: 0; +} + +nav ul { + list-style: none; + text-align: right; +} + +nav a { + -webkit-transition: font-variation-settings 0.3s; + transition: font-variation-settings 0.3s; +} + +nav a:hover { + font-variation-settings: 'wght' var(--font-bold); +} + +nav a.link--active { + font-variation-settings: 'wght' var(--font-bold); +} + +/* big phones onward*/ +@media (min-width: 576px) { + nav h5.title--shown { + opacity: 1; + } +} \ No newline at end of file diff --git a/about.html b/about.html new file mode 100644 index 0000000..c04f6a0 --- /dev/null +++ b/about.html @@ -0,0 +1,331 @@ +--- +title: About – Michele Invernizzi's Portfolio +--- +
+ + + 🏔 + + + 🕳 + + + + 🌲 + + + 🌲 + + + 🌲 + + + 🌲 + + + 🌲 + + + + + + + + + Natrona County High School + year abroad + + + + 2004 — 2009 + I.T.I.S “A. Badoni” + Mechanical engineering technician + + + + 2009 — 2010 + Politecnico di Milano + B.Sc. Aerospace engineering + dropped out + + + + + 🕳 + + + + + + + + + + + + MovieDesign Lab + internship + + + Politecnico di Torino + Systemic Design + double degree + + + Datashack program + Harvard-PoliMi joint program + + + + DensityDesign Research Lab + internship + + + + 2011 — 2014 + Politecnico di Milano + B.Sc. Communication Design + + + 2014 — 2017 + Politecnico di Milano + M.Sc. Communication Design + + + 2017 — 2019 + DensityDesign Research Lab + Research Fellowship + + + + + + + + + + + + + the beauty of + building things + from scratch + + + Turbo Pascal + love for dinosaurs + + Math & Physics + + + + + work in + multidisciplinary + + teams + + + + + + + + + love for maps + and diagrams + + + solve real problems + + through design + + + love for HMTL+CSS + but also the beauty of + + building things from + + scratch on the web + + + + + + + + + + + + + + + 2004 — 2009 + + + 2009 — 2010 + + + 2011 — 2014 + + + 2014 — 2017 + + + 2017 — 2019 + + + + + Paleontologist + + + + Mechanical Engineering + + + Technician + + + + Aerospace Engineer + + + Visual Designer + + + + Visual + + + Information Designer + + + + + Visual + + + Information Designer + + + + interaction design + + + + coding + + + +
+

interests

+
+
+

plans

+
+
+
+
+
+

Workshop supervision

+
    +
  • +

    Visualización de datos con Rawgraphs y ai2html

    +

    VISDatos - Santiago 2018

    +
  • +
  • +

    Visualización en mapas cartográficos

    +

    VISDatos - Santiago 2018

    +
  • +
+
+
+

Workshop facilitation

+
    +
  • +

    Digital Methods Summer School

    +

    UvA - Amsterdam 2018

    +
  • +
  • +

    Visualizing Ambiguity

    +

    TANT Lab -Copenhagen 2017

    +
  • +
  • +

    Datapol

    +

    SciencesPo - Paris 2017

    +
  • +
  • +

    Digital Methods Summer School

    +

    UvA - Amsterdam 2017

    +
  • +
  • +

    COST Action Training School

    +

    Como 2017

    +
  • +
  • +

    Digital Methods Winter School

    +

    UvA - Amsterdam 2017

    +
  • +
  • +

    Digital Methods Summer School

    +

    UvA - Amsterdam 2016

    +
  • +
  • +

    COST Action Training School

    +

    Como 2015

    +
  • +
+
+
+
+
+

Lectures

+
    +
  • +

    Valore PA social PA - ADV

    +

    Politecnico di Milano School of Management - Milano 2018

    +
  • +
  • +

    Nuove tecnologie di valutazione del potenziale e dei nuovi strumenti di + ricerca online

    +

    Innovazione Apprendimento Lavoro - Milano 2018

    +
  • +
+
+
+

Teaching assistance

+
    +
  • +

    DensityDesign F.S.D.S. 14th ed.

    +

    2018 - 2019

    +
  • +
  • +

    DensityDesign F.S.D.S. 13th ed.

    +

    2017 - 2018

    +
  • +
+
+
+

Talks

+
    +
  • +

    2CO Conference

    +

    Tenerife 2017

    +
  • +
+
+
+

michele (dot) invernizzi90 [at] gmail (dot) com

+ + +
+
+
+ \ No newline at end of file diff --git a/assets/.DS_Store b/assets/.DS_Store new file mode 100644 index 0000000..6f3fde1 Binary files /dev/null and b/assets/.DS_Store differ diff --git a/assets/css/about.css b/assets/css/about.css new file mode 100644 index 0000000..513a196 --- /dev/null +++ b/assets/css/about.css @@ -0,0 +1,374 @@ +main { + --main-height: calc(85vh - var(--margin-optimized) - var(--margin) - 20vh); + width: 100%; + height: var(--main-height); + padding-top: 20vh; + display: grid; + grid-template-columns: 116vw; + grid-template-rows: 1fr; +} + +.base__regular { + font-variation-settings: 'wght' var(--font-regular); +} + +.base__bold { + font-variation-settings: 'wght' var(--font-bold); +} + +.base__italic { + font-style: italic; +} + +.base__emoji { + font-size: 1.15rem; +} + +.base__line { + fill: none; + stroke: var(--color-dark); +} + +.base__line.line--dashed { + stroke-dasharray: 6, 6; +} + +.base__line.line--thick { + stroke-width: 3px; +} + +svg.base__interests { + grid-column: 1 / span 1; + grid-row: 1 / span 1; +} + +.base__trees { + -webkit-transform: translate(-102px, 6px); + transform: translate(-102px, 6px); +} + +.base__second-part { + -webkit-transform: translate(-190px, 0); + transform: translate(-190px, 0); +} + +g.lower--small { + -webkit-transform: translate(0, 19.2px); + transform: translate(0, 19.2px); +} + +.interests, +.base__plans, +.plans, +.about__card { + display: none; +} + +.activities { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + margin-top: 6rem; +} + +.activities__column { + width: 100%; +} + +.activities__column h3 { + margin-bottom: 1rem; +} + +.activities__column ul { + list-style: none; + margin-bottom: 3rem; +} + +.activities__column li { + margin: 0.6rem 0; +} + +.activities__column p { + margin: 0.1rem 0; +} + +.activity__info { + font-style: italic; +} + +.activities__column .activity__link { + margin: 1.2rem 0; +} + +.activities__column a { + margin-right: 0.5rem; + padding: 0.4rem 0.6rem; +} + +.activities__column a:hover { + background-color: var(--color-dark); + color: var(--color-light); +} + +.activities__column .external--link { + border: 1px solid var(--color-dark); + border-radius: 2px; +} + +footer { + margin-top: 1.2rem; +} + +footer p { + font-size: 0.9rem; + margin: 0; +} + +/* big phones */ +@media (min-width: 576px) { + main { + --main-height: 585px; + padding-top: 12rem; + grid-template-columns: 1fr 500px 1fr; + } + svg.base__interests { + height: 100%; + grid-column: 2 / span 1; + } + .base__trees { + -webkit-transform: translate(-67px, 6px); + transform: translate(-67px, 6px); + } + + .base__second-part { + -webkit-transform: translate(-120px, 0); + transform: translate(-120px, 0); + } + .activities { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + margin-top: calc(100vh - 585px - var(--margin-optimized) - var(--margin) - 6rem); + } + .activities__column { + width: 292px; + margin-right: calc((100% - 24% * 3) / 3 ); + } +} + +/* tablets */ +@media (min-width: 768px) { + main { + --main-height: 585px; + grid-template-columns: 72% 28%; + } + .interests, + .base__plans, + .plans, + .about__card { + display: block; + } + + g.lower--small { + -webkit-transform: translate(0,0); + transform: translate(0,0); + } + + tspan.show--small { + display: none; + } + + svg.base__interests, + svg.interests { + height: 100%; + grid-column: 1 / span 1; + grid-row: 1 / span 1; + } + + .interests__special { + -webkit-transform: translate(-70px, -14px); + transform: translate(-70px, -14px); + } + + .interests__second-part { + -webkit-transform: translate(-120px, 0); + transform: translate(-120px, 0); + } + + .interests__notes { + fill: var(--color-red); + } + + .line--red { + fill: none; + stroke: var(--color-red); + } + + svg.base__plans, + svg.plans { + height: 100%; + grid-column: 2 / span 1; + grid-row: 1 / span 1; + } + + .plans__notes { + fill: var(--color-blue); + } + + .plans__notes.strike { + text-decoration: line-through; + } + + svg.interests, + svg.plans { + will-change: clip-path; + } + + .about__card { + --margin-card: calc(var(--margin) / 2); + position: absolute; + height: var(--main-height); + cursor: -webkit-grab; + cursor: grab; + border: 1px solid var(--color-dark); + border-radius: 2px; + -webkit-box-shadow: 0px 4px 8px rgba(142,142,142,0.5); + box-shadow: 0px 4px 8px rgba(142,142,142,0.5); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-transform: rotate(10deg); + transform: rotate(10deg); + } + + .about__card.card--moving { + cursor: -webkit-grabbing; + cursor: grabbing; + } + + .card__interests { + width: var(--main-height); + top: 15rem; + left: -479px; + } + + .card__plans { + width: calc(var(--main-height) / 2); + top: -21rem; + right: -300px; + } + + .about__card h3 { + position: absolute; + } + + .card__interests h3 { + top: var(--margin-card); + right: calc(var(--margin-card) * 1.25); + color: var(--color-red); + } + + .card__plans h3 { + bottom: var(--margin-card); + left: calc(var(--margin-card) * 1.25); + color: var(--color-blue); + } + + .about__card h3::after { + content: ""; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + } + + .card__interests h3::after { + border-bottom: 2px solid var(--color-red); + } + + .card__plans h3::after { + border-bottom: 2px solid var(--color-blue); + } + .activities { + margin-top: 9rem; + } + footer { + margin-top: 0; + } +} + +/* desktops */ +@media (min-width: 992px) { + .activities__column { + width: 345px; + margin-right: calc((100% - 24% * 3) / 3 ); + } + .activities__column:first-child { + margin-left: 220px; + } + .card__plans { + top: -30rem; + } +} + +/* big desktops */ +@media (min-width: 1200px) { + main { + --main-height: 715px; + padding-top: 6rem; + grid-template-columns: 64% 36%; + } + .card__plans { + top: 4.5rem; + right: -315px; + } + .base__trees { + -webkit-transform: translate(0, 0); + transform: translate(0, 0); + } + .base__second-part { + -webkit-transform: translate(0, 0); + transform: translate(0, 0); + } + .interests__special { + -webkit-transform: translate(0,0); + transform: translate(0,0); + } + .interests__second-part { + -webkit-transform: translate(0, 0); + transform: translate(0, 0); + } + .card__interests { + top: 12rem; + left: -575px; + } + .activities { + margin-top: 10rem; + } + .activities__column { + width: 380px; + } + .activities__column:first-child { + margin-left: 260px; + } +} + +/* huge desktops */ +@media (min-width: 1800px) { + main { + width: 75vw; + margin: 0 auto; + grid-template-columns: 1000px 1fr; + } + .card__plans { + right: -180px; + } + .activities { + width: 75vw; + margin: 10rem auto 0; + } +} diff --git a/assets/css/home.css b/assets/css/home.css new file mode 100644 index 0000000..2852138 --- /dev/null +++ b/assets/css/home.css @@ -0,0 +1,146 @@ +body { + overflow: hidden; +} + +main { + width: 100%; + height: calc(100vh - var(--margin-optimized) - var(--margin)); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.projects__list { + width: 88vw; + font-size: 6.6vw; + line-height: 1.5; +} + +.projects__list a { + -webkit-transition: font-variation-settings 0.3s; + transition: font-variation-settings 0.3s; +} + +.projects__list a:hover, +.projects__list a.card--match { + font-variation-settings: 'wght' var(--font-bold); +} + +.projects__list a.link--active { + font-variation-settings: 'wght' var(--font-bold); +} + +.project__card { + display: none; +} + +footer { + position: fixed; + bottom: var(--margin); + z-index: -1; +} + +footer p { + font-size: 0.9rem; + margin: 0; +} + +/* big phones */ +@media (min-width: 576px) { + .projects__list { + width: 82vw; + font-size: 4.4vw; + line-height: 1.35; + } + + .project__card { + --margin-card: calc(var(--margin) / 2); + display: block; + position: absolute; + top: -40vmin; + left: 50vw; + width: calc(30vmin - var(--margin-card) * 2); + height: calc(30vmin - var(--margin-card) * 2); + padding: var(--margin-card); + cursor: -webkit-grab; + cursor: grab; + border: 1px solid var(--color-dark); + border-radius: 2px; + -webkit-box-shadow: 0px 4px 8px rgba(142,142,142,0.5); + box-shadow: 0px 4px 8px rgba(142,142,142,0.5); + background-color: var(--color-light); + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transition-property: left, top, -webkit-transform; + transition-property: left, top, -webkit-transform; + transition-property: left, top, transform; + transition-property: left, top, transform, -webkit-transform; + -webkit-transition-duration: 0.7s; + transition-duration: 0.7s; + -webkit-transition-timing-function: ease; + transition-timing-function: ease; + } + + .project__card.card--moving { + -webkit-transition-property: -webkit-transform; + transition-property: -webkit-transform; + transition-property: transform; + transition-property: transform, -webkit-transform; + -webkit-transition-duration: 0.4s; + transition-duration: 0.4s; + -webkit-transition-timing-function: ease; + transition-timing-function: ease; + cursor: -webkit-grabbing; + cursor: grabbing; + } + + .project__card img { + width: calc(100% - 2px); + height: calc(100% - 2px); + border: 1px solid #ebebeb; + pointer-events: none; + } +} + +/* tablets */ +@media (min-width: 768px) { + .projects__list { + width: 70vw; + font-size: 3.8vw; + } +} + +/* desktops */ +@media (min-width: 992px) { + .projects__list { + width: 60vw; + font-size: 3.2vw; + } +} + +/* big desktops */ +@media (min-width: 1200px) { + .projects__list { + width: 45vw; + font-size: 2.4vw; + line-height: 1.25; + } +} + +/* huge desktops */ +@media (min-width: 1800px) { + .projects__list { + font-size: 2.2vw; + line-height: 1.35; + } +} diff --git a/assets/css/master.scss b/assets/css/master.scss new file mode 100644 index 0000000..f452f52 --- /dev/null +++ b/assets/css/master.scss @@ -0,0 +1,4 @@ +--- +--- +@import "main"; +@import "navigation"; diff --git a/assets/css/project.css b/assets/css/project.css new file mode 100644 index 0000000..a36f668 --- /dev/null +++ b/assets/css/project.css @@ -0,0 +1,428 @@ +body { + --content-width: calc(100vw - var(--margin) * 2); + background-color: var(--color-light); +} + +header { + width: 100%; + min-height: calc(100vh - var(--margin-optimized) * 2 - 0.8rem); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-box-align: end; + -ms-flex-align: end; + align-items: flex-end; +} + +.header__container { + width: var(--content-width); +} + +h1 { + font-size: 2rem; + font-variation-settings: 'wght' var(--font-regular); + margin: 0; +} + +h2 { + font-size: 1.3rem; + font-variation-settings: 'wght' var(--font-regular); + margin: 0 0 1.2rem; +} + +.info__container { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + border-top: 1px solid var(--color-dark); + min-height: 140px; + margin-bottom: 2rem; +} + +.info { + width: calc(50% - 0.5rem); +} + +.info h3 { + margin: 1.2rem 0 0.3rem; +} + +.info p { + margin: 0.1rem 0; +} + +.project__link { + font-size: 1rem; + padding: 0.5rem 0.8rem; +} + +.project__link::after { + content: " \2197"; +} + +.external--link { + position: relative; + border: 1px solid var(--color-dark); + border-radius: 2px; +} + +.external--link.link--thick { + border: 2px solid var(--color-dark); +} + +.external--link:hover { + background-color: var(--color-dark); + color: var(--color-light); +} + +.project__summary { + width: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + margin: 4rem 0 3rem; +} + +.summary__container { + width: var(--content-width); +} + +.summary__container p { + max-width: 1280px; + font-size: 5.9vw; + font-style: italic; + line-height: 1.3; +} + +.summary__container a { + padding: 0 0.5rem; +} + +.summary__container .project__video { + max-width: 1280px; + padding-top: 3rem; +} + +.summary__container video { + width: 100%; + border: 1px solid var(--color-dark); + box-shadow: 0 4px 8px rgba(142,142,142,0.5); + border-radius: 2px; +} + +.project__content { + width: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.section__title h3 { + margin-top: 1.55rem; + padding-top: 1.2rem; + border-top: 1px solid var(--color-dark); +} + +.section__body { + width: var(--content-width); +} + +.section__body p { + margin: 0.3rem 0; + width: 100%; + font-size: 1rem; + line-height: 1.4; +} + +.section__body p.paragraph--new { + margin-top: 0.8rem; +} + +.section__body p.paraghraph--spacer { + margin-bottom: 1.2rem; +} + +.section__body a { + padding: 0 0.3rem; +} + +.section__body ul { + width: calc(100% - 2rem); + margin: 1.2rem 0; + padding-left: 2rem; + list-style-type: '\25CB'; +} + +.section__body li { + padding-left: 1rem; + margin: 0.6rem 0; + line-height: 1.4; +} + +.section__body .project__video { + max-width: 1280px; + margin: 2rem 0; + background-size: cover; + background-repeat: no-repeat; +} + +.section__body .project__image { + width: 100%; + max-width: 1280px; + margin: 2rem 0; + border: 1px solid var(--color-dark); + box-shadow: 0 4px 8px rgba(142,142,142,0.5); + border-radius: 2px; +} + +.section__body video { + width: 100%; + display: block; + border: 1px solid var(--color-dark); + box-shadow: 0 4px 8px rgba(142,142,142,0.5); + border-radius: 2px; +} + +footer { + width: 100%; + margin-top: 8rem; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; +} + +.pagination__container { + width: var(--content-width); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +a .pagination__text { + font-variation-settings: 'wght' var(--font-regular); + -webkit-transition: font-variation-settings 0.3s; + transition: font-variation-settings 0.3s; +} + +a:hover .pagination__text { + font-variation-settings: 'wght' var(--font-bold); +} + +a .pagination__arrow { + position: relative; + top: 0; + left: 0; + font-variation-settings: 'wght' var(--font-regular); + -webkit-transition: font-variation-settings 0.3s, left 0.3s ease; + transition: font-variation-settings 0.3s, left 0.3s ease; +} + +a.pagination__left:hover .pagination__arrow { + font-variation-settings: 'wght' var(--font-bold); + left: -4px; +} + +a.pagination__right:hover .pagination__arrow { + font-variation-settings: 'wght' var(--font-bold); + left: 4px; +} + +/* very small devices */ +@media (max-width: 320px) { + h1 { + margin-top: 8rem; + } + .project__link { + display: block; + text-align: center; + } +} + +/* big phones */ +@media (min-width: 576px) { + header { + height: calc(100vh - var(--margin-optimized) * 2 - 0.8rem); + min-height: 0px; + } + h1 { + font-size: 3.3rem; + } + h2 { + font-size: 1.6rem; + } + .project__link { + font-size: 1.6rem; + } + .project__link::after { + content: ""; + } + .project__summary { + margin: 6rem 0; + } + .summary__container p { + font-size: 1.75rem; + } +} + +/* tablets */ +@media (min-width: 768px) { + body { + --content-width: 80vw; + } + header { + height: calc(80vh - var(--margin-optimized) * 2 - 0.8rem); + } + .info__container { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + } + .info { + width: calc(var(--content-width) / 4 - 0.5rem); + } + .summary__container p { + font-size: 1.85rem; + } + .project__content { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + } + .section__title h3 { + padding-right: 1.4rem; + padding-top: 0; + border-top: none; + } + .section__body { + padding-top: 1.2rem; + border-top: 1px solid var(--color-dark); + } + .section__body p { + width: 610px; + } + .section__body ul { + width: calc(610px - 3rem); + padding-left: 3rem; + } +} + +/* desktops */ +@media (min-width: 992px) { + body { + --content-width: 75vw; + } + header { + height: calc(70vh - var(--margin-optimized) * 2 - 0.8rem); + } + h1 { + font-size: 4.1rem; + } + h2 { + font-size: 1.8rem; + margin: 0 0 1.8rem; + } + .project__link { + font-size: 1.8rem; + } + .summary__container p { + font-size: 2.1rem; + } +} + +/* big desktop */ +@media (min-width: 1200px) { + body { + --content-width: 70vw; + } + header { + height: calc(100vh - var(--margin-optimized) * 2 - 0.8rem); + } + h1 { + font-size: 5rem; + } + h2 { + font-size: 2rem; + } + .project__link { + font-size: 2rem; + } + .summary__container p { + font-size: 2.5rem; + } + .section__title h3 { + margin-top: calc(1.55rem + 0.2vw); + font-size: 1vw; + } + + .section__body p { + width: 45vw; + font-size: 1.2vw; + } + + .section__body ul { + width: calc(45vw - 3rem); + } + + .section__body li { + font-size: 1.2vw; + } +} + +/* huge desktop */ +@media (min-width: 1800px) { + header { + height: calc(80vh - var(--margin-optimized) * 2 - 0.8rem); + } + .info__container { + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + } + .info { + width: calc(1280px / 4); + margin-right: 0.5rem; + } + .section__title h3 { + margin-top: 1.7rem; + font-size: 1.1rem; + } + + .section__body p { + width: 860px; + font-size: 1.3rem; + } + + .section__body ul { + width: calc(860px - 3rem); + margin: 1.6rem 0; + padding-left: 3.5rem; + } + + .section__body li { + font-size: 1.3rem; + } +} \ No newline at end of file diff --git a/assets/fonts/Inter-italic.var.woff2 b/assets/fonts/Inter-italic.var.woff2 new file mode 100644 index 0000000..ee3eb80 Binary files /dev/null and b/assets/fonts/Inter-italic.var.woff2 differ diff --git a/assets/fonts/Inter-upright.var.woff2 b/assets/fonts/Inter-upright.var.woff2 new file mode 100644 index 0000000..a21824f Binary files /dev/null and b/assets/fonts/Inter-upright.var.woff2 differ diff --git a/assets/images/.DS_Store b/assets/images/.DS_Store new file mode 100644 index 0000000..abc243c Binary files /dev/null and b/assets/images/.DS_Store differ diff --git a/assets/images/dd-image-tagging-2x.png b/assets/images/dd-image-tagging-2x.png new file mode 100644 index 0000000..a0704d8 Binary files /dev/null and b/assets/images/dd-image-tagging-2x.png differ diff --git a/assets/images/dd-image-tagging.png b/assets/images/dd-image-tagging.png new file mode 100644 index 0000000..dddac3a Binary files /dev/null and b/assets/images/dd-image-tagging.png differ diff --git a/assets/images/dd-website-2x.png b/assets/images/dd-website-2x.png new file mode 100644 index 0000000..8335536 Binary files /dev/null and b/assets/images/dd-website-2x.png differ diff --git a/assets/images/dd-website.png b/assets/images/dd-website.png new file mode 100644 index 0000000..3530b6c Binary files /dev/null and b/assets/images/dd-website.png differ diff --git a/assets/images/ddweb01.png b/assets/images/ddweb01.png new file mode 100644 index 0000000..3e93ede Binary files /dev/null and b/assets/images/ddweb01.png differ diff --git a/assets/images/ddweb02.png b/assets/images/ddweb02.png new file mode 100644 index 0000000..f826e69 Binary files /dev/null and b/assets/images/ddweb02.png differ diff --git a/assets/images/ddweb03.png b/assets/images/ddweb03.png new file mode 100644 index 0000000..b487902 Binary files /dev/null and b/assets/images/ddweb03.png differ diff --git a/assets/images/favicon-16.png b/assets/images/favicon-16.png new file mode 100644 index 0000000..40009a2 Binary files /dev/null and b/assets/images/favicon-16.png differ diff --git a/assets/images/favicon-32.png b/assets/images/favicon-32.png new file mode 100644 index 0000000..977de17 Binary files /dev/null and b/assets/images/favicon-32.png differ diff --git a/assets/images/favicon.ico b/assets/images/favicon.ico new file mode 100644 index 0000000..569a7a2 Binary files /dev/null and b/assets/images/favicon.ico differ diff --git a/assets/images/image-social.jpg b/assets/images/image-social.jpg new file mode 100644 index 0000000..a637647 Binary files /dev/null and b/assets/images/image-social.jpg differ diff --git a/assets/images/location.png b/assets/images/location.png new file mode 100644 index 0000000..e10ba67 Binary files /dev/null and b/assets/images/location.png differ diff --git a/assets/images/privacy-2x.png b/assets/images/privacy-2x.png new file mode 100644 index 0000000..b407631 Binary files /dev/null and b/assets/images/privacy-2x.png differ diff --git a/assets/images/privacy.png b/assets/images/privacy.png new file mode 100644 index 0000000..1692807 Binary files /dev/null and b/assets/images/privacy.png differ diff --git a/assets/images/recon.png b/assets/images/recon.png new file mode 100644 index 0000000..6c655cd Binary files /dev/null and b/assets/images/recon.png differ diff --git a/assets/images/scopus.png b/assets/images/scopus.png new file mode 100644 index 0000000..f569fb7 Binary files /dev/null and b/assets/images/scopus.png differ diff --git a/assets/images/switzerland-2x.png b/assets/images/switzerland-2x.png new file mode 100644 index 0000000..207c49e Binary files /dev/null and b/assets/images/switzerland-2x.png differ diff --git a/assets/images/switzerland.png b/assets/images/switzerland.png new file mode 100644 index 0000000..67995d7 Binary files /dev/null and b/assets/images/switzerland.png differ diff --git a/assets/images/toxic-wastes-2x.png b/assets/images/toxic-wastes-2x.png new file mode 100644 index 0000000..0f95092 Binary files /dev/null and b/assets/images/toxic-wastes-2x.png differ diff --git a/assets/images/toxic-wastes.png b/assets/images/toxic-wastes.png new file mode 100644 index 0000000..52eb624 Binary files /dev/null and b/assets/images/toxic-wastes.png differ diff --git a/assets/images/toxicwaste-gif01.gif b/assets/images/toxicwaste-gif01.gif new file mode 100755 index 0000000..0c8520e Binary files /dev/null and b/assets/images/toxicwaste-gif01.gif differ diff --git a/assets/images/toxicwaste-gif02.gif b/assets/images/toxicwaste-gif02.gif new file mode 100755 index 0000000..fba2f29 Binary files /dev/null and b/assets/images/toxicwaste-gif02.gif differ diff --git a/assets/images/toxicwaste-poster.jpg b/assets/images/toxicwaste-poster.jpg new file mode 100644 index 0000000..c0bd168 Binary files /dev/null and b/assets/images/toxicwaste-poster.jpg differ diff --git a/assets/js/about.js b/assets/js/about.js new file mode 100644 index 0000000..f64578f --- /dev/null +++ b/assets/js/about.js @@ -0,0 +1,96 @@ +(function () { + const $interests = document.querySelector('.interests'); + const $interestsCard = document.querySelector('.card__interests'); + const $plans = document.querySelector('.plans'); + const $plansCard = document.querySelector('.card__plans'); + const $cards = $('.about__card'); + let resizeTimer; + + if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { + console.log('Safari is a terrible browser, please switch to either Chrome or Firefox'); + $interestsCard.style.display = 'none'; + $plansCard.style.display = 'none'; + } + + calculateMask($interests, $interestsCard); + calculateMask($plans, $plansCard); + + $cards.on("touchstart mousedown", function (ev) { + ev.preventDefault(); + initDrag(ev, ev.currentTarget, "about"); + }) + + document.ontouchmove = function (ev) { + dragElement(ev); + if (selected !== null) { + if (selected.el.id == 'interests') { + calculateMask($interests, $interestsCard); + } else { + calculateMask($plans, $plansCard); + } + } + }; + document.ontouchend = emptySelection; + + document.onmousemove = function (ev) { + dragElement(ev); + if (selected !== null) { + if (selected.el.id == 'interests') { + calculateMask($interests, $interestsCard); + } else { + calculateMask($plans, $plansCard); + } + } + }; + document.onmouseup = emptySelection; + + // Credits to Chris Coyier https://css-tricks.com/snippets/jquery/done-resizing-event/ + window.onresize = function (e) { + clearTimeout(resizeTimer); + resizeTimer = setTimeout(function () { + $interests = document.querySelector('.interests'); + $interestsCard = document.querySelector('.card__interests'); + $plans = document.querySelector('.plans'); + $plansCard = document.querySelector('.card__plans'); + calculateMask($interests, $interestsCard); + calculateMask($plans, $plansCard); + }, 250); + } + +})(); + +function calculateMask($annotations, $card) { + const annotationsDimensions = $annotations.getBoundingClientRect(); + const cardDimensions = $card.getBoundingClientRect(); + // console.log(annotationsDimensions, cardDimensions); + const cardHorizontalLenght = $card.id == "interests" ? annotationsDimensions.height : annotationsDimensions.height / 2; + const cardVerticalLenght = annotationsDimensions.height; + const cardHorizontalDelta = cardVerticalLenght * Math.sin(10 * Math.PI / 180); + const cardVerticalDelta = cardHorizontalLenght * Math.sin(10 * Math.PI / 180); + + const cardX1 = cardDimensions.x + cardHorizontalDelta; + const cardY1 = cardDimensions.y; + const cardX2 = cardDimensions.right; + const cardY2 = cardDimensions.y + cardVerticalDelta; + const cardX3 = cardDimensions.right - cardHorizontalDelta; + const cardY3 = cardDimensions.bottom; + const cardX4 = cardDimensions.x; + const cardY4 = cardDimensions.bottom - cardVerticalDelta; + + const maskX1 = round(cardX1 - annotationsDimensions.x, 0); + const maskY1 = round(cardY1 - annotationsDimensions.y, 0); + const maskX2 = round(cardX2 - annotationsDimensions.x, 0); + const maskY2 = round(cardY2 - annotationsDimensions.y, 0); + const maskX3 = round(cardX3 - annotationsDimensions.x, 0); + const maskY3 = round(cardY3 - annotationsDimensions.y, 0); + const maskX4 = round(cardX4 - annotationsDimensions.x, 0); + const maskY4 = round(cardY4 - annotationsDimensions.y, 0); + // console.log(annotationsDimensions.y, cardY2); + + $annotations.style.clipPath = `polygon(${maskX1}px ${maskY1}px, ${maskX2}px ${maskY2}px, ${maskX3}px ${maskY3}px, ${maskX4}px ${maskY4}px)`; + +} + +function round(value, decimals) { + return Number(Math.round(value+'e'+decimals)+'e-'+decimals); +} \ No newline at end of file diff --git a/assets/js/base.js b/assets/js/base.js new file mode 100644 index 0000000..caf4690 --- /dev/null +++ b/assets/js/base.js @@ -0,0 +1,55 @@ +(function () { + const $name = document.getElementById('name'); + const $surname = document.getElementById('surname'); + const colors = ['#000000', '#4469DD', '#F53D3D']; + let lastpair = '#000000#000000'; + let resizeTimer; + + // document.ontouchstart = getRandomColors; + document.onclick = getRandomColors; + + // make jobs move on hover + const $int = document.getElementById('interaction'); + const $inf = document.getElementById('information'); + const $job = document.querySelector('nav h4'); + let intPosition = $int.getBoundingClientRect().left; + let infPosition = $inf.getBoundingClientRect().left; + $int.style.left = 0; + $inf.style.left = 0; + let distance = infPosition - intPosition; + + $job.onmouseenter = function () { + $int.style.left = distance + 'px'; + $inf.style.left = -distance + 'px'; + + }; + $job.onmouseleave = function () { + $int.style.left = 0; + $inf.style.left = 0; + }; + + // Credits to Chris Coyier https://css-tricks.com/snippets/jquery/done-resizing-event/ + window.onresize = function (e) { + clearTimeout(resizeTimer); + resizeTimer = setTimeout(function () { + intPosition = $int.getBoundingClientRect().left; + infPosition = $inf.getBoundingClientRect().left; + $int.style.left = 0; + $inf.style.left = 0; + distance = infPosition - intPosition; + }, 250); + } + + function getRandomColors() { + let randomColor1 = colors[Math.floor(Math.random() * colors.length)]; + let randomColor2 = colors[Math.floor(Math.random() * colors.length)]; + if (randomColor1 + randomColor2 != lastpair) { + $name.style.color = randomColor1; + $surname.style.color = randomColor2; + lastpair = randomColor1 + randomColor2; + } else { + getRandomColors(); + } + }; + +})(); \ No newline at end of file diff --git a/assets/js/home.js b/assets/js/home.js new file mode 100644 index 0000000..8bd2628 --- /dev/null +++ b/assets/js/home.js @@ -0,0 +1,165 @@ +$(function () { + const viewportWidth = $(window).width(); + const viewportHeight = $(window).height(); + const cardDimension = Math.min(viewportWidth, viewportHeight) * 0.3; + const margin = cardDimension / 2; + const dimensionsArray = [margin, margin, viewportWidth - margin, viewportHeight - margin]; + const $cards = $('.project__card'); + const $projects = $('.projects__list a'); + let resizeTimer; + // console.log(viewportWidth, viewportHeight); + + // get random points to throw the cards + const sampleArray = makeSamples(); + + $cards.each(function (i) { + let randomRotation = Math.floor(Math.random() * 30) - 15; + + $(this).css({ + "left": sampleArray[i][0], + "top": sampleArray[i][1], + "transform": `rotate(${randomRotation}deg) scale(1)`, + "transition-delay": `${i * .05}s` + }); + }); + $cards.on("touchstart mousedown", function (ev) { + ev.preventDefault(); + initDrag(ev, ev.currentTarget, "home"); + }).on("mouseover", function (ev) { + let order = ev.currentTarget.getAttribute('data-order'); + let $project = document.querySelector(`.projects__list a[data-order='${order}']`); + + $project.classList.add('card--match'); + }).on("mouseleave", function (ev) { + let order = ev.currentTarget.getAttribute('data-order'); + let $project = document.querySelector(`.projects__list a[data-order='${order}']`); + + $project.classList.remove('card--match'); + }); + document.ontouchmove = dragElement; + document.ontouchend = emptySelection; + document.onmousemove = dragElement; + document.onmouseup = emptySelection; + + $projects.on("mouseover", function (ev) { + let order = ev.currentTarget.getAttribute('data-order'); + let $card = document.querySelector(`.project__card[data-order='${order}']`); + let parentEl = document.getElementById('home'); + let rotation = $card.getAttribute('style').replace(/.*(rotate\(.*deg\)).*/, '$1'); + $card.style.transform = `${rotation} scale(1.05)`; + $card.classList.add('card--moving'); + parentEl.appendChild($card); + + }).on("mouseleave", function (ev) { + let order = ev.currentTarget.getAttribute('data-order'); + let $card = document.querySelector(`.project__card[data-order='${order}']`); + let rotation = $card.getAttribute('style').replace(/.*(rotate\(.*deg\)).*/, '$1'); + $card.style.transform = `${rotation} scale(1)`; + $card.classList.remove('card--moving'); + }); + + // Credits to Chris Coyier https://css-tricks.com/snippets/jquery/done-resizing-event/ + window.onresize = function (e) { + clearTimeout(resizeTimer); + resizeTimer = setTimeout(function () { + const newViewportWidth = $(window).width(); + const newViewportHeight = $(window).height(); + + $cards.each(function (i, el) { + const positionTop = +el.getAttribute('style').replace(/left:.*top: (.*)px; transform.*/, '$1'); + const positionLeft = +el.getAttribute('style').replace(/left: (.*)px; top.*/, '$1'); + + if (newViewportWidth < positionLeft || newViewportHeight < positionTop) { + el.style.left = newViewportWidth < positionLeft ? `${newViewportWidth - 150}px` : `${positionLeft}px`; + el.style.top = newViewportHeight < positionTop ? `${newViewportHeight - 150}px` : `${positionTop}px`; + } + }); + + }, 250); + } + + function makeSamples() { + let newSamples = [...samples(dimensionsArray, $cards.length)]; + if (newSamples.length < $cards.length) { + return makeSamples(); + } else { + let excess = newSamples.length - $cards.length; + if (excess > 0) { + for (let i = 0; i < excess; i++) { + let randomNumber = Math.floor(Math.random() * newSamples.length); + newSamples.splice(randomNumber, 1); + } + } + return newSamples; + } + + } +}); + +// Based on https://observablehq.com/@mbostock/poisson-disk-sampling, credits to Mike Bostock +function* samples([x0, y0, x1, y1], n, k = 30) { + const width = x1 - x0; + const height = y1 - y0; + const radius2 = width * height / (n * 1.5); + const radius = Math.sqrt(radius2); + const radius2_3 = 3 * radius2; + const cellSize = radius * Math.SQRT1_2; + const gridWidth = Math.ceil(width / cellSize); + const gridHeight = Math.ceil(height / cellSize); + const grid = new Array(gridWidth * gridHeight); + const queue = []; + + // Pick the first sample. + yield sample(Math.random() * width, Math.random() * height); + + // Pick a random existing sample from the queue. + pick: while (queue.length) { + const i = Math.random() * queue.length | 0; + const parent = queue[i]; + + // Make a new candidate between [radius, 2 * radius] from the existing sample. + for (let j = 0; j < k; ++j) { + const a = 2 * Math.PI * Math.random(); + const r = Math.sqrt(Math.random() * radius2_3 + radius2); + const x = parent[0] + r * Math.cos(a); + const y = parent[1] + r * Math.sin(a); + + // Accept candidates that are inside the allowed extent + // and farther than 2 * radius to all existing samples. + if (0 <= x && x < width && 0 <= y && y < height && far(x, y)) { + yield sample(x, y); + continue pick; + } + } + + // If none of k candidates were accepted, remove it from the queue. + const r = queue.pop(); + if (i < queue.length) queue[i] = r; + } + + function far(x, y) { + const i = x / cellSize | 0; + const j = y / cellSize | 0; + const i0 = Math.max(i - 2, 0); + const j0 = Math.max(j - 2, 0); + const i1 = Math.min(i + 3, gridWidth); + const j1 = Math.min(j + 3, gridHeight); + for (let j = j0; j < j1; ++j) { + const o = j * gridWidth; + for (let i = i0; i < i1; ++i) { + const s = grid[o + i]; + if (s) { + const dx = s[0] - x; + const dy = s[1] - y; + if (dx * dx + dy * dy < radius2) return false; + } + } + } + return true; + } + + function sample(x, y, parent) { + queue.push(grid[gridWidth * (y / cellSize | 0) + (x / cellSize | 0)] = [x, y]); + return [x + x0, y + y0]; + } +} diff --git a/assets/js/project.js b/assets/js/project.js new file mode 100644 index 0000000..ddd5e92 --- /dev/null +++ b/assets/js/project.js @@ -0,0 +1,25 @@ +(function () { + const options = { root: null, threshold: [0, 0.75] }; + let callback = function (entries, observer) { + entries.forEach(entry => { + // console.log(entry.isIntersecting, entry.intersectionRatio); + + if (entry.isIntersecting) { + $navTitle.classList.remove('title--shown'); + } else { + if (counter > 0) { + $navTitle.classList.add('title--shown'); + } + } + counter++; + }); + }; + + const observer = new IntersectionObserver(callback, options); + const $target = document.querySelector('.header__container h2'); + const $navTitle = document.querySelector('nav h5'); + let counter = 0; + + observer.observe($target); + +})(); \ No newline at end of file diff --git a/assets/js/utils.js b/assets/js/utils.js new file mode 100644 index 0000000..7e4f23d --- /dev/null +++ b/assets/js/utils.js @@ -0,0 +1,69 @@ +let selected = null; +let currentX; +let currentY; +let initialX; +let initialY; +let xOffset = 0; +let yOffset = 0; + +// Will be called when user starts dragging an element +function initDrag(e, el, parent) { + // Store the object of the element which needs to be moved + selected = { el: el, parent: parent }; + if (parent === 'home') { + let parentEl = document.getElementById(parent); + let rotation = el.getAttribute('style').replace(/.*(rotate\(.*deg\)).*/, '$1'); + el.style.transform = `${rotation} scale(1.05)`; + parentEl.appendChild(el); + if (e.type === "touchstart") { + let order = el.getAttribute('data-order'); + let $project = document.querySelector(`.projects__list a[data-order='${order}']`); + $project.classList.add('card--match'); + } + } + el.classList.add('card--moving'); + if (e.type === "touchstart") { + initialX = e.touches[0].clientX - xOffset - selected.el.offsetLeft; + initialY = e.touches[0].clientY - yOffset - selected.el.offsetTop; + } else { + initialX = e.pageX - xOffset - selected.el.offsetLeft; + initialY = e.pageY - yOffset - selected.el.offsetTop; + } +} + +// Will be called when user dragging an element +function dragElement(e) { + if (selected !== null) { + e.preventDefault(); + if (e.type === "touchmove") { + currentX = e.touches[0].clientX - initialX; + currentY = e.touches[0].clientY - initialY; + } else { + currentX = e.clientX - initialX; + currentY = e.clientY - initialY; + } + xOffset = 0; + yOffset = 0; + selected.el.style.left = currentX + 'px'; + selected.el.style.top = currentY + 'px'; + } +} + +// Destroy the object when we are done +function emptySelection(e) { + if (selected !== null) { + if (selected.parent === 'home') { + let rotation = selected.el.getAttribute('style').replace(/.*(rotate\(.*deg\)).*/, '$1'); + selected.el.style.transform = `${rotation} scale(1)`; + if (e.type === "touchend") { + let order = selected.el.getAttribute('data-order'); + let $project = document.querySelector(`.projects__list a[data-order='${order}']`); + $project.classList.remove('card--match'); + } + } + selected.el.classList.remove('card--moving'); + } + initialX = currentX; + initialY = currentY; + selected = null; +} \ No newline at end of file diff --git a/assets/videos/ddweb.mp4 b/assets/videos/ddweb.mp4 new file mode 100644 index 0000000..84ade9e Binary files /dev/null and b/assets/videos/ddweb.mp4 differ diff --git a/assets/videos/fbtrex.mp4 b/assets/videos/fbtrex.mp4 new file mode 100644 index 0000000..531d45a Binary files /dev/null and b/assets/videos/fbtrex.mp4 differ diff --git a/assets/videos/swiss01.mp4 b/assets/videos/swiss01.mp4 new file mode 100644 index 0000000..f51ecb3 Binary files /dev/null and b/assets/videos/swiss01.mp4 differ diff --git a/assets/videos/swiss02.mp4 b/assets/videos/swiss02.mp4 new file mode 100644 index 0000000..7daf702 Binary files /dev/null and b/assets/videos/swiss02.mp4 differ diff --git a/assets/videos/toxicwaste-gif01.mp4 b/assets/videos/toxicwaste-gif01.mp4 new file mode 100755 index 0000000..d0c9797 Binary files /dev/null and b/assets/videos/toxicwaste-gif01.mp4 differ diff --git a/assets/videos/toxicwaste-gif02.mp4 b/assets/videos/toxicwaste-gif02.mp4 new file mode 100755 index 0000000..25a9a08 Binary files /dev/null and b/assets/videos/toxicwaste-gif02.mp4 differ diff --git a/assets/videos/toxicwaste.mp4 b/assets/videos/toxicwaste.mp4 new file mode 100755 index 0000000..7d58b4e Binary files /dev/null and b/assets/videos/toxicwaste.mp4 differ diff --git a/css/style.css b/css/style.css deleted file mode 100644 index fefdbf7..0000000 --- a/css/style.css +++ /dev/null @@ -1,32 +0,0 @@ -html { - font-size: 16px; -} - -body { - padding: 0; - margin: 0; - background-color: #fbfbfb; - font-family: 'IBM Plex Sans', sans-serif; - color: #030718; -} - -.temporary-container { - width: 630px; - height: 100vh; - margin: 0 auto; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - text-align: center; -} -.temporary-container h1 { - font-weight: 600; - font-size: 2.8rem; -} diff --git a/index.html b/index.html index b28800b..6d798f9 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,24 @@ - - - - - Michele Invernizzi - Communication Designer - - - - -
-

I'm upgrading my old website. Be back soon!

-
- - - - +--- +title: Selected Projects – Michele Invernizzi's Portfolio +--- +
+
+ {% assign projects = site.projects | sort: "order" %} + {% for project in projects %} + {{ project.title }} + {% unless forloop.last %} + + {% endunless %} + {% endfor %} +
+ {% assign cards = site.projects | sort: "order" %} + {% for project in cards %} +
+ Thumbnail for project {{ project.title }} +
+ {% endfor %} +
+ \ No newline at end of file diff --git a/js/main.js b/js/main.js deleted file mode 100644 index e69de29..0000000