diff --git a/.gitignore b/.gitignore
index 11fee36c..baa53f43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,16 @@ log/*.log
tmp/**/*
.env
.vagrant
+
+/app/assets/builds/*
+!/app/assets/builds/.keep
+
+/node_modules
+
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/sdks
+!.yarn/versions
diff --git a/Gemfile b/Gemfile
index 0d244e80..3d39928e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -78,3 +78,5 @@ group :test do
gem 'factory_girl_rails', '~> 4.9'
gem 'rspec-rails', '~> 2.0.0.beta.22'
end
+
+gem "jsbundling-rails", "~> 1.1"
diff --git a/Gemfile.lock b/Gemfile.lock
index 1d4d54c9..6a054bb2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -150,6 +150,8 @@ GEM
http_accept_language (2.1.1)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
+ jsbundling-rails (1.1.2)
+ railties (>= 6.0.0)
launchy (2.5.2)
addressable (~> 2.8)
letter_opener (1.8.1)
@@ -329,6 +331,7 @@ DEPENDENCIES
globalize (~> 6.2, >= 6.2.1)
haml (~> 6.1, >= 6.1.1)
http_accept_language (~> 2.1, >= 2.1.1)
+ jsbundling-rails (~> 1.1)
letter_opener (~> 1.8, >= 1.8.1)
memcache-client (~> 1.8.5)
mysql2 (~> 0.5.5)
@@ -354,4 +357,4 @@ RUBY VERSION
ruby 3.1.4p223
BUNDLED WITH
- 2.4.18
+ 2.3.26
diff --git a/Procfile.dev b/Procfile.dev
new file mode 100644
index 00000000..faaa7582
--- /dev/null
+++ b/Procfile.dev
@@ -0,0 +1,2 @@
+web: unset PORT && env RUBY_DEBUG_OPEN=true bin/rails server
+js: yarn build --watch
diff --git a/app/assets/builds/.keep b/app/assets/builds/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/app/javascript/wardrobe-2020-page.js b/app/javascript/wardrobe-2020-page.js
new file mode 100644
index 00000000..1d31ac65
--- /dev/null
+++ b/app/javascript/wardrobe-2020-page.js
@@ -0,0 +1,3 @@
+import { WardrobePage } from "./wardrobe-2020";
+
+console.log("Hello, wardrobe page!", WardrobePage);
diff --git a/app/javascript/wardrobe-2020/ItemPage.js b/app/javascript/wardrobe-2020/ItemPage.js
new file mode 100644
index 00000000..3a7bfc45
--- /dev/null
+++ b/app/javascript/wardrobe-2020/ItemPage.js
@@ -0,0 +1,1442 @@
+import React from "react";
+import { ClassNames } from "@emotion/react";
+import {
+ AspectRatio,
+ Button,
+ Box,
+ HStack,
+ IconButton,
+ SkeletonText,
+ Tooltip,
+ VisuallyHidden,
+ VStack,
+ useBreakpointValue,
+ useColorModeValue,
+ useTheme,
+ useToast,
+ Flex,
+ usePrefersReducedMotion,
+ Grid,
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+ Checkbox,
+} from "@chakra-ui/react";
+import {
+ CheckIcon,
+ ChevronDownIcon,
+ ChevronRightIcon,
+ EditIcon,
+ StarIcon,
+ WarningIcon,
+} from "@chakra-ui/icons";
+import { MdPause, MdPlayArrow } from "react-icons/md";
+import gql from "graphql-tag";
+import { useQuery, useMutation } from "@apollo/client";
+import Link from "next/link";
+
+import ItemPageLayout, { SubtleSkeleton } from "./ItemPageLayout";
+import {
+ Delay,
+ logAndCapture,
+ MajorErrorMessage,
+ useLocalStorage,
+} from "./util";
+import HTML5Badge, { layerUsesHTML5 } from "./components/HTML5Badge";
+import {
+ itemAppearanceFragment,
+ petAppearanceFragment,
+} from "./components/useOutfitAppearance";
+import { useOutfitPreview } from "./components/OutfitPreview";
+import SpeciesColorPicker, {
+ useAllValidPetPoses,
+ getValidPoses,
+ getClosestPose,
+} from "./components/SpeciesColorPicker";
+import useCurrentUser from "./components/useCurrentUser";
+import SpeciesFacesPicker, {
+ colorIsBasic,
+} from "./ItemPage/SpeciesFacesPicker";
+import { useRouter } from "next/router";
+import Head from "next/head";
+
+function ItemPage() {
+ const { query } = useRouter();
+ return