{{ template "jam_2023_visibility_base.html" . }} {{ define "content" }} {{
$discordInviteURL := "https://discord.gg/hmn" }}

<style>
  .projects {
    display: grid;
    grid-template-columns: 1fr;
  }

  @media screen and (min-width: 30em) {
    /* not small styles */

    .projects {
      grid-template-columns: 1fr 1fr;
    }
  }
</style>

<div>
    <div id="top-container" class="flex flex-column items-center ph3">
    <img id="logo" src="{{ static "visjam2023/logo.svg" }}">
    <h1 id="title">Visibility Jam</h1>
    <h2 id="dates">April 14 - 16, 2O23</h2>
    <div id="tagline" class="center">
        See things in a new way.
        {{ if gt .DaysUntilEnd 0 }}
        {{ if eq .DaysUntilStart 0 }}
            <b>Happening now.</b>
        {{ else if eq .DaysUntilStart 1 }}
            <b>Starting tomorrow.</b>
        {{ else }}
            <b>Starting in {{ .DaysUntilStart }} days.</b>
        {{ end }}
        {{ end }}
    </div>
    <div class="actions flex justify-center">
        {{ if gt .DaysUntilStart 0 }}
        <a
            class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns"
            href="#inspiration"
            >Get inspired</a
        >
        {{ else if gt .DaysUntilEnd 0 }}
        {{ if .SubmittedProjectUrl }}
            <a
            class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns"
            target="_blank"
            href="{{ .SubmittedProjectUrl }}"
            >Share your progress</a
            >
        {{ else }}
            <a
            class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3"
            target="_blank"
            href="{{ .ProjectSubmissionUrl }}"
            >Create your project</a
            >
        {{ end }}
        {{ else }}
        <a
            class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3"
            href="{{ .ShowcaseFeedUrl }}"
            >See the results</a
        >
        {{ end }}
        <a
        class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3"
        target="_blank"
        href="{{ $discordInviteURL }}"
        >Join the Discord</a
        >
    </div>
    </div>

    <div class="section mw8 margin-center ph3 ph4-l mv4">
    <p>
        Too many things in computing are <b>invisible</b>.
    </p>
    <p>
        Bugs linger for years because nobody can see their effects. We run arcane command line tools just to find out what port a program is using. Your computer is full of helpful information, but no one can use it until someone <b>makes it visible.</b>
    </p>
    <p>
        So for this jam, make it visible. Maybe it's a data structure in your program. Maybe it's some obscure metrics from your operating system. Maybe it's your sleep schedule. Whether you make a Graphviz diagram or an experimental code editor, you have a weekend to make it happen.
    </p>
    </div>
</div>

<div class="section pv4">
  <div class="mw8 margin-center ph3 ph4-l">
    <h2>Read the recap</h2>
    <p>Now that the jam is over, see which projects stood out. <a class="b" href="{{ .RecapUrl }}">Full post ➜</a></p>
  </div>
</div>

{{ if eq .DaysUntilEnd 0 }}
<div class="section pv4 overflow-hidden">
  <div class="mw8 margin-center ph3 ph4-l">
    <h2>Submitted projects</h2>
    <div class="mt3 projects g3 back-to-normal">
      {{ range .JamProjects }} {{ template "project_card.html" projectcarddata . "" }} {{ end }}
    </div>
    <div class="actions flex justify-center">
      <a
        class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3"
        href="{{ .ShowcaseFeedUrl }}"
        >See all updates</a
      >
    </div>
  </div>
</div>
{{ else if and (eq .DaysUntilStart 0) (not (eq .ShowcaseJson "[]")) }}
<div id="showcase-outer-container" class="pt4 pb3 pb4-ns">
  <div class="section mw8 margin-center ph3 ph4-l">
    {{ if gt .DaysUntilEnd 0 }}
    <h2>Recent updates</h2>
    <p>
      These screenshots and videos were shared by jam participants in
      <b>#project-showcase</b> on our
      <a href="{{ $discordInviteURL }}" target="_blank">Discord</a>. Join us and
      share what you're working on!
      <a class="b" href="{{ .ShowcaseFeedUrl }}">See all ➜</a>
    </p>
    {{ else }}
    <h2>Community showcase</h2>
    <p>
      These screenshots and videos were shared by jam participants in
      <b>#project-showcase</b> on our
      <a href="https://discord.gg/hmn" target="_blank">Discord</a> during the
      jam. Join us and chat about your favorites!
    </p>
    {{ end }}
    <div id="showcase-container" class="mw8 center-layout mh2 mh0-ns"></div>
    <div class="actions flex justify-center">
      <a
        class="ba b--white br2 pv2 pv3-ns ph3 ph4-ns ml3"
        target="_blank"
        href="{{ .ShowcaseFeedUrl }}"
        >See all</a
      >
    </div>
  </div>
</div>

{{ template "showcase_templates.html" }}
<!-- Copy-pasted and mangled from showcase.html  -->
<script>
  const ROW_HEIGHT = 300;
  const ITEM_SPACING = 4;

  const showcaseItems = JSON.parse("{{ .ShowcaseJson }}");
  const addThumbnailFuncs = new Array(showcaseItems.length);

  const showcaseOuterContainer = document.querySelector(
    "#showcase-outer-container"
  );
  let showcaseContainer = document.querySelector("#showcase-container");

  // showcaseOuterContainer.classList.toggle('dn', showcaseItems.length === 0);

  const itemElements = []; // array of arrays
  for (let i = 0; i < showcaseItems.length; i++) {
    const item = showcaseItems[i];

    const [itemEl, addThumbnail] = makeShowcaseItem(item);
    itemEl.container.setAttribute("data-index", i);
    itemEl.container.setAttribute("data-date", item.date);

    addThumbnailFuncs[i] = addThumbnail;

    itemElements.push(itemEl.container);
  }

  function layout() {
    const width = showcaseContainer.getBoundingClientRect().width;
    showcaseContainer = emptyElement(showcaseContainer);

    function addRow(itemEls, rowWidth, container) {
      const totalSpacing = ITEM_SPACING * (itemEls.length - 1);
      const scaleFactor = width / Math.max(rowWidth, width);

      const row = document.createElement("div");
      row.classList.add("flex");
      row.classList.toggle("justify-between", rowWidth >= width);
      row.style.marginBottom = `${ITEM_SPACING}px`;

      for (const itemEl of itemEls) {
        const index = parseInt(itemEl.getAttribute("data-index"), 10);
        const item = showcaseItems[index];

        const aspect = item.width / item.height;
        const baseWidth = aspect * ROW_HEIGHT * scaleFactor;
        const actualWidth = baseWidth - totalSpacing / itemEls.length;

        itemEl.style.width = `${actualWidth}px`;
        itemEl.style.height = `${scaleFactor * ROW_HEIGHT}px`;
        itemEl.style.marginRight = `${ITEM_SPACING}px`;

        row.appendChild(itemEl);
      }

      container.appendChild(row);
    }

    let rowItemEls = [];
    let rowWidth = 0;
    let numRows = 0;

    for (const itemEl of itemElements) {
      const index = parseInt(itemEl.getAttribute("data-index"), 10);
      const item = showcaseItems[index];

      const aspect = item.width / item.height;
      rowWidth += aspect * ROW_HEIGHT;

      rowItemEls.push(itemEl);

      if (rowWidth > width) {
        addRow(rowItemEls, rowWidth, showcaseContainer);
        numRows += 1;
        if (numRows == 3) {
          return;
        }

        rowItemEls = [];
        rowWidth = 0;
      }
    }

    addRow(rowItemEls, rowWidth, showcaseContainer);
  }

  function loadImages() {
    const items = showcaseContainer.querySelectorAll(".showcase-item");
    for (const item of items) {
      const i = parseInt(item.getAttribute("data-index"), 10);
      addThumbnailFuncs[i]();
    }
  }

  layout();
  layout(); // scrollbars are fun!!

  loadImages();

  window.addEventListener("resize", () => {
    layout();
  });
</script>
{{ end }}

<div id="inspiration" class="pt4">
  <div class="section mw8 margin-center ph3 ph4-l">
    <h2>Inspiration</h2>
  </div>
  <div class="inspiration flex flex-column flex-wrap g3 ph3 ph4-l pt3 pt4-ns pb4 overflow-x-scroll">
    <div class="pic">
      <img src="{{ static "visjam2023/gource.png" }}">
      <div class="caption">Gource lets you watch the structure of a codebase change over time.</div>
    </div>
    <div class="pic">
      <img src="{{ static "visjam2023/npm.png" }}">
      <div class="caption">See how often third-party packages ship breaking changes.</div>
    </div>
    <div class="pic">
      <img src="{{ static "visjam2023/graphviz.jpeg" }}">
      <div class="caption">Graphviz can be used to make debug visuals for almost any data structure.</div>
    </div>
    <div class="pic">
      <img src="{{ static "visjam2023/wireshark.jpg" }}">
      <div class="caption">Wireshark exposes all activity on all your network devices.</div>
    </div>
    <div class="pic">
      <img src="{{ static "visjam2023/spall.png" }}">
      <div class="caption">Flamegraphs let you see the big picture of code execution, not just summary stats.</div>
    </div>
    <div class="pic">
      <blockquote class="twitter-tweet" data-conversation="none" data-dnt="true" data-theme="dark"><p lang="en" dir="ltr">A recipe for finding bugs:<br>* predict what the data should look like<br>* render the data<br>* be surprised and confused</p>&mdash; Jamie Brandon (@sc13ts) <a href="https://twitter.com/sc13ts/status/1600907692788580352?ref_src=twsrc%5Etfw">December 8, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 
    </div>
    <div class="pic">
      <img src="{{ static "visjam2023/v8.png" }}">
      <div class="caption">Bugs can be very obvious when you render out the data. (Example: a random number generator.)</div>
    </div>
    <div class="pic">
      <img src="{{ static "visjam2023/bundle-analyzer.png" }}">
      <div class="caption">Webpack Bundle Analyzer lets you see which JS libraries are causing the most bloat.</div>
    </div>
    <div class="pic">
      <img src="{{ static "visjam2023/vmmap.png" }}">
      <div class="caption">vmmap allows you to see exactly how your address space is allocated.</div>
    </div>
    <div class="pic">
      <blockquote class="twitter-tweet" data-conversation="none" data-dnt="true" data-theme="dark"><p lang="en" dir="ltr">potential dream that we could make visible various graph structures that have been hiding in our computer all along</p>&mdash; Omar Rizwan (@rsnous) <a href="https://twitter.com/rsnous/status/1595969592471461890?ref_src=twsrc%5Etfw">November 25, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 
    </div>
  </div>
</div>

<style>
  .inspiration {
    max-height: 34rem;
    scrollbar-color: rgba(189, 89, 158, 0.58) rgba(0, 0, 0, 0.2);
  }

  .inspiration .pic {
    max-width: 18rem;
  }
  
  @media screen and (min-width: 35em) {
    .inspiration {
      max-height: 42rem;
    }

    .inspiration .pic {
      max-width: 22rem;
    }
  }

  .inspiration .pic .twitter-tweet {
    margin: 0 !important;
  }

  .inspiration .pic img {
    border-radius: 4px;
  }

  .inspiration .pic .caption {
    color: rgba(255, 255, 255, 0.8);
    font-size: 0.8rem;
    line-height: 1.2;
    padding-top: 0.25rem;
  }
</style>

<div class="pt4 pb3 pb4-ns">
  <div class="section mw8 margin-center ph3 ph4-l">
    <h2>How to participate</h2>
    <p>
      The jam takes place from Friday, April 14 through Sunday, April 16. Here's
      how you can participate:
    </p>

    <div class="{{ if gt .DaysUntilStart 0 }}emphasized{{ end }}">
      <h3>Pick a project.</h3>
      <p>
        Pick something to visualize! If you want, you can brainstorm ideas in <b>#jam</b> on <a href="{{ $discordInviteURL }}" target="_blank">Discord</a>. You can also use this time to form a team - or you can choose to work solo.
      </p>
    </div>

    <div
      class="{{ if and (eq .DaysUntilStart 0) (gt .DaysUntilEnd 1) }}emphasized{{ end }}"
    >
      <h3>Jam.</h3>
      <p>
        {{ if and (eq .DaysUntilStart 0) (not .SubmittedProjectUrl) }}
          <a href="{{ .ProjectSubmissionUrl }}" target="_blank">
            <b>Create a Handmade Network project.</b>
          </a>
        {{ else }}
          After the jam starts, create a Handmade Network project.
        {{ end }}
        This project will act as your submission and can be used to share your work in progress. Then get started! Share screenshots and videos in #project-showcase on <a href="{{ $discordInviteURL }}" target="_blank">Discord</a>, or directly from your project page.
      </p>
    </div>

    <div class="{{ if eq .DaysUntilEnd 1 }}emphasized{{ end }}">
      <h3>Submit your work!</h3>
      <p>
        <b>Your Handmade Network project is your submission.</b> Fill out the
        project description, making sure to explain the goals of the project and
        what inspired you to visualize it. Include plenty of pictures and videos!
      </p>
      {{ if and (eq .DaysUntilStart 0) (gt .DaysUntilEnd 0) }}
      <p>
        Submissions close
        <b><span class="countdown" data-deadline="{{ .EndTimeUnix }}"></span></b
        >.
      </p>
      {{ else if eq .DaysUntilEnd 0 }}
      <p>
        <b>Submissions are now closed.</b>
      </p>
      {{ end }}
    </div>
  </div>
</div>

<div class="pt4 pb3 pb4-ns">
  <div class="section mw8 margin-center ph3 ph4-l">
    <h2>Rules</h2>
    <ul>
      <li>Any tech is allowed.</li>
      <li>You may work solo or in a team.</li>
      <li>Submit your work by the end of the day on April 16.</li>
    </ul>
    <p>
      We will not be declaring winners, but we will publicly highlight some of our
      favorite entries after the jam.
    </p>

    <h3>Submission rules</h3>
    <p>
      <b
        >{{ with .SubmittedProjectUrl }}
        <a href="{{ . }}" target="_blank">Your Handmade Network project</a>
        {{ else }} Your Handmade Network project {{ end }} is your
        submission.</b
      >
      We will be looking at the project's description and any extra updates you
      share toward the end of the jam.
    </p>
    <ul>
      <li>
        Explain the project and what inspired you to visualize it.
        Also share some closing thoughts - did it turn out how you hoped? What
        did you learn? If you continue the project, what will you do
        differently?
      </li>
      <li>
        <b
          >Your description must contain multiple screenshots of your software
          in action.</b
        >
        You should ideally also share a project update with a demo video. We
        recommend Mārtiņš Možeiko's
        <a href="https://wcap.handmade.network/" target="_blank">wcap</a> for
        recording desktop video on Windows. On Mac, just press ⌘-Option-5 and
        record a video, or use QuickTime.
      </li>
      <li>
        If at all possible, please provide a way for people to either build or
        download your program, or to interact with any visualizations you produce.
      </li>
    </ul>
  </div>
</div>

<!-- This block of styles removes the top border from the footer and adjusts spacing so it looks better. Use this if the final content block has bg-black-20; comment it out otherwise. -->
<style>
  footer {
    border-top: none;
    margin-bottom: 1rem; /* .mb3 */
  }

  @media screen and (min-width: 60em) {
    footer {
      margin-bottom: 2rem; /* .mb4-l */
    }
  }
</style>

<script>
  const carouselContainer = document.querySelector(".carousel-container");
  if (carouselContainer) {
    const { next, prev } = initCarousel(carouselContainer, {
      onChange() {
        if (carouselContainer.getBoundingClientRect().top < 0) {
          carouselContainer.scrollIntoView({ behavior: "smooth" });
        }
      },
    });

    document
      .querySelector(".carousel-thinger.next")
      .addEventListener("click", () => {
        next();
      });
    document
      .querySelector(".carousel-thinger.prev")
      .addEventListener("click", () => {
        prev();
      });
  }
</script>

<script>
  for (const countdown of document.querySelectorAll(".countdown")) {
    const deadline = countdown.getAttribute("data-deadline");
    const deadlineDate = new Date(parseInt(deadline, 10) * 1000);

    function updateCountdown() {
      const remainingMs = deadlineDate.getTime() - new Date().getTime();
      const remainingMinutes = remainingMs / 1000 / 60;
      const remainingHours = remainingMinutes / 60;
      const remainingDays = remainingHours / 24; // no daylight savings transitions during the jam mmkay

      let str = "imminently";
      if (remainingMinutes < 60) {
        str = `in ${Math.ceil(remainingMinutes)} ${
          remainingMinutes === 1 ? "minute" : "minutes"
        }`;
      } else if (remainingHours < 24) {
        str = `in ${Math.ceil(remainingHours)} ${
          remainingHours === 1 ? "hour" : "hours"
        }`;
      } else {
        str = `in ${Math.ceil(remainingDays)} ${
          remainingDays === 1 ? "day" : "days"
        }`;
      }

      countdown.innerText = str;
    }

    updateCountdown();
    setInterval(updateCountdown, 1000 * 60);
  }
</script>
{{ end }}
