diff --git a/app/core/Router.coffee b/app/core/Router.coffee
index 29ce8a800..f9fe031e7 100644
--- a/app/core/Router.coffee
+++ b/app/core/Router.coffee
@@ -96,6 +96,8 @@ module.exports = class CocoRouter extends Backbone.Router
 
     'github/*path': 'routeToServer'
 
+    'hoc': go('courses/CoursesView')
+
     'i18n': go('i18n/I18NHomeView')
     'i18n/thang/:handle': go('i18n/I18NEditThangTypeView')
     'i18n/component/:handle': go('i18n/I18NEditComponentView')
diff --git a/app/locale/en.coffee b/app/locale/en.coffee
index d114391d5..04e41671f 100644
--- a/app/locale/en.coffee
+++ b/app/locale/en.coffee
@@ -913,7 +913,7 @@
     see_the: "See the"
     more_info: "for more information."
     choose_course: "Choose Your Course:"
-    enter_code: "Enter an unlock code"
+    enter_code: "Enter an unlock code to join an existing class" # {change}
     enter_code1: "Enter unlock code"
     enroll: "Enroll"
     pick_from_classes: "Pick from your current classes"
diff --git a/app/styles/courses/courses.sass b/app/styles/courses/courses.sass
index b1d53ca05..30c9d4192 100644
--- a/app/styles/courses/courses.sass
+++ b/app/styles/courses/courses.sass
@@ -25,9 +25,6 @@
       margin-bottom: 20px
       font-size: 14pt
 
-  .btn-enroll
-    margin-top: 20px
-
   .center
     text-align: center
 
diff --git a/app/templates/courses/courses.jade b/app/templates/courses/courses.jade
index 4d740ada5..f41522b23 100644
--- a/app/templates/courses/courses.jade
+++ b/app/templates/courses/courses.jade
@@ -15,24 +15,44 @@ block content
     if state === 'unknown_error'
       .alert.alert-danger.alert-dismissible= stateMessage
 
-    if studentMode
-      +student-main
+    if hocLandingPage
+      +hoc-landing
     else
-      +teacher-main
-    .container-fluid
-      - var i = 0
-      while i < courses.length
-        .row
-          +course-block(courses[i], instances)
-          - i++
-          if i < courses.length
+      if studentMode
+        +student-main
+      else 
+        if hocMode
+          +teacher-hoc
+        else
+          +teacher-main
+      .container-fluid
+        - var i = 0
+        while i < courses.length
+          .row
             +course-block(courses[i], instances)
             - i++
+            if i < courses.length
+              +course-block(courses[i], instances)
+              - i++
+
+mixin hoc-landing
+  h1.center Welcome Hour of Code!
+  br
+  .container-fluid
+    .row
+      .col-md-6.center
+        button.btn.btn-lg.btn-success.btn-student(data-i18n="courses.students_click")
+      .col-md-6.center
+        button.btn.btn-lg.btn-default.btn-teacher(data-i18n="courses.teachers_click")
 
 mixin student-main
   button.btn.btn-warning.btn-teacher(data-i18n="courses.teachers_click")
   h1.center(data-i18n="courses.courses_on_coco")
 
+mixin teacher-hoc
+  button.btn.btn-warning.btn-student(data-i18n="courses.students_click")
+  h1.center(data-i18n="courses.courses_on_coco")
+
 mixin teacher-main
   button.btn.btn-warning.btn-student(data-i18n="courses.students_click")
   h1.center(data-i18n="courses.courses_on_coco")
@@ -87,6 +107,14 @@ mixin student-dialog(course)
                       input.code-input(type='text', data-course-id="#{course.id}", data-i18n="[placeholder]courses.enter_code1", placeholder="Enter unlock code")
                     .col-md-4
                       button.btn.btn-success.btn-enroll(data-course-id="#{course.id}", data-i18n="courses.enroll")
+                  if hocMode && course.get('pricePerSeat') === 0
+                    .row.button-row.center.row-pick-class
+                      .col-md-12
+                        br
+                        div.or(data-i18n="courses.or")
+                    .row.button-row.center
+                      .col-md-12
+                        button.btn.btn-success.btn-lg.btn-hoc-student-continue(data-course-id="#{course.id}") Continue by yourself
 
 mixin teacher-dialog(course)
   .modal.continue-dialog(id="continueModal#{course.id}")
diff --git a/app/views/courses/CoursesView.coffee b/app/views/courses/CoursesView.coffee
index 7718f13da..2ebd5a53c 100644
--- a/app/views/courses/CoursesView.coffee
+++ b/app/views/courses/CoursesView.coffee
@@ -7,6 +7,8 @@ RootView = require 'views/core/RootView'
 template = require 'templates/courses/courses'
 utils = require 'core/utils'
 
+# TODO: Hour of Code (HoC) integration is a mess
+
 module.exports = class CoursesView extends RootView
   id: 'courses-view'
   template: template
@@ -15,12 +17,15 @@ module.exports = class CoursesView extends RootView
     'click .btn-buy': 'onClickBuy'
     'click .btn-enroll': 'onClickEnroll'
     'click .btn-enter': 'onClickEnter'
+    'click .btn-hoc-student-continue': 'onClickHocStudentContinue'
     'click .btn-student': 'onClickStudent'
     'click .btn-teacher': 'onClickTeacher'
 
   constructor: (options) ->
     super(options)
     @praise = utils.getCoursePraise()
+    @hocLandingPage = Backbone.history.getFragment()?.indexOf('hoc') >= 0
+    @hocMode = utils.getQueryVariable('hoc', false)
     @studentMode = Backbone.history.getFragment()?.indexOf('courses/students') >= 0
     @courses = new CocoCollection([], { url: "/db/course", model: Course})
     @supermodel.loadCollection(@courses, 'courses')
@@ -38,6 +43,8 @@ module.exports = class CoursesView extends RootView
     context = super()
     context.courses = @courses.models ? []
     context.enrolledCourses = @enrolledCourses ? {}
+    context.hocLandingPage = @hocLandingPage
+    context.hocMode = @hocMode
     context.instances = @courseInstances.models ? []
     context.praise = @praise
     context.state = @state
@@ -95,14 +102,58 @@ module.exports = class CoursesView extends RootView
     navigationEvent = route: route, viewClass: viewClass, viewArgs: viewArgs
     Backbone.Mediator.publish 'router:navigate', navigationEvent
 
+  onClickHocStudentContinue: (e) ->
+    $('.continue-dialog').modal('hide')
+    return @openModalView new AuthModal() if me.isAnonymous()
+    courseID = $(e.target).data('course-id')
+
+    @state = 'enrolling'
+    @stateMessage = undefined
+    @render?()
+
+    # TODO: Copied from CourseEnrollView
+
+    data =
+      name: 'Single Player'
+      seats: 9999
+      courseID: courseID
+    jqxhr = $.post('/db/course_instance/-/create', data)
+    jqxhr.done (data, textStatus, jqXHR) =>
+      application.tracker?.trackEvent 'Finished HoC student course creation', {courseID: courseID}
+      # TODO: handle fetch errors
+      me.fetch(cache: false).always =>
+        courseID = courseID
+        route = "/courses/#{courseID}"
+        viewArgs = [{}, courseID]
+        if data?.length > 0
+          courseInstanceID = data[0]._id
+          route += "/#{courseInstanceID}"
+          viewArgs[0].courseInstanceID = courseInstanceID
+        Backbone.Mediator.publish 'router:navigate',
+          route: route
+          viewClass: 'views/courses/CourseDetailsView'
+          viewArgs: viewArgs
+    jqxhr.fail (xhr, textStatus, errorThrown) =>
+      console.error 'Got an error purchasing a course:', textStatus, errorThrown
+      application.tracker?.trackEvent 'Failed HoC student course creation', status: textStatus
+      if xhr.status is 402
+        @state = 'declined'
+        @stateMessage = arguments[2]
+      else
+        @state = 'unknown_error'
+        @stateMessage = "#{xhr.status}: #{xhr.responseText}"
+      @render?()
+
   onClickStudent: (e) ->
     route = "/courses/students"
+    route += "?hoc=true" if @hocLandingPage or @hocMode
     viewClass = require 'views/courses/CoursesView'
     navigationEvent = route: route, viewClass: viewClass, viewArgs: []
     Backbone.Mediator.publish 'router:navigate', navigationEvent
 
   onClickTeacher: (e) ->
     route = "/courses/teachers"
+    route += "?hoc=true" if @hocLandingPage or @hocMode
     viewClass = require 'views/courses/CoursesView'
     navigationEvent = route: route, viewClass: viewClass, viewArgs: []
     Backbone.Mediator.publish 'router:navigate', navigationEvent